UNPKG

homebridge-xfinityhome

Version:

A homebridge plugin to control your Xfinity Home security system.

278 lines 17.3 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.XfinityHomePlatform = void 0; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const xfinityhome_1 = __importStar(require("xfinityhome")); const LegacyDryContact_1 = require("xfinityhome/dist/devices/LegacyDryContact"); const Router_1 = require("xfinityhome/dist/devices/Router"); const DryContactAccessory_1 = __importDefault(require("./accessories/DryContactAccessory")); const LeakAccessory_1 = __importDefault(require("./accessories/LeakAccessory")); const LegacyDryContactAccessory_1 = __importDefault(require("./accessories/LegacyDryContactAccessory")); const LegacyMotionAccessory_1 = __importDefault(require("./accessories/LegacyMotionAccessory")); const LightAccessory_1 = __importDefault(require("./accessories/LightAccessory")); const MotionAccessory_1 = __importDefault(require("./accessories/MotionAccessory")); const PanelAccessory_1 = __importDefault(require("./accessories/PanelAccessory")); const SmokeAccessory_1 = __importDefault(require("./accessories/SmokeAccessory")); const UnknownAccessory_1 = __importDefault(require("./accessories/UnknownAccessory")); const CustomCharacteristics_1 = __importDefault(require("./CustomCharacteristics")); const settings_1 = require("./settings"); /** * HomebridgePlatform * This class is the main constructor for your plugin, this is where you should * parse the user config and discover/register accessories with Homebridge. */ class XfinityHomePlatform { constructor(log, config, api) { this.log = log; this.api = api; this.Service = this.api.hap.Service; this.Characteristic = this.api.hap.Characteristic; this.CustomCharacteristic = (0, CustomCharacteristics_1.default)(this.api.hap); /** this is used to track restored cached accessories */ this.cachedAccessories = []; /** this is used to track which accessories have been restored from the cache */ this.restoredAccessories = []; /** this is used to track which accessories have been added */ this.addedAccessories = []; this.config = config; this.api.setMaxListeners(0); this.log.debug('Finished initializing platform:', this.config.name); // When this event is fired it means Homebridge has restored all cached accessories from disk. // Dynamic Platform plugins should only register new accessories after this event was fired, // in order to ensure they weren't added to homebridge already. This event can also be used // to start discovery of new accessories. this.api.on("didFinishLaunching" /* APIEvent.DID_FINISH_LAUNCHING */, () => { log.debug('Executed didFinishLaunching callback'); const projectDir = path_1.default.join(api.user.storagePath(), 'XfinityHome'); const generalLogPath = path_1.default.join(projectDir, 'General.log'); if (!fs_1.default.existsSync(projectDir)) { fs_1.default.mkdirSync(projectDir); } const date = new Date(); const time = `${('0' + (date.getMonth() + 1)).slice(-2)}/${('0' + date.getDate()).slice(-2)}/${date.getFullYear()}, ` + `${('0' + (date.getHours() % 12)).slice(-2)}:${('0' + (date.getMinutes())).slice(-2)}:${('0' + (date.getSeconds())).slice(-2)} ` + `${date.getHours() > 12 ? 'PM' : 'AM'}`; fs_1.default.appendFileSync(generalLogPath, `[${time}] Server Started\n`); // run the method to discover / register your devices as accessories this.discoverDevices(); }); this.api.on("shutdown" /* APIEvent.SHUTDOWN */, () => { const projectDir = path_1.default.join(api.user.storagePath(), 'XfinityHome'); const generalLogPath = path_1.default.join(projectDir, 'General.log'); if (!fs_1.default.existsSync(projectDir)) { fs_1.default.mkdirSync(projectDir); } const date = new Date(); const time = `${('0' + (date.getMonth() + 1)).slice(-2)}/${('0' + date.getDate()).slice(-2)}/${date.getFullYear()}, ` + `${('0' + (date.getHours() % 12)).slice(-2)}:${('0' + (date.getMinutes())).slice(-2)}:${('0' + (date.getSeconds())).slice(-2)} ` + `${date.getHours() > 12 ? 'PM' : 'AM'}`; fs_1.default.appendFileSync(generalLogPath, `[${time}] Server Stopped\n`); }); } /** * This function is invoked when homebridge restores cached accessories from disk at startup. * It should be used to setup event handlers for characteristics and update respective values. */ configureAccessory(accessory) { this.log.debug('Loading accessory from cache:', accessory.displayName); // add the restored accessory to the accessories cache so we can track if it has already been registered this.cachedAccessories.push(accessory); } /** * This is an example method showing how to register discovered accessories. * Accessories must only be registered once, previously created accessories * must not be registered again to prevent "duplicate UUID" errors. */ async discoverDevices() { var _a; if (this.refreshToken) { this.log.info('Using Refresh Token From Cache:', this.refreshToken); } else if (this.config.refreshToken) { this.log.info('Using Refresh Token From Config:', this.config.refreshToken); } else { this.log.error('No Refresh Token Found'); return; } this.xhome = new xfinityhome_1.default(this.refreshToken || this.config.refreshToken, { enabled: true, autoFetch: false, errorHandler: this.config.logWatchdogErrors ? err => this.log.warn('Watchdog Error:', err) : undefined, }); this.log.info(`Loaded ${this.cachedAccessories.length} ${this.cachedAccessories.length === 1 ? 'Accessory' : 'Accessories'} From Cache`); try { for (const device of await this.xhome.getDevices()) { if ([xfinityhome_1.Keyfob, xfinityhome_1.Keypad, xfinityhome_1.Camera, Router_1.Router].find(blockedAccessory => device instanceof blockedAccessory || (device instanceof xfinityhome_1.Unknown && device.device.model === 'TCHU1AL0')) === undefined) { const uuid = this.api.hap.uuid.generate(device.device.hardwareId); const existingAccessory = this.cachedAccessories.find(accessory => accessory.UUID === uuid); if (existingAccessory) { this.log.debug('Restoring existing accessory from cache:', existingAccessory.displayName); this.restoredAccessories.push(existingAccessory); switch (device.constructor) { case xfinityhome_1.Panel: new PanelAccessory_1.default(this, existingAccessory, device); break; case xfinityhome_1.Light: new LightAccessory_1.default(this, existingAccessory, device); break; case xfinityhome_1.Motion: new MotionAccessory_1.default(this, existingAccessory, device); break; case xfinityhome_1.LegacyMotion: new LegacyMotionAccessory_1.default(this, existingAccessory, device); break; case xfinityhome_1.Smoke: new SmokeAccessory_1.default(this, existingAccessory, device); break; case xfinityhome_1.Water: new LeakAccessory_1.default(this, existingAccessory, device); break; case xfinityhome_1.DryContact: new DryContactAccessory_1.default(this, existingAccessory, device); break; case LegacyDryContact_1.LegacyDryContact: new LegacyDryContactAccessory_1.default(this, existingAccessory, device); break; case xfinityhome_1.Keyfob: case xfinityhome_1.Keypad: case xfinityhome_1.Camera: case Router_1.Router: this.restoredAccessories.slice(-1); break; default: switch ('model' in device.device ? device.device.model : '') { case 'TCHU1AL0': break; default: new UnknownAccessory_1.default(this, existingAccessory, device); break; } break; } } else { const name = device instanceof xfinityhome_1.Panel ? 'Panel' : device.device.name || ('model' in device.device ? device.device.model : 'unknown'); // the accessory does not yet exist, so we need to create it this.log.info('Adding new accessory:', name); // create a new accessory let accessory; switch (device.constructor) { case xfinityhome_1.Panel: accessory = new this.api.platformAccessory(name, uuid, 11 /* Categories.SECURITY_SYSTEM */); new PanelAccessory_1.default(this, accessory, device); break; case xfinityhome_1.Light: accessory = new this.api.platformAccessory(name, uuid, 7 /* Categories.OUTLET */); new LightAccessory_1.default(this, accessory, device); break; case xfinityhome_1.Motion: accessory = new this.api.platformAccessory(name, uuid, 10 /* Categories.SENSOR */); new MotionAccessory_1.default(this, accessory, device); break; case xfinityhome_1.LegacyMotion: accessory = new this.api.platformAccessory(name, uuid, 10 /* Categories.SENSOR */); new LegacyMotionAccessory_1.default(this, accessory, device); break; case xfinityhome_1.Smoke: accessory = new this.api.platformAccessory(name, uuid, 10 /* Categories.SENSOR */); new SmokeAccessory_1.default(this, accessory, device); break; case xfinityhome_1.Water: accessory = new this.api.platformAccessory(name, uuid, 10 /* Categories.SENSOR */); new LeakAccessory_1.default(this, accessory, device); break; case xfinityhome_1.DryContact: accessory = new this.api.platformAccessory(name, uuid, device.device.properties.type === 'door' ? 12 /* Categories.DOOR */ : 13 /* Categories.WINDOW */); new DryContactAccessory_1.default(this, accessory, device); break; case LegacyDryContact_1.LegacyDryContact: accessory = new this.api.platformAccessory(name, uuid, device.device.properties.type === 'door' ? 12 /* Categories.DOOR */ : 13 /* Categories.WINDOW */); new LegacyDryContactAccessory_1.default(this, accessory, device); break; default: accessory = new this.api.platformAccessory(name, uuid); new UnknownAccessory_1.default(this, accessory, device); break; } // store a copy of the device object in the `accessory.context` // the `context` property can be used to store any data about the accessory you may need accessory.context.device = device.device; this.addedAccessories.push(accessory); } } } } catch (err) { this.log.error('Failed To Login With Error:', (typeof err === 'object' && err && 'message' in err) ? err.message : err); const projectDir = path_1.default.join(this.api.user.storagePath(), 'XfinityHome'); const generalLogPath = path_1.default.join(projectDir, 'General.log'); if (!fs_1.default.existsSync(projectDir)) { fs_1.default.mkdirSync(projectDir); } const date = new Date(); const time = `${('0' + (date.getMonth() + 1)).slice(-2)}/${('0' + date.getDate()).slice(-2)}/${date.getFullYear()}, ` + `${('0' + (date.getHours() % 12)).slice(-2)}:${('0' + (date.getMinutes())).slice(-2)}:${('0' + (date.getSeconds())).slice(-2)} ` + `${date.getHours() > 12 ? 'PM' : 'AM'}`; fs_1.default.appendFileSync(generalLogPath, `[${time}] Error Encountered While Logging In: ${JSON.stringify(err)}\n`); if (this.refreshToken) { this.log.warn('Attempting To Login With Config Refresh Token'); this.refreshToken = undefined; this.discoverDevices(); } else { const error = (err && typeof err === 'object' && 'isAxiosError' in err) ? err : undefined; if (error) { if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.code) === 400) { this.log.warn('Refresh Token is Invalid'); this.log.warn('Xfinity May Have Reset Your Account Password'); this.log.warn('See https://assets.xfinity.com/assets/dotcom/learn/Data-Incident.pdf For More Details'); } } this.log.error('Plugin Setup Failed, Will Not Restart'); } return; } const accessoriesToRemove = this.cachedAccessories.filter(cachedAccessory => !this.restoredAccessories.find(restoredAccessory => restoredAccessory.UUID === cachedAccessory.UUID)); for (const accessory of accessoriesToRemove) { this.log.warn('Removing Accessory: ', accessory.displayName); this.api.unregisterPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory]); } // link the accessories to your platform this.api.registerPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [...this.addedAccessories]); this.log.info(`Restored ${this.restoredAccessories.length} ${this.restoredAccessories.length === 1 ? 'Accessory' : 'Accessories'}`); this.log.info(`Added ${this.addedAccessories.length} ${this.addedAccessories.length === 1 ? 'Accessory' : 'Accessories'}`); this.log.info(`Removed ${accessoriesToRemove.length} ${accessoriesToRemove.length === 1 ? 'Accessory' : 'Accessories'}`); } } exports.XfinityHomePlatform = XfinityHomePlatform; //# sourceMappingURL=platform.js.map