import { Logging } from "homebridge"; import { inject, injectable } from "tsyringe"; import { ICommand } from "../models"; import { IConfig } from "../models/config"; import { IDeviceConfig } from "../models/config/deviceConfig"; import { IHub } from "../models/config/hub"; import { HarmonyDevice } from "../models/harmonyDevice"; import { HarmonyHub } from "../models/harmonyHub"; @injectable() export class HarmonyDataProvider { private _hubs: { [hubName: string]: HarmonyHub } = {}; private _deviceConfigByName: { [deviceName: string]: IDeviceConfig } = {}; constructor( @inject("IConfig") private _config: IConfig, @inject("log") private _log: Logging ) { _config.Devices.forEach((deviceConfig: IDeviceConfig) => { this._deviceConfigByName[deviceConfig.Name] = deviceConfig; }); this.connect(_config.Hubs); this.emitInfo(); } public async powerOnDevices(devices: Array): Promise { await Promise.all( devices.map(async (device: HarmonyDevice) => { if (device && device.name) { if (!device.on) { this._log.info(`Turning on device ${device.name}`); await this.powerOnDevice(device); } } }) ); } public async powerOffDevices(devices: Array) { await Promise.all( //Turn off devices devices.map(async (device: HarmonyDevice) => { if (device) { if (device.on) { this._log.info(`Turning off device ${device.name}`); await this.powerOffDevice(device); } } }) ); } public async sendCommand( commandName: string, harmonyDevice: HarmonyDevice ): Promise { let command!: ICommand; commandName = this.getOverrideCommand(commandName, harmonyDevice); if (harmonyDevice.supportsCommand(commandName)) { command = harmonyDevice.getCommand(commandName); } const hub = this.getHubByDevice(harmonyDevice); await hub.sendCommand(command); } /** * Get the IDevice by name. * @param deviceName The device to retrieve. */ public getDeviceByName(deviceName: string): HarmonyDevice { let device: HarmonyDevice | undefined; try { device = this._hubs[this._deviceConfigByName[deviceName].Hub].getDeviceByName( deviceName ); } catch (err) { this._log.info(`Error retrieving device from hub: ${err}`); } return device!; } private connect = async (hubs: Array) => { let readyCount = 0; await Promise.all( hubs.map(async (hub: IHub): Promise => { const newHarmonyHub = new HarmonyHub(hub.Name, hub.Ip, this._log.info); this._hubs[hub.Name] = newHarmonyHub; newHarmonyHub.on("Ready", () => { readyCount++; if (readyCount === Object.keys(this._hubs).length) { // this.emit("Ready"); } }); await newHarmonyHub.initialize(); }) ); }; private emitInfo(): void { //Emit devices if requested this._log.info("All hubs connected"); if (this._config.EmitDevicesOnStartup) { const hubs = this._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}`); }); }); }); } } private getHubByDevice(device: HarmonyDevice) { return this._hubs[this._deviceConfigByName[device.name].Hub]; } private async powerOnDevice(harmonyDevice: HarmonyDevice): Promise { let powerOnCommand: string = "Power On"; let powerToggleCommand: string = "Power Toggle"; if (harmonyDevice.supportsCommand(powerOnCommand)) { await this.sendCommand(powerOnCommand, harmonyDevice); harmonyDevice.on = true; } else if (harmonyDevice.supportsCommand(powerToggleCommand)) { await this.sendCommand(powerToggleCommand, harmonyDevice); harmonyDevice.on = true; } else { await this.sendCommand(powerOnCommand, harmonyDevice); } } private async powerOffDevice(harmonyDevice: HarmonyDevice): Promise { let powerOffCommand: string = "Power Off"; let powerToggleCommand: string = "Power Toggle"; if (harmonyDevice.supportsCommand(powerOffCommand)) { await this.sendCommand(powerOffCommand, harmonyDevice); harmonyDevice.on = false; } else if (harmonyDevice.supportsCommand(powerToggleCommand)) { await this.sendCommand(powerToggleCommand, harmonyDevice); harmonyDevice.on = false; } } private getOverrideCommand( commandName: string, harmonyDevice: HarmonyDevice ) { const deviceConfig: IDeviceConfig = this._deviceConfigByName[harmonyDevice.name]; if (!deviceConfig.Overrides) { return commandName; } const overrideCommand = deviceConfig.Overrides.find( (e) => e.Command == commandName ); return overrideCommand ? overrideCommand.Override : commandName; } }