Added device buttons
This commit is contained in:
parent
80ac6423e5
commit
588205e507
143
src/Accessories/DeviceButton.ts
Normal file
143
src/Accessories/DeviceButton.ts
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import HarmonyDataProvider from "../DataProviders/HarmonyDataProvider";
|
||||||
|
import { IDeviceButton } from "../Models/DeviceButton";
|
||||||
|
import { IAccessory } from "./IAccessory";
|
||||||
|
import { sleep } from "../Util/Sleep";
|
||||||
|
|
||||||
|
let Service: HAPNodeJS.Service;
|
||||||
|
let Characteristic: HAPNodeJS.Characteristic;
|
||||||
|
|
||||||
|
export interface IDeviceButtonProps {
|
||||||
|
dataProvider: HarmonyDataProvider,
|
||||||
|
name: 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: string = "";
|
||||||
|
|
||||||
|
private _buttonState: boolean;
|
||||||
|
|
||||||
|
|
||||||
|
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.name = props.name;
|
||||||
|
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) {
|
||||||
|
this._deviceCommand = this._dataProvider.getCommand(this._buttonInfo.ButtonName, this._buttonInfo.DeviceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
//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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -278,6 +278,37 @@ class HarmonyDataProvider {
|
|||||||
return this.states[controlUnitName] ? this.states[controlUnitName]!.currentActivity : undefined;
|
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): string {
|
||||||
|
const device: IDevice = this.getDeviceFromName(deviceName);
|
||||||
|
if (device && device.supportsCommand(deviceCommandName)) {
|
||||||
|
return device.getCommand(deviceCommandName);
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a command to the harmony hub.
|
||||||
|
* @param command The command to send.
|
||||||
|
*/
|
||||||
|
public sendCommand = async (command: string) => {
|
||||||
|
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
|
* Connect to harmony and receive device info
|
||||||
*/
|
*/
|
||||||
@ -386,23 +417,6 @@ class HarmonyDataProvider {
|
|||||||
|
|
||||||
return devicesToTurnOn;
|
return devicesToTurnOn;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a command to the harmony hub.
|
|
||||||
* @param command The command to send.
|
|
||||||
*/
|
|
||||||
private sendCommand = async (command: string) => {
|
|
||||||
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}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HarmonyDataProvider;
|
export default HarmonyDataProvider;
|
5
src/Models/DeviceButton.ts
Normal file
5
src/Models/DeviceButton.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export interface IDeviceButton {
|
||||||
|
DeviceName: string;
|
||||||
|
ButtonName: string;
|
||||||
|
IsStateful: boolean;
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
import { IMatrix } from "./Matrix";
|
import { IMatrix } from "./Matrix";
|
||||||
import { IActivity } from "./Activity";
|
import { IActivity } from "./Activity";
|
||||||
|
import { IDeviceButton } from "./DeviceButton";
|
||||||
|
|
||||||
export interface IControlUnit {
|
export interface IControlUnit {
|
||||||
DisplayName: string;
|
DisplayName: string;
|
||||||
@ -10,4 +11,5 @@ export interface IConfig {
|
|||||||
hubIp: string;
|
hubIp: string;
|
||||||
Matrix: IMatrix
|
Matrix: IMatrix
|
||||||
ControlUnits: Array<IControlUnit>
|
ControlUnits: Array<IControlUnit>
|
||||||
|
DeviceButtons: Array<IDeviceButton>
|
||||||
}
|
}
|
29
src/index.ts
29
src/index.ts
@ -1,9 +1,12 @@
|
|||||||
import { ControlUnit } from "./Accessories/ControlUnit";
|
import { ControlUnit } from "./Accessories/ControlUnit";
|
||||||
|
import { DeviceButton } from './Accessories/DeviceButton';
|
||||||
import { IActivity } from "./Models/Activity";
|
import { IActivity } from "./Models/Activity";
|
||||||
import { IDeviceSetupItem } from "./Models/DeviceSetupItem";
|
import { IDeviceSetupItem } from "./Models/DeviceSetupItem";
|
||||||
import { IInput, IOutput, IMatrix } from "./Models/Matrix";
|
import { IInput, IOutput, IMatrix } from "./Models/Matrix";
|
||||||
import HarmonyDataProvider from "./DataProviders/HarmonyDataProvider";
|
import HarmonyDataProvider from "./DataProviders/HarmonyDataProvider";
|
||||||
import { IConfig, IControlUnit } from "./Models/IConfig";
|
import { IConfig, IControlUnit } from "./Models/IConfig";
|
||||||
|
import { IDeviceButton } from "./Models/DeviceButton";
|
||||||
|
import { IAccessory } from "./Accessories/IAccessory";
|
||||||
|
|
||||||
let Accessory: any;
|
let Accessory: any;
|
||||||
let Homebridge: any;
|
let Homebridge: any;
|
||||||
@ -28,7 +31,7 @@ class HarmonyMatrixPlatform {
|
|||||||
config: IConfig;
|
config: IConfig;
|
||||||
api: any;
|
api: any;
|
||||||
dataProvider: HarmonyDataProvider | null;
|
dataProvider: HarmonyDataProvider | null;
|
||||||
controlUnits: Array<ControlUnit> = [];
|
accessoryList: Array<IAccessory> = [];
|
||||||
|
|
||||||
constructor(log: any, config: any, api: any) {
|
constructor(log: any, config: any, api: any) {
|
||||||
this.log = log;
|
this.log = log;
|
||||||
@ -48,8 +51,10 @@ class HarmonyMatrixPlatform {
|
|||||||
this.log(`Publishing external accessories`);
|
this.log(`Publishing external accessories`);
|
||||||
|
|
||||||
//This is required in order to have multiple tv remotes on one platform
|
//This is required in order to have multiple tv remotes on one platform
|
||||||
this.controlUnits.forEach((accessory: ControlUnit) => {
|
this.accessoryList.forEach((accessory: IAccessory) => {
|
||||||
|
if (accessory instanceof ControlUnit) {
|
||||||
this.api.publishExternalAccessories("HarmonyMatrixPlatform", [accessory.platformAccessory]);
|
this.api.publishExternalAccessories("HarmonyMatrixPlatform", [accessory.platformAccessory]);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +62,7 @@ class HarmonyMatrixPlatform {
|
|||||||
* Called by homebridge to gather accessories.
|
* Called by homebridge to gather accessories.
|
||||||
* @param callback
|
* @param callback
|
||||||
*/
|
*/
|
||||||
accessories(callback: (accessories: Array<ControlUnit>) => void) {
|
accessories(callback: (accessories: Array<IAccessory>) => void) {
|
||||||
//construct data provider
|
//construct data provider
|
||||||
this.dataProvider = new HarmonyDataProvider({
|
this.dataProvider = new HarmonyDataProvider({
|
||||||
hubAddress: this.config.hubIp,
|
hubAddress: this.config.hubIp,
|
||||||
@ -65,8 +70,9 @@ class HarmonyMatrixPlatform {
|
|||||||
log: this.log
|
log: this.log
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//Add control units
|
||||||
this.config.ControlUnits.forEach((unit: IControlUnit) => {
|
this.config.ControlUnits.forEach((unit: IControlUnit) => {
|
||||||
this.controlUnits.push(new ControlUnit({
|
this.accessoryList.push(new ControlUnit({
|
||||||
dataProvider: this.dataProvider!,
|
dataProvider: this.dataProvider!,
|
||||||
displayName: unit.DisplayName,
|
displayName: unit.DisplayName,
|
||||||
api: this.api,
|
api: this.api,
|
||||||
@ -75,6 +81,19 @@ class HarmonyMatrixPlatform {
|
|||||||
homebridge: Homebridge,
|
homebridge: Homebridge,
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
callback(this.controlUnits);
|
|
||||||
|
//Add device buttons
|
||||||
|
this.config.DeviceButtons.forEach((button: IDeviceButton) => {
|
||||||
|
this.accessoryList.push(new DeviceButton({
|
||||||
|
dataProvider: this.dataProvider!,
|
||||||
|
name: button.ButtonName,
|
||||||
|
deviceInfo: button,
|
||||||
|
api: this.api,
|
||||||
|
log: this.log,
|
||||||
|
homebridge: Homebridge,
|
||||||
|
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
callback(this.accessoryList);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user