UNPKG

homebridge-tahoma

Version:

Sample Platform plugin for TaHoma and Cozytouch services (Somfy,Atlantic,Thermor,Sauter): https://github.com/dubocr/homebridge-tahoma

254 lines 13.1 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 () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __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.Platform = exports.Characteristics = exports.Services = void 0; const settings_1 = require("./settings"); const overkiz_client_1 = require("overkiz-client"); const Mapper_1 = __importDefault(require("./Mapper")); const SceneMapper_1 = __importDefault(require("./SceneMapper")); const CustomCharacteristics_1 = require("./CustomCharacteristics"); const colors_1 = require("./colors"); const DEFAULT_RETRY_DELAY = 60; /** * 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 Platform { constructor(log, config, api) { var _a; this.log = log; this.config = config; this.api = api; // this is used to track restored cached accessories this.accessories = []; this.devicesConfig = []; this.retryDelay = DEFAULT_RETRY_DELAY; exports.Services = this.api.hap.Service; exports.Characteristics = this.api.hap.Characteristic; new CustomCharacteristics_1.CustomCharacteristics(this.api.hap); this.log.debug('Finished initializing platform:', this.config.name); process.on('unhandledRejection', (error) => this.log.error(error)); process.on('uncaughtException', (error) => this.log.error(error)); this.exclude = config.exclude || []; this.exclude.push('Pod', 'ConfigurationComponent', 'NetworkComponent', 'ProtocolGateway', 'ConsumptionSensor', 'OnOffHeatingSystem', 'Wifi', 'RemoteController', // AtlanticElectricalTowelDryer bad sensors 'io:LightIOSystemDeviceSensor', 'io:RelativeHumidityIOSystemDeviceSensor', 'WeatherForecastSensor'); this.exposeScenarios = config.exposeScenarios; (_a = config.devicesConfig) === null || _a === void 0 ? void 0 : _a.forEach(x => this.devicesConfig[x.key] = x); const logger = Object.assign({}, log, { debug: (...args) => { if (config['debug']) { log.info('\x1b[90m', ...args); } else { log.debug(args.shift(), ...args); } }, }); this.client = new overkiz_client_1.Client(logger, config); // 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', () => { log.debug('Executed didFinishLaunching callback'); // run the method to discover / register your devices as accessories this.discoverDevices(); if (this.config['service'] !== 'local') { this.loadLocation(); } }); } /** * 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. */ async loadLocation() { let countryCode = 'en'; const location = await this.client.getSetupLocation().catch((error) => this.log.warn('Fail to load lang file:', error)); if (location === null || location === void 0 ? void 0 : location.countryCode) { countryCode = location.countryCode.toLowerCase().trim(); } this.translations = await Promise.resolve(`${`./lang/${countryCode}.json`}`).then(s => __importStar(require(s))).catch(() => Promise.resolve().then(() => __importStar(require('./lang/en.json')))) .then((c) => c.default); } /** * 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. */ async configureAccessory(accessory) { if (!this.accessories.map((a) => a.UUID).includes(accessory.UUID)) { this.accessories.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() { try { const uuids = Array(); const devices = await this.client.getDevices(); this.log.debug(devices.length + ' devices discovered'); // loop over the discovered devices and register each one if it has not already been registered for (const device of devices) { if (this.exclude.includes(device.definition.uiClass) || this.exclude.includes(device.definition.widgetName) || this.exclude.includes(device.controllableName) || this.exclude.includes(device.label) || this.exclude.includes(device.protocol)) { continue; } // see if an accessory with the same uuid has already been registered and restored from // the cached devices we stored in the `configureAccessory` method above let accessory = this.accessories.find(accessory => accessory.UUID === device.uuid); if (accessory) { // the accessory already exists //this.log.info('Updating accessory:', accessory.displayName); /* const newaccessory = new this.api.platformAccessory(device.label, device.uuid); newaccessory.context.device = device; await this.configureAccessory(newaccessory); const services = newaccessory.services.map((service) => service.UUID); accessory.services .filter((service) => !services.includes(service.UUID)) .forEach((services) => accessory?.removeService(services)); this.api.updatePlatformAccessories([accessory]); */ } else { // the accessory does not yet exist, so we need to create it this.log.info('Create accessory:', device.label); accessory = new this.api.platformAccessory(device.label, device.uuid); //accessory.context.device = device; await this.configureAccessory(accessory); this.api.registerPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory]); } this.log.info(`Configure device ${colors_1.BLUE}${accessory.displayName}${colors_1.RESET}`); this.log.info(`${colors_1.GREY} ${device.definition.uiClass} > ${device.definition.widgetName}`); const mapper = await Promise.resolve(`${`./mappers/${device.definition.uiClass}/${device.definition.widgetName}/${device.uniqueName}`}`).then(s => __importStar(require(s))).catch(() => Promise.resolve(`${`./mappers/${device.definition.uiClass}/${device.definition.widgetName}`}`).then(s => __importStar(require(s)))) .catch(() => Promise.resolve(`${`./mappers/${device.definition.uiClass}`}`).then(s => __importStar(require(s)))) .then((c) => c.default) .catch(() => Mapper_1.default); new mapper(this, accessory, device).build(); uuids.push(device.uuid); } if (this.exposeScenarios) { const actionGroups = await this.client.getActionGroups(); for (const actionGroup of actionGroups) { if (this.exclude.includes(actionGroup.label) || actionGroup.label.startsWith('internal:') || actionGroup.label === '') { continue; } let accessory = this.accessories.find(accessory => accessory.UUID === actionGroup.oid); if (!accessory) { // the accessory does not yet exist, so we need to create it this.log.info('Create accessory', actionGroup.label); accessory = new this.api.platformAccessory(actionGroup.label, actionGroup.oid); await this.configureAccessory(accessory); this.api.registerPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory]); } this.log.info('Map scene', accessory.displayName); new SceneMapper_1.default(this, accessory, actionGroup); uuids.push(actionGroup.oid); } } const deleted = this.accessories.filter((accessory) => !uuids.includes(accessory.UUID)); this.api.unregisterPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, deleted); this.retryDelay = DEFAULT_RETRY_DELAY; } catch (error) { this.log.error(error); this.log.error('Retry in ' + this.retryDelay + ' sec...'); setTimeout(this.discoverDevices.bind(this), this.retryDelay * 1000); this.retryDelay *= 2; } } /* action: The action to execute */ executeAction(label, action, highPriority = false, standalone = false) { if (standalone) { // Run action in standalone execution return this.client.execute(highPriority ? 'apply/highPriority' : 'apply', new overkiz_client_1.Execution(label + ' - HomeKit', action)); } else { if (this.executionPromise) { this.executionPromise.execution.addAction(action); this.executionPromise.execution.label = 'Execute scene (' + this.executionPromise.execution.actions.length + ' devices) - HomeKit'; } else { this.executionPromise = new Promise((resolve, reject) => { setTimeout(() => { this.client.execute(highPriority ? 'apply/highPriority' : 'apply', this.executionPromise.execution) .then(resolve) .catch(reject); this.executionPromise = null; }, 100); }); this.executionPromise.execution = new overkiz_client_1.Execution(label + ' - HomeKit', action); } return this.executionPromise; } } /** * Translate * @param path * @returns string */ translate(label) { const path = label.split('.'); let translation = this.translations; for (const key of path) { if (typeof translation === 'object' && key in translation) { translation = translation[key]; } else if (typeof translation === 'string') { if (translation.includes(':param')) { translation = translation.replace(':param', key); } return translation; } } return label; } } exports.Platform = Platform; //# sourceMappingURL=Platform.js.map