hap-fluent / FluentCharacteristic
Class: FluentCharacteristic<T>
Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:85
Type-safe, chainable wrapper around a single HAP-NodeJS Characteristic.
Remarks
Every HomeKit characteristic has a HAP-specified UUID, a value type (boolean, number, string, or object), and optional min/max/step constraints defined in the HAP specification. FluentCharacteristic enforces the TypeScript-level type via the T type parameter and delegates all runtime mutations to the underlying hap-nodejs characteristic so the HomeKit protocol contract is never broken.
Interceptors (logging, rate-limiting, clamping, codec, transform) are executed only inside onGet/onSet handler pipelines — not when you call set() or update() directly from your plugin code.
Use When
- You need fine-grained control over a single characteristic (interceptors, value clamping, codec translation, audit trail).
- You want to chain
.clamp().log().onSet(handler)declaratively. - You're wrapping a characteristic returned by
FluentService.characteristics.
Avoid When
- You only need bulk initial-value assignment — use
initializeAccessory()orFluentService.update()instead. - You need raw hap-nodejs
Characteristicaccess (e.g., to callcharacteristic.getDefaultValue()) — retrieve.characteristicfrom the underlying service object, or use hap-nodejs directly.
Pitfalls
- NEVER call
set()with a value outside the HAP-specified range for that characteristic — iOS silently discards accessories that violate type constraints, causing the Home app to show the device as "Not Responding". - NEVER register more than one
onGetoronSethandler on the same characteristic — hap-nodejs replaces the previous handler without warning, and the first handler's logic is silently dropped. - NEVER pass
nulltoset()—isCharacteristicValuerejectsnulland throwsFluentCharacteristicError; useupdate()only with typed values. - NEVER add interceptors after registering
onGet/onSethandlers — the interceptor chain is captured atonGet/onSetcall time; later.clamp()or.log()calls will not apply to already-registered handlers. - NEVER assume interceptors apply to direct
set()calls — they only wraponGet/onSethandlers triggered by HomeKit polling or user actions.
Example
import { getOrAddService } from 'hap-fluent';
const lightbulb = getOrAddService(accessory, hap.Service.Lightbulb);
lightbulb.characteristics.brightness
.clamp(0, 100) // clamp incoming HomeKit values to valid range
.log() // log all get/set operations
.onGet(async () => currentBrightness)
.onSet(async (value) => { currentBrightness = value; });
// Programmatic update (no SET handler triggered)
lightbulb.characteristics.brightness.update(75);Type Parameters
| Type Parameter | Description |
|---|---|
T extends CharacteristicValue | The TypeScript value type for this characteristic (boolean, number, string, or CharacteristicValue). |
Constructors
Constructor
new FluentCharacteristic<T>(characteristic): FluentCharacteristic<T>;Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:91
Parameters
| Parameter | Type | Description |
|---|---|---|
characteristic | Characteristic | HAP characteristic to wrap. |
Returns
FluentCharacteristic<T>
Methods
audit()
audit(maxEntries?): this;Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:398
Add audit trail interceptor that tracks all operations.
Parameters
| Parameter | Type | Default value |
|---|---|---|
maxEntries | number | 1000 |
Returns
this
This FluentCharacteristic instance for chaining
Example
characteristic.audit().onSet(handler); // Logs audit trailclamp()
clamp(min, max): this;Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:367
Add value clamping interceptor to ensure numeric values stay within bounds.
Parameters
| Parameter | Type | Description |
|---|---|---|
min | number | Minimum value (inclusive) |
max | number | Maximum value (inclusive) |
Returns
this
This FluentCharacteristic instance for chaining
Example
characteristic.clamp(0, 100).onSet(handler); // Ensures value is 0-100clearInterceptors()
clearInterceptors(): this;Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:482
Remove all interceptors from this characteristic.
Returns
this
This FluentCharacteristic instance for chaining
codec()
codec(encode, decode): this;Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:469
Add a codec interceptor for two-way value transformation.
Codecs allow you to transform values when setting (encode) and retrieving (decode). This is useful for converting between different formats or units.
Parameters
| Parameter | Type | Description |
|---|---|---|
encode | (value) => CharacteristicValue | Function to transform values when setting (to HAP format) |
decode | (value) => CharacteristicValue | Function to transform values when getting (from HAP format) |
Returns
this
This FluentCharacteristic instance for chaining
Example
// Convert between Celsius and Fahrenheit
characteristic.codec(
(celsius) => (celsius * 9/5) + 32, // encode: C to F
(fahrenheit) => (fahrenheit - 32) * 5/9 // decode: F to C
).onSet(async (fahrenheit) => {
console.log('Temperature in F:', fahrenheit);
});
// Convert between different string formats
characteristic.codec(
(value) => String(value).toUpperCase(), // encode
(value) => String(value).toLowerCase() // decode
);
// Convert complex objects to/from JSON
characteristic.codec(
(obj) => JSON.stringify(obj), // encode
(str) => JSON.parse(String(str)) // decode
);get()
get(): T | undefined;Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:109
Get the current characteristic value.
Returns
T | undefined
The current characteristic value, or undefined if not set.
limit()
limit(maxCalls, windowMs): this;Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:350
Add rate limiting interceptor to prevent excessive updates.
Parameters
| Parameter | Type | Description |
|---|---|---|
maxCalls | number | Maximum number of calls allowed |
windowMs | number | Time window in milliseconds |
Returns
this
This FluentCharacteristic instance for chaining
Example
characteristic.limit(5, 1000).onSet(handler); // Max 5 calls per secondlog()
log(): this;Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:333
Add logging interceptor that logs all operations (beforeSet, afterSet, beforeGet, afterGet, errors).
Returns
this
This FluentCharacteristic instance for chaining
Example
characteristic.log().onSet(async (value) => {
console.log('Value from HomeKit:', value);
});onGet()
onGet(handler): this;Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:223
Register an async getter for the characteristic.
Parameters
| Parameter | Type | Description |
|---|---|---|
handler | () => Promise<T> | Async getter returning the current value. |
Returns
this
This FluentCharacteristic instance for chaining.
onSet()
onSet(handler): this;Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:267
Register an async setter for the characteristic.
Parameters
| Parameter | Type | Description |
|---|---|---|
handler | (value) => Promise<void> | Async setter receiving the new value. |
Returns
this
This FluentCharacteristic instance for chaining.
set()
set(value): this;Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:130
Set the characteristic value.
Parameters
| Parameter | Type | Description |
|---|---|---|
value | T | New value to set. |
Returns
this
This FluentCharacteristic instance for chaining.
Throws
If value is invalid or setValue fails
Remarks
This method is for direct programmatic value setting. Interceptors are applied in onSet handlers, which are triggered when HomeKit accesses the characteristic.
setProps()
setProps(props): this;Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:99
Update the characteristic's metadata properties.
Parameters
| Parameter | Type | Description |
|---|---|---|
props | PartialAllowingNull<CharacteristicProps> | Partial characteristic properties to apply. |
Returns
this
This FluentCharacteristic instance for chaining.
transform()
transform(transformFn): this;Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:383
Add value transformation interceptor that applies a custom function.
Parameters
| Parameter | Type | Description |
|---|---|---|
transformFn | (value) => CharacteristicValue | Function to transform the value |
Returns
this
This FluentCharacteristic instance for chaining
Example
characteristic.transform(v => Math.round(v as number)).onSet(handler);update()
update(value): this;Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:178
Update the characteristic value without calling SET handlers.
Parameters
| Parameter | Type | Description |
|---|---|---|
value | T | New value to apply. |
Returns
this
This FluentCharacteristic instance for chaining.
Throws
If value is invalid or updateValue fails