diff --git a/package.json b/package.json index ddc714a..aa217fd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-harmony-control", - "version": "1.0.5", + "version": "1.0.7", "description": "Homebridge platform to control smart home equipment by room.", "main": "bin/index.js", "scripts": { diff --git a/src/Accessories/DeviceButton.ts b/src/Accessories/DeviceButton.ts index 4b66967..d37c4fa 100644 --- a/src/Accessories/DeviceButton.ts +++ b/src/Accessories/DeviceButton.ts @@ -2,6 +2,7 @@ import HarmonyDataProvider from "../DataProviders/HarmonyDataProvider"; import { IDeviceButton } from "../Models/Config"; import { IAccessory } from "./IAccessory"; import { ICommand } from "../Models"; +import { HarmonyDevice } from "../Models/HarmonyDevice"; let Service: HAPNodeJS.Service; let Characteristic: HAPNodeJS.Characteristic; @@ -29,7 +30,7 @@ export class DeviceButton implements IAccessory { private _dataProvider: HarmonyDataProvider; - private _deviceCommand?: ICommand; + private _device!: HarmonyDevice; private _buttonState: boolean; @@ -48,6 +49,15 @@ export class DeviceButton implements IAccessory { this._buttonState = false; + if (this._buttonInfo.NumberOfKeyPresses && this._buttonInfo.IsStateful) { + throw new Error("A button cannot be stateful and be pressed more than once"); + } + + //Assign default number of key presses + if (!this._buttonInfo.NumberOfKeyPresses) { + this._buttonInfo.NumberOfKeyPresses = 1; + } + this.platformAccessory = new this._homebridge.platformAccessory(this.name, this.generateUUID(), this._homebridge.hap.Accessory.Categories.SWITCH); //@ts-ignore @@ -92,25 +102,24 @@ export class DeviceButton implements IAccessory { } //Get device command if we don't have it - if (!this._deviceCommand) { - let cmd = this._dataProvider.getCommand(this._buttonInfo.ButtonName, this._buttonInfo.DeviceName); - if (cmd) { - this._deviceCommand = cmd; - } + if (!this._device) { + this._device = this._dataProvider.getDeviceFromName(this._buttonInfo.DeviceName); } //Execute command - if (this._deviceCommand) { + if (this._device) { //change state if stateful if (this._buttonInfo.IsStateful && this._buttonState != newState) { this._buttonState = newState - await this._dataProvider.sendCommand(this._deviceCommand); + await this._device.sendCommand(this._buttonInfo.ButtonName); } else if (!this._buttonInfo.IsStateful) { - await this._dataProvider.sendCommand(this._deviceCommand); + //Send the number of configured key presses + for (let i = 0; i < this._buttonInfo.NumberOfKeyPresses; i++) { + await this._device.sendCommand(this._buttonInfo.ButtonName); + } this._switchService.getCharacteristic(Characteristic.On).updateValue(false); return callback(new Error("Normal Response")); } - } return callback(); } diff --git a/src/DataProviders/HarmonyDataProvider.ts b/src/DataProviders/HarmonyDataProvider.ts index f273ecd..592ab41 100644 --- a/src/DataProviders/HarmonyDataProvider.ts +++ b/src/DataProviders/HarmonyDataProvider.ts @@ -2,9 +2,12 @@ import { IActivity } from "../Models/Config/IActivity"; import { IDeviceSetupItem } from "../Models/Config/IDeviceSetupItem"; import { IInput, IMatrix, IOutput } from "../Models/Config/IMatrix"; import { RemoteKey } from '../Accessories/ControlUnit'; -import { sleep } from '../Util/Sleep'; import { EventEmitter } from "events"; -import { IDevice, ICommand } from '../Models/IDevice'; +import { ICommand } from '../Models/IDevice'; +import { IHub } from "../Models/Config/IHub"; +import { IDeviceConfig } from "../Models/Config/IDeviceConfig"; +import { HarmonyDevice } from "../Models/HarmonyDevice"; +import { HarmonyHub } from "../Models/HarmonyHub"; let Characteristic: HAPNodeJS.Characteristic; @@ -15,18 +18,17 @@ interface IActivityState { } interface IHarmonyDataProviderProps { - hubAddress: string, + hubs: Array; + deviceConfigs: Array; log: any, matrix: IMatrix } class HarmonyDataProvider extends EventEmitter { - private _harmony: any; private _log: any; - private _hubAddress: string = ""; - private _connected: boolean = false; - - private _devices: { [name: string]: IDevice; } = {}; + private _hubsByDevice: { [deviceName: string]: string } = {}; + private _hubs: { [hubName: string]: HarmonyHub } = {}; + // private _devicesByHub: { [hubName: string]: { [deviceName: string]: HarmonyDevice } } = {}; private _states: { [controlUnitName: string]: (IActivityState | undefined) } = {}; private _matrix: IMatrix; @@ -34,24 +36,21 @@ class HarmonyDataProvider extends EventEmitter { constructor(props: IHarmonyDataProviderProps) { super(); this._log = props.log; - this._hubAddress = props.hubAddress; this._matrix = props.matrix; - - this._harmony = new Harmony(); - - //Listeners - this._harmony.on('open', () => { - this._connected = true; - }); - this._harmony.on('close', () => { - this._connected = false; + props.deviceConfigs.forEach((deviceConfig: IDeviceConfig) => { + this._hubsByDevice[deviceConfig.Name] = deviceConfig.Hub; }); + // this._deviceConfigs = props.deviceConfigs; - this.connect(); + this.connect(props.hubs); } - public get devices(): { [name: string]: IDevice; } { - return this._devices; + // public get devicesByHub(): { [hubName: string]: { [deviceName: string]: HarmonyDevice } } { + // return this._devicesByHub; + // } + + public get hubs(): { [hubName: string]: HarmonyHub } { + return this._hubs; } /** @@ -73,8 +72,8 @@ class HarmonyDataProvider extends EventEmitter { return; } //Build potential list of devices to turn off - let devicesToTurnOff: Array = this._states[controlUnitName]!.currentActivity.DeviceSetupList - .map((value: IDeviceSetupItem): IDevice => { + let devicesToTurnOff: Array = this._states[controlUnitName]!.currentActivity.DeviceSetupList + .map((value: IDeviceSetupItem): HarmonyDevice => { return this.getDeviceFromName(value.DeviceName); }); @@ -82,8 +81,10 @@ class HarmonyDataProvider extends EventEmitter { devicesToTurnOff = this.sanitizeDeviceList(devicesToTurnOff, controlUnitName); //Turn off devices - devicesToTurnOff.forEach((device: IDevice) => { - this.powerOffDevice(device); + devicesToTurnOff.forEach(async (device: HarmonyDevice) => { + if (device) { + await device.powerOff(); + } }); this._states[controlUnitName] = undefined; @@ -100,7 +101,7 @@ class HarmonyDataProvider extends EventEmitter { } //Build potential list of devices to to turn on - let devicesToTurnOn: Array = activity.DeviceSetupList.map((value: IDeviceSetupItem): IDevice => { + let devicesToTurnOn: Array = activity.DeviceSetupList.map((value: IDeviceSetupItem): HarmonyDevice => { return this.getDeviceFromName(value.DeviceName); }); @@ -108,11 +109,11 @@ class HarmonyDataProvider extends EventEmitter { devicesToTurnOn = this.sanitizeDeviceList(devicesToTurnOn, controlUnitName); //Turn on devices - await Promise.all(devicesToTurnOn.map(async (device: IDevice) => { - if (device && device.name && this._devices[device.name]) { + await Promise.all(devicesToTurnOn.map(async (device: HarmonyDevice) => { + if (device && device.name) { if (!device.on) { this._log(`Turning on device ${device.name}`) - await this.powerOnDevice(device); + await device.powerOn(); } } })); @@ -120,11 +121,10 @@ class HarmonyDataProvider extends EventEmitter { //Assign correct input await Promise.all( activity.DeviceSetupList.map(async (value: IDeviceSetupItem) => { - let device: IDevice = this.getDeviceFromName(value.DeviceName); + let device: HarmonyDevice = this.getDeviceFromName(value.DeviceName); if (device && device.supportsCommand(`Input${value.Input}`)) { - let command: ICommand = device.getCommand(`Input${value.Input}`); - await this.sendCommand(command); + await device.sendCommand(`Input${value.Input}`) } }) ); @@ -137,26 +137,26 @@ class HarmonyDataProvider extends EventEmitter { let inputCommandName: string = `In ${input.InputNumber}`; let outputCommandName: string = `Out ${output.OutputLetter}`; - let matrixDevice: IDevice = this.getDeviceFromName(this._matrix.DeviceName); + let matrixDevice: HarmonyDevice = this.getDeviceFromName(this._matrix.DeviceName); //Route hdmi if (matrixDevice.supportsCommand(inputCommandName) && matrixDevice.supportsCommand(outputCommandName)) { - await this.sendCommand(matrixDevice.getCommand(outputCommandName)); - await this.sendCommand(matrixDevice.getCommand(inputCommandName)); - await this.sendCommand(matrixDevice.getCommand(outputCommandName)); - await this.sendCommand(matrixDevice.getCommand(inputCommandName)); + await matrixDevice.sendCommand(outputCommandName); + await matrixDevice.sendCommand(inputCommandName); + await matrixDevice.sendCommand(outputCommandName); + await matrixDevice.sendCommand(inputCommandName); } } //Build potential list of devices to turn off if (lastActivity) { - let devicesToTurnOff: Array = lastActivity.DeviceSetupList.map((value: IDeviceSetupItem): IDevice => { + let devicesToTurnOff: Array = lastActivity.DeviceSetupList.map((value: IDeviceSetupItem): HarmonyDevice => { return this.getDeviceFromName(value.DeviceName); }); //remove devices that will be used for next activity from list //delete array[index] is stupid because it just nulls out the index. But now i have to deal with nulls - devicesToTurnOff.forEach((device: IDevice, index: number) => { + devicesToTurnOff.forEach((device: HarmonyDevice, index: number) => { if (device && device.name && activity.DeviceSetupList.some(e => { return (e && e.DeviceName === device.name) })) { @@ -171,11 +171,11 @@ class HarmonyDataProvider extends EventEmitter { await Promise.all( //Turn off devices - devicesToTurnOff.map(async (device: IDevice) => { + devicesToTurnOff.map(async (device: HarmonyDevice) => { if (device) { if (device.on) { this._log(`Turning off device ${device.name}`) - await this.powerOffDevice(device); + await device.powerOff(); } } }) @@ -193,10 +193,8 @@ class HarmonyDataProvider extends EventEmitter { public volumeUp = async (controlUnitName: string) => { let volumeUpCommand: string = "Volume Up" if (this._states[controlUnitName]) { - let volumeDevice: IDevice = this.getDeviceFromName(this._states[controlUnitName]!.currentActivity.VolumeDevice); - if (volumeDevice.supportsCommand(volumeUpCommand)) { - this.sendCommand(volumeDevice.getCommand(volumeUpCommand)); - } + let volumeDevice: HarmonyDevice = this.getDeviceFromName(this._states[controlUnitName]!.currentActivity.VolumeDevice); + await volumeDevice.sendCommand(volumeUpCommand); } } @@ -206,10 +204,8 @@ class HarmonyDataProvider extends EventEmitter { public volumeDown = async (controlUnitName: string) => { let volumeDownCommand: string = "Volume Down" if (this._states[controlUnitName]) { - let volumeDevice: IDevice = this.getDeviceFromName(this._states[controlUnitName]!.currentActivity.VolumeDevice); - if (volumeDevice.supportsCommand(volumeDownCommand)) { - this.sendCommand(volumeDevice.getCommand(volumeDownCommand)); - } + let volumeDevice: HarmonyDevice = this.getDeviceFromName(this._states[controlUnitName]!.currentActivity.VolumeDevice); + await volumeDevice.sendCommand(volumeDownCommand); } } @@ -223,7 +219,7 @@ class HarmonyDataProvider extends EventEmitter { if (this._states[controlUnitName]) { let commandName: string = ""; - let device: IDevice = this.getDeviceFromName(this._states[controlUnitName]!.currentActivity.ControlDevice); + let device: HarmonyDevice = this.getDeviceFromName(this._states[controlUnitName]!.currentActivity.ControlDevice); switch (key) { case RemoteKey.ARROW_UP: { commandName = "Direction Up"; @@ -263,9 +259,7 @@ class HarmonyDataProvider extends EventEmitter { } } - if (device && device.supportsCommand(commandName)) { - this.sendCommand(device.getCommand(commandName)); - } + await device.sendCommand(commandName); } } @@ -277,118 +271,50 @@ class HarmonyDataProvider extends EventEmitter { return this._states[controlUnitName] ? this._states[controlUnitName]!.currentActivity : undefined; } - /** - * Gets device button commands - * @param deviceCommandName The device command name - * @param deviceName The device name - */ - public getCommand(deviceCommandName: string, deviceName: string): ICommand | undefined { - const device: IDevice = this.getDeviceFromName(deviceName); - if (device && device.supportsCommand(deviceCommandName)) { - return device.getCommand(deviceCommandName); - } else { - return undefined; - } - } - - /** - * Send a command to the harmony hub. - * @param command The command to send. - */ - public sendCommand = async (command: ICommand) => { - try { - //Execute command - let response = await this._harmony.sendCommand(JSON.stringify(command)); - - //Sleep - await sleep(800); - } catch (err) { - this._log(`ERROR - error sending command to harmony: ${err}`); - } - - } - - /** - * Connect to harmony and receive device info - */ - private connect = async () => { - await this._harmony.connect(this._hubAddress); - let self = this; - - setTimeout(async function () { - if (self._connected) { - let devices: any = await self._harmony.getDevices(); - try { - await Promise.all( - //Add each to dictionary - devices.map(async (dev: any) => { - //get commands - let commands: { [name: string]: ICommand } = {}; - let deviceCommands: any = await self._harmony.getDeviceCommands(dev.id); - deviceCommands.forEach((command: any) => { - commands[command.label] = command.action; - }); - self._devices[dev.label] = { - id: dev.id, - name: dev.label, - commands: commands, - on: false, - //Define device methods - supportsCommand(commandName: string): boolean { - let command = commands[commandName]; - return (command) ? true : false; - }, - getCommand(commandName: string): ICommand { - return commands[commandName]; - } - } - })); - self._log(`Harmony data provider ready`); - self.emit("Ready"); - - } catch (err) { - self._log(`ERROR - error connecting to harmony: ${err}`); - } - } - }, 1000); - } - - /** - * Power off a device (Power toggle if no power off). - */ - private powerOffDevice = async (device: IDevice) => { - let powerOffCommand: string = "Power Off"; - let powerToggleCommand: string = "Power Toggle"; - if (device && device.supportsCommand(powerOffCommand)) { - await this.sendCommand(device.getCommand(powerOffCommand)); - device.on = false; - } else if (device && device.supportsCommand(powerToggleCommand)) { - await this.sendCommand(device.getCommand(powerToggleCommand)); - device.on = false; - } - } - - /** - * Power on a device (Power toggle if no power on). - */ - private powerOnDevice = async (device: IDevice) => { - let powerOnCommand: string = "Power On"; - let powerToggleCommand: string = "Power Toggle"; - if (device && device.supportsCommand(powerOnCommand)) { - await this.sendCommand(device.getCommand(powerOnCommand)); - device.on = true; - } else if (device && device.supportsCommand(powerToggleCommand)) { - await this.sendCommand(device.getCommand(powerToggleCommand)); - device.on = true; - } - } - /** * Get the IDevice by name. * @param deviceName The device to retrieve. */ - private getDeviceFromName(deviceName: string): IDevice { - return this._devices[deviceName]; + public getDeviceFromName(deviceName: string): HarmonyDevice { + let device: HarmonyDevice | undefined; + try { + device = this._hubs[this._hubsByDevice[deviceName]].getDeviceByName(deviceName); + } catch (err) { + this._log(`Error retrieving device from hub: ${err}`); + } + + return device!; + } + + // /** + // * Gets device button commands + // * @param deviceCommandName The device command name + // * @param deviceName The device name + // */ + // public getCommand(deviceCommandName: string, deviceName: string): ICommand | undefined { + // const device: HarmonyDevice = this.getDeviceFromName(deviceName); + // if (device && device.supportsCommand(deviceCommandName)) { + // return device.getCommand(deviceCommandName); + // } else { + // return undefined; + // } + // } + + 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); + this._hubs[hub.Name] = newHarmonyHub; + newHarmonyHub.on("Ready", () => { + readyCount++; + if (readyCount === Object.keys(this._hubs).length) { + this.emit("Ready"); + } + }) + await newHarmonyHub.initialize(); + }) + ) } /** @@ -396,7 +322,7 @@ class HarmonyDataProvider extends EventEmitter { * @param devicesToTurnOn The list of devices to modify. * @param controlUnitName The name of the control unit in question. */ - private sanitizeDeviceList(devicesToTurnOn: Array, controlUnitName: string): Array { + private sanitizeDeviceList(devicesToTurnOn: Array, controlUnitName: string): Array { for (let controlUnitKey in this._states) { //Skip self if (controlUnitKey === controlUnitName) { @@ -408,7 +334,7 @@ class HarmonyDataProvider extends EventEmitter { currentOtherState.currentActivity.DeviceSetupList.forEach((value: IDeviceSetupItem) => { //there are devices to remove if (devicesToTurnOn.some(e => e && e.name === value.DeviceName)) { - let deviceToRemove: IDevice = devicesToTurnOn.filter(i => i.name === value.DeviceName)[0]; + let deviceToRemove: HarmonyDevice = devicesToTurnOn.filter(i => i.name === value.DeviceName)[0]; delete devicesToTurnOn[devicesToTurnOn.indexOf(deviceToRemove)]; } }); diff --git a/src/Models/Config/IConfig.ts b/src/Models/Config/IConfig.ts index 6d7929c..2c1e9b0 100644 --- a/src/Models/Config/IConfig.ts +++ b/src/Models/Config/IConfig.ts @@ -1,6 +1,8 @@ import { IMatrix } from "./IMatrix"; import { IActivity } from "./IActivity"; import { IDeviceButton } from "./IDeviceButton"; +import { IDeviceConfig } from "./IDeviceConfig"; +import { IHub } from './IHub'; export interface IControlUnit { DisplayName: string; @@ -9,8 +11,10 @@ export interface IControlUnit { export interface IConfig { hubIp: string; - EmitDevicesOnStartup: boolean, - Matrix: IMatrix - ControlUnits: Array - DeviceButtons: Array + EmitDevicesOnStartup: boolean; + Matrix: IMatrix; + ControlUnits: Array; + DeviceButtons: Array; + Devices: Array; + Hubs: Array; } \ No newline at end of file diff --git a/src/Models/Config/IDeviceButton.ts b/src/Models/Config/IDeviceButton.ts index 2e1795d..d6a3e22 100644 --- a/src/Models/Config/IDeviceButton.ts +++ b/src/Models/Config/IDeviceButton.ts @@ -2,5 +2,6 @@ export interface IDeviceButton { DeviceName: string; ButtonName: string; DisplayName: string; + NumberOfKeyPresses: number; IsStateful: boolean; } \ No newline at end of file diff --git a/src/Models/Config/IDeviceConfig.ts b/src/Models/Config/IDeviceConfig.ts new file mode 100644 index 0000000..97b74a0 --- /dev/null +++ b/src/Models/Config/IDeviceConfig.ts @@ -0,0 +1,4 @@ +export interface IDeviceConfig { + Name: string; + Hub: string; +} \ No newline at end of file diff --git a/src/Models/Config/IHub.ts b/src/Models/Config/IHub.ts new file mode 100644 index 0000000..95b0f45 --- /dev/null +++ b/src/Models/Config/IHub.ts @@ -0,0 +1,5 @@ +export interface IHub { + Name: string; + Ip: string; + Harmony: any; +} \ No newline at end of file diff --git a/src/Models/HarmonyDevice.ts b/src/Models/HarmonyDevice.ts new file mode 100644 index 0000000..cecece4 --- /dev/null +++ b/src/Models/HarmonyDevice.ts @@ -0,0 +1,94 @@ +import { ICommand } from "./IDevice"; +import { sleep } from "../Util/Sleep"; + +export interface IHarmonyDeviceProps { + id: string; + name: string; + harmony: any; + log: any; + commands: { [name: string]: ICommand }; +} + +export class HarmonyDevice { + private _harmony: any; + private _log: any; + private _commands: { [name: string]: ICommand } = {}; + private _on: boolean; + + constructor(props: IHarmonyDeviceProps) { + this.id = props.id; + this.name = props.name; + this._harmony = props.harmony; + this._on = false; + this._commands = props.commands; + } + + public id: string; + public name: string; + + public get on(): boolean { + return this._on; + } + + public get commands(): { [name: string]: ICommand } { + return this._commands; + } + + //Define device methods + public supportsCommand(commandName: string): boolean { + let command = this._commands[commandName]; + return (command) ? true : false; + } + + public getCommand(commandName: string): ICommand { + return this._commands[commandName]; + } + + public async powerOn(): Promise { + let powerOnCommand: string = "Power On"; + let powerToggleCommand: string = "Power Toggle"; + if (this.supportsCommand(powerOnCommand)) { + await this.sendCommand(powerOnCommand); + this._on = true; + } else if (this.supportsCommand(powerToggleCommand)) { + await this.sendCommand(powerToggleCommand); + this._on = true; + } + } + + public async powerOff(): Promise { + let powerOffCommand: string = "Power Off"; + let powerToggleCommand: string = "Power Toggle"; + if (this.supportsCommand(powerOffCommand)) { + await this.sendCommand(powerOffCommand); + this._on = false; + } else if (this.supportsCommand(powerToggleCommand)) { + await this.sendCommand(powerToggleCommand); + this._on = false; + } + } + + public async sendCommand(commandName: string): Promise { + let command!: ICommand; + if (this.supportsCommand(commandName)) { + command = this.getCommand(commandName); + } + + try { + //Execute command + //HACK to fix Harmon Kardon receiver not turning off + if (command.command === "PowerOff") { + for (let i = 0; i < 2; i++) { + await this._harmony.sendCommand(JSON.stringify(command)); + } + + } + await this._harmony.sendCommand(JSON.stringify(command)); + + //Sleep + await sleep(800); + } catch (err) { + this._log(`ERROR - error sending command to harmony: ${err}`); + } + } +} \ No newline at end of file diff --git a/src/Models/HarmonyHub.ts b/src/Models/HarmonyHub.ts new file mode 100644 index 0000000..8e4ce88 --- /dev/null +++ b/src/Models/HarmonyHub.ts @@ -0,0 +1,68 @@ +import { HarmonyDevice } from './HarmonyDevice'; +const Harmony = require("harmony-websocket"); +import { ICommand } from './IDevice'; +import { EventEmitter } from 'events'; + + + +export class HarmonyHub extends EventEmitter { + private _devices: { [deviceName: string]: HarmonyDevice } = {} + private _ip: string; + private _harmony: any; + private _log: any; + private _name: string; + + constructor(hubName: string, ipAddress: string, log: any) { + super(); + this._ip = ipAddress; + this._log = log; + this._name = hubName; + } + + public get devices(): { [deviceName: string]: HarmonyDevice } { + return this._devices; + } + + public get hubName(): string { + return this._name; + } + + public getDeviceByName = (deviceName: string): HarmonyDevice => { + return this._devices[deviceName]; + } + + public initialize = async () => { + this._harmony = new Harmony(); + await this._harmony.connect(this._ip); + + //Gather devices + let devices: any = await this._harmony.getDevices(); + try { + await Promise.all( + //Add each to dictionary + devices.map(async (dev: any) => { + //get commands + let commands: { [name: string]: ICommand } = {}; + let deviceCommands: any = await this._harmony.getDeviceCommands(dev.id); + deviceCommands.forEach((command: any) => { + commands[command.label] = command.action; + }); + this._devices[dev.label] = new HarmonyDevice({ + id: dev.id, + name: dev.label, + commands: commands, + log: this._log, + harmony: this._harmony + }); + })); + this.emit("Ready"); + + } catch (err) { + this._log(`ERROR - error connecting to harmony: ${err}`); + } + } + + private connect = async (): Promise => { + await this._harmony.Connect(this._ip); + } +} \ No newline at end of file diff --git a/src/Models/IDevice.ts b/src/Models/IDevice.ts index bcede86..eaedc78 100644 --- a/src/Models/IDevice.ts +++ b/src/Models/IDevice.ts @@ -5,10 +5,15 @@ export interface ICommand { } export interface IDevice { - id: string, - name: string, + id: string; + name: string; + harmony: any; + log: any supportsCommand(commandName: string): boolean, getCommand(commandName: string): ICommand, + powerOn(): Promise; + powerOff(): Promise; + sendCommand(commandName: string): Promise; commands: { [name: string]: ICommand }; on: boolean; } \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 2526c17..9a904c4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,6 +2,8 @@ import * as Accessories from "./Accessories"; import HarmonyDataProvider from "./DataProviders/HarmonyDataProvider"; import * as Config from "./Models/Config"; import { IDevice } from "./Models"; +import { HarmonyDevice } from "./Models/HarmonyDevice"; +import { HarmonyHub } from "./Models/HarmonyHub"; let Accessory: any; let Homebridge: any; @@ -40,23 +42,32 @@ class HarmonyMatrixPlatform { if (this.config) { //construct data provider this.dataProvider = new HarmonyDataProvider({ - hubAddress: this.config.hubIp, + hubs: this.config.Hubs, + deviceConfigs: this.config.Devices, matrix: this.config.Matrix, log: this.log }); //Emit devices if requested - if (this.config.EmitDevicesOnStartup) { - this.dataProvider.on("Ready", () => { - const devices: { [name: string]: IDevice } = this.dataProvider!.devices; - Object.values(devices).forEach((device: IDevice) => { - this.log(`${device.name} : ${device.id}`); - Object.keys(device.commands).forEach((command: string) => { - this.log(` ${command}`); + + this.dataProvider.on("Ready", () => { + this.log("All hubs connected"); + if (this.config.EmitDevicesOnStartup) { + const hubs = this.dataProvider!.hubs; + Object.values(hubs).forEach((hub: HarmonyHub) => { + const deviceDictionary = hub.devices; + this.log(`${hub.hubName}`) + + Object.values(deviceDictionary).forEach((device: HarmonyDevice) => { + this.log(` ${device.name} : ${device.id}`); + Object.keys(device.commands).forEach((command: string) => { + this.log(` ${command}`); + }); }); }); - }); - } + } + }); + } }