@homebridge-plugins/homebridge-resideo
Version:
The Resideo plugin allows you to access your Resideo device(s) from HomeKit.
125 lines • 6.36 kB
JavaScript
import { ResideoPlatform } from './Platform.HAP.js';
import { PLATFORM_NAME, PLUGIN_NAME } from './settings.js';
/**
* ResideoMatterPlatform
* Extends ResideoPlatform with Homebridge Matter support (Homebridge v2.0+).
* When Matter is available and enabled the platform registers Resideo devices
* as Matter accessories; otherwise it falls back to the standard HAP path
* inherited from ResideoPlatform.
*/
export class ResideoMatterPlatform extends ResideoPlatform {
/**
* Map of cached Matter accessories restored from disk at startup.
* Keyed by UUID so duplicates are avoided on re-launch.
*/
matterAccessories = new Map();
constructor(log, config, api) {
super(log, config, api);
}
/**
* Delegates to the base-class implementation so the HAP accessories array
* (`this.accessories`) is always populated. This is required for the HAP
* fallback path inside `discoverDevices` to work correctly and prevents
* duplicate HAP accessories from being created on re-launch.
*
* When Matter mode is active those HAP accessories will be unregistered at
* the start of `discoverDevices`, cleanly migrating away from legacy HAP.
*/
configureAccessory(accessory) {
super.configureAccessory(accessory);
}
/**
* Called by Homebridge when a cached Matter accessory is restored from disk.
*/
configureMatterAccessory(accessory) {
this.debugLog(`Loading cached Matter accessory: ${accessory.displayName}`);
this.matterAccessories.set(accessory.UUID, accessory);
}
/**
* Returns true when the running Homebridge instance has Matter available
* and the user has Matter enabled (both bridge-level and plugin-level).
*/
get matterActive() {
const iface = this.api;
return !!(iface?.isMatterAvailable?.() && iface?.isMatterEnabled?.());
}
/**
* Overrides ResideoPlatform.discoverDevices.
*
* When Matter is active all discovered Resideo devices are registered as
* Matter accessories via `api.matter.registerPlatformAccessories`.
* Any previously cached HAP accessories are unregistered first to avoid
* leaving stale HAP accessories when transitioning to Matter.
*
* When Matter is not active the call is delegated to the parent HAP
* implementation so the plugin continues to work with Homebridge v1.x.
*/
async discoverDevices() {
if (!this.matterActive) {
this.debugLog('Matter is not available or not enabled – falling back to HAP device discovery.');
return super.discoverDevices();
}
this.infoLog('Matter is available and enabled – registering Resideo devices as Matter accessories.');
// Unregister any legacy HAP accessories that were restored from cache so
// they don't remain as duplicate/stale entries alongside Matter accessories.
if (this.accessories.length > 0) {
this.debugLog(`Removing ${this.accessories.length} cached HAP accessory(s) before switching to Matter.`);
for (const hapAccessory of this.accessories) {
this.unregisterPlatformAccessories(hapAccessory);
}
this.accessories.length = 0;
}
try {
const locations = await this.discoverlocations() ?? [];
this.infoLog(`Total Locations Found: ${locations.length}`);
if (locations.length === 0) {
this.debugLog('No locations found.');
return;
}
const matterApi = this.api.matter;
const accessories = [];
for (const location of locations) {
this.infoLog(`Total Devices Found at ${location.name}: ${location.devices.length}`);
const deviceLists = location.devices;
const configDevices = this.config.options?.devices;
const devices = configDevices
? this.mergeByDeviceID(deviceLists.map((device) => ({ ...device, deviceID: String(device.deviceID).trim() })), configDevices.map((device) => ({ ...device, deviceID: String(device.deviceID).trim() })))
: deviceLists.slice();
for (const device of devices) {
if (device.hide_device) {
this.debugLog(`Skipping hidden device: ${device.userDefinedDeviceName}`);
continue;
}
const uuid = matterApi.uuid.generate(`${device.deviceID}-${device.deviceClass}`);
const displayName = device.configDeviceName ?? device.userDefinedDeviceName ?? `${device.deviceClass} ${device.deviceID}`;
const existingAccessory = this.matterAccessories.get(uuid);
if (existingAccessory) {
this.infoLog(`Restoring existing Matter accessory from cache: ${existingAccessory.displayName}`);
existingAccessory.context.device = device;
existingAccessory.context.location = location;
await matterApi.updatePlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAccessory]);
this.matterAccessories.set(uuid, existingAccessory);
}
else {
this.debugLog(`Creating new Matter accessory for: ${displayName} (${device.deviceClass})`);
const MatterAccessory = this.api.matterAccessory;
const accessory = new MatterAccessory(displayName, uuid);
accessory.context.device = device;
accessory.context.location = location;
accessories.push(accessory);
this.matterAccessories.set(uuid, accessory);
}
}
}
if (accessories.length > 0) {
this.infoLog(`Registering ${accessories.length} new Matter accessory(s).`);
await matterApi.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessories);
}
}
catch (e) {
this.action = 'Discover Devices (Matter)';
this.apiError(e);
}
}
}
//# sourceMappingURL=Platform.Matter.js.map