@henrywang/homebridge-yalesyncalarm
Version:
Homebridge plugin for the Yale Sync Alarm
366 lines • 18.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const yalesyncalarm_1 = require("yalesyncalarm");
const YaleSyncPlatformConfig_1 = require("./YaleSyncPlatformConfig");
const Logger_1 = require("yalesyncalarm/dist/Logger");
const Model_1 = require("yalesyncalarm/dist/Model");
const Wait_1 = require("./Wait");
let Service;
let Characteristic;
let UUIDGenerator;
let Categories;
let PlatformAccessory;
let pluginName = 'homebridge-yalesyncalarm';
let platformName = 'YaleSyncAlarm';
function default_1(homebridge) {
Service = homebridge.hap.Service;
Characteristic = homebridge.hap.Characteristic;
UUIDGenerator = homebridge.hap.uuid;
Categories = homebridge.hap.Accessory.Categories;
PlatformAccessory = homebridge.platformAccessory;
homebridge.registerPlatform(pluginName, platformName, YaleSyncPlatform, true);
}
exports.default = default_1;
function modeToCurrentState(mode) {
switch (mode) {
case "arm":
return Characteristic.SecuritySystemCurrentState.AWAY_ARM;
case "disarm":
return Characteristic.SecuritySystemCurrentState.DISARMED;
case "home":
return Characteristic.SecuritySystemCurrentState.NIGHT_ARM;
}
}
function targetStateToString(state) {
if (state === Characteristic.SecuritySystemTargetState.STAY_ARM) {
return 'home';
}
else if (state === Characteristic.SecuritySystemTargetState.AWAY_ARM) {
return 'away';
}
else if (state === Characteristic.SecuritySystemTargetState.NIGHT_ARM) {
return 'night';
}
else if (state === Characteristic.SecuritySystemTargetState.DISARM) {
return 'off';
}
}
function currentStateToString(state) {
if (state === Characteristic.SecuritySystemCurrentState.STAY_ARM) {
return 'home';
}
else if (state === Characteristic.SecuritySystemCurrentState.AWAY_ARM) {
return 'away';
}
else if (state === Characteristic.SecuritySystemCurrentState.NIGHT_ARM) {
return 'night';
}
else if (state === Characteristic.SecuritySystemCurrentState.DISARMED) {
return 'off';
}
else if (state === Characteristic.SecuritySystemCurrentState.ALARM_TRIGGERED) {
return 'triggered';
}
}
function targetStateToMode(targetState) {
if (targetState === Characteristic.SecuritySystemTargetState.AWAY_ARM) {
return "arm";
}
else if (targetState === Characteristic.SecuritySystemTargetState.DISARM) {
return "disarm";
}
else {
return "home";
}
}
class YaleSyncPlatform {
constructor(_log, config, _api) {
this._log = _log;
this._api = _api;
this._accessories = {};
try {
const platformConfig = YaleSyncPlatformConfig_1.platformConfigDecoder.decodeAny(config);
this._yale = new yalesyncalarm_1.Yale(platformConfig.username, platformConfig.password, new Logger_1.Logger(Logger_1.LogLevel.Info | Logger_1.LogLevel.Error, this._log));
this._api.on('didFinishLaunching', async () => {
await this.onDidFinishLaunching();
const refreshInterval = platformConfig.refreshInterval;
if (refreshInterval >= 1) {
this._log(`Refresh interval is ${refreshInterval} seconds, starting periodic updates`);
this.heartbeat(refreshInterval);
}
else {
this._log(`Refresh interval is < 1 second, periodic updates disabled`);
}
});
}
catch (error) {
this._log(error.message);
}
}
async heartbeat(interval) {
var _a, _b, _c;
if (this._yale === undefined) {
return;
}
await Wait_1.default(interval * 1000);
await this._yale.update();
const [panel, motionSensors, contactSensors] = await Promise.all([
await this._yale.panel(),
await this._yale.motionSensors(),
await this._yale.contactSensors(),
]);
for (let [uuid, accessory] of Object.entries(this._accessories)) {
if (accessory.context.kind === 'panel' && panel !== undefined) {
if (accessory.identifier === panel.identifier) {
(_a = accessory
.getService(Service.SecuritySystem)
.getCharacteristic(Characteristic.SecuritySystemCurrentState)) === null || _a === void 0 ? void 0 : _a.setValue(modeToCurrentState(panel.state), undefined, 'no_recurse');
}
}
else if (accessory.context.kind === 'motionSensor') {
const motionSensor = motionSensors[accessory.context.identifier];
if (motionSensor) {
(_b = accessory
.getService(Service.MotionSensor)
.getCharacteristic(Characteristic.MotionDetected)) === null || _b === void 0 ? void 0 : _b.setValue(motionSensor.state === Model_1.MotionSensor.State.Triggered ? true : false, undefined, 'no_recurse');
}
}
else if (accessory.context.kind === 'contactSensor') {
const contactSensor = contactSensors[accessory.context.identifier];
if (contactSensor) {
(_c = accessory
.getService(Service.ContactSensor)
.getCharacteristic(Characteristic.ContactSensorState)) === null || _c === void 0 ? void 0 : _c.setValue(contactSensor.state === Model_1.ContactSensor.State.Closed
? 0
: 1, undefined, 'no_recurse');
}
}
}
this.heartbeat(interval);
}
async onDidFinishLaunching() {
if (this._yale === undefined) {
return;
}
this._log('Searching for devices');
await this._yale.update();
const panel = await this._yale.panel();
if (panel !== undefined) {
this._log(`Discovered panel: ${panel.identifier}`);
const uuid = UUIDGenerator.generate(`${pluginName}.${platformName}.panel.${panel.identifier}`);
if (this._accessories[uuid] === undefined) {
const accessory = new PlatformAccessory('Alarm System', uuid, Categories.SECURITY_SYSTEM);
accessory.context.identifier = panel.identifier;
accessory.context.kind = 'panel';
this.configurePanel(accessory);
this._log(`Registering alarm panel: ${panel.identifier}`);
this._api.registerPlatformAccessories(pluginName, platformName, [
accessory,
]);
}
else {
this._log(`Panel: ${panel.identifier} already registered with Homebridge`);
}
}
const motionSensors = await this._yale.motionSensors();
for (let [identifier, motionSensor] of Object.entries(motionSensors)) {
this._log(`Discovered moton sensor: ${motionSensor.name}, ${motionSensor.identifier}`);
const uuid = UUIDGenerator.generate(`${pluginName}.${platformName}.motionSensor.${identifier}`);
if (this._accessories[uuid] === undefined) {
const accessory = new PlatformAccessory(motionSensor.name, uuid, Categories.SENSOR);
accessory.context.identifier = identifier;
accessory.context.kind = 'motionSensor';
this.configureMotionSensor(accessory);
this._log(`Registering motion sensor: ${motionSensor.name} ${motionSensor.identifier}`);
this._api.registerPlatformAccessories(pluginName, platformName, [
accessory,
]);
}
else {
this._log(`Motion sensor: ${motionSensor.name} ${motionSensor.identifier} already registered with Homebridge`);
}
}
const contactSensors = await this._yale.contactSensors();
for (let [identifier, contactSensor] of Object.entries(contactSensors)) {
this._log(`Discovered moton sensor: ${contactSensor.name} ${contactSensor.identifier}`);
const uuid = UUIDGenerator.generate(`${pluginName}.${platformName}.contactSensor.${identifier}`);
if (this._accessories[uuid] === undefined) {
const accessory = new PlatformAccessory(contactSensor.name, uuid, Categories.SENSOR);
accessory.context.identifier = identifier;
accessory.context.kind = 'contactSensor';
this.configureContactSensor(accessory);
this._log(`Registering contact sensor: ${contactSensor.name} ${contactSensor.identifier}`);
this._api.registerPlatformAccessories(pluginName, platformName, [
accessory,
]);
}
else {
this._log(`Contact sensor: ${contactSensor.name} ${contactSensor.identifier} already registered with Homebridge`);
}
}
}
configureAccessory(accessory) {
if (this._yale === undefined) {
return;
}
if (this._accessories[accessory.UUID] === undefined) {
if (accessory.context.kind === 'panel') {
this.configurePanel(accessory);
}
else if (accessory.context.kind === 'motionSensor') {
this.configureMotionSensor(accessory);
}
else if (accessory.context.kind === 'contactSensor') {
this.configureContactSensor(accessory);
}
}
}
configureMotionSensor(accessory) {
var _a;
if (this._yale === undefined) {
return;
}
if (this._accessories[accessory.UUID] === undefined) {
const informationService = accessory.getService(Service.AccessoryInformation);
informationService
.setCharacteristic(Characteristic.Name, accessory.displayName)
.setCharacteristic(Characteristic.Manufacturer, 'Yale')
.setCharacteristic(Characteristic.Model, 'Motion Sensor')
.setCharacteristic(Characteristic.SerialNumber, accessory.context.identifier);
const sensorService = accessory.getService(Service.MotionSensor) !== undefined
? accessory.getService(Service.MotionSensor)
: accessory.addService(Service.MotionSensor);
(_a = sensorService
.getCharacteristic(Characteristic.MotionDetected)) === null || _a === void 0 ? void 0 : _a.on('get', async (callback, context, connectionID) => {
var _a;
if (this._yale === undefined) {
callback(new Error(`${pluginName} incorrectly configured`));
return;
}
const motionSensors = await this._yale.motionSensors();
const motionSensor = motionSensors[accessory.context.identifier];
if (motionSensor !== undefined) {
this._log(`Fetching status of motion sensor: ${motionSensor.name} ${motionSensor.identifier}`);
callback(null, false);
const updated = await this._yale.updateMotionSensor(motionSensor);
if (updated !== undefined) {
this._log(`Motion sensor: ${motionSensor.name} ${motionSensor.identifier}, state: ${updated.state === Model_1.MotionSensor.State.Triggered
? 'triggered'
: 'none detected'}`);
(_a = sensorService
.getCharacteristic(Characteristic.MotionDetected)) === null || _a === void 0 ? void 0 : _a.updateValue(updated.state === Model_1.MotionSensor.State.Triggered ? true : false);
}
else {
callback(new Error(`Failed to get status of motion sensor: ${motionSensor.name} ${motionSensor.identifier}`));
}
}
else {
callback(new Error(`Motion sensor: ${accessory.context.identifier} not found`));
}
});
}
accessory.updateReachability(true);
this._accessories[accessory.UUID] = accessory;
}
configureContactSensor(accessory) {
var _a;
if (this._yale === undefined) {
return;
}
if (this._accessories[accessory.UUID] === undefined) {
const informationService = accessory.getService(Service.AccessoryInformation);
informationService
.setCharacteristic(Characteristic.Name, accessory.displayName)
.setCharacteristic(Characteristic.Manufacturer, 'Yale')
.setCharacteristic(Characteristic.Model, 'Contact Sensor')
.setCharacteristic(Characteristic.SerialNumber, accessory.context.identifier);
const sensorService = accessory.getService(Service.ContactSensor) !== undefined
? accessory.getService(Service.ContactSensor)
: accessory.addService(Service.ContactSensor);
(_a = sensorService
.getCharacteristic(Characteristic.ContactSensorState)) === null || _a === void 0 ? void 0 : _a.on('get', async (callback, context, connectionID) => {
var _a;
if (this._yale === undefined) {
callback(new Error(`${pluginName} incorrectly configured`));
return;
}
const contactSensors = await this._yale.contactSensors();
const contactSensor = contactSensors[accessory.context.identifier];
if (contactSensor !== undefined) {
this._log(`Fetching status of contact sensor: ${contactSensor.name} ${contactSensor.identifier}`);
callback(null, 0);
const updated = await this._yale.updateContactSensor(contactSensor);
if (updated !== undefined) {
this._log(`Contact sensor: ${contactSensor.name} ${contactSensor.identifier}, state: ${updated.state === Model_1.ContactSensor.State.Closed
? 'closed'
: 'open'}`);
(_a = sensorService
.getCharacteristic(Characteristic.ContactSensorState)) === null || _a === void 0 ? void 0 : _a.updateValue(updated.state === Model_1.ContactSensor.State.Closed
? 0 : 1);
}
else {
callback(new Error(`Failed to get status of contact sensor: ${contactSensor.name} ${contactSensor.identifier}`));
}
}
else {
callback(new Error(`Contact sensor: ${accessory.context.identifier} not found`));
}
});
}
accessory.updateReachability(true);
this._accessories[accessory.UUID] = accessory;
}
configurePanel(accessory) {
var _a, _b, _c;
if (this._yale === undefined) {
return;
}
if (this._accessories[accessory.UUID] === undefined) {
const informationService = accessory.getService(Service.AccessoryInformation);
informationService
.setCharacteristic(Characteristic.Name, accessory.displayName)
.setCharacteristic(Characteristic.Manufacturer, 'Yale')
.setCharacteristic(Characteristic.Model, 'Yale IA-320')
.setCharacteristic(Characteristic.SerialNumber, accessory.context.identifier);
const securitySystem = accessory.getService(Service.SecuritySystem) !== undefined
? accessory.getService(Service.SecuritySystem)
: accessory.addService(Service.SecuritySystem);
(_a = securitySystem
.getCharacteristic(Characteristic.SecuritySystemCurrentState)) === null || _a === void 0 ? void 0 : _a.on('get', async (callback, context, connectionID) => {
if (this._yale === undefined) {
callback(new Error(`${pluginName} incorrectly configured`));
return;
}
this._log(`Fetching panel state`);
let panelMode = await this._yale.getPanelState();
let panelState = modeToCurrentState(panelMode);
this._log(`Panel mode: ${panelMode}, HomeKit state: ${currentStateToString(panelState)}`);
callback(null, panelState);
});
(_c = (_b = securitySystem
.getCharacteristic(Characteristic.SecuritySystemTargetState)) === null || _b === void 0 ? void 0 : _b.on('get', async (callback, context, connectionID) => {
if (this._yale === undefined) {
callback(new Error(`${pluginName} incorrectly configured`));
return;
}
let panelState = await this._yale.getPanelState();
callback(null, modeToCurrentState(panelState));
})) === null || _c === void 0 ? void 0 : _c.on('set', async (targetState, callback, context, connectionID) => {
var _a;
if (this._yale === undefined) {
callback(new Error(`${pluginName} incorrectly configured`));
return;
}
if (context !== 'no_recurse') {
callback();
const mode = await this._yale.setPanelState(targetStateToMode(targetState));
this._log(`Panel mode: ${mode}, HomeKit state: ${currentStateToString(modeToCurrentState(mode))}`);
(_a = securitySystem.getCharacteristic(Characteristic.SecuritySystemCurrentState)) === null || _a === void 0 ? void 0 : _a.updateValue(modeToCurrentState(mode));
}
});
accessory.updateReachability(true);
this._accessories[accessory.UUID] = accessory;
}
}
}
//# sourceMappingURL=YaleSyncPlatform.js.map