homebridge
Version:
HomeKit support for the impatient
354 lines • 14.8 kB
JavaScript
/**
* Matter Types for Homebridge Plugin API
*
* This module provides types and interfaces for plugin developers
* to create Matter-compatible accessories.
*/
/**
* Optimized Matter.js Device and Cluster Imports
*
* Imports Matter.js devices and clusters from individual files instead of barrel exports,
* which dramatically reduces startup time.
*
* Why this matters:
* - Barrel import: `import * as devices from '@matter/main/devices'` loads ALL 186+ exports (~800ms)
* - Individual imports: Only loads the 23 devices we actually use (~50-100ms)
* - Result: 50-100x faster on powerful machines, even more improvement on Raspberry Pi
*
* This optimization is especially important for users on resource-constrained devices like
* Raspberry Pi where the difference can be several minutes of startup time.
*/
// Direct imports from individual cluster files
import { AirQuality } from '@matter/main/clusters/air-quality';
import { BooleanState } from '@matter/main/clusters/boolean-state';
import { CarbonMonoxideConcentrationMeasurement } from '@matter/main/clusters/carbon-monoxide-concentration-measurement';
import { ColorControl } from '@matter/main/clusters/color-control';
import { DoorLock } from '@matter/main/clusters/door-lock';
import { FanControl } from '@matter/main/clusters/fan-control';
import { LevelControl } from '@matter/main/clusters/level-control';
import { NitrogenDioxideConcentrationMeasurement } from '@matter/main/clusters/nitrogen-dioxide-concentration-measurement';
import { OnOff } from '@matter/main/clusters/on-off';
import { OzoneConcentrationMeasurement } from '@matter/main/clusters/ozone-concentration-measurement';
import { Pm10ConcentrationMeasurement } from '@matter/main/clusters/pm10-concentration-measurement';
import { Pm25ConcentrationMeasurement } from '@matter/main/clusters/pm25-concentration-measurement';
import { RvcOperationalState } from '@matter/main/clusters/rvc-operational-state';
import { Thermostat } from '@matter/main/clusters/thermostat';
import { ValveConfigurationAndControl } from '@matter/main/clusters/valve-configuration-and-control';
import { WindowCovering } from '@matter/main/clusters/window-covering';
// Direct imports from individual device files
import { AirQualitySensorDevice } from '@matter/main/devices/air-quality-sensor';
import { ColorTemperatureLightDevice } from '@matter/main/devices/color-temperature-light';
import { ContactSensorDevice } from '@matter/main/devices/contact-sensor';
import { DimmableLightDevice } from '@matter/main/devices/dimmable-light';
import { DimmablePlugInUnitDevice } from '@matter/main/devices/dimmable-plug-in-unit';
import { DoorLockDevice } from '@matter/main/devices/door-lock';
import { ExtendedColorLightDevice } from '@matter/main/devices/extended-color-light';
import { FanDevice } from '@matter/main/devices/fan';
import { GenericSwitchDevice } from '@matter/main/devices/generic-switch';
import { HumiditySensorDevice } from '@matter/main/devices/humidity-sensor';
import { LightSensorDevice } from '@matter/main/devices/light-sensor';
import { OccupancySensorDevice } from '@matter/main/devices/occupancy-sensor';
import { OnOffLightDevice } from '@matter/main/devices/on-off-light';
import { OnOffLightSwitchDevice } from '@matter/main/devices/on-off-light-switch';
import { OnOffPlugInUnitDevice } from '@matter/main/devices/on-off-plug-in-unit';
import { PumpDevice } from '@matter/main/devices/pump';
import { RoboticVacuumCleanerDevice, RoboticVacuumCleanerRequirements } from '@matter/main/devices/robotic-vacuum-cleaner';
import { RoomAirConditionerDevice } from '@matter/main/devices/room-air-conditioner';
import { SmokeCoAlarmDevice } from '@matter/main/devices/smoke-co-alarm';
import { TemperatureSensorDevice } from '@matter/main/devices/temperature-sensor';
import { ThermostatDevice, ThermostatRequirements } from '@matter/main/devices/thermostat';
import { WaterLeakDetectorDevice } from '@matter/main/devices/water-leak-detector';
import { WaterValveDevice, WaterValveRequirements } from '@matter/main/devices/water-valve';
import { WindowCoveringDevice } from '@matter/main/devices/window-covering';
import { BridgedNodeEndpoint } from '@matter/main/endpoints/bridged-node';
// Note: the canonical MatterServerEvents declaration is at the bottom of this file.
// A second declaration here is unnecessary; TypeScript would merge it silently and
// the comment ("Currently empty - all events removed") was misleading because the
// file's other declaration adds two events.
/**
* Matter Accessory Event Types
*
* Events that can be emitted by Matter accessories during their lifecycle.
*
* @example
* ```typescript
* Listen for when a Matter accessory is ready
* const accessory: MatterAccessory = { ... };
* api.matter?.publishExternalAccessories('plugin-name', [accessory]);
*
* const internal = accessory as any;
* internal._eventEmitter?.on(MatterAccessoryEventTypes.READY, (port: number) => {
* console.log(`Accessory ready on port ${port}`);
* });
* ```
*
* @group Matter Accessory
*/
export var MatterAccessoryEventTypes;
(function (MatterAccessoryEventTypes) {
/**
* Emitted when the Matter server is ready and the accessory is available on the network.
* This is the main event to listen for to know when an external accessory is ready.
*
* **HAP Equivalent:** `AccessoryEventTypes.ADVERTISED`
*
* @param port - The port number the Matter server is listening on
*/
MatterAccessoryEventTypes["READY"] = "ready";
})(MatterAccessoryEventTypes || (MatterAccessoryEventTypes = {}));
/**
* Matter error type enum (for error handler categorization)
*/
export var MatterErrorType;
(function (MatterErrorType) {
MatterErrorType["INITIALIZATION"] = "INITIALIZATION";
MatterErrorType["NETWORK"] = "NETWORK";
MatterErrorType["COMMISSIONING"] = "COMMISSIONING";
MatterErrorType["DEVICE_SYNC"] = "DEVICE_SYNC";
MatterErrorType["SERVER"] = "SERVER";
MatterErrorType["STORAGE"] = "STORAGE";
MatterErrorType["CONFIGURATION"] = "CONFIGURATION";
MatterErrorType["DEVICE_ERROR"] = "DEVICE_ERROR";
MatterErrorType["UNKNOWN"] = "UNKNOWN";
})(MatterErrorType || (MatterErrorType = {}));
/**
* Matter error types
*/
export class MatterError extends Error {
code;
details;
type;
timestamp;
recoverable;
constructor(message, code, details) {
super(message);
this.code = code;
this.details = details;
this.name = 'MatterError';
this.type = details?.type ?? MatterErrorType.UNKNOWN;
this.timestamp = new Date();
this.recoverable = details?.recoverable ?? true;
}
}
export class MatterCommissioningError extends MatterError {
constructor(message, details) {
super(message, 'COMMISSIONING_ERROR', { ...details, type: MatterErrorType.COMMISSIONING });
this.name = 'MatterCommissioningError';
}
}
export class MatterStorageError extends MatterError {
constructor(message, details) {
super(message, 'STORAGE_ERROR', { ...details, type: MatterErrorType.STORAGE });
this.name = 'MatterStorageError';
}
}
export class MatterDeviceError extends MatterError {
constructor(message, details) {
super(message, 'DEVICE_ERROR', { ...details, type: MatterErrorType.DEVICE_ERROR });
this.name = 'MatterDeviceError';
}
}
export class MatterNetworkError extends MatterError {
constructor(message, details) {
super(message, 'NETWORK_ERROR', { ...details, type: MatterErrorType.NETWORK });
this.name = 'MatterNetworkError';
}
}
/**
* Matter device types
*
* All supported Matter device types, imported from individual files for optimal performance.
*/
const devices = {
AirQualitySensorDevice,
ColorTemperatureLightDevice,
ContactSensorDevice,
DimmableLightDevice,
DimmablePlugInUnitDevice,
DoorLockDevice,
ExtendedColorLightDevice,
FanDevice,
GenericSwitchDevice,
HumiditySensorDevice,
LightSensorDevice,
OccupancySensorDevice,
OnOffLightDevice,
OnOffLightSwitchDevice,
OnOffPlugInUnitDevice,
PumpDevice,
RoboticVacuumCleanerDevice,
RoboticVacuumCleanerRequirements,
RoomAirConditionerDevice,
SmokeCoAlarmDevice,
TemperatureSensorDevice,
ThermostatDevice,
ThermostatRequirements,
WaterLeakDetectorDevice,
WaterValveDevice,
WaterValveRequirements,
WindowCoveringDevice,
};
/**
* Matter cluster types
*
* All supported Matter cluster types, imported from individual files for optimal performance.
*/
const clusters = {
AirQuality,
BooleanState,
CarbonMonoxideConcentrationMeasurement,
ColorControl,
DoorLock,
FanControl,
LevelControl,
NitrogenDioxideConcentrationMeasurement,
OnOff,
OzoneConcentrationMeasurement,
Pm10ConcentrationMeasurement,
Pm25ConcentrationMeasurement,
RvcOperationalState,
Thermostat,
ValveConfigurationAndControl,
WindowCovering,
};
// Export Matter.js clusters and devices for direct access
// Note: types.ts is only imported by MatterServer, MatterBridgeManager, etc.
// which are themselves lazy-loaded, so these imports only happen when Matter is used
export { clusters, devices };
/**
* Friendly device type names for the Plugin API
* Maps simplified names to actual Matter.js device types
*/
export const deviceTypes = {
// Lighting
OnOffLight: devices.OnOffLightDevice,
DimmableLight: devices.DimmableLightDevice,
ColorTemperatureLight: devices.ColorTemperatureLightDevice,
ExtendedColorLight: devices.ExtendedColorLightDevice,
// Switches & Outlets
OnOffSwitch: devices.OnOffLightSwitchDevice,
OnOffOutlet: devices.OnOffPlugInUnitDevice,
DimmableOutlet: devices.DimmablePlugInUnitDevice,
// Sensors
AirQualitySensor: devices.AirQualitySensorDevice,
TemperatureSensor: devices.TemperatureSensorDevice,
HumiditySensor: devices.HumiditySensorDevice,
LightSensor: devices.LightSensorDevice,
MotionSensor: devices.OccupancySensorDevice,
ContactSensor: devices.ContactSensorDevice,
LeakSensor: devices.WaterLeakDetectorDevice,
SmokeSensor: devices.SmokeCoAlarmDevice,
// HVAC
Thermostat: devices.ThermostatDevice.with(devices.ThermostatRequirements.ThermostatServer.with('Heating', 'Cooling', 'AutoMode', 'Occupancy')),
Fan: devices.FanDevice,
// Security
DoorLock: devices.DoorLockDevice,
// Window Coverings (features will be auto-detected based on accessory attributes)
WindowCovering: devices.WindowCoveringDevice,
// Appliances
// RVC optional clusters (RvcCleanMode, ServiceArea) are added dynamically in matterServer
// based on whether they're defined in the accessory configuration
RoboticVacuumCleaner: devices.RoboticVacuumCleanerDevice,
// Water Valve
WaterValve: devices.WaterValveDevice.with(devices.WaterValveRequirements.ValveConfigurationAndControlServer),
// Other
GenericSwitch: devices.GenericSwitchDevice,
Pump: devices.PumpDevice,
RoomAirConditioner: devices.RoomAirConditionerDevice,
// Composed device container — use as parent for accessories with parts.
// Children appear as a single accessory in Apple Home, expandable into separate tiles.
BridgedNode: BridgedNodeEndpoint,
};
/**
* Matter Cluster Names
* Commonly used cluster names for type safety and autocomplete
* Use these with api.updateMatterAccessoryState() and api.getAccessoryState()
*
* @example
* ```typescript
* With autocomplete and type safety:
* api.updateMatterAccessoryState(uuid, api.matterClusterNames.OnOff, { onOff: true })
* api.getAccessoryState(uuid, api.matterClusterNames.LevelControl)
* ```
*/
export const clusterNames = {
// Control Clusters
OnOff: 'onOff',
LevelControl: 'levelControl',
ColorControl: 'colorControl',
DoorLock: 'doorLock',
WindowCovering: 'windowCovering',
Thermostat: 'thermostat',
FanControl: 'fanControl',
// Sensor Clusters
AirQuality: 'airQuality',
CarbonMonoxideConcentrationMeasurement: 'carbonMonoxideConcentrationMeasurement',
NitrogenDioxideConcentrationMeasurement: 'nitrogenDioxideConcentrationMeasurement',
OzoneConcentrationMeasurement: 'ozoneConcentrationMeasurement',
Pm10ConcentrationMeasurement: 'pm10ConcentrationMeasurement',
Pm25ConcentrationMeasurement: 'pm25ConcentrationMeasurement',
TemperatureMeasurement: 'temperatureMeasurement',
RelativeHumidityMeasurement: 'relativeHumidityMeasurement',
IlluminanceMeasurement: 'illuminanceMeasurement',
OccupancySensing: 'occupancySensing',
BooleanState: 'booleanState',
SmokeCoAlarm: 'smokeCoAlarm',
// Robotic Vacuum Cleaner Clusters
RvcRunMode: 'rvcRunMode',
RvcOperationalState: 'rvcOperationalState',
RvcCleanMode: 'rvcCleanMode',
ServiceArea: 'serviceArea',
// Power
PowerSource: 'powerSource',
// Pump & Other
PumpConfigurationAndControl: 'pumpConfigurationAndControl',
// Valve
ValveConfigurationAndControl: 'valveConfigurationAndControl',
// Identification
Identify: 'identify',
// Switch (GenericSwitch - stateless remotes and buttons)
Switch: 'switch',
// Device Information (read-only, set during registration)
BasicInformation: 'basicInformation',
BridgedDeviceBasicInformation: 'bridgedDeviceBasicInformation',
};
/**
* Check if endpoint has state property (type guard)
*
* We use a runtime check to determine if an endpoint has a settable state.
* This is necessary because Endpoint's state structure is complex and varies
* based on device type.
*
* @param endpoint - The endpoint to check
* @returns True if endpoint has state and set method
*/
export function hasEndpointState(endpoint) {
return 'state' in endpoint
&& typeof endpoint.state === 'object'
&& endpoint.state !== null
&& 'set' in endpoint
&& typeof endpoint.set === 'function';
}
/**
* Safely update endpoint state
* Uses the Endpoint's set method to update cluster attributes
*
* @param endpoint - The Matter endpoint
* @param cluster - Cluster name
* @param attributes - Attributes to update
* @throws {Error} If endpoint does not support state updates
*/
export async function updateEndpointState(endpoint, cluster, attributes) {
if (!hasEndpointState(endpoint)) {
throw new Error('Endpoint does not support state updates');
}
const updateObject = { [cluster]: attributes };
await endpoint.set(updateObject);
}
/**
* Type-safe cluster access for WindowCovering
*/
export function getWindowCoveringCluster(accessory) {
return accessory.clusters?.windowCovering;
}
//# sourceMappingURL=types.js.map