homebridge-xfinityhome
Version:
A homebridge plugin to control your Xfinity Home security system.
194 lines • 10.6 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const xfinityhome_1 = require("xfinityhome");
const Accessory_1 = __importDefault(require("./Accessory"));
class PanelAccessory extends Accessory_1.default {
constructor(platform, accessory, device) {
super(platform, accessory, device, accessory.getService(platform.Service.SecuritySystem) ||
accessory.addService(platform.Service.SecuritySystem));
this.platform = platform;
this.accessory = accessory;
this.device = device;
this.armModes = ['stay', 'away', 'night', 'disarmed', 'triggered'];
this.service.addOptionalCharacteristic(this.platform.CustomCharacteristic.PanelStatus);
this.service.getCharacteristic(this.platform.Characteristic.SecuritySystemCurrentState)
.onGet(this.getCurrentState.bind(this, false))
.on('change', this.notifyCurrentStateChange.bind(this));
this.service.getCharacteristic(this.platform.Characteristic.SecuritySystemTargetState)
.onGet(this.getTargetState.bind(this))
.onSet(this.setTargetState.bind(this))
.on('change', this.notifyTargetChange.bind(this));
this.service.getCharacteristic(this.platform.Characteristic.StatusTampered)
.onGet(this.getTampered.bind(this))
.on('change', this.notifyTamperedChange.bind(this));
this.service.getCharacteristic(this.platform.CustomCharacteristic.PanelStatus)
.onGet(this.getStatus.bind(this))
.on('change', this.notifyStatusChange.bind(this));
this.service.getCharacteristic(this.platform.CustomCharacteristic.PanelArmType)
.onGet(this.getArmType.bind(this))
.on('change', this.notifyArmTypeChange.bind(this));
this.device.onevent = async (event) => {
if (event.mediaType === 'event/securityStateChange') {
this.device.device.properties.status = event.metadata.status;
this.service.updateCharacteristic(this.platform.CustomCharacteristic.PanelStatus, this.getStatus());
event.metadata.armType !== null ? this.device.device.properties.armType = event.metadata.armType : undefined;
this.service.updateCharacteristic(this.platform.CustomCharacteristic.PanelArmType, this.getArmType());
this.service.updateCharacteristic(this.platform.Characteristic.SecuritySystemTargetState, this.getTargetState());
this.service.updateCharacteristic(this.platform.Characteristic.SecuritySystemCurrentState, await this.getCurrentState(true));
}
};
this.device.onchange = async (_oldState, newState) => {
/** Normally not updated until AFTER `onchange` function execution */
this.device.device = newState;
this.service.updateCharacteristic(this.platform.Characteristic.StatusTampered, this.getTampered());
this.service.updateCharacteristic(this.platform.CustomCharacteristic.PanelStatus, this.getStatus());
this.service.updateCharacteristic(this.platform.CustomCharacteristic.PanelArmType, this.getArmType());
this.service.updateCharacteristic(this.platform.Characteristic.SecuritySystemTargetState, this.getTargetState());
this.service.updateCharacteristic(this.platform.Characteristic.SecuritySystemCurrentState, await this.getCurrentState(true));
this.accessory.context.logPath = this.logPath;
this.accessory.context.device = newState;
this.accessory.context.refreshToken = this.platform.xhome.refreshToken;
this.platform.api.updatePlatformAccessories([this.accessory]);
if (this.device.device.trouble.length && !this.getTampered()) {
this.log('warn', 'Unknown trouble detected!');
this.log('warn', 'Please open an issue about this.');
this.log('warn', JSON.stringify(this.device.device.trouble, null, 2));
}
if (!xfinityhome_1.status.includes(this.device.device.properties.status)) {
this.log('warn', 'Unknown current state:', this.device.device.properties.status);
this.log('warn', 'Please open an issue about this.');
}
};
}
getTargetState() {
return this.armModes.indexOf(this.device.device.properties.armType || 'disarmed');
}
async setTargetState(state) {
if (this.platform.config.pin) {
if (state === this.armModes.indexOf('disarmed')) {
this.device.device.properties.armType = '';
try {
await this.device.disarm(this.platform.config.pin);
}
catch (err) {
this.log('error', 'Failed To Disarm With Error:', err);
return Promise.reject(new this.StatusError(-70402 /* HAPStatus.SERVICE_COMMUNICATION_FAILURE */));
}
}
else {
this.device.device.properties.armType = this.armModes[state];
if (this.device.device.properties.status !== 'ready') {
try {
await this.device.arm(this.platform.config.pin, this.armModes[state]);
}
catch (err) {
this.log('error', 'Failed To Arm With Error:', 'NOT_READY');
this.log('debug', err);
this.service.updateCharacteristic(this.platform.Characteristic.SecuritySystemTargetState, this.getTargetState());
}
/*this.log('warn', 'Failed To Arm With Error:', 'NOT_ALLOWED_IN_CURRENT_STATE');
throw new this.StatusError(HAPStatus.NOT_ALLOWED_IN_CURRENT_STATE);*/
}
else {
try {
await this.device.arm(this.platform.config.pin, this.armModes[state]);
}
catch (err) {
this.log('error', 'Failed To Arm With Error:', err);
return Promise.reject(new this.StatusError(-70402 /* HAPStatus.SERVICE_COMMUNICATION_FAILURE */));
}
}
}
}
else {
this.log('warn', `Failed To ${state === this.armModes.indexOf('disarmed') ? 'Disarm' : 'Arm'} With Error:`, 'No Pin Configured');
return Promise.reject(new this.StatusError(-70411 /* HAPStatus.INSUFFICIENT_AUTHORIZATION */));
}
}
async notifyTargetChange(value) {
if (value.newValue !== value.oldValue) {
const mode = this.armModes[value.newValue].charAt(0).toUpperCase() + this.armModes[value.newValue].slice(1);
this.log(1, value.newValue === this.armModes.indexOf('disarmed') ? 'Disarming...' : `Arming ${mode}...`);
}
}
async getCurrentState(skipUpdate) {
if (skipUpdate !== true) {
if (this.platform.config.lazyUpdates) {
process.nextTick(() => {
this.device.get().catch(err => {
this.log('error', 'Failed To Fetch Current State With Error:', err);
// throw new this.StatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
});
});
}
else {
try {
const device = await this.device.get();
return device.properties.status === 'arming' ?
this.armModes.indexOf('disarmed') :
((device.properties.status === 'entryDelay' && this.platform.config.entryTrigger !== false) ||
device.properties.status === 'alarm') ?
this.armModes.indexOf('triggered') : this.armModes.indexOf(device.properties.armType || 'disarmed');
}
catch (err) {
this.log('error', 'Failed To Fetch Current State With Error:', err);
return Promise.reject(new this.StatusError(-70402 /* HAPStatus.SERVICE_COMMUNICATION_FAILURE */));
}
}
}
return this.device.device.properties.status === 'arming' ?
this.armModes.indexOf('disarmed') :
((this.device.device.properties.status === 'entryDelay' && this.platform.config.entryTrigger !== false) ||
this.device.device.properties.status === 'alarm') ?
this.armModes.indexOf('triggered') : this.armModes.indexOf(this.device.device.properties.armType || 'disarmed');
}
async notifyCurrentStateChange(value) {
if (value.newValue !== value.oldValue) {
const mode = this.armModes[value.newValue].charAt(0).toUpperCase() + this.armModes[value.newValue].slice(1);
setTimeout(() => {
if (value.newValue === this.armModes.indexOf('triggered')) {
this.log('warn', 'Alarm Triggered');
}
else {
this.log(1, value.newValue === this.armModes.indexOf('disarmed') ? 'Disarmed' : `Armed ${mode}`);
}
}, 500);
}
}
getTampered() {
return this.device.device.trouble.find(trouble => trouble.name === 'senTamp') ? 1 : 0;
}
async notifyTamperedChange(value) {
if (value.newValue !== value.oldValue) {
if (value.newValue) {
this.log('warn', 'Tampered');
}
else {
this.log(2, 'Fixed');
}
}
}
getStatus() {
return this.device.device.properties.status.charAt(0).toUpperCase() +
this.device.device.properties.status.slice(1).replace(/([A-Z])/g, ' $1').trim();
}
async notifyStatusChange(value) {
if (value.newValue !== value.oldValue) {
this.log(4, `Status Changed To ${value.newValue}`);
}
}
getArmType() {
return (this.device.device.properties.armType.charAt(0).toUpperCase() +
this.device.device.properties.armType.slice(1).replace(/([A-Z])/g, ' $1').trim()) || '(Disarmed)';
}
async notifyArmTypeChange(value) {
if (value.newValue !== value.oldValue) {
this.log(4, `Arm Type Changed To ${value.newValue}`);
}
}
}
exports.default = PanelAccessory;
//# sourceMappingURL=PanelAccessory.js.map