UNPKG

homebridge

Version:
238 lines 12.4 kB
/** * Helper functions for MatterServer.registerAccessory() * Extracted from the monolithic 521-line function for better maintainability */ import type { EndpointType } from '@matter/main'; import type { LevelControl } from '@matter/main/clusters/level-control'; import type { Behavior } from '@matter/node'; import type { MatterAccessory } from './types.js'; /** * Type representing a behavior class (constructor) */ type BehaviorType = Behavior.Type; /** * Cluster IDs from Matter specification * Using Matter.js Cluster references instead of magic numbers */ export declare const CLUSTER_IDS: { readonly AIR_QUALITY: import("@matter/main").Brand<"ClusterId"> & 91; readonly CARBON_MONOXIDE_CONCENTRATION: import("@matter/main").Brand<"ClusterId"> & 1036; readonly CLOSURE_CONTROL: import("@matter/main").Brand<"ClusterId"> & 260; readonly COLOR_CONTROL: import("@matter/main").Brand<"ClusterId"> & 768; readonly DOOR_LOCK: import("@matter/main").Brand<"ClusterId"> & 257; readonly KEYPAD_INPUT: import("@matter/main").Brand<"ClusterId"> & 1289; readonly LEVEL_CONTROL: import("@matter/main").Brand<"ClusterId"> & 8; readonly MEDIA_PLAYBACK: import("@matter/main").Brand<"ClusterId"> & 1286; readonly NITROGEN_DIOXIDE_CONCENTRATION: import("@matter/main").Brand<"ClusterId"> & 1043; readonly ON_OFF: import("@matter/main").Brand<"ClusterId"> & 6; readonly OZONE_CONCENTRATION: import("@matter/main").Brand<"ClusterId"> & 1045; readonly PM10_CONCENTRATION: import("@matter/main").Brand<"ClusterId"> & 1069; readonly PM25_CONCENTRATION: import("@matter/main").Brand<"ClusterId"> & 1066; readonly THERMOSTAT: import("@matter/main").Brand<"ClusterId"> & 513; readonly WINDOW_COVERING: import("@matter/main").Brand<"ClusterId"> & 258; }; /** * Validates required fields on a Matter accessory * @throws MatterDeviceError if validation fails */ export declare function validateAccessoryRequiredFields(accessory: MatterAccessory): void; /** * Generic feature detection from device type behaviors * Extracts supported features from a device type's cluster definition * * @param deviceType - The Matter device type * @param clusterIdOrName - Cluster ID (number) or name (string) * @param featureExtractor - Function to extract feature names from supportedFeatures * @returns Array of detected features or null if cluster not found */ export declare function detectBehaviorFeatures(deviceType: EndpointType, clusterIdOrName: number | string, featureExtractor: (supportedFeatures: Record<string, boolean>) => string[]): string[] | null; /** * Extract whatever features a behavior already declares, whatever the cluster. * * matter.js records a composed behavior's features as camelCase booleans and * `.with(...)` takes the PascalCase names, so carrying a feature set across is * just a capitalise - the same mapping the per-cluster extractors below do by * hand (`hueSaturation` to `HueSaturation`, `xy` to `Xy`). * * Used for clusters whose features we have no reason to reason about. We only * need them preserved when a Homebridge behavior replaces the base one, and a * hand-written list would silently drop any feature matter.js adds later. */ export declare function extractDeclaredFeatures(supportedFeatures: Record<string, boolean>): string[]; /** * Extract ColorControl features from supportedFeatures */ export declare function extractColorControlFeatures(supportedFeatures: Record<string, boolean>): string[]; /** * Extract Thermostat features from supportedFeatures */ export declare function extractThermostatFeatures(supportedFeatures: Record<string, boolean>): string[]; /** * Extract LevelControl features from supportedFeatures. * * Used to read features off a device type's declared LevelControl requirement * (e.g. DimmableLightDevice's `LevelControlServer.with("Lighting","OnOff")`). * When the device type doesn't declare LevelControl at all (e.g. PumpDevice, * which has LevelControl only in its `optional` requirements and not in * `SupportedBehaviors`), the caller should apply an empty feature set via * `.with()` so the Lighting feature inherited from matter.js's internal * `LevelControlBase = LevelControlBehavior.with(OnOff, Lighting)` is stripped * — otherwise the Pump endpoint inherits the `[LT]` branch of the spec * (minLevel constraint 1-254, initializeLighting warnings) that only applies * to lighting devices. */ export declare function extractLevelControlFeatures(supportedFeatures: Record<string, boolean>): LevelControl.Features[]; /** * Determine ColorControl features based on handlers * Only includes features that have corresponding handler methods */ export declare function determineColorControlFeaturesFromHandlers(handlers: Record<string, unknown>): string[]; /** * Determine ColorControl features from the cluster's own attributes. * * The handler-based detection above cannot work on a cache restore: handlers are * functions, so they are not cached, and the restore synthesizes empty stubs in * their place. That left ColorControl with no features at all, and a persisted * `colorTemperatureMireds` or `currentHue` then failed Matter's conformance check * ("Matter does not allow you to set this attribute") and took the whole accessory * registration down with it. * * The attributes do survive the cache, so they are what we fall back to - the same * approach {@link detectWindowCoveringFeatures} already takes. * * @param clusters - the accessory's cluster state * @returns Array of detected feature names */ export declare function determineColorControlFeaturesFromClusters(clusters: Record<string, unknown> | undefined): string[]; /** * Detect WindowCovering features from accessory attributes * Auto-detects Lift and Tilt capabilities based on cluster attributes * * @param accessory - Matter accessory to inspect * @returns Array of detected feature names */ export declare function detectWindowCoveringFeatures(accessory: MatterAccessory): string[]; /** * Detect SmokeCoAlarm features from accessory attributes. * The Matter spec requires at least one of SmokeAlarm/CoAlarm, so an accessory * that declares neither state attribute falls back to SmokeAlarm — matching the * friendly device type name "SmokeSensor". */ export declare function detectSmokeCoAlarmFeatures(accessory: MatterAccessory): string[]; /** * Apply SmokeCoAlarm features to device type. * SmokeCoAlarm is not part of the base SmokeCoAlarmDevice — matter.js requires * the features to be chosen — so without this the endpoint would be created * without the cluster and the accessory's smokeCoAlarm state silently dropped. */ export declare function applySmokeCoAlarmFeatures(deviceType: EndpointType, accessory: MatterAccessory, features: string[]): EndpointType; /** * Raise a LevelControl floor of 0 to 1 when the Lighting feature is active. * * The Lighting feature reserves level 0 for "off", so the spec constrains * MinLevel to 1-254 and matter.js rejects 0 outright. Homebridge's own guidance * has suggested `minLevel: 0`, so accessories in the wild carry it. Lift those * to 1 with a warning rather than refusing to register the accessory. */ export declare function applyLevelControlLightingFloor(accessory: MatterAccessory, levelControlFeatures: string[] | null): void; /** * Detect Thermostat features from accessory attributes. * * A thermostat that only heats should not advertise cooling, so the features * follow the setpoints the accessory actually declares. The Matter spec requires * at least one of Heating/Cooling, so an accessory declaring neither falls back * to Heating. AutoMode is only meaningful when the device can do both, and * Occupancy only when the unoccupied setpoints are present. */ export declare function detectThermostatFeatures(accessory: MatterAccessory): string[]; /** * Check that an AutoMode thermostat's setpoint LIMITS can satisfy its deadband. * * ⚠️ The deadband applies to the limits, not only to the setpoints. matter.js * requires both of these, in 0.01°C: * maxCoolSetpointLimit - maxHeatSetpointLimit >= deadband * minCoolSetpointLimit - minHeatSetpointLimit >= deadband * * `minSetpointDeadBand` is declared in 0.1°C, so it is multiplied by 10 first. * * This is easy to get wrong and the symptom is badly disconnected from the * cause: the endpoint is created happily, then EVERY later setpoint update * fails with "Thermostat setpoints could not be reconciled within the * configured limits". matter.js 0.17.6 only validated the attribute being * written, so an impossible configuration went unnoticed until 0.17.7 began * validating the whole cluster. Warning here points at the real problem. * * Returns a message describing the problem, or undefined when the limits are * satisfiable. */ export declare function checkThermostatSetpointLimits(accessory: MatterAccessory, features: string[]): string | undefined; /** * Apply Thermostat features to device type. * Thermostat is not part of the base ThermostatDevice — matter.js requires the * features to be chosen — so without this the endpoint would be created without * the cluster and the accessory's thermostat state silently dropped. */ export declare function applyThermostatFeatures(deviceType: EndpointType, accessory: MatterAccessory, features: string[]): EndpointType; /** * Detect ServiceArea features from cluster attributes */ export declare function detectServiceAreaFeatures(serviceAreaCluster: Record<string, unknown> | undefined): string[]; /** * Apply WindowCovering features to device type */ export declare function applyWindowCoveringFeatures(deviceType: EndpointType, accessory: MatterAccessory, features: string[]): EndpointType; /** * Build custom behaviors for RoboticVacuumCleaner devices */ export declare function buildRvcCustomBehaviors(accessory: MatterAccessory, serviceAreaFeatures: string[] | null): BehaviorType[]; /** * Apply detected features to a behavior class */ export declare function applyFeaturesToBehavior(behaviorClass: BehaviorType, features: string[] | null, clusterName: string): BehaviorType; /** * The subset of an accessory (or composed-device part) the electrical * measurement helpers need - lets the same detection run for both. */ export interface ElectricalMeasurementHost { clusters?: MatterAccessory['clusters']; displayName?: string; } /** * Result of detecting electrical measurement clusters on an accessory */ export interface ElectricalMeasurementDetection { /** Accessory declares electricalPowerMeasurement cluster state */ hasPowerMeasurement: boolean; /** * ElectricalEnergyMeasurement features derived from the declared attributes * (empty when the cluster is not declared) */ energyFeatures: string[]; } /** * Detect electrical measurement clusters from the accessory's declared state. * * ElectricalEnergyMeasurement is feature-gated in matter.js (Imported/Exported * x Cumulative/Periodic), so the features are chosen from which energy * attributes the accessory declares. */ export declare function detectElectricalMeasurementClusters(accessory: ElectricalMeasurementHost): ElectricalMeasurementDetection; /** * Fill in the mandatory ElectricalPowerMeasurement / ElectricalEnergyMeasurement * attributes (powerMode, numberOfMeasurementTypes, accuracy) that plugins should * not have to write themselves. Mutates the accessory's declared cluster state * so the values flow into the endpoint options and the state cache together. */ export declare function applyElectricalMeasurementDefaults(accessory: ElectricalMeasurementHost, detection: ElectricalMeasurementDetection): void; /** * Apply the electrical measurement behaviors to a device type. * * PowerTopology is mandatory on the ElectricalSensor device type and is * feature-gated in matter.js; TreeTopology fits a bridged endpoint that * measures itself. The EEM server keeps matter.js's setMeasurement() helper, * which also emits the CumulativeEnergyMeasured / PeriodicEnergyMeasured * events required by the spec. */ export declare function applyElectricalMeasurementClusters(deviceType: EndpointType, accessory: ElectricalMeasurementHost, detection: ElectricalMeasurementDetection): EndpointType; export {}; //# sourceMappingURL=serverHelpers.d.ts.map