Created sequence accessory
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
1121dbc52c
commit
cdab6327f5
101
src/Accessories/Sequence.ts
Normal file
101
src/Accessories/Sequence.ts
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import {
|
||||||
|
CharacteristicGetCallback,
|
||||||
|
CharacteristicSetCallback,
|
||||||
|
PlatformAccessory,
|
||||||
|
Service,
|
||||||
|
} from "homebridge";
|
||||||
|
import HarmonyDataProvider from "../DataProviders/HarmonyDataProvider";
|
||||||
|
import { ISequence } from "../Models/Config/ISequence";
|
||||||
|
import { HarmonyDevice } from "../Models/HarmonyDevice";
|
||||||
|
import { Platform } from "../platform";
|
||||||
|
import { sleep } from "../Util";
|
||||||
|
|
||||||
|
export class Sequence {
|
||||||
|
private _devices: { [deviceName: string]: HarmonyDevice };
|
||||||
|
private _switchService: Service;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _platform: Platform,
|
||||||
|
private readonly _accessory: PlatformAccessory,
|
||||||
|
private _dataProvider: HarmonyDataProvider,
|
||||||
|
private _sequence: ISequence
|
||||||
|
) {
|
||||||
|
this._accessory
|
||||||
|
.getService(this._platform.Service.AccessoryInformation)!
|
||||||
|
.setCharacteristic(
|
||||||
|
this._platform.Characteristic.Manufacturer,
|
||||||
|
"Brandon Watson"
|
||||||
|
)
|
||||||
|
.setCharacteristic(this._platform.Characteristic.Model, "Sequence Button")
|
||||||
|
.setCharacteristic(
|
||||||
|
this._platform.Characteristic.SerialNumber,
|
||||||
|
"123-456-789"
|
||||||
|
);
|
||||||
|
|
||||||
|
const switchUUID = this._platform.api.hap.uuid.generate(
|
||||||
|
`${this._accessory.displayName} Switch`
|
||||||
|
);
|
||||||
|
|
||||||
|
this._switchService =
|
||||||
|
this._accessory.getService(this._platform.Service.Switch) ||
|
||||||
|
this._accessory.addService(
|
||||||
|
this._platform.Service.Switch,
|
||||||
|
this._accessory.displayName,
|
||||||
|
switchUUID
|
||||||
|
);
|
||||||
|
|
||||||
|
this._switchService
|
||||||
|
.getCharacteristic(this._platform.Characteristic.On)
|
||||||
|
.on("set", this.onSwitchSet)
|
||||||
|
.updateValue(false)
|
||||||
|
.on("get", (callback: CharacteristicGetCallback): void => {
|
||||||
|
return callback(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
this._devices = {};
|
||||||
|
// Get devices in sequence
|
||||||
|
for (const deviceName of _sequence.Steps.map((e) => e.DeviceName)) {
|
||||||
|
if (!deviceName) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const device = this._dataProvider.getDeviceFromName(deviceName);
|
||||||
|
if (device) {
|
||||||
|
this._devices[deviceName] = device;
|
||||||
|
} else {
|
||||||
|
this._platform.log.warn(
|
||||||
|
`Device ${deviceName} was not found in harmony configuration`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for switchSet command
|
||||||
|
* @param callback
|
||||||
|
*/
|
||||||
|
public async onSwitchSet(callback: CharacteristicSetCallback): Promise<void> {
|
||||||
|
// Execute sequence
|
||||||
|
for (const step of this._sequence.Steps) {
|
||||||
|
await sleep(step.Delay);
|
||||||
|
const device: HarmonyDevice = this._devices[step.DeviceName ?? ""];
|
||||||
|
if (
|
||||||
|
device &&
|
||||||
|
step.DeviceCommand &&
|
||||||
|
device.supportsCommand(step.DeviceCommand)
|
||||||
|
) {
|
||||||
|
await device.sendCommand(step.DeviceCommand);
|
||||||
|
} else {
|
||||||
|
this._platform.log.warn(
|
||||||
|
`Attempted to execute command ${step.DeviceCommand} on device ${step.DeviceName} but the device or command was not found`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deactivate button
|
||||||
|
this._switchService
|
||||||
|
.getCharacteristic(this._platform.Characteristic.On)
|
||||||
|
.updateValue(false);
|
||||||
|
|
||||||
|
callback(null);
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
export interface ISequence {
|
export interface ISequence {
|
||||||
name: string;
|
DisplayName: string;
|
||||||
steps: Array<IStep>;
|
Steps: Array<IStep>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IStep {
|
export interface IStep {
|
||||||
deviceName: string;
|
DeviceName?: string;
|
||||||
deviceCommand: string;
|
DeviceCommand?: string;
|
||||||
delay: number;
|
Delay: number;
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,10 @@ import {
|
|||||||
Service,
|
Service,
|
||||||
} from "homebridge";
|
} from "homebridge";
|
||||||
import { ControlUnit, DeviceButton } from "./Accessories";
|
import { ControlUnit, DeviceButton } from "./Accessories";
|
||||||
|
import { Sequence } from "./Accessories/Sequence";
|
||||||
import HarmonyDataProvider from "./DataProviders/HarmonyDataProvider";
|
import HarmonyDataProvider from "./DataProviders/HarmonyDataProvider";
|
||||||
import { IConfig, IControlUnit, IDeviceButton } from "./Models/Config";
|
import { IConfig, IControlUnit, IDeviceButton } from "./Models/Config";
|
||||||
|
import { ISequence } from "./Models/Config/ISequence";
|
||||||
import { HarmonyDevice } from "./Models/HarmonyDevice";
|
import { HarmonyDevice } from "./Models/HarmonyDevice";
|
||||||
import { HarmonyHub } from "./Models/HarmonyHub";
|
import { HarmonyHub } from "./Models/HarmonyHub";
|
||||||
import { PLATFORM_NAME, PLUGIN_NAME } from "./settings";
|
import { PLATFORM_NAME, PLUGIN_NAME } from "./settings";
|
||||||
@ -33,7 +35,6 @@ export class Platform implements DynamicPlatformPlugin {
|
|||||||
|
|
||||||
this.api.on("didFinishLaunching", async () => {
|
this.api.on("didFinishLaunching", async () => {
|
||||||
log.debug("Executed didFinishLaunching callback");
|
log.debug("Executed didFinishLaunching callback");
|
||||||
this.discoverDevices(dataProvider);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.dataProvider = null;
|
this.dataProvider = null;
|
||||||
@ -51,6 +52,9 @@ export class Platform implements DynamicPlatformPlugin {
|
|||||||
|
|
||||||
this.dataProvider.on("Ready", () => {
|
this.dataProvider.on("Ready", () => {
|
||||||
this.log.info("All hubs connected");
|
this.log.info("All hubs connected");
|
||||||
|
this.discoverControlUnitAccessories(dataProvider);
|
||||||
|
this.discoverDeviceButtonAccessories(dataProvider);
|
||||||
|
this.discoverSequenceAccessories(dataProvider);
|
||||||
if (this.config.EmitDevicesOnStartup) {
|
if (this.config.EmitDevicesOnStartup) {
|
||||||
const hubs = this.dataProvider!.hubs;
|
const hubs = this.dataProvider!.hubs;
|
||||||
Object.values(hubs).forEach((hub: HarmonyHub) => {
|
Object.values(hubs).forEach((hub: HarmonyHub) => {
|
||||||
@ -78,10 +82,17 @@ export class Platform implements DynamicPlatformPlugin {
|
|||||||
public config: IConfig;
|
public config: IConfig;
|
||||||
public dataProvider: HarmonyDataProvider | null;
|
public dataProvider: HarmonyDataProvider | null;
|
||||||
|
|
||||||
public discoverDevices(dataProvider: HarmonyDataProvider) {
|
/**
|
||||||
|
* Discover new control unit accessories
|
||||||
|
* @param dataProvider
|
||||||
|
*/
|
||||||
|
private discoverControlUnitAccessories(
|
||||||
|
dataProvider: HarmonyDataProvider
|
||||||
|
): void {
|
||||||
this.config.ControlUnits.forEach((unit: IControlUnit) => {
|
this.config.ControlUnits.forEach((unit: IControlUnit) => {
|
||||||
const uuid = this.api.hap.uuid.generate(unit.DisplayName);
|
const uuid = this.api.hap.uuid.generate(unit.DisplayName);
|
||||||
const existingAccessory = this.accessories.find((e) => e.UUID === uuid);
|
const existingAccessory = this.accessories.find((e) => e.UUID === uuid);
|
||||||
|
|
||||||
if (existingAccessory) {
|
if (existingAccessory) {
|
||||||
this.log.info(
|
this.log.info(
|
||||||
"Restoring existing accessory from cache: " +
|
"Restoring existing accessory from cache: " +
|
||||||
@ -106,7 +117,15 @@ export class Platform implements DynamicPlatformPlugin {
|
|||||||
console.log("Publishing external accessory: " + uuid);
|
console.log("Publishing external accessory: " + uuid);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discover new device button accessories
|
||||||
|
* @param dataProvider
|
||||||
|
*/
|
||||||
|
private discoverDeviceButtonAccessories(
|
||||||
|
dataProvider: HarmonyDataProvider
|
||||||
|
): void {
|
||||||
this.config.DeviceButtons.forEach((button: IDeviceButton) => {
|
this.config.DeviceButtons.forEach((button: IDeviceButton) => {
|
||||||
const uuid = this.api.hap.uuid.generate(button.DisplayName);
|
const uuid = this.api.hap.uuid.generate(button.DisplayName);
|
||||||
const existingAccessory = this.accessories.find((e) => e.UUID === uuid);
|
const existingAccessory = this.accessories.find((e) => e.UUID === uuid);
|
||||||
@ -133,6 +152,65 @@ export class Platform implements DynamicPlatformPlugin {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Remove old device buttons
|
||||||
|
for (const accessory of this.accessories) {
|
||||||
|
if (
|
||||||
|
this.config.DeviceButtons.filter(
|
||||||
|
(button) => button.DisplayName === accessory.displayName
|
||||||
|
).length === 0
|
||||||
|
) {
|
||||||
|
this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [
|
||||||
|
accessory,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discover new sequence accessories
|
||||||
|
* @param dataProvider
|
||||||
|
*/
|
||||||
|
public discoverSequenceAccessories(dataProvider: HarmonyDataProvider): void {
|
||||||
|
this.config.Sequences.forEach((sequence: ISequence) => {
|
||||||
|
const uuid = this.api.hap.uuid.generate(sequence.DisplayName);
|
||||||
|
const existingAccessory = this.accessories.find((e) => e.UUID === uuid);
|
||||||
|
if (existingAccessory) {
|
||||||
|
this.log.info(
|
||||||
|
"Restoring existing accessory from cache: " +
|
||||||
|
existingAccessory.displayName
|
||||||
|
);
|
||||||
|
|
||||||
|
new Sequence(this, existingAccessory, dataProvider, sequence);
|
||||||
|
this.api.updatePlatformAccessories([existingAccessory]);
|
||||||
|
} else {
|
||||||
|
this.log.info("Adding new accessory: " + sequence.DisplayName);
|
||||||
|
const accessory = new this.api.platformAccessory(
|
||||||
|
sequence.DisplayName,
|
||||||
|
uuid
|
||||||
|
);
|
||||||
|
accessory.context["DeviceName"] = sequence.DisplayName;
|
||||||
|
|
||||||
|
new Sequence(this, accessory, dataProvider, sequence);
|
||||||
|
|
||||||
|
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [
|
||||||
|
accessory,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove old device buttons
|
||||||
|
for (const accessory of this.accessories) {
|
||||||
|
if (
|
||||||
|
this.config.Sequences.filter(
|
||||||
|
(sequence) => sequence.DisplayName === accessory.displayName
|
||||||
|
).length === 0
|
||||||
|
) {
|
||||||
|
this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [
|
||||||
|
accessory,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configureAccessory(accessory: PlatformAccessory<Record<string, any>>): void {
|
configureAccessory(accessory: PlatformAccessory<Record<string, any>>): void {
|
||||||
|
Loading…
Reference in New Issue
Block a user