UNPKG

homebridge-tado-platform

Version:
338 lines (273 loc) 11.2 kB
'use strict'; const DeviceHandler = require('./helper/handler.js'); const Logger = require('./helper/logger.js'); const packageFile = require('../package.json'); const TadoConfig = require('./tado/tado-config.js'); //Accessories const AirqualityAccessory = require('./accessories/airquality.js'); const ContactAccessory = require('./accessories/contact.js'); const FaucetAccessory = require('./accessories/faucet.js'); const HeaterCoolerAccessory = require('./accessories/heatercooler.js'); const HumidityAccessory = require('./accessories/humidity.js'); const MotionAccessory = require('./accessories/motion.js'); const OccupancyAccessory = require('./accessories/occupancy.js'); const SecurityAccessory = require('./accessories/security.js'); const SolarLightbulbAccessory = require('./accessories/lightbulb.js'); const SolarLightsensorAccessory = require('./accessories/lightsensor.js'); const SwitchAccessory = require('./accessories/switch.js'); const TemperatureAccessory = require('./accessories/temperature.js'); const ThermostatAccessory = require('./accessories/thermostat.js'); //Custom Types const CustomTypes = require('./types/custom.js'); const EveTypes = require('./types/eve.js'); const PLUGIN_NAME = 'homebridge-tado-platform'; const PLATFORM_NAME = 'TadoPlatform'; var Accessory, UUIDGen, FakeGatoHistoryService; module.exports = function (homebridge) { Accessory = homebridge.platformAccessory; UUIDGen = homebridge.hap.uuid; return TadoPlatform; }; function TadoPlatform(log, config, api) { if (!api || !config) return; //init logger Logger.init(log, config.debug); //init types/fakegato CustomTypes.registerWith(api.hap); EveTypes.registerWith(api.hap); FakeGatoHistoryService = require('fakegato-history')(api); this.api = api; this.accessories = []; this.config = config; this.user = []; //setup config/plugin this.setupPlugin(); if (!this.user.length) this.setupConfig(); this.api.on('didFinishLaunching', this.didFinishLaunching.bind(this)); } TadoPlatform.prototype = { setupPlugin: async function () { try { if (this.config.user && this.config.user.length) { for (const credentials of this.config.user) { let error = false; if (!credentials.username) { Logger.warn('There is no username configured for the user. This user will be skipped.'); error = true; } else if (!credentials.password) { Logger.warn('There is no password configured for the user. This user will be skipped.'); error = true; } else if (credentials.reconfigure === false) { error = true; } if (!error) { this.user.push({ username: credentials.username, password: credentials.password, }); } } } if (this.user.length) { for (const user of this.user) { if (user.reconfigure || user.reconfigure === undefined) { if (this.config.homes && this.config.homes.length) { let foundHome = this.config.homes.filter((home) => home && home.username === user.username); if (foundHome.length) { //refresh if (foundHome[0].name && foundHome[0].username && foundHome[0].password) { Logger.info('Refreshing home...', foundHome[0].name); this.config = await TadoConfig.refresh(foundHome[0].name, this.config, { username: foundHome[0].username, password: foundHome[0].password, }); } } else { Logger.info('Generating new home...', user.username); this.config = await TadoConfig.add(this.config, [user]); } } else { Logger.info('Generating new home...', user.username); this.config = await TadoConfig.add(this.config, [user]); } } } //store config Logger.info('Storing config...'); this.config.user = this.user .map((user) => { return { reconfigure: false, username: user.username, password: user.password, }; }) .filter((user) => user); await TadoConfig.store(this.config, this.api.user.storagePath()); Logger.info('Done!'); //setup config this.user = []; this.setupConfig(); //configure accessories this.accessories.forEach((accessory) => { this.configureAccessory(accessory, true); }); //finish this.didFinishLaunching(); } } catch (err) { Logger.error('An error occured during setting up plugin!'); Logger.error(err); } return; }, setupConfig: function () { try { const { config, devices, deviceHandler, telegram } = TadoConfig.setup(this.config, UUIDGen); this.config = config; this.devices = devices; this.deviceHandler = deviceHandler; this.telegram = telegram; } catch (err) { Logger.error('An error occured during setting up plugin!'); Logger.error(err); } return; }, didFinishLaunching: function () { if (this.user.length) return; for (const entry of this.devices.entries()) { let uuid = entry[0]; let device = entry[1]; const cachedAccessory = this.accessories.find((curAcc) => curAcc.UUID === uuid); if (!cachedAccessory) { const accessory = new Accessory(device.name, uuid); Logger.info('Configuring new accessory...', accessory.displayName); this.setupAccessory(accessory, device); this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); this.accessories.push(accessory); } } this.accessories.forEach((accessory) => { const device = this.devices.get(accessory.UUID); try { if (!device) this.removeAccessory(accessory); } catch (err) { Logger.info('It looks like the device has already been removed. Skip removing.', device.name); Logger.debug(err); } }); for (const entry of this.deviceHandler.entries()) { const name = entry[0]; const config = entry[1]; const tado = config.tado; delete config.tado; let accessories = this.accessories.filter((acc) => acc && acc.context.config.homeName === name); const deviceHandler = DeviceHandler(this.api, accessories, config, tado, this.telegram); deviceHandler.getStates(); } }, setupAccessory: function (accessory, device) { accessory.on('identify', () => { Logger.info('Identify requested.', accessory.displayName); }); const manufacturer = 'Tado'; const model = device.model ? device.model : device.subtype; const serialNumber = device.serialNumber ? device.serialNumber : '123456789'; const AccessoryInformation = accessory.getService(this.api.hap.Service.AccessoryInformation); AccessoryInformation.setCharacteristic(this.api.hap.Characteristic.Manufacturer, manufacturer) .setCharacteristic(this.api.hap.Characteristic.Model, model) .setCharacteristic(this.api.hap.Characteristic.SerialNumber, serialNumber) .setCharacteristic(this.api.hap.Characteristic.FirmwareRevision, packageFile.version); const tado = device.tado; delete device.tado; delete device.geolocation; delete device.zones; delete device.presence; delete device.anyone; delete device.weather; delete device.extras; delete device.childLock; accessory.context.config = device; const configHandler = this.deviceHandler.get(accessory.context.config.homeName); const deviceHandler = DeviceHandler(this.api, false, configHandler, tado, this.telegram); switch (device.subtype) { case 'zone-thermostat': new ThermostatAccessory(this.api, accessory, this.accessories, tado, deviceHandler, FakeGatoHistoryService); break; case 'zone-heatercooler': case 'zone-heatercooler-boiler': new HeaterCoolerAccessory(this.api, accessory, this.accessories, tado, deviceHandler, FakeGatoHistoryService); break; case 'zone-switch': case 'zone-window-switch': case 'extra-childswitch': case 'extra-cntrlswitch': case 'extra-boost': case 'extra-shedule': case 'extra-turnoff': case 'extra-plockswitch': new SwitchAccessory(this.api, accessory, this.accessories, tado, deviceHandler); break; case 'zone-faucet': new FaucetAccessory(this.api, accessory, this.accessories, tado, deviceHandler); break; case 'zone-window-contact': new ContactAccessory(this.api, accessory, this.accessories, tado, deviceHandler, FakeGatoHistoryService); break; case 'zone-temperature': new TemperatureAccessory(this.api, accessory, this.accessories, tado, deviceHandler, FakeGatoHistoryService); break; case 'zone-humidity': new HumidityAccessory(this.api, accessory, this.accessories, tado, deviceHandler, FakeGatoHistoryService); break; case 'presence-motion': new MotionAccessory(this.api, accessory, this.accessories, tado, deviceHandler, FakeGatoHistoryService); break; case 'presence-occupancy': new OccupancyAccessory(this.api, accessory, this.accessories, tado, deviceHandler); break; case 'weather-temperature': new TemperatureAccessory(this.api, accessory, this.accessories, tado, deviceHandler, FakeGatoHistoryService); break; case 'weather-lightbulb': new SolarLightbulbAccessory(this.api, accessory, this.accessories, tado); break; case 'weather-lightsensor': new SolarLightsensorAccessory(this.api, accessory, this.accessories, tado); break; case 'weather-airquality': new AirqualityAccessory(this.api, accessory, this.accessories, tado); break; case 'extra-plock': new SecurityAccessory(this.api, accessory, this.accessories, tado, deviceHandler); break; default: Logger.warn('Unknown accessory type: ' + device.subtype, accessory.displayName); break; } return; }, configureAccessory: function (accessory, refresh) { if (!this.user.length) { const device = this.devices.get(accessory.UUID); if (device) { Logger.info('Configuring accessory...', accessory.displayName); this.setupAccessory(accessory, device); } } if (!refresh) this.accessories.push(accessory); }, removeAccessory: function (accessory) { Logger.info('Removing accessory...', accessory.displayName); let accessories = this.accessories.map((cachedAccessory) => { if (cachedAccessory.displayName !== accessory.displayName) { return cachedAccessory; } }); this.accessories = accessories.filter(function (el) { return el != null; }); this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); }, };