151 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			151 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
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<HAPNodeJS.Service> => {
 | 
						|
        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);
 | 
						|
        });
 | 
						|
    }
 | 
						|
} |