Skip to content

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 @homebridge/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() or FluentService.update() instead.
  • You need raw @homebridge/hap-nodejs Characteristic access (e.g., to call characteristic.getDefaultValue()) — retrieve .characteristic from the underlying service object, or use @homebridge/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 onGet or onSet handler on the same characteristic — @homebridge/hap-nodejs replaces the previous handler without warning, and the first handler's logic is silently dropped.
  • NEVER pass null to set() — isCharacteristicValue rejects null and throws FluentCharacteristicError; use update() only with typed values.
  • NEVER add interceptors after registering onGet/onSet handlers — the interceptor chain is captured at onGet/onSet call time; later .clamp() or .log() calls will not apply to already-registered handlers.
  • NEVER assume interceptors apply to direct set() calls — they only wrap onGet/onSet handlers triggered by HomeKit polling or user actions.

Example ​

typescript
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 ParameterDescription
T extends CharacteristicValueThe TypeScript value type for this characteristic (boolean, number, string, or CharacteristicValue).

Constructors ​

Constructor ​

ts
new FluentCharacteristic<T>(characteristic): FluentCharacteristic<T>;

Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:91

Parameters ​

ParameterTypeDescription
characteristicCharacteristicHAP characteristic to wrap.

Returns ​

FluentCharacteristic<T>

Methods ​

audit() ​

ts
audit(maxEntries?): this;

Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:398

Add audit trail interceptor that tracks all operations.

Parameters ​

ParameterTypeDefault value
maxEntriesnumber1000

Returns ​

this

This FluentCharacteristic instance for chaining

Example ​

typescript
characteristic.audit().onSet(handler); // Logs audit trail

clamp() ​

ts
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 ​

ParameterTypeDescription
minnumberMinimum value (inclusive)
maxnumberMaximum value (inclusive)

Returns ​

this

This FluentCharacteristic instance for chaining

Example ​

typescript
characteristic.clamp(0, 100).onSet(handler); // Ensures value is 0-100

clearInterceptors() ​

ts
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() ​

ts
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 ​

ParameterTypeDescription
encode(value) => CharacteristicValueFunction to transform values when setting (to HAP format)
decode(value) => CharacteristicValueFunction to transform values when getting (from HAP format)

Returns ​

this

This FluentCharacteristic instance for chaining

Example ​

typescript
// 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() ​

ts
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() ​

ts
limit(maxCalls, windowMs): this;

Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:350

Add rate limiting interceptor to prevent excessive updates.

Parameters ​

ParameterTypeDescription
maxCallsnumberMaximum number of calls allowed
windowMsnumberTime window in milliseconds

Returns ​

this

This FluentCharacteristic instance for chaining

Example ​

typescript
characteristic.limit(5, 1000).onSet(handler); // Max 5 calls per second

log() ​

ts
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 ​

typescript
characteristic.log().onSet(async (value) => {
  console.log('Value from HomeKit:', value);
});

onGet() ​

ts
onGet(handler): this;

Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:223

Register an async getter for the characteristic.

Parameters ​

ParameterTypeDescription
handler() => Promise<T>Async getter returning the current value.

Returns ​

this

This FluentCharacteristic instance for chaining.


onSet() ​

ts
onSet(handler): this;

Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:267

Register an async setter for the characteristic.

Parameters ​

ParameterTypeDescription
handler(value) => Promise<void>Async setter receiving the new value.

Returns ​

this

This FluentCharacteristic instance for chaining.


set() ​

ts
set(value): this;

Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:130

Set the characteristic value.

Parameters ​

ParameterTypeDescription
valueTNew 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() ​

ts
setProps(props): this;

Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:99

Update the characteristic's metadata properties.

Parameters ​

ParameterTypeDescription
propsPartialAllowingNull<CharacteristicProps>Partial characteristic properties to apply.

Returns ​

this

This FluentCharacteristic instance for chaining.


transform() ​

ts
transform(transformFn): this;

Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:383

Add value transformation interceptor that applies a custom function.

Parameters ​

ParameterTypeDescription
transformFn(value) => CharacteristicValueFunction to transform the value

Returns ​

this

This FluentCharacteristic instance for chaining

Example ​

typescript
characteristic.transform(v => Math.round(v as number)).onSet(handler);

update() ​

ts
update(value): this;

Defined in: packages/hap-fluent/src/FluentCharacteristic.ts:178

Update the characteristic value without calling SET handlers.

Parameters ​

ParameterTypeDescription
valueTNew value to apply.

Returns ​

this

This FluentCharacteristic instance for chaining.

Throws ​

If value is invalid or updateValue fails

Released under the Apache-2.0 License.