import { API, Characteristic, DynamicPlatformPlugin, Logger, PlatformAccessory, PlatformConfig, Service, } from "homebridge"; import { ControlUnit, DeviceButton } from "./Accessories"; import HarmonyDataProvider from "./DataProviders/HarmonyDataProvider"; import { IConfig, IControlUnit, IDeviceButton } from "./Models/Config"; import { HarmonyDevice } from "./Models/HarmonyDevice"; import { HarmonyHub } from "./Models/HarmonyHub"; import { PLATFORM_NAME, PLUGIN_NAME } from "./settings"; export class Platform implements DynamicPlatformPlugin { constructor( public readonly log: Logger, config: PlatformConfig, public readonly api: API ) { this.log.debug("Finished initializing platform:", config.name); this.config = (config as unknown) as IConfig; //construct data provider const dataProvider = new HarmonyDataProvider({ hubs: this.config.Hubs, deviceConfigs: this.config.Devices, matrix: this.config.Matrix, log: this.log, }); this.api.on("didFinishLaunching", async () => { log.debug("Executed didFinishLaunching callback"); this.discoverDevices(dataProvider); }); this.dataProvider = null; if (this.config) { //construct data provider this.dataProvider = new HarmonyDataProvider({ hubs: this.config.Hubs, deviceConfigs: this.config.Devices, matrix: this.config.Matrix, log: this.log, }); //Emit devices if requested this.dataProvider.on("Ready", () => { this.log.info("All hubs connected"); if (this.config.EmitDevicesOnStartup) { const hubs = this.dataProvider!.hubs; Object.values(hubs).forEach((hub: HarmonyHub) => { const deviceDictionary = hub.devices; this.log.info(`${hub.hubName}`); Object.values(deviceDictionary).forEach((device: HarmonyDevice) => { this.log.info(` ${device.name} : ${device.id}`); Object.keys(device.commands).forEach((command: string) => { this.log.info(` ${command}`); }); }); }); } }); } } public readonly Service: typeof Service = this.api.hap.Service; public readonly Characteristic: typeof Characteristic = this.api.hap .Characteristic; // this is used to track restored cached accessories public readonly accessories: PlatformAccessory[] = []; public config: IConfig; public dataProvider: HarmonyDataProvider | null; public discoverDevices(dataProvider: HarmonyDataProvider) { this.config.ControlUnits.forEach((unit: IControlUnit) => { const uuid = this.api.hap.uuid.generate(unit.DisplayName); const existingAccessory = this.accessories.find((e) => e.UUID === uuid); if (existingAccessory) { this.log.info( "Restoring existing accessory from cache: " + existingAccessory.displayName ); new ControlUnit(this, existingAccessory, dataProvider, unit.Activities); this.api.publishExternalAccessories(PLUGIN_NAME, [existingAccessory]); console.log("Publishing external accessory: " + uuid); } else { this.log.info("Adding new accessory: " + unit.DisplayName); const accessory = new this.api.platformAccessory( unit.DisplayName, uuid ); accessory.context["DeviceName"] = unit.DisplayName; new ControlUnit(this, accessory, dataProvider, unit.Activities); this.api.publishExternalAccessories(PLUGIN_NAME, [accessory]); console.log("Publishing external accessory: " + uuid); } }); this.config.DeviceButtons.forEach((button: IDeviceButton) => { const uuid = this.api.hap.uuid.generate(button.DisplayName); const existingAccessory = this.accessories.find((e) => e.UUID === uuid); if (existingAccessory) { this.log.info( "Restoring existing accessory from cache: " + existingAccessory.displayName ); new DeviceButton(this, existingAccessory, dataProvider, button); this.api.updatePlatformAccessories([existingAccessory]); } else { this.log.info("Adding new accessory: " + button.DisplayName); const accessory = new this.api.platformAccessory( button.DisplayName, uuid ); accessory.context["DeviceName"] = button.DisplayName; new DeviceButton(this, accessory, dataProvider, button); this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [ accessory, ]); } }); } configureAccessory(accessory: PlatformAccessory>): void { this.log.info("Loading accessory from cache:", accessory.displayName); // add the restored accessory to the accessories cache so we can track if it has already been registered this.accessories.push(accessory); } }