import HarmonyDataProvider from "../DataProviders/HarmonyDataProvider"; import { IDeviceButton } from "../Models/Config/IDeviceButton"; import { IAccessory } from "./IAccessory"; import { sleep } from "../Util/Sleep"; import { ICommand } from "../Models/IDevice"; let Service: HAPNodeJS.Service; let Characteristic: HAPNodeJS.Characteristic; export interface IDeviceButtonProps { dataProvider: HarmonyDataProvider, buttonName: string, displayName: string, deviceInfo: IDeviceButton, api: any, log: any, homebridge: any, } export class DeviceButton implements IAccessory { private _api: any; private _homebridge: any; private _log: any = {}; //Service fields private _switchService: HAPNodeJS.Service; private _infoService: HAPNodeJS.Service; private _buttonInfo: IDeviceButton; private _dataProvider: HarmonyDataProvider; private _deviceCommand?: ICommand; private _buttonState: boolean; private _buttonName: string; constructor(props: IDeviceButtonProps) { //Assign class variables this._log = props.log; this._api = props.api; Service = props.api.hap.Service; Characteristic = props.api.hap.Characteristic; this._buttonName = props.buttonName; this.name = props.displayName; this._homebridge = props.homebridge; this._buttonInfo = props.deviceInfo; this._dataProvider = props.dataProvider; this._buttonState = false; this.platformAccessory = new this._homebridge.platformAccessory(this.name, this.generateUUID(), this._homebridge.hap.Accessory.Categories.SWITCH); //@ts-ignore this._infoService = new Service.AccessoryInformation(); this._infoService.setCharacteristic(Characteristic.Manufacturer, "The Watson Project") this._infoService.setCharacteristic(Characteristic.Model, "Device Button") this._infoService.setCharacteristic(Characteristic.SerialNumber, "123-456-789"); this._switchService = new Service.Switch( this.name, 'switchService' ) this._switchService.getCharacteristic(Characteristic.On) //@ts-ignore .on("set", this.onSwitchSet) .updateValue(this._buttonState) .on("get", this.onSwitchGet); } /** * Required by homebridge. */ public name: string; public platformAccessory: any; /** * Called by homebridge to gather services. */ public getServices = (): Array => { return [this._infoService, this._switchService!]; } /** * Handler for switch set event * @param callback The callback function to call when complete */ private onSwitchSet = async (activeState: boolean, callback: (error?: Error | null | undefined) => void) => { if (!this._buttonInfo.IsStateful && activeState === this._buttonState) { return callback(); } //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; } } //Execute command if (this._deviceCommand) { await this._dataProvider.sendCommand(this._deviceCommand); //change state if stateful if (this._buttonInfo.IsStateful) { this._buttonState != this._buttonState } else { this._switchService.getCharacteristic(Characteristic.On).updateValue(false); return callback(new Error("Normal Response")); } } return callback(); } /** * Handler for switch get event * @param callback The callback function to call when complete */ private onSwitchGet = (callback: (error: Error | null, value: boolean) => void) => { //Only return state if button is stateful if (this._buttonInfo.IsStateful) { return callback(null, this._buttonState); } else { return callback(null, false) } } /** * Helper function to generate a UUID */ private generateUUID(): string { // Public Domain/MIT var d = new Date().getTime(); if (typeof performance !== 'undefined' && typeof performance.now === 'function') { d += performance.now(); //use high-precision timer if available } return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = (d + Math.random() * 16) % 16 | 0; d = Math.floor(d / 16); return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); }); } }