hap-fluent / FluentService
Type Alias: FluentService<T>
type FluentService<T> = InterfaceForService<T> & {
characteristics: { [K in CharacteristicNamesOf<T> as CamelCase<K>]: FluentCharacteristic<InterfaceForService<T>[K] & CharacteristicValue> };
onGet: void;
onSet: void;
update: void;
};Defined in: packages/hap-fluent/src/FluentService.ts:79
Strongly-typed, fluent view of a HAP service and all its characteristics.
Type Declaration
| Name | Type | Description | Defined in |
|---|---|---|---|
characteristics | { [K in CharacteristicNamesOf<T> as CamelCase<K>]: FluentCharacteristic<InterfaceForService<T>[K] & CharacteristicValue> } | Collection of all characteristics for this service Keys are camelCase characteristic names (e.g., 'on', 'brightness') | packages/hap-fluent/src/FluentService.ts:84 |
onGet() | (key, callback) => void | Register an async getter for a characteristic Example service.onGet('on', async () => { const state = await getDeviceState(); return state.isOn; }); | packages/hap-fluent/src/FluentService.ts:103 |
onSet() | (key, callback) => void | Register an async setter for a characteristic Example service.onSet('on', async (value) => { await setDeviceState({ isOn: value }); }); | packages/hap-fluent/src/FluentService.ts:120 |
update() | (key, value) => void | Update a characteristic value without triggering SET handlers Example // Update brightness from external state change service.update('brightness', newBrightness); | packages/hap-fluent/src/FluentService.ts:136 |
Type Parameters
| Type Parameter | Description |
|---|---|
T extends typeof Service | HAP service class constructor (e.g., typeof hap.Service.Lightbulb). |
Remarks
FluentService<T> is an intersection of the generated HAP interface for service T and a set of helper methods (onGet, onSet, update) plus a characteristics map of FluentCharacteristic instances keyed by camelCase characteristic name.
Shorthand property accessors (both camelCase on and PascalCase On) are defined at runtime via Object.defineProperty so that TypeScript infers the correct value type from the service interface.
The type parameter T must be a HAP service constructor with an interface declaration (generated by hap-codegen). Without the generated interface, InterfaceForService<T> resolves to never and the type collapses.
Use When
- You are building a Homebridge plugin that wraps one or more HAP services.
- You want compile-time IntelliSense on characteristic names and their value types (booleans, numbers, strings) for a specific service.
- You need to register
onGet/onSethandlers or update characteristic values without manually typing characteristic display names.
Avoid When
- You need direct hap-nodejs
Serviceaccess (e.g.,service.getCharacteristic(),service.setPrimaryService(true)) —FluentServicedoes not expose all service methods; obtain the raw service viaplatformAccessory.getService(). - Your accessory has a single, trivial characteristic —
hap-nodejsdirectly may be simpler and incurs no overhead.
Pitfalls
- NEVER register the same characteristic handler twice on the same service — hap-nodejs silently replaces the first handler, causing the original logic to be permanently dropped with no runtime error.
- NEVER mutate
characteristicsafterplatformAccessoryhas been published viaapi.registerPlatformAccessories()— hap-nodejs caches the service state at publish time; post-publish structural changes cause a silent desync with the iOS Home controller. - NEVER assume
characteristicscontains characteristics that were not present on the service whenwrapService()was called — optional HAP characteristics must be added to the service before wrapping. - NEVER mix PascalCase and camelCase for the same characteristic in one handler registration call — the shorthand properties are aliases; prefer consistent camelCase to avoid confusion.
Example
import { getOrAddService } from 'hap-fluent';
const lightbulb = getOrAddService(accessory, hap.Service.Lightbulb, 'Living Room');
// Register HomeKit GET/SET handlers
lightbulb.onGet('on', async () => await getLightState());
lightbulb.onSet('on', async (value) => await setLightState(value));
// Programmatic update (no SET handler triggered, notifies HomeKit)
lightbulb.update('brightness', 75);
// Shorthand property access
lightbulb.on = false;
const brightness = lightbulb.brightness; // number