From 825ccadd11ecc42f8b7184a84d987b8691097f9f Mon Sep 17 00:00:00 2001 From: fabianoflnsp <45748723+fabianoflnsp@users.noreply.github.com> Date: Tue, 21 Apr 2020 01:55:10 -0300 Subject: [PATCH 0001/3183] Update index.js Added Support for Sonoff Mini --- index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.js b/index.js index a7710bf1..9450617a 100644 --- a/index.js +++ b/index.js @@ -142,6 +142,7 @@ function eWeLink(log, config, api) { if ((deviceInformationFromWebApi !== undefined) && (deviceInformationFromWebApi["productModel"])) { switch (deviceInformationFromWebApi.productModel) { case 'B1': + case 'MINI': powerState = deviceInformationFromWebApi.params.state; break; case 'iFan02': @@ -217,6 +218,7 @@ eWeLink.prototype.getStateFromDevice = function(device) { if ((device !== undefined) && (device["productModel"])) { switch (device.productModel) { case 'B1': + case "MINI": powerState = device.params.state; break; case 'iFan02': From 133af6b4040adfbe4a934e3785507021476970d8 Mon Sep 17 00:00:00 2001 From: George <19616587+gbro115@users.noreply.github.com> Date: Tue, 19 May 2020 11:38:39 -0400 Subject: [PATCH 0002/3183] Update package.json Modify name post merge --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 6c64e424..b66653c9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "homebridge-ewelink-complete", + "name": "homebridge-ewelink", "version": "0.1.76", - "description": "Fork of homebridge-eWeLink is a Homebrige plugin to control Sonoff relays running OEM firmware", + "description": "homebridge-eWeLink is a Homebrige plugin to control Sonoff relays running OEM firmware", "license": "MIT", "keywords": [ "homebridge-plugin", @@ -13,7 +13,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/ronnieroberts/homebridge-ewelink.git" + "url": "https://github.com/gbro115/homebridge-ewelink.git" }, "dependencies": { "ewelink-api": "^2.0.0", From 87388442fe9025db866e364aa11ef913618239b5 Mon Sep 17 00:00:00 2001 From: George <19616587+gbro115@users.noreply.github.com> Date: Tue, 19 May 2020 11:40:16 -0400 Subject: [PATCH 0003/3183] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 82d1b8c4..d476dd88 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ -## This is a fork of homebridge-ewelink +# Changes from homebridge-ewelink-complete have been merged into the master The largest change here is to use evelink-api for all API needs rather than rewrite -# homebridge-ewelink-complete +# About + Homebridge plugin to control Sonoff relays with OEM firmware. It uses the same API as the iOS app to communicate with your devices. The platform will dynamically add/remove devices based on what is configured in your eWeLink account. From b56ea1b9b8521d331042cbb1fde81173b1eaee04 Mon Sep 17 00:00:00 2001 From: George <19616587+gbro115@users.noreply.github.com> Date: Tue, 19 May 2020 11:40:39 -0400 Subject: [PATCH 0004/3183] Update README.md Formatting --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d476dd88..fc4f06d7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Changes from homebridge-ewelink-complete have been merged into the master +### Changes from homebridge-ewelink-complete have been merged into the master The largest change here is to use evelink-api for all API needs rather than rewrite From 043705b3dbfc2b7bd3fa298457eeb32eefe37b0f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 16 Aug 2020 07:53:42 +0100 Subject: [PATCH 0005/3183] jshint format tweaks --- index.js | 710 +++++++++++++++++++++++++++---------------------------- 1 file changed, 343 insertions(+), 367 deletions(-) diff --git a/index.js b/index.js index 9450617a..fadb4c55 100644 --- a/index.js +++ b/index.js @@ -1,382 +1,358 @@ -var WebSocket = require('ws'); -var http = require('http'); -var url = require('url'); -var request = require('request-json'); +/* jshint esversion: 9, -W030, node: true */ const ewelinkapi = require('ewelink-api'); -var nonce = require('nonce')(); - -var wsc; -var isSocketOpen = false; -var sequence = 0; -var webClient = ''; -var apiKey = 'UNCONFIGURED'; -var authenticationToken = 'UNCONFIGURED'; -var phoneNumberOrEmail = ''; -var accountPassword = ''; -var connection = 0; var Accessory, Service, Characteristic, UUIDGen; -var debug = false; - -module.exports = function(homebridge) { - console.log("homebridge API version: " + homebridge.version); - - // Accessory must be created from PlatformAccessory Constructor - Accessory = homebridge.platformAccessory; - // Service and Characteristic are from hap-nodejs - Service = homebridge.hap.Service; - Characteristic = homebridge.hap.Characteristic; - UUIDGen = homebridge.hap.uuid; - - // For platform plugin to be considered as dynamic platform plugin, - // registerPlatform(pluginName, platformName, constructor, dynamic), dynamic must be true - homebridge.registerPlatform("homebridge-eWeLink", "eWeLink", eWeLink, true); - -} +module.exports = function (homebridge) { + console.log("homebridge API version: " + homebridge.version); + + // Accessory must be created from PlatformAccessory Constructor + Accessory = homebridge.platformAccessory; + + // Service and Characteristic are from hap-nodejs + Service = homebridge.hap.Service; + Characteristic = homebridge.hap.Characteristic; + UUIDGen = homebridge.hap.uuid; + + // For platform plugin to be considered as dynamic platform plugin, + // registerPlatform(pluginName, platformName, constructor, dynamic), dynamic must be true + homebridge.registerPlatform("homebridge-eWeLink", "eWeLink", eWeLink, true); + +}; // Platform constructor function eWeLink(log, config, api) { - - log("Intialising eWeLink"); - - var platform = this; - - this.log = log; - this.config = config; - this.accessories = new Map(); - this.authenticationToken = 'UNCONFIGURED'; - this.phoneNumberOrEmail = config['phoneNumberOrEmail']; - this.accountPassword = config['accountPassword']; - this.debug = (config['debug'] == 'true') ? true : false; - - - if (api) { - - // Save the API object as plugin needs to register new accessory via this object - this.api = api; - - // Listen to event "didFinishLaunching", this means homebridge already finished loading cached accessories. - // Platform Plugin should only register new accessory that doesn't exist in homebridge after this event. - // Or start discover new accessories. - - - this.api.on('didFinishLaunching', function() { - - platform.log("A total of [%s] accessories were loaded from the local cache", platform.accessories.size); - - // Get a list of all devices from the API, and compare it to the list of cached devices. - // New devices will be added, and devices that exist in the cache but not in the web list - // will be removed from Homebridge. - - (async() => { - - const connection = new ewelinkapi({ - email: this.phoneNumberOrEmail, - password: this.accountPassword - }); - this.connection = connection; - this.authenticationToken = await connection.getCredentials(); - if(this.debug) platform.log("authenticationToken %s", JSON.stringify(this.authenticationToken)); - - /* get all devices */ - platform.log("Requesting a list of devices from eWeLink HTTPS API"); - const devices = await connection.getDevices(); - // console.log(JSON.stringify(devices)); - - var size = devices.length; - platform.log("eWeLink HTTPS API reports that there are a total of [%s] devices registered", size); - - if (size == 0) { - platform.log("As there were no devices were found, all devices have been removed from the platorm's cache. Please regiester your devices using the eWeLink app and restart HomeBridge"); - platform.accessories.clear(); - platform.api.unregisterPlatformAccessories("homebridge-eWeLink", "eWeLink", platform.accessories); - return; - } - - var devicesFromApi = new Map(); - var newDevicesToAdd = new Map(); - - devices.forEach((device) => { - platform.apiKey = device.apikey; - devicesFromApi.set(device.deviceid, device); - }) - - // Now we compare the cached devices against the web list - platform.log("Evaluating if devices need to be removed..."); - - function checkIfDeviceIsStillRegistered(value, deviceId, map) { - - var accessory = platform.accessories.get(deviceId); - - if (devicesFromApi.has(deviceId)) { - platform.log('Device [%s] is regeistered with API. Nothing to do.', accessory.displayName); - } else { - platform.log('Device [%s], ID : [%s] was not present in the response from the API. It will be removed.', accessory.displayName, accessory.UUID); - platform.removeAccessory(accessory); - }; - } - - // If we have devices in our cache, check that they exist in the web response - if (platform.accessories.size > 0) { - platform.log("Verifying that all cached devices are still registered with the API. Devices that are no longer registered with the API will be removed."); - platform.accessories.forEach(checkIfDeviceIsStillRegistered); - } - - platform.log("Evaluating if new devices need to be added..."); - - // Now we compare the cached devices against the web list - function checkIfDeviceIsAlreadyConfigured(value, deviceId, map) { - if (platform.accessories.has(deviceId)) { - - platform.log('Device with ID [%s] is already configured. Ensuring that the configuration is current.', deviceId); - - var accessory = platform.accessories.get(deviceId); - var deviceInformationFromWebApi = devicesFromApi.get(deviceId); - - accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.Name, deviceInformationFromWebApi.name); - accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.SerialNumber, deviceInformationFromWebApi.extra.extra.mac); - accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.Manufacturer, deviceInformationFromWebApi.brandName); - accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.Model, deviceInformationFromWebApi.productModel); - accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.FirmwareRevision, deviceInformationFromWebApi.params.fwVersion); - if ((deviceInformationFromWebApi !== undefined) && (deviceInformationFromWebApi["productModel"])) { - switch (deviceInformationFromWebApi.productModel) { - case 'B1': - case 'MINI': - powerState = deviceInformationFromWebApi.params.state; - break; - case 'iFan02': - powerState = deviceInformationFromWebApi.params.switches[0].switch; - break; - case 'AD500--X': - powerState = deviceInformationFromWebApi.params.switch; - }; - } - if(this.debug) platform.log("::checkIfDeviceIsAlreadyConfigured() " + deviceInformationFromWebApi.name + " is " + powerState); - - platform.updatePowerStateCharacteristic(deviceId, powerState); - - - } else { - var deviceToAdd = devicesFromApi.get(deviceId); - platform.log('Device [%s], ID : [%s] will be added', deviceToAdd.name, deviceToAdd.deviceid); - platform.addAccessory(deviceToAdd); - }; - } - - // Go through the web response to make sure that all the devices that are in the response do exist in the accessories map - if (devicesFromApi.size > 0) { - devicesFromApi.forEach(checkIfDeviceIsAlreadyConfigured); - } - - if(this.debug) platform.log("API key retrieved from web service is [%s]", platform.apiKey); - - - })().catch(function(error) { - platform.log("Error in intialization"); - }); - }.bind(this)); - } + + log("Intialising eWeLink"); + + var platform = this; + + this.log = log; + this.config = config; + this.accessories = new Map(); + this.authenticationToken = 'UNCONFIGURED'; + this.phoneNumberOrEmail = config.phoneNumberOrEmail; + this.accountPassword = config.accountPassword; + this.debug = (config.debug === 'true') ? true : false; + + if (api) { + + // Save the API object as plugin needs to register new accessory via this object + this.api = api; + + // Listen to event "didFinishLaunching", this means homebridge already finished loading cached accessories. + // Platform Plugin should only register new accessory that doesn't exist in homebridge after this event. + // Or start discover new accessories. + + this.api.on('didFinishLaunching', function () { + + platform.log("A total of [%s] accessories were loaded from the local cache", platform.accessories.size); + + // Get a list of all devices from the API, and compare it to the list of cached devices. + // New devices will be added, and devices that exist in the cache but not in the web list + // will be removed from Homebridge. + + (async () => { + + const connection = new ewelinkapi({ + email: this.phoneNumberOrEmail, + password: this.accountPassword + }); + this.connection = connection; + this.authenticationToken = await connection.getCredentials(); + if (this.debug) platform.log("authenticationToken %s", JSON.stringify(this.authenticationToken)); + + /* get all devices */ + platform.log("Requesting a list of devices from eWeLink HTTPS API"); + const devices = await connection.getDevices(); + // console.log(JSON.stringify(devices)); + + var size = devices.length; + platform.log("eWeLink HTTPS API reports that there are a total of [%s] devices registered", size); + + if (size == 0) { + platform.log("As there were no devices were found, all devices have been removed from the platorm's cache. Please regiester your devices using the eWeLink app and restart HomeBridge"); + platform.accessories.clear(); + platform.api.unregisterPlatformAccessories("homebridge-eWeLink", "eWeLink", platform.accessories); + return; + } + + var devicesFromApi = new Map(); + + devices.forEach((device) => { + platform.apiKey = device.apikey; + devicesFromApi.set(device.deviceid, device); + }); + + // Now we compare the cached devices against the web list + platform.log("Evaluating if devices need to be removed..."); + + function checkIfDeviceIsStillRegistered(value, deviceId, map) { + + var accessory = platform.accessories.get(deviceId); + + if (devicesFromApi.has(deviceId)) { + platform.log('Device [%s] is regeistered with API. Nothing to do.', accessory.displayName); + } else { + platform.log('Device [%s], ID : [%s] was not present in the response from the API. It will be removed.', accessory.displayName, accessory.UUID); + platform.removeAccessory(accessory); + } + } + + // If we have devices in our cache, check that they exist in the web response + if (platform.accessories.size > 0) { + platform.log("Verifying that all cached devices are still registered with the API. Devices that are no longer registered with the API will be removed."); + platform.accessories.forEach(checkIfDeviceIsStillRegistered); + } + + platform.log("Evaluating if new devices need to be added..."); + + // Now we compare the cached devices against the web list + function checkIfDeviceIsAlreadyConfigured(value, deviceId, map) { + if (platform.accessories.has(deviceId)) { + + platform.log('Device with ID [%s] is already configured. Ensuring that the configuration is current.', deviceId); + + var accessory = platform.accessories.get(deviceId); + var deviceInformationFromWebApi = devicesFromApi.get(deviceId); + + accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.Name, deviceInformationFromWebApi.name); + accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.SerialNumber, deviceInformationFromWebApi.extra.extra.mac); + accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.Manufacturer, deviceInformationFromWebApi.brandName); + accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.Model, deviceInformationFromWebApi.productModel); + accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.FirmwareRevision, deviceInformationFromWebApi.params.fwVersion); + let powerState; + if ((deviceInformationFromWebApi !== undefined) && (deviceInformationFromWebApi.productModel)) { + switch (deviceInformationFromWebApi.productModel) { + case 'B1': + case 'MINI': + powerState = deviceInformationFromWebApi.params.state; + break; + case 'iFan02': + powerState = deviceInformationFromWebApi.params.switches[0].switch; + break; + case 'AD500--X': + powerState = deviceInformationFromWebApi.params.switch; + } + } + if (this.debug) platform.log("::checkIfDeviceIsAlreadyConfigured() " + deviceInformationFromWebApi.name + " is " + powerState); + + platform.updatePowerStateCharacteristic(deviceId, powerState); + + } else { + var deviceToAdd = devicesFromApi.get(deviceId); + platform.log('Device [%s], ID : [%s] will be added', deviceToAdd.name, deviceToAdd.deviceid); + platform.addAccessory(deviceToAdd); + } + } + + // Go through the web response to make sure that all the devices that are in the response do exist in the accessories map + if (devicesFromApi.size > 0) { + devicesFromApi.forEach(checkIfDeviceIsAlreadyConfigured); + } + + if (this.debug) platform.log("API key retrieved from web service is [%s]", platform.apiKey); + + })().catch(function (error) { + platform.log("Error in intialization"); + }); + }.bind(this)); + } } - // Function invoked when homebridge tries to restore cached accessory. // We update the existing devices as part of didFinishLaunching(), as to avoid an additional call to the the HTTPS API. -eWeLink.prototype.configureAccessory = function(accessory) { - - this.log(accessory.displayName, "Configure Accessory"); - - var platform = this; - accessory.reachable = true; - - accessory.on('identify', function(paired, callback) { - platform.log(accessory.displayName, "Identify!!!"); - callback(); - }); - - if (accessory.getService(Service.Switch)) { - - accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) - .on('set', function(value, callback) { - platform.setPowerState(accessory, value); - callback(); - }) - .on('get', function(callback) { - platform.getPowerState(accessory); - callback(); - }); - - } - - this.accessories.set(accessory.context.deviceId, accessory); - -} - -eWeLink.prototype.getStateFromDevice = function(device) { - if(this.debug) this.log("getStateFromDevice:: ENTER"); - var powerState = 'on'; - if ((device !== undefined) && (device["productModel"])) { - switch (device.productModel) { - case 'B1': - case "MINI": - powerState = device.params.state; - break; - case 'iFan02': - powerState = device.params.switches[0].switch; - break; - case 'AD500--X': - powerState = device.params.switch; - }; - } - if(this.debug) this.log("getStateFromDevice:: " + device.name + " is " + powerState); - if(this.debug) this.log("getStateFromDevice:: EXIT"); - return powerState; -} +eWeLink.prototype.configureAccessory = function (accessory) { + + this.log(accessory.displayName, "Configure Accessory"); + + var platform = this; + accessory.reachable = true; + + accessory.on('identify', function (paired, callback) { + platform.log(accessory.displayName, "Identify!!!"); + callback(); + }); + + if (accessory.getService(Service.Switch)) { + + accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) + .on('set', function (value, callback) { + platform.setPowerState(accessory, value); + callback(); + }) + .on('get', function (callback) { + platform.getPowerState(accessory); + callback(); + }); + + } + + this.accessories.set(accessory.context.deviceId, accessory); + +}; + +eWeLink.prototype.getStateFromDevice = function (device) { + if (this.debug) this.log("getStateFromDevice:: ENTER"); + var powerState = 'on'; + if ((device !== undefined) && (device.productModel)) { + switch (device.productModel) { + case 'B1': + case "MINI": + powerState = device.params.state; + break; + case 'iFan02': + powerState = device.params.switches[0].switch; + break; + case 'AD500--X': + powerState = device.params.switch; + } + } + if (this.debug) this.log("getStateFromDevice:: " + device.name + " is " + powerState); + if (this.debug) this.log("getStateFromDevice:: EXIT"); + return powerState; +}; // Sample function to show how developer can add accessory dynamically from outside event -eWeLink.prototype.addAccessory = function(device) { - - // Here we need to check if it is currently there - if (this.accessories.get(device.deviceid)) { - this.log("Not adding [%s] as it already exists in the cache", device.deviceid); - return - } - - var platform = this; - - if (device.type != 10) { - this.log("A device with an unknown type was returned. It will be skipped.", device.type); - return; - } - - this.log("Found Accessory with Name : [%s], Manufacturer : [%s], Status : [%s], Is Online : [%s], API Key: [%s] ", device.name, device.productModel, this.getStateFromDevice(device), device.online, device.apikey); - - const accessory = new Accessory(device.name, UUIDGen.generate(device.deviceid.toString())) - - accessory.context.deviceId = device.deviceid - accessory.context.apiKey = device.apikey; - - // if (device.online == 'true') { - accessory.reachable = true; - // } else { - // accessory.reachable = false; - // } - - var platform = this; - accessory.addService(Service.Switch, device.name) - .getCharacteristic(Characteristic.On) - .on('set', function(value, callback) { - platform.setPowerState(accessory, value); - callback(); - }) - .on('get', function(callback) { - platform.getPowerState(accessory); - callback(); - }); - - - accessory.on('identify', function(paired, callback) { - platform.log(accessory.displayName, "Identify not supported"); - callback(); - }); - - accessory.getService(Service.AccessoryInformation).Characteristic(Characteristic.SerialNumber, device.extra.extra.mac); - accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.Manufacturer, device.productModel); - accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.Model, device.extra.extra.model); - accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.Identify, false); - accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); - - this.accessories.set(device.deviceid, accessory); - - this.api.registerPlatformAccessories("homebridge-eWeLink", - "eWeLink", [accessory]); - -} - -eWeLink.prototype.getSequence = function() { - var time_stamp = new Date() / 1000; - this.sequence = Math.floor(time_stamp * 1000); - return this.sequence; -} - -eWeLink.prototype.updatePowerStateCharacteristic = function(deviceId, state) { - var platform = this; - if (platform.debug) platform.log("::updatePowerStateCharacteristic() : ENTER with (deviceId='"+deviceId+"',state='"+state+"')"); - - // Used when we receive an update from an external source - var isOn = false; - var accessory = platform.accessories.get(deviceId); - if (state == 'on') { - isOn = true; - } - //if (platform.debug) platform.log("::updatePowerStateCharacteristic() : accessory before update: "+JSON.stringify(accessory)); - - if (platform.debug) platform.log("::updatePowerStateCharacteristic() : Updating recorded Characteristic.On for [%s] to [%s]. No request will be sent to the device.", accessory.context.deviceId, isOn); - accessory.getService(Service.Switch).setCharacteristic(Characteristic.On, isOn); - //if (platform.debug) platform.log("::updatePowerStateCharacteristic() : accessory after update: "+JSON.stringify(accessory)); - //platform.updatePowerStateCharacteristic(deviceId, powerState); - if (platform.debug) platform.log("::updatePowerStateCharacteristic() : EXIT"); -} - - -eWeLink.prototype.getPowerState = function(accessory, callback) { - var platform = this; - - if (this.debug) platform.log("::getPowerState() : ENTER Requesting power state for [%s].", accessory.displayName); //, JSON.stringify(accessory)); - - (async() => { - // const device = await platform.connection.getDevice(accessory.context.deviceId); - var interestedDevice = null; -///////////// - const devices = await platform.connection.getDevices(); - //if (platform.debug) platform.log("::getPowerState() : retrieved all devices, found "+devices.length+" devices"); - - //if (platform.debug) platform.log("::getPowerState() : Looking for interested device"); - devices.forEach((device) => { -// if (platform.debug) platform.log("::getPowerState() : Found : "+JSON.stringify(device)); - //if (platform.debug) platform.log("::getPowerState() : Looking for " + accessory.context.deviceId + ", but found "+device.deviceid); - if(accessory.context.deviceId==device.deviceid) { - //if (platform.debug) platform.log("::getPowerState() : found what I was looking for"); - interestedDevice = device; - } - }) -///////////// - powerState = platform.getStateFromDevice(interestedDevice) - if (platform.debug) platform.log("::getPowerState() : power state for [%s] is %s", accessory.displayName, powerState); - this.updatePowerStateCharacteristic(accessory.context.deviceId, powerState); - if (this.debug) platform.log("::getPowerState() : EXIT"); - })() - .catch(function(error) { - platform.log("::getPowerState() : Error in retrieving device\n"+JSON.stringify(error)); - }); -} - -eWeLink.prototype.setPowerState = function(accessory, isOn, callback) { - var platform = this; - if(platform.debug) platform.log("::setPowerState() : ENTER"); - - var targetState = 'off'; - - if (isOn==true || isOn=='on') { - targetState = 'on'; - } - - if (this.debug) platform.log("::setPowerState() : Setting power state to [%s] for device [%s]", targetState, accessory.displayName); - (async() => { - const status = await platform.connection.setDevicePowerState(accessory.context.deviceId, targetState); - if (this.debug) platform.log("::setPowerState() : power state for [%s] is %s", accessory.displayName, JSON.stringify(status)); - //this.updatePowerStateCharacteristic(accessory.context.deviceId, targetState); - if(platform.debug) platform.log("::setPowerState() : EXIT"); - })().catch(function(error) { - platform.log("::setPowerState() : Error in retrieving device\n"+JSON.stringify(error)); - }); -} - +eWeLink.prototype.addAccessory = function (device) { + + // Here we need to check if it is currently there + if (this.accessories.get(device.deviceid)) { + this.log("Not adding [%s] as it already exists in the cache", device.deviceid); + return; + } + + var platform = this; + + if (device.type != 10) { + this.log("A device with an unknown type was returned. It will be skipped.", device.type); + return; + } + + this.log("Found Accessory with Name : [%s], Manufacturer : [%s], Status : [%s], Is Online : [%s], API Key: [%s] ", device.name, device.productModel, this.getStateFromDevice(device), device.online, device.apikey); + + const accessory = new Accessory(device.name, UUIDGen.generate(device.deviceid.toString())); + + accessory.context.deviceId = device.deviceid; + accessory.context.apiKey = device.apikey; + + // if (device.online == 'true') { + accessory.reachable = true; + // } else { + // accessory.reachable = false; + // } + + accessory.addService(Service.Switch, device.name) + .getCharacteristic(Characteristic.On) + .on('set', function (value, callback) { + platform.setPowerState(accessory, value); + callback(); + }) + .on('get', function (callback) { + platform.getPowerState(accessory); + callback(); + }); + + accessory.on('identify', function (paired, callback) { + platform.log(accessory.displayName, "Identify not supported"); + callback(); + }); + + accessory.getService(Service.AccessoryInformation).Characteristic(Characteristic.SerialNumber, device.extra.extra.mac); + accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.Manufacturer, device.productModel); + accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.Model, device.extra.extra.model); + accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.Identify, false); + accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); + + this.accessories.set(device.deviceid, accessory); + + this.api.registerPlatformAccessories("homebridge-eWeLink", + "eWeLink", [accessory]); + +}; + +eWeLink.prototype.getSequence = function () { + var time_stamp = new Date() / 1000; + this.sequence = Math.floor(time_stamp * 1000); + return this.sequence; +}; + +eWeLink.prototype.updatePowerStateCharacteristic = function (deviceId, state) { + var platform = this; + if (platform.debug) platform.log("::updatePowerStateCharacteristic() : ENTER with (deviceId='" + deviceId + "',state='" + state + "')"); + + // Used when we receive an update from an external source + var isOn = false; + var accessory = platform.accessories.get(deviceId); + if (state == 'on') { + isOn = true; + } + //if (platform.debug) platform.log("::updatePowerStateCharacteristic() : accessory before update: "+JSON.stringify(accessory)); + + if (platform.debug) platform.log("::updatePowerStateCharacteristic() : Updating recorded Characteristic.On for [%s] to [%s]. No request will be sent to the device.", accessory.context.deviceId, isOn); + accessory.getService(Service.Switch).setCharacteristic(Characteristic.On, isOn); + //if (platform.debug) platform.log("::updatePowerStateCharacteristic() : accessory after update: "+JSON.stringify(accessory)); + //platform.updatePowerStateCharacteristic(deviceId, powerState); + if (platform.debug) platform.log("::updatePowerStateCharacteristic() : EXIT"); +}; + +eWeLink.prototype.getPowerState = function (accessory, callback) { + var platform = this; + + if (this.debug) platform.log("::getPowerState() : ENTER Requesting power state for [%s].", accessory.displayName); //, JSON.stringify(accessory)); + + (async () => { + // const device = await platform.connection.getDevice(accessory.context.deviceId); + var interestedDevice = null; + ///////////// + const devices = await platform.connection.getDevices(); + //if (platform.debug) platform.log("::getPowerState() : retrieved all devices, found "+devices.length+" devices"); + + //if (platform.debug) platform.log("::getPowerState() : Looking for interested device"); + devices.forEach((device) => { + // if (platform.debug) platform.log("::getPowerState() : Found : "+JSON.stringify(device)); + //if (platform.debug) platform.log("::getPowerState() : Looking for " + accessory.context.deviceId + ", but found "+device.deviceid); + if (accessory.context.deviceId == device.deviceid) { + //if (platform.debug) platform.log("::getPowerState() : found what I was looking for"); + interestedDevice = device; + } + }); + ///////////// + let powerState = platform.getStateFromDevice(interestedDevice); + if (platform.debug) platform.log("::getPowerState() : power state for [%s] is %s", accessory.displayName, powerState); + this.updatePowerStateCharacteristic(accessory.context.deviceId, powerState); + if (this.debug) platform.log("::getPowerState() : EXIT"); + })() + .catch(function (error) { + platform.log("::getPowerState() : Error in retrieving device\n" + JSON.stringify(error)); + }); +}; + +eWeLink.prototype.setPowerState = function (accessory, isOn, callback) { + var platform = this; + if (platform.debug) platform.log("::setPowerState() : ENTER"); + + var targetState = 'off'; + + if (isOn == true || isOn == 'on') { + targetState = 'on'; + } + + if (this.debug) platform.log("::setPowerState() : Setting power state to [%s] for device [%s]", targetState, accessory.displayName); + (async () => { + const status = await platform.connection.setDevicePowerState(accessory.context.deviceId, targetState); + if (this.debug) platform.log("::setPowerState() : power state for [%s] is %s", accessory.displayName, JSON.stringify(status)); + //this.updatePowerStateCharacteristic(accessory.context.deviceId, targetState); + if (platform.debug) platform.log("::setPowerState() : EXIT"); + })().catch(function (error) { + platform.log("::setPowerState() : Error in retrieving device\n" + JSON.stringify(error)); + }); +}; // Sample function to show how developer can remove accessory dynamically from outside event -eWeLink.prototype.removeAccessory = function(accessory) { - - this.log('Removing accessory [%s]', accessory.displayName); - this.accessories.delete(accessory.context.deviceId); - this.api.unregisterPlatformAccessories('homebridge-eWeLink', 'eWeLink', [accessory]); -} +eWeLink.prototype.removeAccessory = function (accessory) { + + this.log('Removing accessory [%s]', accessory.displayName); + this.accessories.delete(accessory.context.deviceId); + this.api.unregisterPlatformAccessories('homebridge-eWeLink', 'eWeLink', [accessory]); +}; \ No newline at end of file From 9bdc20edf798653f4487f5f298a006f59383720b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 16 Aug 2020 07:53:58 +0100 Subject: [PATCH 0006/3183] remove unused deps --- package-lock.json | 382 +--------------------------------------------- package.json | 8 +- 2 files changed, 4 insertions(+), 386 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6e8d52cf..212a164d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { - "name": "homebridge-ewelink-complete", - "version": "0.1.11", + "name": "homebridge-ewelink", + "version": "0.1.76", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -15,16 +15,6 @@ "uri-js": "^4.2.2" } }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, "arpping": { "version": "github:skydiver/arpping#ae65410343bdcbddb64b37ac9f674c65af1fe92c", "from": "github:skydiver/arpping", @@ -38,39 +28,11 @@ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" }, - "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" - }, - "async": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", - "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", - "requires": { - "lodash": "^4.14.0" - } - }, - "async-limiter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" - }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, - "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" - }, - "aws4": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", - "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" - }, "babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", @@ -89,44 +51,11 @@ "tweetnacl": "^0.14.3" } }, - "bl": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz", - "integrity": "sha1-/cqHGplxOqANGeO7ukHER4emU5g=", - "requires": { - "readable-stream": "~2.0.5" - } - }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "requires": { - "hoek": "2.x.x" - } - }, - "caseless": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", - "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, "child_process": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/child_process/-/child_process-1.0.2.tgz", @@ -137,19 +66,6 @@ "resolved": "https://registry.npmjs.org/chnl/-/chnl-0.5.0.tgz", "integrity": "sha512-0dl4ZJfAZdLn9mDnWejs5nasZKVnDTwdXV+dkxodYbb//GJDtXNhPlqCCYUb1xF0NQpIB5zlHRDrU1RCB4BRog==" }, - "combined-stream": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", - "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz", - "integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA==" - }, "core-js": { "version": "2.6.11", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", @@ -160,14 +76,6 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "requires": { - "boom": "2.x.x" - } - }, "crypto-js": { "version": "3.1.9-1", "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz", @@ -223,11 +131,6 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, - "depd": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz", - "integrity": "sha1-4b2Cxqq2ztlluXuIsX7T5SjKGMM=" - }, "ecc-jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", @@ -294,11 +197,6 @@ "ext": "^1.1.2" } }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, "ewelink-api": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ewelink-api/-/ewelink-api-2.0.0.tgz", @@ -466,11 +364,6 @@ } } }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" - }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -496,34 +389,11 @@ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, - "form-data": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz", - "integrity": "sha1-rjFduaSQf6BlUCMEpm13M0de43w=", - "requires": { - "async": "^2.0.1", - "combined-stream": "^1.0.5", - "mime-types": "^2.1.11" - } - }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, - "generate-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", - "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=" - }, - "generate-object-property": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", - "requires": { - "is-property": "^1.0.0" - } - }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -544,17 +414,6 @@ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, - "har-validator": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", - "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", - "requires": { - "chalk": "^1.1.1", - "commander": "^2.9.0", - "is-my-json-valid": "^2.12.4", - "pinkie-promise": "^2.0.0" - } - }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -563,50 +422,11 @@ "function-bind": "^1.1.1" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, "has-symbols": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "requires": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x", - "sntp": "1.x.x" - } - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" - }, - "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "requires": { - "assert-plus": "^0.2.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, "is-callable": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", @@ -617,22 +437,6 @@ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" }, - "is-my-json-valid": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz", - "integrity": "sha512-ochPsqWS1WXj8ZnMIV0vnNXooaMhp7cyL4FMSIPKTtnV0Ha/T19G2b9kkhcNsabV9bxYkze7/aLZJb/bYuFduQ==", - "requires": { - "generate-function": "^2.0.0", - "generate-object-property": "^1.1.0", - "jsonpointer": "^4.0.0", - "xtend": "^4.0.0" - } - }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" - }, "is-regex": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", @@ -654,11 +458,6 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -685,11 +484,6 @@ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, - "jsonpointer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", - "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=" - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -708,24 +502,6 @@ } } }, - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" - }, - "mime-db": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", - "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" - }, - "mime-types": { - "version": "2.1.17", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", - "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", - "requires": { - "mime-db": "~1.30.0" - } - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -741,26 +517,11 @@ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" }, - "node-uuid": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", - "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=" - }, "nonce": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/nonce/-/nonce-1.0.4.tgz", "integrity": "sha1-7nMCrejBvvR28wG4yR9cxRpIdhI=" }, - "npmrc": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/npmrc/-/npmrc-1.1.1.tgz", - "integrity": "sha1-KBupOt6FxN4rBGEQMfL/LyTmId0=" - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" - }, "object-inspect": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", @@ -802,24 +563,6 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "^2.0.0" - } - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" - }, "promise-controller": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/promise-controller/-/promise-controller-0.5.2.tgz", @@ -845,11 +588,6 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, - "qs": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.3.tgz", - "integrity": "sha1-HPyyXBCpsrSDBT/zn138kjOQjP4=" - }, "random": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/random/-/random-2.1.1.tgz", @@ -861,61 +599,11 @@ "seedrandom": "^2.4.4" } }, - "readable-stream": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" - } - }, "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" }, - "request": { - "version": "2.74.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.74.0.tgz", - "integrity": "sha1-dpPKdou7DqXIzgjAhKRe+gW4kqs=", - "requires": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", - "bl": "~1.1.2", - "caseless": "~0.11.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", - "forever-agent": "~0.6.1", - "form-data": "~1.0.0-rc4", - "har-validator": "~2.0.6", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "node-uuid": "~1.4.7", - "oauth-sign": "~0.8.1", - "qs": "~6.2.0", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", - "tunnel-agent": "~0.4.1" - } - }, - "request-json": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/request-json/-/request-json-0.6.2.tgz", - "integrity": "sha1-KMdtBdYMU8nhjUCXywFyO5UGkyI=", - "requires": { - "depd": "1.1.0", - "request": "2.74.0" - } - }, "request-promise": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.5.tgz", @@ -942,24 +630,11 @@ } } }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" - }, "seedrandom": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-2.4.4.tgz", "integrity": "sha512-9A+PDmgm+2du77B5i0Ip2cxOqqHjgNxnBgglxLcX78A2D6c2rTo61z4jnVABpF4cKeDMDG+cmXXvdnqse2VqMA==" }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "requires": { - "hoek": "2.x.x" - } - }, "sshpk": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", @@ -1005,29 +680,6 @@ "function-bind": "^1.1.1" } }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - }, "tough-cookie": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", @@ -1036,11 +688,6 @@ "punycode": "^1.4.1" } }, - "tunnel-agent": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", - "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=" - }, "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", @@ -1060,11 +707,6 @@ "is-typedarray": "^1.0.0" } }, - "ultron": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" - }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", @@ -1080,11 +722,6 @@ } } }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", @@ -1130,21 +767,6 @@ "promise.prototype.finally": "^3.1.0" } }, - "ws": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.2.tgz", - "integrity": "sha512-t+WGpsNxhMR4v6EClXS8r8km5ZljKJzyGhJf7goJz9k5Ye3+b5Bvno5rjqPuIBn5mnn5GBb7o8IrIWHxX1qOLQ==", - "requires": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" - } - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" - }, "yaeti": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", diff --git a/package.json b/package.json index b66653c9..94e0b697 100644 --- a/package.json +++ b/package.json @@ -13,13 +13,9 @@ }, "repository": { "type": "git", - "url": "https://github.com/gbro115/homebridge-ewelink.git" + "url": "https://github.com/bwp91/homebridge-ewelink.git" }, "dependencies": { - "ewelink-api": "^2.0.0", - "nonce": "^1.0.4", - "npmrc": "^1.1.1", - "request-json": "^0.6.2", - "ws": "^3.3.2" + "ewelink-api": "^2.0.0" } } From 6fe3d2b23685ba2e6f2178284b39e7a7e032eb9f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 16 Aug 2020 08:02:00 +0100 Subject: [PATCH 0007/3183] update ewelink-api --- package-lock.json | 550 ++++++---------------------------------------- package.json | 2 +- 2 files changed, 68 insertions(+), 484 deletions(-) diff --git a/package-lock.json b/package-lock.json index 212a164d..94d0313e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,17 +4,6 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "ajv": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.11.0.tgz", - "integrity": "sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, "arpping": { "version": "github:skydiver/arpping#ae65410343bdcbddb64b37ac9f674c65af1fe92c", "from": "github:skydiver/arpping", @@ -23,16 +12,6 @@ "os": "^0.1.1" } }, - "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, "babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", @@ -42,44 +21,25 @@ "regenerator-runtime": "^0.11.0" } }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "optional": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, "child_process": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/child_process/-/child_process-1.0.2.tgz", "integrity": "sha1-sffn/HPSXn/R1FWtyU4UODAYK1o=" }, "chnl": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/chnl/-/chnl-0.5.0.tgz", - "integrity": "sha512-0dl4ZJfAZdLn9mDnWejs5nasZKVnDTwdXV+dkxodYbb//GJDtXNhPlqCCYUb1xF0NQpIB5zlHRDrU1RCB4BRog==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/chnl/-/chnl-1.2.0.tgz", + "integrity": "sha512-g5gJb59edwCliFbX2j7G6sBfY4sX9YLy211yctONI2GRaiX0f2zIbKWmBm+sPqFNEpM7Ljzm7IJX/xrjiEbPrw==" }, "core-js": { "version": "2.6.11", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, "crypto-js": { - "version": "3.1.9-1", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz", - "integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg=" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.0.0.tgz", + "integrity": "sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg==" }, "d": { "version": "1.0.1", @@ -90,21 +50,6 @@ "type": "^1.0.1" } }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } - } - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -122,40 +67,26 @@ } }, "delay": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/delay/-/delay-4.3.0.tgz", - "integrity": "sha512-Lwaf3zVFDMBop1yDuFZ19F9WyGcZcGacsbdlZtWjQmM50tOcMntm1njF/Nb/Vjij3KaSvCF+sEYGKrrjObu2NA==" - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "optional": true, - "requires": { - "jsbn": "~0.1.0" - } + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-4.4.0.tgz", + "integrity": "sha512-txgOrJu3OdtOfTiEOT2e76dJVfG/1dz2NZ4F0Pyt4UGZJryssMRp5vdM5wQoLwSOBNdrJv3F9PAhp/heqd7vrA==" }, "es-abstract": { - "version": "1.17.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", - "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "has": "^1.0.3", "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", "object-inspect": "^1.7.0", "object-keys": "^1.1.1", "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" } }, "es-to-primitive": { @@ -198,155 +129,17 @@ } }, "ewelink-api": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ewelink-api/-/ewelink-api-2.0.0.tgz", - "integrity": "sha512-VcIs2PBK2F0RckZAOvZHcPb8ZpLz4eQclFPmHNZFABI/0XGG3UJw+Ev4LGDz9AkAUFHkSc29LM3hRWlfmNdWgQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ewelink-api/-/ewelink-api-3.0.0.tgz", + "integrity": "sha512-W60dGUIPnV8b/ckCKRAi+0mYyIYil/YrkVrAknlf6CtnivHIVxvcQPUxQPOX6ctWzK10n+ACAh8V7uOok1rjMA==", "requires": { "arpping": "github:skydiver/arpping", - "crypto-js": "^3.1.9-1", + "crypto-js": "^4.0.0", "delay": "^4.3.0", - "nonce": "^1.0.4", - "random": "^2.1.1", - "request": "^2.88.0", - "request-promise": "^4.2.4", - "websocket": "^1.0.30", - "websocket-as-promised": "^0.10.1" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" - }, - "aws4": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", - "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "mime-db": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", - "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" - }, - "mime-types": { - "version": "2.1.26", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", - "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", - "requires": { - "mime-db": "1.43.0" - } - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" - }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" - } - } + "node-fetch": "^2.6.0", + "random": "^2.2.0", + "websocket": "^1.0.31", + "websocket-as-promised": "^1.0.1" } }, "ext": { @@ -364,56 +157,11 @@ } } }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-deep-equal": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "flat-options": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/flat-options/-/flat-options-0.1.3.tgz", - "integrity": "sha512-z1vH9mb4ly55dWUZZFUeLNqhFWhwSQNngHpK8RQOhFuNw/sWcNDZhkHl3GS1YTHiYxB5qvcbSRbH7X6ThzX9UA==" - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -428,9 +176,9 @@ "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" }, "is-callable": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==" }, "is-date-object": { "version": "1.0.2", @@ -438,11 +186,11 @@ "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" }, "is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", "requires": { - "has": "^1.0.3" + "has-symbols": "^1.0.1" } }, "is-symbol": { @@ -458,74 +206,30 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } - } - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", + "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==" }, "next-tick": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" }, - "nonce": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/nonce/-/nonce-1.0.4.tgz", - "integrity": "sha1-7nMCrejBvvR28wG4yR9cxRpIdhI=" + "node-fetch": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" }, "object-inspect": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==" }, "object-keys": { "version": "1.1.1", @@ -558,15 +262,10 @@ "resolved": "https://registry.npmjs.org/ow-lite/-/ow-lite-0.0.2.tgz", "integrity": "sha1-359QDmdAtlkKHpqWVzDUmo61l9E=" }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, "promise-controller": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/promise-controller/-/promise-controller-0.5.2.tgz", - "integrity": "sha512-ymVCGfCxN+A+6TqESLnGZhGfQdQJ08SpIMyft4xQPUDrOgoqzKcQnLIYaqQk7/rPyg4wpKpxBKefeGkvumWgUg==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/promise-controller/-/promise-controller-1.0.0.tgz", + "integrity": "sha512-goA0zA9L91tuQbUmiMinSYqlyUtEgg4fxJcjYnLYOQnrktb4o4UqciXDNXiRUPiDBPACmsr1k8jDW4r7UDq9Qw==" }, "promise.prototype.finally": { "version": "3.1.2", @@ -578,25 +277,15 @@ "function-bind": "^1.1.1" } }, - "psl": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", - "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==" - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - }, "random": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/random/-/random-2.1.1.tgz", - "integrity": "sha512-8HQriGPwjc8R+7hPOI9ZphAEEWmIt/RmuqXZ682ww9kjK5HRGXcN7hgWUxZ9AabgjZm5wIa6EwapTI1sg11XXg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/random/-/random-2.2.0.tgz", + "integrity": "sha512-4HBR4Xye4jJ41QBi6RfIaO1yKQpxVUZafQtdE6NvvjzirNlwWgsk3tkGLTbQtWUarF4ofZsUVEmWqB1TDQlkwA==", "requires": { "babel-runtime": "^6.26.0", "ow": "^0.4.0", "ow-lite": "^0.0.2", - "seedrandom": "^2.4.4" + "seedrandom": "^3.0.5" } }, "regenerator-runtime": { @@ -604,96 +293,29 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" }, - "request-promise": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.5.tgz", - "integrity": "sha512-ZgnepCykFdmpq86fKGwqntyTiUrHycALuGggpyCZwMvGaZWgxW6yagT0FHkgo5LzYvOaCNvxYwWYIjevSH1EDg==", - "requires": { - "bluebird": "^3.5.0", - "request-promise-core": "1.1.3", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - } - }, - "request-promise-core": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", - "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", - "requires": { - "lodash": "^4.17.15" - }, - "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" - } - } - }, "seedrandom": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-2.4.4.tgz", - "integrity": "sha512-9A+PDmgm+2du77B5i0Ip2cxOqqHjgNxnBgglxLcX78A2D6c2rTo61z4jnVABpF4cKeDMDG+cmXXvdnqse2VqMA==" - }, - "sshpk": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", - "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "tweetnacl": "~0.14.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } - } + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" - }, - "string.prototype.trimleft": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", - "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", "requires": { "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "es-abstract": "^1.17.5" } }, - "string.prototype.trimright": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", - "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", "requires": { "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "es-abstract": "^1.17.5" } }, - "tough-cookie": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", - "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", - "requires": { - "punycode": "^1.4.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true - }, "type": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", @@ -707,43 +329,6 @@ "is-typedarray": "^1.0.0" } }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "requires": { - "punycode": "^2.1.0" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - } - } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } - } - }, "websocket": { "version": "1.0.31", "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.31.tgz", @@ -757,14 +342,13 @@ } }, "websocket-as-promised": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/websocket-as-promised/-/websocket-as-promised-0.10.1.tgz", - "integrity": "sha512-hKAZPSIGaao4WPoporPkDQpKl9jz0I0Hh9x/Dn05k6u//e44+0rAhMam4/gvBlYZl02wJYELD561bAenyxwJJQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/websocket-as-promised/-/websocket-as-promised-1.0.1.tgz", + "integrity": "sha512-+gBevna4yxisb8cigL8NxcS8s241cvfMeyy1fNFcFgBcX/6vknMT84MwMmBNLYmsYH2giVoxOSEiAeeb7txFOw==", "requires": { - "chnl": "^0.5.0", - "flat-options": "^0.1.3", - "promise-controller": "^0.5.2", - "promise.prototype.finally": "^3.1.0" + "chnl": "^1.0.0", + "promise-controller": "^1.0.0", + "promise.prototype.finally": "^3.1.1" } }, "yaeti": { diff --git a/package.json b/package.json index 94e0b697..cb41333c 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,6 @@ "url": "https://github.com/bwp91/homebridge-ewelink.git" }, "dependencies": { - "ewelink-api": "^2.0.0" + "ewelink-api": "^3.0.0" } } From 3d00c1873e3b98f0b7fedd9e65fb29611b2bd24a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 16 Aug 2020 08:34:24 +0100 Subject: [PATCH 0008/3183] .github --- .github/FUNDING.yml | 2 ++ .github/ISSUE_TEMPLATE/feature-request.md | 20 ++++++++++++++++++++ .github/ISSUE_TEMPLATE/new-issue.md | 20 ++++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 .github/FUNDING.yml create mode 100644 .github/ISSUE_TEMPLATE/feature-request.md create mode 100644 .github/ISSUE_TEMPLATE/new-issue.md diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..addfcd2d --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +patreon: bwp91 +custom: ["https://www.paypal.me/BenPotter"] diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 00000000..47b2c95b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,20 @@ +--- +name: Feature Request +about: I have an idea for the package! +title: '' +labels: '' +assignees: '' + +--- + +**Please explain your feature request in one sentence.** +... + +**Is your feature request related to a problem? Please describe.** +... + +**Any particular Sonoff devices that this relates to?** +... + +**Anything else?** +... diff --git a/.github/ISSUE_TEMPLATE/new-issue.md b/.github/ISSUE_TEMPLATE/new-issue.md new file mode 100644 index 00000000..44f070df --- /dev/null +++ b/.github/ISSUE_TEMPLATE/new-issue.md @@ -0,0 +1,20 @@ +--- +name: New Issue +about: I have a problem with the package! +title: '' +labels: '' +assignees: '' + +--- + +**What issue do you have? Please be as thorough and explicit as possible.** + +... + +**Which version of the package are you using?** + +... + +**Please paste any relevant logs below. It helps if you can turn `debug` and `debugReqRes` in the package settings for more thorough logging.** + +... From 2f47c90df01e87653f0eac31e548a955dd54cfe9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 16 Aug 2020 08:38:27 +0100 Subject: [PATCH 0009/3183] align with ewelink-sonoff --- .gitignore | 6 +- .npmignore | 5 + LICENSE | 4 +- config.schema.json | 322 ++++++++ index.js | 359 +-------- lib/constants.js | 119 +++ lib/eWeLink.js | 1825 ++++++++++++++++++++++++++++++++++++++++++++ lib/eWeLinkHTTP.js | 158 ++++ lib/eWeLinkLAN.js | 157 ++++ lib/eWeLinkWS.js | 271 +++++++ package-lock.json | 412 ++-------- package.json | 74 +- 12 files changed, 2979 insertions(+), 733 deletions(-) create mode 100644 .npmignore create mode 100644 config.schema.json create mode 100644 lib/constants.js create mode 100644 lib/eWeLink.js create mode 100644 lib/eWeLinkHTTP.js create mode 100644 lib/eWeLinkLAN.js create mode 100644 lib/eWeLinkWS.js diff --git a/.gitignore b/.gitignore index 3c3629e6..45fb205e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ -node_modules +.DS_Store +.nova +.github +.npm +node_modules/ \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 00000000..45fb205e --- /dev/null +++ b/.npmignore @@ -0,0 +1,5 @@ +.DS_Store +.nova +.github +.npm +node_modules/ \ No newline at end of file diff --git a/LICENSE b/LICENSE index 85986b7d..23e8aaa0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017 George +Copyright (c) 2020 Ben Potter Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +SOFTWARE. \ No newline at end of file diff --git a/config.schema.json b/config.schema.json new file mode 100644 index 00000000..b8a7a5cf --- /dev/null +++ b/config.schema.json @@ -0,0 +1,322 @@ +{ + "pluginAlias":"eWeLink", + "pluginType":"platform", + "singular":true, + "headerDisplay":"Homebridge plugin to control Sonoff devices with OEM firmware.", + "footerDisplay":"If you have any suggestions, please open an issue on [GitHub](https://github.com/bwp91/homebridge-ewelink/issues).", + "schema":{ + "type":"object", + "properties":{ + "name":{ + "type":"string", + "default":"eWeLink" + }, + "countryCode":{ + "type":"string", + "title":"Country Code", + "description":"The telephone country code linked to your eWeLink account (without the +)." + }, + "username":{ + "type":"string", + "title":"Username", + "description":"The phone number or email address linked to your eWeLink account. If you use a phone number please enter the country code (with the +), for example +8613185260282." + }, + "password":{ + "type":"string", + "title":"Password", + "description":"The password for your eWeLink account." + }, + "debug":{ + "title":"Debug Logging", + "type":"boolean", + "required":true, + "description":"If enabled, more information will be added to the Homebridge log.", + "default":false + }, + "debugReqRes":{ + "title":"Request & Response Logging", + "type":"boolean", + "required":true, + "description":"If enabled, HTTP, web socket and LAN mode messages will be added to the log. Not recommended for long-term use.", + "default":false + }, + "mode":{ + "type":"string", + "title":"Connection Mode", + "required":true, + "default":"ws", + "description":"Preferred method of updating devices. Devices that don't support LAN mode will use web socket.", + "oneOf":[ + { + "title":"LAN Mode (Recommended)", + "enum":[ + "lan" + ] + }, + { + "title":"Web Socket", + "enum":[ + "ws" + ] + } + ] + }, + "hideDevFromHB":{ + "type":"string", + "title":"Hide Devices", + "description":"A list of eWeLink devices to hide from Homebridge. For example '10009553c8' or multiple devices separated with a comma '10009553c8,10009553c9'.", + "default":"" + }, + "hideFromHB":{ + "type":"string", + "title":"Hide Device Channels", + "description":"A list of device channels to hide from Homebridge. For example '10009553c8SW1' or multiple channels separated with a comma '10009553c8SW1,10009553c9SW2'. Only channels from switches, lights and irrigation valves can be hidden.", + "default":"" + }, + "sensorTimeLength":{ + "type":"integer", + "title":"Sensor Length", + "description":"The number of seconds which the sensor tile in the Home app will light up for if a sensor detects something.", + "default":"2", + "maximum":999 + }, + "sensorTimeDifference":{ + "type":"integer", + "title":"Sensor Lag", + "description":"An offset in seconds to ignore any notifications if they is a delay between a sensor detecting something and Homebridge receiving the notification.", + "default":"120", + "maximum":999 + }, + "valveTimeLength":{ + "type":"integer", + "title":"Valve Duration", + "description":"The default number of seconds that irrigation valves will run for.", + "default":"20", + "maximum":999 + }, + "hideZBLDPress":{ + "title":"Hide Double/Long Press", + "type":"boolean", + "description":"If enabled, double and long press options will be hidden for the ZigBee button.", + "default":false + }, + "groups":{ + "type":"array", + "title":"Custom Groups", + "description":"You can group channels of Sonoff devices to simulate another HomeKit accessory instead of having each switch separately. Currently only blinds and garage doors are supported.", + "items":{ + "type":"object", + "properties":{ + "type":{ + "type":"string", + "title":"Type", + "default":"null", + "description":"A description of this group.", + "oneOf":[ + { + "title":"Blind", + "enum":[ + "blind" + ] + }, + { + "title":"Garage Door", + "enum":[ + "garage" + ] + } + ] + }, + "deviceId":{ + "type":"string", + "title":"Device ID", + "description":"Device ID from your eWeLink app (ten digits normally in the format 1000******)." + }, + "setup":{ + "type":"string", + "title":"Device Setup", + "default":"null", + "description":"The device setup.", + "oneOf":[ + { + "title":"One Switch - for up and down", + "enum":[ + "oneSwitch" + ] + }, + { + "title":"Two Switches - one for up and one for down", + "enum":[ + "twoSwitch" + ] + } + ] + }, + "operationTime":{ + "type":"number", + "title":"Operation Time", + "description":"Total time in deciseconds to fully open/close the blind/door. Count the time in seconds and multiply by 10, for example 100 for 10 seconds or 75 for 7.5 seconds.", + "default":100 + }, + "inched":{ + "title":"Device Inching", + "type":"boolean", + "description":"If device inching is already setup in your eWeLink account then set this to true. Otherwise this plugin will send an 'off' command after half a second to mimic the inching behaviour.", + "default":true + }, + "sensorId":{ + "type":"string", + "title":"Sensor", + "description":"A Sonoff DW2 sensor can be used for a 'one switch' setup. This is to determine the current open/closed state of this device. Please enter the 10 digit device ID. Otherwise leave this blank." + } + } + } + }, + "bridgeSensors":{ + "type":"array", + "title":"Sensors", + "description":"You can expose different types of sensors connected to your RF Bridge in HomeKit.", + "items":{ + "type":"object", + "properties":{ + "deviceId":{ + "type":"string", + "title":"RF Bridge Device ID", + "description":"Device ID of your RF Bridge from your eWeLink app (10 digits normally in the format 1000******)." + }, + "fullDeviceId":{ + "type":"string", + "title":"Sensor Device ID", + "description":"Device ID of the sensor from Homebridge (13 digits normally in the format 1000******SW*)." + }, + "type":{ + "type":"string", + "title":"Sensor Type", + "default":"motion", + "description":"Select the type of sensor you would like to expose this as in Homebridge.", + "oneOf":[ + { + "title":"Button", + "enum":[ + "button" + ] + }, + { + "title":"Motion", + "enum":[ + "motion" + ] + }, + { + "title":"Smoke/Fire", + "enum":[ + "smoke" + ] + }, + { + "title":"Water/Leak", + "enum":[ + "water" + ] + }, + { + "title":"Carbon Monoxide", + "enum":[ + "co" + ] + }, + { + "title":"Carbon Dioxide", + "enum":[ + "co2" + ] + }, + { + "title":"Occupancy", + "enum":[ + "occupancy" + ] + }, + { + "title":"Contact", + "enum":[ + "contact" + ] + } + ] + } + } + } + } + }, + "required":[ + "countryCode", + "username", + "password" + ] + }, + "layout":[ + { + "type":"fieldset", + "items":[ + "countryCode", + "username", + "password" + ] + }, + { + "type":"fieldset", + "title":"Optional", + "description":"Only adjust these settings if you know what you are doing.", + "expandable":true, + "items":[ + "debug", + "debugReqRes", + "mode", + "hideDevFromHB", + "hideFromHB", + "sensorTimeLength", + "sensorTimeDifference", + "valveTimeLength", + "hideZBLDPress" + ] + }, + { + "key":"groups", + "expandable":true, + "title":"Custom Groups", + "add":"Add Another Group", + "type":"array", + "items":[ + { + "type":"fieldset", + "items":[ + "groups[].type", + "groups[].deviceId", + "groups[].setup", + "groups[].operationTime", + "groups[].inched", + "groups[].sensorId" + ] + } + ] + }, + { + "key":"bridgeSensors", + "title":"RF Bridge Devices", + "expandable":true, + "add":"Add Another Device", + "type":"array", + "items":[ + { + "type":"fieldset", + "items":[ + "bridgeSensors[].deviceId", + "bridgeSensors[].fullDeviceId", + "bridgeSensors[].type" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/index.js b/index.js index fadb4c55..3083dd2d 100644 --- a/index.js +++ b/index.js @@ -1,358 +1,7 @@ /* jshint esversion: 9, -W030, node: true */ -const ewelinkapi = require('ewelink-api'); - -var Accessory, Service, Characteristic, UUIDGen; - +"use strict"; +const constants = require("./lib/constants"); module.exports = function (homebridge) { - console.log("homebridge API version: " + homebridge.version); - - // Accessory must be created from PlatformAccessory Constructor - Accessory = homebridge.platformAccessory; - - // Service and Characteristic are from hap-nodejs - Service = homebridge.hap.Service; - Characteristic = homebridge.hap.Characteristic; - UUIDGen = homebridge.hap.uuid; - - // For platform plugin to be considered as dynamic platform plugin, - // registerPlatform(pluginName, platformName, constructor, dynamic), dynamic must be true - homebridge.registerPlatform("homebridge-eWeLink", "eWeLink", eWeLink, true); - -}; - -// Platform constructor -function eWeLink(log, config, api) { - - log("Intialising eWeLink"); - - var platform = this; - - this.log = log; - this.config = config; - this.accessories = new Map(); - this.authenticationToken = 'UNCONFIGURED'; - this.phoneNumberOrEmail = config.phoneNumberOrEmail; - this.accountPassword = config.accountPassword; - this.debug = (config.debug === 'true') ? true : false; - - if (api) { - - // Save the API object as plugin needs to register new accessory via this object - this.api = api; - - // Listen to event "didFinishLaunching", this means homebridge already finished loading cached accessories. - // Platform Plugin should only register new accessory that doesn't exist in homebridge after this event. - // Or start discover new accessories. - - this.api.on('didFinishLaunching', function () { - - platform.log("A total of [%s] accessories were loaded from the local cache", platform.accessories.size); - - // Get a list of all devices from the API, and compare it to the list of cached devices. - // New devices will be added, and devices that exist in the cache but not in the web list - // will be removed from Homebridge. - - (async () => { - - const connection = new ewelinkapi({ - email: this.phoneNumberOrEmail, - password: this.accountPassword - }); - this.connection = connection; - this.authenticationToken = await connection.getCredentials(); - if (this.debug) platform.log("authenticationToken %s", JSON.stringify(this.authenticationToken)); - - /* get all devices */ - platform.log("Requesting a list of devices from eWeLink HTTPS API"); - const devices = await connection.getDevices(); - // console.log(JSON.stringify(devices)); - - var size = devices.length; - platform.log("eWeLink HTTPS API reports that there are a total of [%s] devices registered", size); - - if (size == 0) { - platform.log("As there were no devices were found, all devices have been removed from the platorm's cache. Please regiester your devices using the eWeLink app and restart HomeBridge"); - platform.accessories.clear(); - platform.api.unregisterPlatformAccessories("homebridge-eWeLink", "eWeLink", platform.accessories); - return; - } - - var devicesFromApi = new Map(); - - devices.forEach((device) => { - platform.apiKey = device.apikey; - devicesFromApi.set(device.deviceid, device); - }); - - // Now we compare the cached devices against the web list - platform.log("Evaluating if devices need to be removed..."); - - function checkIfDeviceIsStillRegistered(value, deviceId, map) { - - var accessory = platform.accessories.get(deviceId); - - if (devicesFromApi.has(deviceId)) { - platform.log('Device [%s] is regeistered with API. Nothing to do.', accessory.displayName); - } else { - platform.log('Device [%s], ID : [%s] was not present in the response from the API. It will be removed.', accessory.displayName, accessory.UUID); - platform.removeAccessory(accessory); - } - } - - // If we have devices in our cache, check that they exist in the web response - if (platform.accessories.size > 0) { - platform.log("Verifying that all cached devices are still registered with the API. Devices that are no longer registered with the API will be removed."); - platform.accessories.forEach(checkIfDeviceIsStillRegistered); - } - - platform.log("Evaluating if new devices need to be added..."); - - // Now we compare the cached devices against the web list - function checkIfDeviceIsAlreadyConfigured(value, deviceId, map) { - if (platform.accessories.has(deviceId)) { - - platform.log('Device with ID [%s] is already configured. Ensuring that the configuration is current.', deviceId); - - var accessory = platform.accessories.get(deviceId); - var deviceInformationFromWebApi = devicesFromApi.get(deviceId); - - accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.Name, deviceInformationFromWebApi.name); - accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.SerialNumber, deviceInformationFromWebApi.extra.extra.mac); - accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.Manufacturer, deviceInformationFromWebApi.brandName); - accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.Model, deviceInformationFromWebApi.productModel); - accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.FirmwareRevision, deviceInformationFromWebApi.params.fwVersion); - let powerState; - if ((deviceInformationFromWebApi !== undefined) && (deviceInformationFromWebApi.productModel)) { - switch (deviceInformationFromWebApi.productModel) { - case 'B1': - case 'MINI': - powerState = deviceInformationFromWebApi.params.state; - break; - case 'iFan02': - powerState = deviceInformationFromWebApi.params.switches[0].switch; - break; - case 'AD500--X': - powerState = deviceInformationFromWebApi.params.switch; - } - } - if (this.debug) platform.log("::checkIfDeviceIsAlreadyConfigured() " + deviceInformationFromWebApi.name + " is " + powerState); - - platform.updatePowerStateCharacteristic(deviceId, powerState); - - } else { - var deviceToAdd = devicesFromApi.get(deviceId); - platform.log('Device [%s], ID : [%s] will be added', deviceToAdd.name, deviceToAdd.deviceid); - platform.addAccessory(deviceToAdd); - } - } - - // Go through the web response to make sure that all the devices that are in the response do exist in the accessories map - if (devicesFromApi.size > 0) { - devicesFromApi.forEach(checkIfDeviceIsAlreadyConfigured); - } - - if (this.debug) platform.log("API key retrieved from web service is [%s]", platform.apiKey); - - })().catch(function (error) { - platform.log("Error in intialization"); - }); - }.bind(this)); - } -} - -// Function invoked when homebridge tries to restore cached accessory. -// We update the existing devices as part of didFinishLaunching(), as to avoid an additional call to the the HTTPS API. -eWeLink.prototype.configureAccessory = function (accessory) { - - this.log(accessory.displayName, "Configure Accessory"); - - var platform = this; - accessory.reachable = true; - - accessory.on('identify', function (paired, callback) { - platform.log(accessory.displayName, "Identify!!!"); - callback(); - }); - - if (accessory.getService(Service.Switch)) { - - accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) - .on('set', function (value, callback) { - platform.setPowerState(accessory, value); - callback(); - }) - .on('get', function (callback) { - platform.getPowerState(accessory); - callback(); - }); - - } - - this.accessories.set(accessory.context.deviceId, accessory); - -}; - -eWeLink.prototype.getStateFromDevice = function (device) { - if (this.debug) this.log("getStateFromDevice:: ENTER"); - var powerState = 'on'; - if ((device !== undefined) && (device.productModel)) { - switch (device.productModel) { - case 'B1': - case "MINI": - powerState = device.params.state; - break; - case 'iFan02': - powerState = device.params.switches[0].switch; - break; - case 'AD500--X': - powerState = device.params.switch; - } - } - if (this.debug) this.log("getStateFromDevice:: " + device.name + " is " + powerState); - if (this.debug) this.log("getStateFromDevice:: EXIT"); - return powerState; -}; - -// Sample function to show how developer can add accessory dynamically from outside event -eWeLink.prototype.addAccessory = function (device) { - - // Here we need to check if it is currently there - if (this.accessories.get(device.deviceid)) { - this.log("Not adding [%s] as it already exists in the cache", device.deviceid); - return; - } - - var platform = this; - - if (device.type != 10) { - this.log("A device with an unknown type was returned. It will be skipped.", device.type); - return; - } - - this.log("Found Accessory with Name : [%s], Manufacturer : [%s], Status : [%s], Is Online : [%s], API Key: [%s] ", device.name, device.productModel, this.getStateFromDevice(device), device.online, device.apikey); - - const accessory = new Accessory(device.name, UUIDGen.generate(device.deviceid.toString())); - - accessory.context.deviceId = device.deviceid; - accessory.context.apiKey = device.apikey; - - // if (device.online == 'true') { - accessory.reachable = true; - // } else { - // accessory.reachable = false; - // } - - accessory.addService(Service.Switch, device.name) - .getCharacteristic(Characteristic.On) - .on('set', function (value, callback) { - platform.setPowerState(accessory, value); - callback(); - }) - .on('get', function (callback) { - platform.getPowerState(accessory); - callback(); - }); - - accessory.on('identify', function (paired, callback) { - platform.log(accessory.displayName, "Identify not supported"); - callback(); - }); - - accessory.getService(Service.AccessoryInformation).Characteristic(Characteristic.SerialNumber, device.extra.extra.mac); - accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.Manufacturer, device.productModel); - accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.Model, device.extra.extra.model); - accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.Identify, false); - accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); - - this.accessories.set(device.deviceid, accessory); - - this.api.registerPlatformAccessories("homebridge-eWeLink", - "eWeLink", [accessory]); - -}; - -eWeLink.prototype.getSequence = function () { - var time_stamp = new Date() / 1000; - this.sequence = Math.floor(time_stamp * 1000); - return this.sequence; -}; - -eWeLink.prototype.updatePowerStateCharacteristic = function (deviceId, state) { - var platform = this; - if (platform.debug) platform.log("::updatePowerStateCharacteristic() : ENTER with (deviceId='" + deviceId + "',state='" + state + "')"); - - // Used when we receive an update from an external source - var isOn = false; - var accessory = platform.accessories.get(deviceId); - if (state == 'on') { - isOn = true; - } - //if (platform.debug) platform.log("::updatePowerStateCharacteristic() : accessory before update: "+JSON.stringify(accessory)); - - if (platform.debug) platform.log("::updatePowerStateCharacteristic() : Updating recorded Characteristic.On for [%s] to [%s]. No request will be sent to the device.", accessory.context.deviceId, isOn); - accessory.getService(Service.Switch).setCharacteristic(Characteristic.On, isOn); - //if (platform.debug) platform.log("::updatePowerStateCharacteristic() : accessory after update: "+JSON.stringify(accessory)); - //platform.updatePowerStateCharacteristic(deviceId, powerState); - if (platform.debug) platform.log("::updatePowerStateCharacteristic() : EXIT"); -}; - -eWeLink.prototype.getPowerState = function (accessory, callback) { - var platform = this; - - if (this.debug) platform.log("::getPowerState() : ENTER Requesting power state for [%s].", accessory.displayName); //, JSON.stringify(accessory)); - - (async () => { - // const device = await platform.connection.getDevice(accessory.context.deviceId); - var interestedDevice = null; - ///////////// - const devices = await platform.connection.getDevices(); - //if (platform.debug) platform.log("::getPowerState() : retrieved all devices, found "+devices.length+" devices"); - - //if (platform.debug) platform.log("::getPowerState() : Looking for interested device"); - devices.forEach((device) => { - // if (platform.debug) platform.log("::getPowerState() : Found : "+JSON.stringify(device)); - //if (platform.debug) platform.log("::getPowerState() : Looking for " + accessory.context.deviceId + ", but found "+device.deviceid); - if (accessory.context.deviceId == device.deviceid) { - //if (platform.debug) platform.log("::getPowerState() : found what I was looking for"); - interestedDevice = device; - } - }); - ///////////// - let powerState = platform.getStateFromDevice(interestedDevice); - if (platform.debug) platform.log("::getPowerState() : power state for [%s] is %s", accessory.displayName, powerState); - this.updatePowerStateCharacteristic(accessory.context.deviceId, powerState); - if (this.debug) platform.log("::getPowerState() : EXIT"); - })() - .catch(function (error) { - platform.log("::getPowerState() : Error in retrieving device\n" + JSON.stringify(error)); - }); -}; - -eWeLink.prototype.setPowerState = function (accessory, isOn, callback) { - var platform = this; - if (platform.debug) platform.log("::setPowerState() : ENTER"); - - var targetState = 'off'; - - if (isOn == true || isOn == 'on') { - targetState = 'on'; - } - - if (this.debug) platform.log("::setPowerState() : Setting power state to [%s] for device [%s]", targetState, accessory.displayName); - (async () => { - const status = await platform.connection.setDevicePowerState(accessory.context.deviceId, targetState); - if (this.debug) platform.log("::setPowerState() : power state for [%s] is %s", accessory.displayName, JSON.stringify(status)); - //this.updatePowerStateCharacteristic(accessory.context.deviceId, targetState); - if (platform.debug) platform.log("::setPowerState() : EXIT"); - })().catch(function (error) { - platform.log("::setPowerState() : Error in retrieving device\n" + JSON.stringify(error)); - }); -}; - -// Sample function to show how developer can remove accessory dynamically from outside event -eWeLink.prototype.removeAccessory = function (accessory) { - - this.log('Removing accessory [%s]', accessory.displayName); - this.accessories.delete(accessory.context.deviceId); - this.api.unregisterPlatformAccessories('homebridge-eWeLink', 'eWeLink', [accessory]); + let eWeLink = require("./lib/eWeLink.js")(homebridge); + homebridge.registerPlatform(constants.packageName, "eWeLink", eWeLink, true); }; \ No newline at end of file diff --git a/lib/constants.js b/lib/constants.js new file mode 100644 index 00000000..27699ea5 --- /dev/null +++ b/lib/constants.js @@ -0,0 +1,119 @@ +/* jshint esversion: 9, -W030, node: true */ +"use strict"; +module.exports = { + appId: "oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq", + packageName: "homebridge-ewelink", + devicesHideable: ["switch", "light", "valve"], + devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], + devicesSingleSwitchLight: ["T1 1C", "L1", "B1", "B1_R2", "TX1C", "D1", "D1R1", "KING-M4", "Slampher"], + devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], + devicesMultiSwitchLight: ["T1 2C", "T1 3C", "TX2C", "TX3C"], + devicesBrightable: [36, 44], + devicesColourable: [22, 59], + devicesSensor: [102], + devicesThermostat: [15], + devicesFan: [34], + devicesOutlet: [32], + devicesUSB: [77], + devicesSCM: [78], + devicesRFBridge: [28], + devicesZBBridge: [66], + devicesZB: [1000, 1770, 2026, 3026], + paramsToKeep: ["bright", "brightness", "channel", "cmd", "colorB", "colorG", "colorR", "currentHumidity", "currentTemperature", "fan", "humidity", "key", "light", "lock", "mainSwitch", "mode", "online", "rfChl", "rfList", "rfTrig", "sensorType", "speed", "state", "switch", "switches", "temperature", "type", "zyx_mode"], + chansFromUiid: { + 1: 1, // "SOCKET" \\ 20, MINI, BASIC, S26 + 2: 2, // "SOCKET_2" \\ + 3: 3, // "SOCKET_3" \\ + 4: 4, // "SOCKET_4", \\ + 5: 1, // "SOCKET_POWER" \\ + 6: 1, // "SWITCH" \\ T1 1C, TX1C + 7: 2, // "SWITCH_2" \\ T1 2C, TX2C + 8: 3, // "SWITCH_3" \\ T1 3C, TX3C + 9: 4, // "SWITCH_4" \\ + 10: 0, // "OSPF" \\ + 11: 0, // "CURTAIN" \\ King Q4 Cover + 12: 0, // "EW-RE" \\ + 13: 0, // "FIREPLACE" \\ + 14: 1, // "SWITCH_CHANGE" \\ + 15: 1, // "THERMOSTAT" \\ TH10, TH16 + 16: 0, // "COLD_WARM_LED" \\ + 17: 0, // "THREE_GEAR_FAN" \\ + 18: 0, // "SENSORS_CENTER" \\ + 19: 0, // "HUMIDIFIER" \\ + 22: 1, // "RGB_BALL_LIGHT" \\ B1, B1_R2 + 23: 0, // "NEST_THERMOSTAT" \\ + 24: 1, // "GSM_SOCKET" \\ + 25: 0, // "AROMATHERAPY", \\ Diffuser + 26: 0, // "RuiMiTeWenKongQi" \\ + 27: 1, // "GSM_UNLIMIT_SOCKET" \\ + 28: 1, // "RF_BRIDGE" \\ RFBridge, RF_Bridge + 29: 2, // "GSM_SOCKET_2" \\ + 30: 3, // "GSM_SOCKET_3" \\ + 31: 4, // "GSM_SOCKET_4" \\ + 32: 1, // "POWER_DETECTION_SOCKET" \\ Pow_R2 POW + 33: 0, // "LIGHT_BELT", \\ + 34: 4, // "FAN_LIGHT" \\ iFan02, iFan + 35: 0, // "EZVIZ_CAMERA", \\ + 36: 1, // "SINGLE_CHANNEL_DIMMER_SWITCH" \\ KING-M4 + 38: 0, // "HOME_KIT_BRIDGE", \\ + 40: 0, // "FUJIN_OPS" \\ + 41: 4, // "CUN_YOU_DOOR" \\ + 42: 0, // "SMART_BEDSIDE_AND_NEW_RGB_BALL_LIGHT" \\ + 43: 0, // "?" \\ + 44: 1, // "SNOFF_LIGHT" \\ D1 + 45: 0, // "DOWN_CEILING_LIGHT" \\ + 46: 0, // "AIR_CLEANER" \\ + 49: 0, // "MACHINE_BED" \\ + 51: 0, // "COLD_WARM_DESK_LIGHT" \\ + 52: 0, // "DOUBLE_COLOR_DEMO_LIGHT" \\ + 53: 0, // "ELECTRIC_FAN_WITH_LAMP" \\ + 55: 0, // "SWEEPING_ROBOT" \\ + 56: 0, // "RGB_BALL_LIGHT_4" \\ + 57: 0, // "MONOCHROMATIC_BALL_LIGHT" \\ + 59: 1, // "MUSIC_LIGHT_BELT" \\ L1 + 60: 0, // "NEW_HUMIDIFIER" \\ + 61: 0, // "KAI_WEI_ROUTER" \\ + 62: 0, // "MEARICAMERA" \\ + 64: 0, // "HeatingTable" \\ + 65: 0, // "CustomCamera" \\ + 66: 0, // "ZIGBEE_MAIN_DEVICE" \\ + 67: 0, // "RollingDoor" \\ + 68: 0, // "KOOCHUWAH" \\ + 69: 0, // "ATMOSPHERE_LAMP" \\ + 76: 0, // "YI_GE_ER_LAMP" \\ + 77: 4, // "SINGLE_SOCKET_MULTIPLE" \\ (1 socket device using data structure of four :() + 78: 4, // "SINGLE_SWITCH_MULTIPLE" \\ (1 switch device using data structure of four :() + 79: 0, // "CHRISTMAS_LIGHT" \\ + 80: 0, // "HANYUAN_AIR_CONDITION" \\ + 81: 1, // "GSM_SOCKET_NO_FLOW" \\ + 82: 2, // "GSM_SOCKET_2_NO_FLOW" \\ + 83: 3, // "GSM_SOCKET_3_NO_FLOW" \\ + 84: 4, // "GSM_SOCKET_4_NO_FLOW" \\ + 86: 0, // "CLEAR_BOOT" \\ + 87: 0, // "EWELINK_IOT_CAMERA" \\ GK-200MP2B + 88: 0, // "YK_INFRARED" \\ + 89: 0, // "SMART_OPEN_MACHINE" \\ + 90: 0, // "GSM_RFBridge" \\ + 91: 0, // "ROLLING_DOOR_91" \\ + 93: 0, // "HTHD_AIR_CLEANER" \\ + 94: 0, // "YIAN_ELECTRIC_PROTECT" \\ + 98: 0, // "DOORBELL_RFBRIDGE" \\ + 102: 1, // "DOOR_MAGNETIC" \\ OPL-DMA, DW2 + 103: 0, // "WOTEWODE_TEM_LIGHT" \\ + 104: 0, // "WOTEWODE_RGB_TEM_LIGHT" \\ + 107: 0, // "GSM_SOCKET_NO_FLOW" \\ + 109: 0, // "YK_INFRARED_2" \\ + 1000: 1, // "ZIGBEE_WIRELESS_SWITCH" \\ + 1001: 0, // "BLADELESS_FAN" \\ + 1002: 0, // "NEW_HUMIDIFIER" \\ + 1003: 0, // "WARM_AIR_BLOWER" \\ + 1256: 1, // "ZIGBEE_SINGLE_SWITCH" \\ + 1770: 1, // "ZIGBEE_TEMPERATURE_SENSOR" \\ + 2026: 1, // "ZIGBEE_MOBILE_SENSOR" \\ + 2256: 2, // "ZIGBEE_SWITCH_2" \\ + 3026: 1, // "ZIGBEE_DOOR_AND_WINDOW_SENSOR" \\ + 3256: 3, // "ZIGBEE_SWITCH_3" \\ + 4026: 1, // "ZIGBEE_WATER_SENSOR" \\ + 4256: 4, // "ZIGBEE_SWITCH_4" \\ + } +}; \ No newline at end of file diff --git a/lib/eWeLink.js b/lib/eWeLink.js new file mode 100644 index 00000000..8cfdceec --- /dev/null +++ b/lib/eWeLink.js @@ -0,0 +1,1825 @@ +/* jshint esversion: 9, -W030, node: true */ +"use strict"; +const constants = require("./constants"); +const convert = require("color-convert"); +const eWeLinkHTTP = require("./eWeLinkHTTP"); +const eWeLinkWS = require("./eWeLinkWS"); +const eWeLinkLAN = require("./eWeLinkLAN"); +let Accessory, Service, Characteristic, UUIDGen; +class eWeLink { + constructor(log, config, api) { + if (!log || !api) { + return; + } + if (!config || (!config.username || !config.password || !config.countryCode)) { + log.error("** Could not load " + constants.packageName + " **"); + log.warn("Make sure your eWeLink credentials are in the Homebridge configuration."); + return; + } + this.log = log; + this.config = config; + this.api = api; + this.mode = this.config.mode || "lan"; + this.debug = this.config.debug || false; + this.debugReqRes = this.config.debugReqRes || false; + this.customHideChanFromHB = this.config.hideFromHB || ""; + this.customHideDvceFromHB = this.config.hideDevFromHB || ""; + this.customNameOverride = this.config.nameOverride || {}; + this.sensorTimeLength = this.config.sensorTimeLength || 2; + this.sensorTimeDifference = this.config.sensorTimeDifference || 120; + this.valveTimeLength = this.config.valveTimeLength || 120; + this.hideZBLDPress = this.config.hideZBLDPress || false; + this.devicesInHB = new Map(); + this.devicesInEwe = new Map(); + this.cusG = new Map(); + this.cusS = new Map(); + this.api.on("didFinishLaunching", () => { + this.log("Plugin has finished initialising. Starting synchronisation with eWeLink account."); + //*** Set up HTTP client and get the user HTTP host ***\\ + this.httpClient = new eWeLinkHTTP(this.config, this.log); + this.httpClient.getHost() + .then(res => { //*** Use the HTTP API host to log into eWeLink ***\\ + return this.httpClient.login(); + }).then(res => { //*** Set up the web socket client ***\\ + this.wsClient = new eWeLinkWS(this.config, this.log, res); + return this.wsClient.getHost(); + }).then(res => { //*** Open web socket connection and get device list via HTTP ***\\ + this.wsClient.login(); + return this.httpClient.getDevices(); + }).then(res => { //*** Get device IP addresses for LAN mode ***\\ + this.httpDevices = res; + this.lanClient = new eWeLinkLAN(this.config, this.log, this.httpDevices); + return this.lanClient.getHosts(); + }).then(res => { //*** Set up the LAN mode listener ***\\ + this.lanDevices = res; + return this.lanClient.startMonitor(); + }).then(res => { //*** Use the device list to refresh Homebridge accessories ***\\ + (() => { + //*** Remove all Homebridge accessories if none found ***\\ + if (Object.keys(this.httpDevices).length === 0 && Object.keys(this.lanDevices).length === 0) { + this.removeAllAccessories(); + return; + } + //*** Make a map of devices from eWeLink ***\\ + this.httpDevices.forEach(device => { + if (this.customHideDvceFromHB.includes(device.deviceid)) { + return; + } + this.devicesInEwe.set(device.deviceid, device); + }); + //*** Make a map of custom groups from Homebridge config ***\\ + if (this.config.groups && Object.keys(this.config.groups).length > 0) { + this.config.groups.forEach(group => { + if (typeof group.deviceId !== "undefined" && this.devicesInEwe.has(group.deviceId.toLowerCase())) { + this.cusG.set(group.deviceId + "SWX", group); + } + }); + } + //*** Make a map of RF Bridge custom sensors from Homebridge config ***\\ + if (this.config.bridgeSensors && Object.keys(this.config.bridgeSensors).length > 0) { + this.config.bridgeSensors.forEach(bridgeSensor => { + if (typeof bridgeSensor.deviceId !== "undefined" && this.devicesInEwe.has(bridgeSensor.deviceId.toLowerCase())) { + this.cusS.set(bridgeSensor.fullDeviceId, bridgeSensor); + } + }); + } + //*** Logging always helps to see if everything is okay so far ***\\ + this.log("[%s] eWeLink devices were loaded from the Homebridge cache.", this.devicesInHB.size); + this.log("[%s] primary devices were loaded from your eWeLink account.", this.devicesInEwe.size); + this.log("[%s] primary devices were discovered on your local network.", Object.keys(this.lanDevices).length); + //*** Remove Homebridge accessories that don't appear in eWeLink ***\\ + if (this.devicesInHB.size > 0) { + this.devicesInHB.forEach(accessory => { + if (!this.devicesInEwe.has(accessory.context.eweDeviceId)) { + this.removeAccessory(accessory); + } + }); + } + //*** Disable plugin if no eWeLink devices ***\\ + if (this.devicesInEwe.size === 0) { + return; + } + //*** Synchronise (add/refresh) devices between eWeLink and Homebridge ***\\ + this.devicesInEwe.forEach(device => { + this.initialiseDevice(device); + }); + //*** Set up the ws listener for future external device updates ***\\ + this.wsClient.receiveUpdate(device => { + this.receiveDeviceUpdate(device); + }); + //*** Set up the lan listener for future external device updates ***\\ + this.lanClient.receiveUpdate(device => { + this.receiveDeviceUpdate(device); + }); + this.log("Synchronisation complete. Ready to go!"); + if (this.debugReqRes) { + this.log.warn("You have 'Request & Response Logging' enabled. This setting is not recommended for long-term use."); + } + })(); + }).catch(err => { + this.log.error("** eWeLink synchronisation error: **"); + this.log.warn(err); + this.log.error("** Plugin will not be loaded. **"); + }); + }); + } + initialiseDevice(device) { + let accessory; + //*** First add the device if it isn't already in Homebridge ***\\ + if (!this.devicesInHB.has(device.deviceid + "SWX") && !this.devicesInHB.has(device.deviceid + "SW0")) { + if (device.extra.uiid === 2 && device.brandName === "coolkit" && device.productModel === "0285") { + this.addAccessory(device, device.deviceid + "SWX", "valve"); + } else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "blind") { + this.addAccessory(device, device.deviceid + "SWX", "blind"); + } else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "garage") { + this.addAccessory(device, device.deviceid + "SWX", "garage"); + } else if (constants.devicesSensor.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SWX", "sensor"); + } else if (constants.devicesFan.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SWX", "fan"); + } else if (constants.devicesThermostat.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SWX", "thermostat"); + } else if (constants.devicesOutlet.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SWX", "outlet"); + } else if (constants.devicesUSB.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SWX", "usb"); + } else if (constants.devicesSCM.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SWX", "scm"); + } else if (constants.devicesSingleSwitch.includes(device.extra.uiid) && constants.devicesSingleSwitchLight.includes(device.productModel)) { + this.addAccessory(device, device.deviceid + "SWX", "light"); + } else if (constants.devicesMultiSwitch.includes(device.extra.uiid) && constants.devicesMultiSwitchLight.includes(device.productModel)) { + for (let i = 0; i <= constants.chansFromUiid[device.extra.uiid]; i++) { + this.addAccessory(device, device.deviceid + "SW" + i, "light"); + } + } else if (constants.devicesSingleSwitch.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SWX", "switch"); + } else if (constants.devicesMultiSwitch.includes(device.extra.uiid)) { + for (let i = 0; i <= constants.chansFromUiid[device.extra.uiid]; i++) { + this.addAccessory(device, device.deviceid + "SW" + i, "switch"); + } + } else if (constants.devicesRFBridge.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SW0", "rf_pri"); + for (let i = 1; i <= Object.keys(device.params.rfList).length; i++) { + this.addAccessory(device, device.deviceid + "SW" + i, "rf_sub"); + } + } else if (constants.devicesZBBridge.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SWX", "zb_pri"); + } else if (constants.devicesZB.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SWX", "zb_sub"); + } else { + this.log.warn("[%s] could not be added as it is not supported by this plugin.", device.name); + } + } + //*** Next refresh the device ***\\ + if ((accessory = this.devicesInHB.get(device.deviceid + "SWX"))) { + accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); + accessory.context.reachableWAN = accessory.context.eweUIID !== 102 ? + device.online : + true; //*** DW2 offline sometimes (as battery powered?) ***\\ + accessory.context.reachableLAN = this.lanDevices[device.deviceid].ip || false; + let str = accessory.context.reachableLAN ? + "and locally with IP [" + accessory.context.reachableLAN + "]" : + (accessory.context.reachableWAN) ? + "but LAN mode unavailable as unsupported/shared device" : + "but LAN mode unavailable as device offline"; + this.log("[%s] found in eWeLink %s.", accessory.displayName, str); + try { + this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + this.api.updatePlatformAccessories(constants.packageName, "eWeLink", [accessory]); + } catch (e) { + this.log.warn("[%s] online/offline status could not be updated - [%s].", accessory.displayName, e); + } + } else if ((accessory = this.devicesInHB.get(device.deviceid + "SW0"))) { + accessory.context.reachableLAN = this.lanDevices[device.deviceid].ip || false; + let str = accessory.context.reachableLAN ? + "and locally with IP [" + accessory.context.reachableLAN + "]" : + (accessory.context.reachableWAN) ? + "but LAN mode unavailable as unsupported/shared device" : + "but LAN mode unavailable as device offline"; + this.log("[%s] found in eWeLink %s.", accessory.displayName, str); + let isRf = constants.devicesRFBridge.includes(device.extra.uiid); + let rfCh = false; + for (let i = 0; i <= accessory.context.channelCount; i++) { + let oAccessory; + try { + if (!this.devicesInHB.has(device.deviceid + "SW" + i)) { + if (i > 0 && this.customHideChanFromHB.includes(device.deviceid + "SW" + i) && constants.devicesHideable.includes(accessory.context.type)) { + continue; + } else { + this.addAccessory(device, device.deviceid + "SW" + i, "switch"); + } + } + oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); + if (i > 0 && this.customHideChanFromHB.includes(device.deviceid + "SW" + i) && constants.devicesHideable.includes(accessory.context.type)) { + this.removeAccessory(oAccessory); + continue; + } + if (i > 0 && isRf) { + let ct = this.cusS.has(oAccessory.context.hbDeviceId) ? this.cusS.get(oAccessory.context.hbDeviceId).type : "motion"; + if (ct !== oAccessory.context.sensorType) { + rfCh = true; + } + } + oAccessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); + oAccessory.context.reachableWAN = device.online; + oAccessory.context.reachableLAN = this.lanDevices[device.deviceid].ip || false; + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); + this.api.updatePlatformAccessories(constants.packageName, "eWeLink", [oAccessory]); + } catch (e) {} + } + if (rfCh) { + this.log.warn("RF Bridge configuration changed. Devices will be removed and readded."); + try { + for (let i = 0; i <= accessory.context.channelCount; i++) { + let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); + this.removeAccessory(oAccessory); + } + this.initialiseDevice(device); + } catch (err) {} + return; + } + } else { + this.log.warn("[%s] will not be refreshed as it wasn't found in Homebridge.", device.name); + return; + } + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + this.log.warn("[%s] will not be refreshed as it has been reported offline.", accessory.displayName); + return; + } + device.params.updateSource = "http"; + if (!this.refreshAccessory(accessory, device.params)) { + this.log.warn("[%s] could not be refreshed. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.). Debugging: [%s:%s:%s]", accessory.displayName, "initialise", accessory.context.type, accessory.context.channelCount); + } + } + addAccessory(device, hbDeviceId, type) { + let channelCount = type === "rf_pri" ? Object.keys(device.params.rfList).length : constants.chansFromUiid[device.extra.uiid], + switchNumber = hbDeviceId.substr(-1).toString(), + newDeviceName = device.name; + if (["1", "2", "3", "4"].includes(switchNumber)) { + newDeviceName += " SW" + switchNumber; + if (this.customHideChanFromHB.includes(hbDeviceId) && type === "switch") { + this.log.warn("[%s] has not been added as per configuration", newDeviceName); + return; + } + } + if (this.customNameOverride.hasOwnProperty(hbDeviceId)) { + newDeviceName = this.customNameOverride[hbDeviceId]; + } + const accessory = new Accessory(newDeviceName, UUIDGen.generate(hbDeviceId).toString()); + try { + accessory.getService(Service.AccessoryInformation) + .setCharacteristic(Characteristic.SerialNumber, hbDeviceId) + .setCharacteristic(Characteristic.Manufacturer, device.brandName) + .setCharacteristic(Characteristic.Model, device.productModel + " (" + device.extra.model + ")") + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) + .setCharacteristic(Characteristic.Identify, false); + accessory.context = { + hbDeviceId, + eweDeviceId: device.deviceid, + eweUIID: device.extra.uiid, + eweModel: device.productModel, + eweApiKey: device.apikey, + switchNumber, + channelCount, + type + }; + switch (type) { + case "valve": + ["A", "B"].forEach(v => { + accessory.addService(Service.Valve, "Valve " + v, "valve" + v.toLowerCase()) + .setCharacteristic(Characteristic.Active, 0) + .setCharacteristic(Characteristic.InUse, 0) + .setCharacteristic(Characteristic.ValveType, 1) + .setCharacteristic(Characteristic.SetDuration, this.valveTimeLength) + .addCharacteristic(Characteristic.RemainingDuration); + }); + break; + case "blind": + accessory.addService(Service.WindowCovering) + .setCharacteristic(Characteristic.CurrentPosition, 100) + .setCharacteristic(Characteristic.TargetPosition, 100) + .setCharacteristic(Characteristic.PositionState, 2); + break; + case "garage": + accessory.addService(Service.GarageDoorOpener) + .setCharacteristic(Characteristic.CurrentDoorState, 1) + .setCharacteristic(Characteristic.TargetDoorState, 1) + .setCharacteristic(Characteristic.ObstructionDetected, false); + break; + case "sensor": + accessory.addService(Service.ContactSensor) + .setCharacteristic(Characteristic.ContactSensorState, 0); + break; + case "fan": + accessory.addService(Service.Fanv2); + accessory.addService(Service.Lightbulb); + break; + case "thermostat": + accessory.addService(Service.Switch); + accessory.addService(Service.TemperatureSensor); + if (device.params.sensorType !== "DS18B20") { + accessory.addService(Service.HumiditySensor); + } + break; + case "outlet": + case "usb": + accessory.addService(Service.Outlet); + break; + case "light": + accessory.addService(Service.Lightbulb); + break; + case "switch": + case "scm": + accessory.addService(Service.Switch); + break; + case "rf_pri": + case "zb_pri": + break; + case "rf_sub": + accessory.context.sensorType = this.cusS.has(hbDeviceId) ? this.cusS.get(hbDeviceId).type : "motion"; + accessory.context.rfChl = parseInt(switchNumber) - 1; + switch (accessory.context.sensorType) { + case "button": + accessory.addService(Service.Switch); + break; + case "water": + accessory.addService(Service.LeakSensor); + break; + case "fire": + case "smoke": + accessory.addService(Service.SmokeSensor); + break; + case "co": + accessory.addService(Service.CarbonMonoxideSensor); + break; + case "co2": + accessory.addService(Service.CarbonDioxideSensor); + break; + case "contact": + accessory.addService(Service.ContactSensor); + break; + case "occupancy": + accessory.addService(Service.OccupancySensor); + break; + case "motion": + default: + accessory.addService(Service.MotionSensor); + break; + } + break; + case "zb_sub": + switch (device.extra.uiid) { + case 1000: //*** credit @tasict ***\\ + accessory.addService(Service.StatelessProgrammableSwitch); + if (this.hideZBLDPress) { + accessory.getService(Service.StatelessProgrammableSwitch) + .getCharacteristic(Characteristic.ProgrammableSwitchEvent) + .setProps({ + validValues: [0] + }); + } + break; + case 1770: + accessory.addService(Service.TemperatureSensor); + accessory.addService(Service.HumiditySensor); + break; + case 2026: + accessory.addService(Service.MotionSensor); + break; + case 3026: + accessory.addService(Service.ContactSensor).setCharacteristic(Characteristic.ContactSensorState, 0); + break; + default: + throw "unsupported zigbee device type with uiid [" + device.extra.uiid + "]"; + } + break; + default: + throw "device is not supported by this plugin"; + } + this.devicesInHB.set(hbDeviceId, accessory); + this.api.registerPlatformAccessories(constants.packageName, "eWeLink", [accessory]); + this.configureAccessory(accessory); + this.log("[%s] has been added to Homebridge.", newDeviceName); + } catch (e) { + this.log.warn("[%s] could not be added as %s.", accessory.displayName, e); + } + } + configureAccessory(accessory) { + if (!this.log) { + return; + } + try { + switch (accessory.context.type) { + case "valve": + ["A", "B"].forEach(v => { + accessory.getService("Valve " + v).getCharacteristic(Characteristic.Active) + .on("set", (value, callback) => { + accessory.getService("Valve " + v).getCharacteristic(Characteristic.Active).value !== value ? + this.internalValveUpdate(accessory, "Valve " + v, value, callback) : + callback(); + }); + accessory.getService("Valve " + v).getCharacteristic(Characteristic.SetDuration) + .on("set", (value, callback) => { + if (accessory.getService("Valve " + v).getCharacteristic(Characteristic.InUse).value) { + accessory.getService("Valve " + v).updateCharacteristic(Characteristic.RemainingDuration, value); + clearTimeout(accessory.getService("Valve " + v).timer); + accessory.getService("Valve " + v).timer = setTimeout(() => { + accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); + }, (value * 1000)); + } + callback(); + }); + }); + break; + case "blind": + accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.TargetPosition) + .setProps({ + minStep: 100 + }) + .on("set", (value, callback) => { + accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.TargetPosition).value !== value ? + this.internalBlindUpdate(accessory, value, callback) : + callback(); + }); + break; + case "garage": + accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.TargetDoorState) + .on("set", (value, callback) => { + accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.TargetDoorState).value !== value ? + this.internalGarageUpdate(accessory, value, callback) : + callback(); + }); + break; + case "fan": + accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active) + .on("set", (value, callback) => { + accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active).value !== value ? + this.internalFanUpdate(accessory, "power", value, callback) : + callback(); + }); + accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.RotationSpeed) + .setProps({ + minStep: 33 + }) + .on("set", (value, callback) => { + accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.RotationSpeed).value !== value ? + this.internalFanUpdate(accessory, "speed", value, callback) : + callback(); + }); + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) + .on("set", (value, callback) => { + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value !== value ? + this.internalFanUpdate(accessory, "light", value, callback) : + callback(); + }); + break; + case "thermostat": + accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) + .on("set", (value, callback) => { + accessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value !== value ? + this.internalThermostatUpdate(accessory, value, callback) : + callback(); + }); + break; + case "outlet": + accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) + .on("set", (value, callback) => { + accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value !== value ? + this.internalOutletUpdate(accessory, value, callback) : + callback(); + }); + break; + case "usb": + accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) + .on("set", (value, callback) => { + accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value !== value ? + this.internalUSBUpdate(accessory, value, callback) : + callback(); + }); + break; + case "scm": + accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) + .on("set", (value, callback) => { + accessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value !== value ? + this.internalSCMUpdate(accessory, value, callback) : + callback(); + }); + break; + case "light": + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) + .on("set", (value, callback) => { + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value !== value ? + this.internalLightbulbUpdate(accessory, value, callback) : + callback(); + }); + if (constants.devicesBrightable.includes(accessory.context.eweUIID)) { + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Brightness) + .on("set", (value, callback) => { + if (value > 0) { + if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + this.internalLightbulbUpdate(accessory, true, callback); + } + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Brightness).value !== value ? + this.internalBrightnessUpdate(accessory, value, callback) : + callback(); + } else { + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value ? + this.internalLightbulbUpdate(accessory, false, callback) : + callback(); + } + }); + } else if (constants.devicesColourable.includes(accessory.context.eweUIID)) { + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Brightness) + .on("set", (value, callback) => { + if (value > 0) { + if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + this.internalLightbulbUpdate(accessory, true, callback); + } + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Brightness).value !== value ? + this.internalHSBUpdate(accessory, "bri", value, callback) : + callback(); + } else { + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value ? + this.internalLightbulbUpdate(accessory, false, callback) : + callback(); + } + }); + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Hue) + .on("set", (value, callback) => { + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Hue).value !== value ? + this.internalHSBUpdate(accessory, "hue", value, callback) : + callback(); + }); + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Saturation) + .on("set", (value, callback) => { + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Saturation, value); + callback(); + }); + } + break; + case "switch": + accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) + .on("set", (value, callback) => { + accessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value !== value ? + this.internalSwitchUpdate(accessory, value, callback) : + callback(); + }); + break; + case "rf_sub": + if (accessory.context.sensorType === "button") { + accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) + .on("set", (value, callback) => { + this.internalRFDeviceUpdate(accessory, true, callback); + }); + } + break; + } + accessory.context.reachableWAN = true; + accessory.context.reachableLAN = true; + this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + this.api.updatePlatformAccessories(constants.packageName, "eWeLink", [accessory]); + } catch (e) { + this.log.warn("[%s] could not be refreshed - [%s].", accessory.displayName, e); + } + } + refreshAccessory(accessory, newParams) { + switch (accessory.context.type) { + case "valve": + if (Array.isArray(newParams.switches)) { + this.externalValveUpdate(accessory, newParams); + } + return true; + case "blind": + if (Array.isArray(newParams.switches)) { + this.externalBlindUpdate(accessory, newParams); + } + return true; + case "garage": + if (newParams.hasOwnProperty("switch") || Array.isArray(newParams.switches)) { + this.externalGarageUpdate(accessory, newParams); + } + return true; + case "sensor": + if (newParams.hasOwnProperty("switch")) { + this.externalSensorUpdate(accessory, newParams); + } + return true; + case "fan": + if (Array.isArray(newParams.switches) || (newParams.hasOwnProperty("light") && newParams.hasOwnProperty("fan") && newParams.hasOwnProperty("speed"))) { + this.externalFanUpdate(accessory, newParams); + } + return true; + case "thermostat": + if (newParams.hasOwnProperty("currentTemperature") || newParams.hasOwnProperty("currentHumidity") || newParams.hasOwnProperty("switch") || newParams.hasOwnProperty("masterSwitch")) { + this.externalThermostatUpdate(accessory, newParams); + } + return true; + case "outlet": + if (newParams.hasOwnProperty("switch")) { + this.externalOutletUpdate(accessory, newParams); + } + return true; + case "usb": + if (Array.isArray(newParams.switches)) { + this.externalUSBUpdate(accessory, newParams); + } + return true; + case "scm": + if (Array.isArray(newParams.switches)) { + this.externalSCMUpdate(accessory, newParams); + } + return true; + case "light": + if (constants.devicesSingleSwitch.includes(accessory.context.eweUIID) && constants.devicesSingleSwitchLight.includes(accessory.context.eweModel)) { + if (newParams.hasOwnProperty("switch") || newParams.hasOwnProperty("state") || newParams.hasOwnProperty("bright") || newParams.hasOwnProperty("colorR") || newParams.hasOwnProperty("brightness") || newParams.hasOwnProperty("channel0") || newParams.hasOwnProperty("channel2") || newParams.hasOwnProperty("zyx_mode")) { + this.externalSingleLightUpdate(accessory, newParams); + } + } else if (constants.devicesMultiSwitch.includes(accessory.context.eweUIID) && constants.devicesMultiSwitchLight.includes(accessory.context.eweModel)) { + if (Array.isArray(newParams.switches)) { + this.externalMultiLightUpdate(accessory, newParams); + } + } + return true; + case "switch": + if (constants.devicesSingleSwitch.includes(accessory.context.eweUIID)) { + if (newParams.hasOwnProperty("switch")) { + this.externalSingleSwitchUpdate(accessory, newParams); + } + } else if (constants.devicesMultiSwitch.includes(accessory.context.eweUIID)) { + if (Array.isArray(newParams.switches)) { + this.externalMultiSwitchUpdate(accessory, newParams); + } + } + return true; + case "rf_pri": + this.externalRFDeviceUpdate(accessory, newParams); + return true; + case "rf_sub": + return true; + case "zb_pri": + return true; + case "zb_sub": + this.externalZBDeviceUpdate(accessory, newParams); + return true; + default: + return false; + } + } + removeAccessory(accessory) { + try { + this.devicesInHB.delete(accessory.context.hbDeviceId); + this.api.unregisterPlatformAccessories(constants.packageName, "eWeLink", [accessory]); + this.log("[%s] will be removed from Homebridge.", accessory.displayName); + } catch (e) { + this.log.warn("[%s] needed to be removed but couldn't - [%s].", accessory.displayName, e); + } + } + removeAllAccessories() { + try { + this.log.warn("[0] primary devices were loaded from your eWeLink account so any eWeLink devices in the Homebridge cache will be removed. This plugin will not load as there is no reason to continue."); + this.api.unregisterPlatformAccessories(constants.packageName, "eWeLink", Array.from(this.devicesInHB.values())); + this.devicesInHB.clear(); + } catch (e) { + this.log.warn("Accessories could not be removed from the Homebridge cache - [%s].", e); + } + } + sendDeviceUpdate(accessory, params, callback) { + let payload = { + apikey: accessory.context.eweApiKey, + deviceid: accessory.context.eweDeviceId, + params + }; + switch (this.mode) { + case "lan": + default: + this.lanClient.sendUpdate(payload) + .then(res => { + callback(); + }) + .catch(err => { + if (accessory.context.reachableWAN) { + if (this.debug) { + this.log.warn("[%s] LAN update failed as %s. Trying web socket update.", accessory.displayName, err); + } + this.wsClient.sendUpdate(payload, callback); + setTimeout(() => { + this.wsClient.requestUpdate(accessory); + }, 2500); + } else { + this.log.error("[%s] could not be updated as it appears to be offline.", accessory.displayName); + callback("Device has failed to update"); + } + }); + break; + case "ws": + this.wsClient.sendUpdate(payload, callback); + setTimeout(() => { + this.wsClient.requestUpdate(accessory); + }, 2500); + break; + } + } + receiveDeviceUpdate(device) { + let accessory; + switch (device.action) { + case "sysmsg": + if (this.devicesInHB.has(device.deviceid + "SWX") || this.devicesInHB.has(device.deviceid + "SW0")) { + accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0"); + try { + if (accessory.context.reachableWAN !== device.params.online) { + accessory.context.reachableWAN = device.params.online; + this.log("[%s] has been reported [%s].", accessory.displayName, accessory.context.reachableWAN ? "online" : "offline"); + this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + this.api.updatePlatformAccessories(constants.packageName, "eWeLink", [accessory]); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory); + } + } + } catch (e) { + this.log.warn("[%s] online/offline status could not be updated - [%s].", accessory.displayName, e); + } + if (this.devicesInHB.has(device.deviceid + "SW0")) { + let oAccessory; + for (let i = 1; i <= accessory.context.channelCount; i++) { + try { + if (this.devicesInHB.has(device.deviceid + "SW" + i)) { + oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); + oAccessory.context.reachableWAN = device.params.online; + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); + this.api.updatePlatformAccessories(constants.packageName, "eWeLink", [oAccessory]); + } + } catch (e) { + this.log.warn("[%s] online/offline status could not be updated - [%s].", oAccessory.displayName, e); + } + } + } + } + break; + case "update": + let source = device.params.updateSource === "ws" ? "WS" : "LAN"; + if (this.devicesInHB.has(device.deviceid + "SWX") || this.devicesInHB.has(device.deviceid + "SW0")) { + accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0"); + if (source === "ws" && !accessory.context.reachableWAN) { + accessory.context.reachableWAN = true; + } + if (source === "lan" && !accessory.context.reachableLAN) { + accessory.context.reachableLAN = true; + } + if (this.debug) { + this.log("[%s] externally updated from above %s message and will be refreshed.", accessory.displayName, source); + } + if (this.refreshAccessory(accessory, device.params)) { + return; + } + this.log.warn("[%s] cannot be refreshed. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.). Debugging: [%s:%s:%s]", accessory.displayName, "refresh", accessory.context.type, accessory.context.channelCount); + } else if (this.customHideDvceFromHB.includes(device.deviceid)) { + this.log.warn("[%s] %s update is for hidden accessory.", device.deviceid, source); + } else { + this.log.warn("[%s] Accessory received via %s update does not exist in Homebridge. If it's a new accessory please restart Homebridge so it is added.", device.deviceid, source); + } + break; + } + } + internalValveUpdate(accessory, valve, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let params = {}; + accessory.getService(valve) + .updateCharacteristic(Characteristic.Active, value) + .updateCharacteristic(Characteristic.InUse, value); + switch (value) { + case 0: + accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, 0); + clearTimeout(accessory.getService(valve).timer); + break; + case 1: + let timer = accessory.getService(valve).getCharacteristic(Characteristic.SetDuration).value; + accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, timer); + accessory.getService(valve).timer = setTimeout(() => { + accessory.getService(valve).setCharacteristic(Characteristic.Active, 0); + }, (timer * 1000)); + break; + } + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + switch (valve) { + case "Valve A": + params.switches[0].switch = value ? "on" : "off"; + params.switches[1].switch = accessory.getService("Valve B").getCharacteristic(Characteristic.Active).value ? "on" : "off"; + break; + case "Valve B": + params.switches[0].switch = accessory.getService("Valve A").getCharacteristic(Characteristic.Active).value ? "on" : "off"; + params.switches[1].switch = value ? "on" : "off"; + break; + default: + throw "unknown valve [" + valve + "]"; + } + params.switches[2].switch = "off"; + params.switches[3].switch = "off"; + this.sendDeviceUpdate(accessory, params, callback); + } catch (err) { + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + internalBlindUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let blindConfig; + if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; + } + if (blindConfig.type !== "blind" || !["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { + throw "improper configuration"; + } + let pSte, params = {}; + value = value >= 50 ? 100 : 0; + pSte = accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.PositionState).value; + if (value === pSte * 100) { + accessory.getService(Service.WindowCovering) + .updateCharacteristic(Characteristic.TargetPosition, value) + .updateCharacteristic(Characteristic.PositionState, pSte); + callback(); + return; + } + switch (blindConfig.setup) { + case "oneSwitch": + params.switch = "on"; + break; + case "twoSwitch": + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = value === 100 ? "on" : "off"; + params.switches[1].switch = value === 0 ? "on" : "off"; + break; + } + this.sendDeviceUpdate(accessory, params, function () { + return; + }); + accessory.getService(Service.WindowCovering) + .updateCharacteristic(Characteristic.TargetPosition, value) + .updateCharacteristic(Characteristic.PositionState, (value / 100)); + if (!blindConfig.inched || blindConfig.inched === "false") { + setTimeout(() => { + switch (blindConfig.setup) { + case "oneSwitch": + params.switch = "off"; + break; + case "twoSwitch": + params.switches[0].switch = "off"; + params.switches[1].switch = "off"; + break; + } + this.sendDeviceUpdate(accessory, params, function () { + return; + }); + }, 500); + } + setTimeout(() => { + accessory.getService(Service.WindowCovering) + .updateCharacteristic(Characteristic.CurrentPosition, value) + .updateCharacteristic(Characteristic.PositionState, 2); + callback(); + }, parseInt(blindConfig.operationTime) * 100); + } catch (err) { + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + internalGarageUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let garageConfig; + if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; + } + if (garageConfig.type !== "garage" || !["oneSwitch", "twoSwitch"].includes(garageConfig.setup)) { + throw "improper configuration"; + } + let sensorDefinition = garageConfig.sensorId || false, + sAccessory = false, + pSte, + params = {}; + if (sensorDefinition && !(sAccessory = this.devicesInHB.get(garageConfig.sensorId + "SWX"))) { + throw "defined sensor doesn't exist"; + } + this.log("[%s] has received request to [%s].", accessory.displayName, value === 0 ? "open" : "close"); + pSte = sAccessory ? + sAccessory.getService(Service.ContactSensor).getCharacteristic(Characteristic.ContactSensorState).value === 0 ? 1 : 0 : [0, 2].includes(accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.CurrentDoorState).value) ? 0 : 1; + if (value === pSte) { + accessory.getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.TargetDoorState, value) + .updateCharacteristic(Characteristic.CurrentDoorState, value); + callback(); + return; + } + switch (garageConfig.setup) { + case "oneSwitch": + params.switch = "on"; + break; + case "twoSwitch": + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = value === 0 ? "on" : "off"; + params.switches[1].switch = value === 1 ? "on" : "off"; + break; + } + this.sendDeviceUpdate(accessory, params, function () { + return; + }); + accessory.getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.TargetDoorState, value) + .updateCharacteristic(Characteristic.CurrentDoorState, value === 0 ? 2 : 3); + if (!garageConfig.inched || garageConfig.inched === "false") { + setTimeout(() => { + switch (garageConfig.setup) { + case "oneSwitch": + params.switch = "off"; + break; + case "twoSwitch": + params.switches[0].switch = "off"; + params.switches[1].switch = "off"; + break; + } + this.sendDeviceUpdate(accessory, params, function () { + return; + }); + }, 500); + } + if (!sAccessory) { + setTimeout(() => { + accessory.getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.CurrentDoorState, value === 0 ? 0 : 1); + callback(); + }, parseInt(garageConfig.operationTime) * 100); + } else { + callback(); + } + } catch (err) { + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + internalFanUpdate(accessory, type, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let newPower, newSpeed, newLight; + switch (type) { + case "power": + newPower = value; + newSpeed = value ? 33 : 0; + newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; + break; + case "speed": + newPower = value >= 33 ? 1 : 0; + newSpeed = value; + newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; + break; + case "light": + newPower = accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active).value; + newSpeed = accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.RotationSpeed).value; + newLight = value; + break; + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, newLight); + accessory.getService(Service.Fanv2) + .updateCharacteristic(Characteristic.Active, newPower) + .updateCharacteristic(Characteristic.RotationSpeed, newSpeed); + let params = { + switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches + }; + params.switches[0].switch = newLight ? "on" : "off"; + params.switches[1].switch = (newPower === 1 && newSpeed >= 33) ? "on" : "off"; + params.switches[2].switch = (newPower === 1 && newSpeed >= 66 && newSpeed < 99) ? "on" : "off"; + params.switches[3].switch = (newPower === 1 && newSpeed >= 99) ? "on" : "off"; + if (this.debug) { + this.log.warn("Fan Update - setting " + type + " to " + value); + this.log("[%s] new stats: power [%s], speed [%s%], light [%s].", accessory.displayName, newPower, newSpeed, newLight); + } + this.sendDeviceUpdate(accessory, params, callback); + } catch (err) { + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + internalThermostatUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let params = { + switch: value ? "on" : "off", + mainSwitch: value ? "on" : "off" + }; + if (this.debug) { + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + this.sendDeviceUpdate(accessory, params, callback); + } catch (err) { + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + internalOutletUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let params = { + switch: value ? "on" : "off" + }; + if (this.debug) { + this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); + this.sendDeviceUpdate(accessory, params, callback); + } catch (err) { + callback("[" + accessory.displayName + "] " + err + "."); + } + } + internalUSBUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let params = { + switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches + }; + params.switches[0].switch = value ? "on" : "off"; + if (this.debug) { + this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); + this.sendDeviceUpdate(accessory, params, callback); + } catch (err) { + callback("[" + accessory.displayName + "] " + err + "."); + } + } + internalSCMUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let params = { + switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches + }; + params.switches[0].switch = value ? "on" : "off"; + if (this.debug) { + this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + this.sendDeviceUpdate(accessory, params, callback); + } catch (err) { + callback("[" + accessory.displayName + "] " + err + "."); + } + } + internalLightbulbUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let oAccessory, params = {}; + switch (accessory.context.switchNumber) { + case "X": + if (accessory.context.eweUIID === 22) { //*** B1 ***\\ + params.state = value ? "on" : "off"; + } else { + params.switch = value ? "on" : "off"; + } + if (this.debug) { + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + break; + case "0": + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = value ? "on" : "off"; + params.switches[1].switch = value ? "on" : "off"; + params.switches[2].switch = value ? "on" : "off"; + params.switches[3].switch = value ? "on" : "off"; + if (this.debug) { + this.log("[%s] updating to turn group [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + for (let i = 1; i <= 4; i++) { + if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); + oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + } + } + break; + case "1": + case "2": + case "3": + case "4": + if (this.debug) { + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + let tAccessory, + masterState = "off"; + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + for (let i = 1; i <= 4; i++) { + if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + i === parseInt(accessory.context.switchNumber) ? + params.switches[i - 1].switch = value ? "on" : "off" : + params.switches[i - 1].switch = tAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value ? "on" : "off"; + if (tAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + masterState = "on"; + } + } else { + params.switches[i - 1].switch = "off"; + } + } + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); + oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, masterState === "on"); + break; + default: + throw "unknown switch number [" + accessory.context.switchNumber + "]"; + } + this.sendDeviceUpdate(accessory, params, callback); + } catch (err) { + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + internalBrightnessUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let params = {}; + if (value === 0) { + params.switch = "off"; + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, false); + } else { + if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + params.switch = "on"; + } + switch (accessory.context.eweUIID) { + case 36: //*** KING-M4 ***\\ + params.bright = Math.round(value * 9 / 10 + 10); + break; + case 44: //*** D1 ***\\ + params.brightness = value; + params.mode = 0; + break; + default: + throw "unknown device UIID"; + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, value); + } + if (this.debug) { + this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); + } + setTimeout(() => { + this.sendDeviceUpdate(accessory, params, callback); + }, 250); + } catch (err) { + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + internalHSBUpdate(accessory, type, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let newRGB, + params = {}, + curHue = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Hue).value, + curSat = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Saturation).value; + switch (type) { + case "hue": + newRGB = convert.hsv.rgb(value, curSat, 100); + switch (accessory.context.eweUIID) { + case 22: //*** B1 ***\\ + params = { + zyx_mode: 2, + type: "middle", + channel0: "0", + channel1: "0", + channel2: newRGB[0].toString(), + channel3: newRGB[1].toString(), + channel4: newRGB[2].toString() + }; + break; + case 59: //*** L1 ***\\ + params = { + mode: 1, + colorR: newRGB[0], + colorG: newRGB[1], + colorB: newRGB[2] + }; + break; + default: + throw "unknown device UIID"; + } + if (this.debug) { + this.log("[%s] updating hue to [%s°].", accessory.displayName, value); + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Hue, value); + break; + case "bri": + switch (accessory.context.eweUIID) { + case 22: //*** B1 ***\\ + newRGB = convert.hsv.rgb(curHue, curSat, value); + params = { + zyx_mode: 2, + type: "middle", + channel0: "0", + channel1: "0", + channel2: newRGB[0].toString(), + channel3: newRGB[1].toString(), + channel4: newRGB[2].toString() + }; + break; + case 59: //*** L1 ***\\ + params = { + mode: 1, + bright: value + }; + break; + } + if (this.debug) { + this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, value); + break; + default: + throw "unknown device UIID"; + } + setTimeout(() => { + this.sendDeviceUpdate(accessory, params, callback); + }, 250); + } catch (err) { + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + internalSwitchUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let oAccessory, params = {}; + switch (accessory.context.switchNumber) { + case "X": + params.switch = value ? "on" : "off"; + if (this.debug) { + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + break; + case "0": + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = value ? "on" : "off"; + params.switches[1].switch = value ? "on" : "off"; + params.switches[2].switch = value ? "on" : "off"; + params.switches[3].switch = value ? "on" : "off"; + if (this.debug) { + this.log("[%s] updating to turn group [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + for (let i = 1; i <= 4; i++) { + if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); + oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + } + } + break; + case "1": + case "2": + case "3": + case "4": + if (this.debug) { + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + let tAccessory, + masterState = "off"; + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + for (let i = 1; i <= 4; i++) { + if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + i === parseInt(accessory.context.switchNumber) ? + params.switches[i - 1].switch = value ? "on" : "off" : + params.switches[i - 1].switch = tAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value ? "on" : "off"; + if (tAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value) { + masterState = "on"; + } + } else { + params.switches[i - 1].switch = "off"; + } + } + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); + oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, masterState === "on"); + break; + default: + throw "unknown switch number [" + accessory.context.switchNumber + "]"; + } + this.sendDeviceUpdate(accessory, params, callback); + } catch (err) { + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + externalValveUpdate(accessory, params) { + try { + ["A", "B"].forEach((v, k) => { + accessory.getService("Valve " + v) + .updateCharacteristic(Characteristic.Active, params.switches[k].switch === "on") + .updateCharacteristic(Characteristic.InUse, params.switches[k].switch === "on"); + if (params.switches[k].switch === "on") { + let timer = accessory.getService("Valve " + v).getCharacteristic(Characteristic.SetDuration).value; + accessory.getService("Valve " + v).updateCharacteristic(Characteristic.RemainingDuration, timer); + accessory.getService("Valve " + v).timer = setTimeout(() => { + accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); + }, (timer * 1000)); + } else { + accessory.getService("Valve " + v).updateCharacteristic(Characteristic.RemainingDuration, 0); + clearTimeout(accessory.getService("Valve " + v).timer); + } + }); + } catch (err) { + this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + } + } + internalRFDeviceUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let params = { + cmd: "transmit", + rfChl: accessory.context.rfChl + }; + if (this.debug) { + this.log("[%s] mimicking RF button press.", accessory.displayName); + } + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, true); + this.sendDeviceUpdate(accessory, params, callback); + setTimeout(() => { + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, false); + }, 500); + } catch (err) { + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + externalBlindUpdate(accessory, params) { + try { + let blindConfig, nSte; + if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; + } + if (blindConfig.type !== "blind" || ["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { + throw "improper configuration"; + } + switch (blindConfig.setup) { + case "oneSwitch": + if (params.switch === "off") { + return; + } + nSte = accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.PositionState).value === 0 ? 1 : 0; + break; + case "twoSwitch": + if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { + return; + } + let switchUp = params.switches[0].switch === "on" ? -1 : 0, // matrix of numbers to get + switchDown = params.switches[1].switch === "on" ? 0 : 2; // ... the correct HomeKit value + nSte = switchUp + switchDown; + break; + } + accessory.getService(Service.WindowCovering) + .updateCharacteristic(Characteristic.PositionState, nSte) + .updateCharacteristic(Characteristic.TargetPosition, nSte * 100); + setTimeout(() => { + accessory.getService(Service.WindowCovering) + .updateCharacteristic(Characteristic.PositionState, 2) + .updateCharacteristic(Characteristic.CurrentPosition, nSte * 100); + }, parseInt(blindConfig.operationTime) * 100); + } catch (err) { + this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + } + } + externalGarageUpdate(accessory, params) { + try { + let garageConfig, nSte; + if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; + } + if (garageConfig.type !== "garage" || !["oneSwitch", "twoSwitch"].includes(garageConfig.setup)) { + throw "improper configuration"; + } + switch (garageConfig.setup) { + case "oneSwitch": + if (params.switch === "off" || garageConfig.sensorId) { + return; + } + nSte = [0, 2].includes(accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.CurrentDoorState).value) ? 3 : 2; + break; + case "twoSwitch": + if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { + return; + } + // @TODO twoSwitch garage external update + return; + } + if (garageConfig.setup !== "oneSwitch" || !garageConfig.sensorId) { + accessory.getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.CurrentDoorState, nSte) + .updateCharacteristic(Characteristic.TargetDoorState, nSte - 2); + setTimeout(() => { + accessory.getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.CurrentDoorState, nSte - 2); + }, parseInt(garageConfig.operationTime) * 100); + } + } catch (err) { + this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + } + } + externalSensorUpdate(accessory, params) { + try { + let oldState = accessory.getService(Service.ContactSensor).getCharacteristic(Characteristic.ContactSensorState).value, + newState = params.switch === "on" ? 1 : 0, + oAccessory = false; + accessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, newState); + this.log("[%s] sent update that it was [%s] and is now [%s].", accessory.displayName, oldState ? "apart" : "joined", newState ? "apart" : "joined"); + this.cusG.forEach(group => { + if (group.sensorId === accessory.context.eweDeviceId && group.type === "garage") { + if ((oAccessory = this.devicesInHB.get(group.deviceId + "SWX"))) { + switch (newState) { + case 0: + oAccessory.getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.TargetDoorState, 1) + .updateCharacteristic(Characteristic.CurrentDoorState, 1); + this.log("[%s] updating to [closed] based on sensor.", oAccessory.displayName); + break; + case 1: + setTimeout(() => { + oAccessory.getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.TargetDoorState, 0) + .updateCharacteristic(Characteristic.CurrentDoorState, 0); + this.log("[%s] updating to [open] based on sensor.", oAccessory.displayName); + }, group.operationTime * 100); + break; + default: + throw "unknown sensor status received"; + } + } + } + }); + } catch (err) { + this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + } + } + externalFanUpdate(accessory, params) { + try { + let light, status, speed; + if (Array.isArray(params.switches)) { + light = params.switches[0].switch === "on"; + switch (params.switches[1].switch+params.switches[2].switch+params.switches[3].switch) { + default: + status = 0; + speed = 0; + break; + case "onoffoff": + status = 1; + speed = 33; + break; + case "ononoff": + status = 1; + speed = 66; + break; + case "onoffon": + status = 1; + speed = 99; + } + } else if (params.hasOwnProperty("light") && params.hasOwnProperty("fan") && params.hasOwnProperty("speed")) { + light = params.light === "on"; + status = params.fan === "on" ? 1 : 0; + speed = params.speed * 33 * status; + } else { + throw "unknown parameters received"; + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, light); + accessory.getService(Service.Fanv2) + .updateCharacteristic(Characteristic.Active, status) + .updateCharacteristic(Characteristic.RotationSpeed, speed); + } catch (err) { + this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + } + } + externalThermostatUpdate(accessory, params) { + try { + if (params.hasOwnProperty("switch") || params.hasOwnProperty("mainSwitch")) { + let newState = params.hasOwnProperty("switch") ? params.switch === "on" : params.mainSwitch === "on"; + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, newState); + } + if (params.hasOwnProperty("currentTemperature") && accessory.getService(Service.TemperatureSensor)) { + let currentTemp = params.currentTemperature !== "unavailable" ? params.currentTemperature : 0; + accessory.getService(Service.TemperatureSensor).updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); + } + if (params.hasOwnProperty("currentHumidity") && accessory.getService(Service.HumiditySensor)) { + let currentHumi = params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; + accessory.getService(Service.HumiditySensor).updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); + } + } catch (err) { + this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + } + } + externalOutletUpdate(accessory, params) { + try { + accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switch === "on"); + } catch (err) { + this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + } + } + externalUSBUpdate(accessory, params) { + try { + accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); + } catch (err) { + this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + } + } + externalSCMUpdate(accessory, params) { + try { + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); + } catch (err) { + this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + } + } + externalSingleLightUpdate(accessory, params) { + try { + let newColour, mode, isOn = false; + if (accessory.context.eweUIID === 22 && params.hasOwnProperty("state")) { + isOn = params.state === "on"; + } else if (accessory.context.eweUIID !== 22 && params.hasOwnProperty("switch")) { + isOn = params.switch === "on"; + } else { + isOn = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; + } + if (isOn) { + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, true); + switch (accessory.context.eweUIID) { + case 36: // KING-M4 + if (params.hasOwnProperty("bright")) { + let nb = Math.round((params.bright - 10) * 10 / 9); // eWeLink scale is 10-100 and HomeKit scale is 0-100. + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, nb); + } + break; + case 44: // D1 + if (params.hasOwnProperty("brightness")) { + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, params.brightness); + } + break; + case 22: // B1 + if (params.hasOwnProperty("zyx_mode")) { + mode = parseInt(params.zyx_mode); + } else if (params.hasOwnProperty("channel0") && (parseInt(params.channel0) + parseInt(params.channel1) > 0)) { + mode = 1; + } else { + mode = 2; + } + if (mode === 2) { + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, true); + newColour = convert.rgb.hsv(parseInt(params.channel2), parseInt(params.channel3), parseInt(params.channel4)); + accessory.getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.Hue, newColour[0]) + .updateCharacteristic(Characteristic.Saturation, 100) + .updateCharacteristic(Characteristic.Brightness, 100); + } else if (mode === 1) { + throw "has been set to white mode which is not supported"; + } + break; + case 59: // L1 + if (params.hasOwnProperty("bright")) { + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, params.bright); + } + if (params.hasOwnProperty("colorR")) { + newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB); + accessory.getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.Hue, newColour[0]) + .updateCharacteristic(Characteristic.Saturation, newColour[1]); + } + break; + default: + return; + } + } else { + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, false); + } + } catch (err) { + this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + } + } + externalMultiLightUpdate(accessory, params) { + try { + let idToCheck = accessory.context.hbDeviceId.slice(0, -1), + primaryState = false; + for (let i = 1; i <= accessory.context.channelCount; i++) { + if (this.devicesInHB.has(idToCheck + i)) { + let oAccessory = this.devicesInHB.get(idToCheck + i); + oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); + if (params.switches[i - 1].switch === "on") { + primaryState = true; + } + } + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, primaryState); + } catch (err) { + this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + } + } + externalSingleSwitchUpdate(accessory, params) { + try { + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switch === "on"); + } catch (err) { + this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + } + } + externalMultiSwitchUpdate(accessory, params) { + try { + let idToCheck = accessory.context.hbDeviceId.slice(0, -1), + primaryState = false; + for (let i = 1; i <= accessory.context.channelCount; i++) { + if (this.devicesInHB.has(idToCheck + i)) { + let oAccessory = this.devicesInHB.get(idToCheck + i); + oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); + if (params.switches[i - 1].switch === "on") { + primaryState = true; + } + } + } + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState); + } catch (err) { + this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + } + } + externalRFDeviceUpdate(accessory, params) { + try { + let idToCheck = accessory.context.hbDeviceId.slice(0, -1), + timeNow = new Date(); + if (params.hasOwnProperty("cmd") && params.cmd === "transmit" && params.hasOwnProperty("rfChl")) { // RF Button + let bAccessory; + if ((bAccessory = this.devicesInHB.get(idToCheck + (params.rfChl + 1)))) { + bAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, 1); + setTimeout(() => { + bAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, 0); + }, 500); + } else { + throw "rf button not found in Homebridge"; + } + return; + } // else RF Sensor + for (let i = 1; i <= accessory.context.channelCount; i++) { + if (this.devicesInHB.has(idToCheck + i)) { + let oAccessory = this.devicesInHB.get(idToCheck + i); + if (params.hasOwnProperty("rfTrig" + (i - 1))) { + let timeOfMotion = new Date(params["rfTrig" + (i - 1)]), + timeDifference = (timeNow.getTime() - timeOfMotion.getTime()) / 1000; + if (timeDifference < this.sensorTimeDifference) { + switch (oAccessory.context.sensorType) { + case "button": + break; + case "water": + oAccessory.getService(Service.LeakSensor).updateCharacteristic(Characteristic.LeakDetected, 1); + break; + case "fire": + case "smoke": + oAccessory.getService(Service.SmokeSensor).updateCharacteristic(Characteristic.SmokeDetected, 1); + break; + case "co": + oAccessory.getService(Service.CarbonMonoxideSensor).updateCharacteristic(Characteristic.CarbonMonoxideDetected, 1); + break; + case "co2": + oAccessory.getService(Service.CarbonDioxideSensor).updateCharacteristic(Characteristic.CarbonDioxideDetected, 1); + break; + case "contact": + oAccessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, 1); + break; + case "occupancy": + oAccessory.getService(Service.OccupancySensor).updateCharacteristic(Characteristic.OccupancyDetected, 1); + break; + case "motion": + default: + oAccessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, true); + break; + } + if (this.debug) { + this.log("[%s] has detected [%s].", oAccessory.displayName, oAccessory.context.sensorType); + } + } + } + } + } + setTimeout(() => { + for (let i = 1; i <= accessory.context.channelCount; i++) { + if (this.devicesInHB.has(idToCheck + i)) { + let oAccessory = this.devicesInHB.get(idToCheck + i); + switch (oAccessory.context.sensorType) { + case "button": + break; + case "water": + oAccessory.getService(Service.LeakSensor).updateCharacteristic(Characteristic.LeakDetected, 0); + break; + case "fire": + case "smoke": + oAccessory.getService(Service.SmokeSensor).updateCharacteristic(Characteristic.SmokeDetected, 0); + break; + case "co": + oAccessory.getService(Service.CarbonMonoxideSensor).updateCharacteristic(Characteristic.CarbonMonoxideDetected, 0); + break; + case "co2": + oAccessory.getService(Service.CarbonDioxideSensor).updateCharacteristic(Characteristic.CarbonDioxideDetected, 0); + break; + case "contact": + oAccessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, 0); + break; + case "occupancy": + oAccessory.getService(Service.OccupancySensor).updateCharacteristic(Characteristic.OccupancyDetected, 0); + break; + case "motion": + default: + oAccessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, false); + break; + } + } + } + }, this.sensorTimeLength * 1000); + } catch (err) { + this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + } + } + externalZBDeviceUpdate(accessory, params) { + try { + switch (accessory.context.eweUIID) { + case 1000: + if (params.hasOwnProperty("key")) { + if ([0, 1, 2].includes(params.key)) { + accessory.getService(Service.StatelessProgrammableSwitch).updateCharacteristic(Characteristic.ProgrammableSwitchEvent, params.key); //*** credit @tasict ***\\ + } else { + throw "unknown 'key' parameter received [" + params.key + "]"; + } + } + break; + case 1770: + if (params.hasOwnProperty("temperature")) { + let currentTemp = parseInt(params.temperature) / 100; + accessory.getService(Service.TemperatureSensor).updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); + } + if (params.hasOwnProperty("humidity")) { + let currentHumi = parseInt(params.humidity) / 100; + accessory.getService(Service.HumiditySensor).updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); + } + break; + case 2026: + if (params.hasOwnProperty("motion")) { + if ([0, 1].includes(params.lock)) { + accessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, params.motion); + } else { + throw "unknown 'motion' parameter received [" + params.motion + "]"; + } + } + break; + case 3026: + if (params.hasOwnProperty("lock")) { + if ([0, 1].includes(params.lock)) { + accessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, params.lock); + } else { + throw "unknown 'lock' parameter received [" + params.lock + "]"; + } + } + break; + default: + throw "unsupported zigbee device type"; + } + } catch (err) { + this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + } + } +} +module.exports = function (homebridge) { + Accessory = homebridge.platformAccessory; + Service = homebridge.hap.Service; + Characteristic = homebridge.hap.Characteristic; + UUIDGen = homebridge.hap.uuid; + return eWeLink; +}; \ No newline at end of file diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js new file mode 100644 index 00000000..f6c0c71d --- /dev/null +++ b/lib/eWeLinkHTTP.js @@ -0,0 +1,158 @@ +/* jshint esversion: 9, -W030, node: true */ +"use strict"; +const axios = require("axios"); +const constants = require("./constants"); +const crypto = require("crypto"); +module.exports = class eWeLinkHTTP { + constructor(config, log) { + this.config = config; + this.log = log; + this.debug = this.config.debug || false; + this.debugReqRes = this.config.debugReqRes || false; + } + login() { + let data = { + countryCode: "+" + this.config.countryCode.toString().replace("+", "").replace(" ", ""), + password: this.config.password + }; + this.config.username.includes("@") ? + data.email = this.config.username : + data.phoneNumber = this.config.username; + if (this.debugReqRes) { + let msg = JSON.stringify(data, null, 2).replace(this.config.password, "**hidden**").replace(this.config.username, "**hidden**"); + this.log.warn("Sending HTTP login request. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("Sending HTTP login request."); + } + let dataToSign = crypto.createHmac("sha256", "6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM").update(JSON.stringify(data)).digest("base64"); + return new Promise((resolve, reject) => { + axios({ + url: "https://" + this.httpHost + "/v2/user/login", + method: "post", + headers: { + Authorization: "Sign " + dataToSign, + "Content-Type": "application/json", + Host: this.httpHost, + "X-CK-Appid": constants.appId, + "X-CK-Nonce": Math.random().toString(36).substr(2, 8) + }, + data + }).then(res => { + let body = res.data; + if (body.hasOwnProperty("error") && body.error === 10004 && body.hasOwnProperty("data") && body.data.hasOwnProperty("region")) { + switch (body.data.region) { + case "eu": + case "us": + case "as": + this.httpHost = body.data.region + "-apia.coolkit.cc"; + break; + case "cn": + this.httpHost = "cn-apia.coolkit.cn"; + break; + default: + throw "No valid region received - [" + body.data.region + "]."; + } + if (this.debug) { + this.log("New HTTP API host received [%s].", this.httpHost); + } + resolve(this.login()); + return; + } + if (!body.data.at) { + throw "Server did not respond with an authentication token. Please double check your eWeLink username and password in the Homebridge configuration.\n" + JSON.stringify(body, null, 2); + } + this.aToken = body.data.at; + this.apiKey = body.data.user.apikey; + resolve({ + aToken: body.data.at, + apiKey: body.data.user.apikey, + httpHost: this.httpHost + }); + }).catch(err => { + reject(err); + }); + }); + } + getHost() { + let data = { + appid: constants.appId, + country_code: this.config.countryCode.toString().replace("+", "").replace(" ", ""), + nonce: Math.random().toString(36).substr(2, 8), + ts: Math.floor(new Date().getTime() / 1000), + version: 8 + }, + dataToSign = []; + Object.keys(data).forEach(function (key) { + dataToSign.push({ + key: key, + value: data[key] + }); + }); + dataToSign.sort(function (a, b) { + return a.key < b.key ? -1 : 1; + }); + dataToSign = dataToSign.map(function (kv) { + return kv.key + "=" + kv.value; + }).join("&"); + dataToSign = crypto.createHmac("sha256", "6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM").update(dataToSign).digest("base64"); + return new Promise((resolve, reject) => { + axios.get("https://api.coolkit.cc:8080/api/user/region", { + headers: { + Authorization: "Sign " + dataToSign, + "Content-Type": "application/json" + }, + params: data + }).then(res => { + let body = res.data; + if (!body.region) { + throw "Server did not respond with a region.\n" + JSON.stringify(body, null, 2); + } + switch (body.region) { + case "eu": + case "us": + case "as": + this.httpHost = body.region + "-apia.coolkit.cc"; + break; + case "cn": + this.httpHost = "cn-apia.coolkit.cn"; + break; + default: + throw "No valid region received - [" + body.region + "]."; + } + if (this.debug) { + this.log("HTTP API host received [%s].", this.httpHost); + } + resolve(this.httpHost); + }).catch(err => { + reject(err); + }); + }); + } + getDevices() { + return new Promise((resolve, reject) => { + axios.get("https://" + this.httpHost + "/v2/device/thing", { + headers: { + Authorization: "Bearer " + this.aToken, + "Content-Type": "application/json", + Host: this.httpHost, + "X-CK-Appid": constants.appId, + "X-CK-Nonce": Math.random().toString(36).substr(2, 8) + } + }).then(res => { + let body = res.data; + if (!body.hasOwnProperty("error") || (body.hasOwnProperty("error") && body.error !== 0)) { + throw JSON.stringify(body, null, 2); + } + let deviceList = []; + if (body.data.thingList && body.data.thingList.length > 0) { + body.data.thingList.forEach(device => { + deviceList.push(device.itemData); + }); + } + resolve(deviceList); + }).catch(err => { + reject(err); + }); + }); + } +}; \ No newline at end of file diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js new file mode 100644 index 00000000..9146dbe7 --- /dev/null +++ b/lib/eWeLinkLAN.js @@ -0,0 +1,157 @@ +/* jshint esversion: 9, -W030, node: true */ +"use strict"; +const axios = require("axios"); +const constants = require("./constants"); +const crypto = require("crypto"); +const dns = require("node-dns-sd"); +const eventemitter = require("events"); +module.exports = class eWeLinkLAN { + constructor(config, log, devices) { + this.config = config; + this.log = log; + this.devices = devices; + let deviceMap = {}; + devices.forEach(device => { + deviceMap[device.deviceid] = { + apiKey: device.devicekey, + ip: false + }; + }); + this.deviceMap = deviceMap; + this.debug = this.config.debug || false; + this.debugReqRes = this.config.debugReqRes || false; + this.emitter = new eventemitter(); + } + getHosts() { + return new Promise((resolve, reject) => { + dns.discover({ + name: "_ewelink._tcp.local" + }).then(res => { + res.forEach(device => { + let a = device.fqdn.replace("._ewelink._tcp.local", "").replace("eWeLink_", ""); + if (this.deviceMap.hasOwnProperty(a)) { + this.deviceMap[a].ip = device.address; + } + }); + resolve(this.deviceMap); + }).catch(err => { + reject(err); + }); + }); + } + startMonitor() { + dns.ondata = packet => { + if (packet.answers) { + packet.answers + .filter(value => value.name.includes("_ewelink._tcp.local")) + .forEach(value => { + if (value.type === "TXT") { + let rdata = value.rdata; + if (this.deviceMap.hasOwnProperty(rdata.id)) { + let deviceKey = this.deviceMap[rdata.id].apiKey, + data = rdata.data1 + + (rdata.hasOwnProperty("data2") ? rdata.data2 : "") + + (rdata.hasOwnProperty("data3") ? rdata.data3 : "") + + (rdata.hasOwnProperty("data4") ? rdata.data4 : ""), + key = crypto.createHash("md5").update(Buffer.from(deviceKey, "utf8")).digest(), + dText = crypto.createDecipheriv("aes-128-cbc", key, Buffer.from(rdata.iv, "base64")), + pText = Buffer.concat([dText.update(Buffer.from(data, "base64")), dText.final()]).toString("utf8"), + params; + try { + params = JSON.parse(pText); + } catch (e) { + this.log.warn("[%s] An error occured reading the LAN message [%s]", rdata.id, e); + return; + } + for (let param in params) { + if (params.hasOwnProperty(param)) { + if (!constants.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { + delete params[param]; + } + } + } + params.updateSource = "lan"; + if (Object.keys(params).length > 0) { + let returnTemplate = { + deviceid: rdata.id, + action: "update", + params + }; + if (this.debugReqRes) { + let msg = JSON.stringify(returnTemplate, null, 2).replace(rdata.id, "**hidden**"); + this.log("LAN message received.\n%s", msg); + } else if (this.debug) { + this.log("LAN message received."); + } + this.emitter.emit("update", returnTemplate); + } + } + } + }); + } + }; + return new Promise((resolve, reject) => { + dns.startMonitoring().then(() => { + resolve(); + }).catch(err => { + reject(err); + }); + }); + } + sendUpdate(json) { + return new Promise((resolve, reject) => { + if (!this.deviceMap[json.deviceid].ip) { + throw "device does not support LAN mode"; + } + let apiKey, suffix, params = {}; + if (json.params.hasOwnProperty("switches")) { + params.switches = json.params.switches; + suffix = "switches"; + } else if (json.params.hasOwnProperty("switch")) { + params.switch = json.params.switch; + suffix = "switch"; + } else { + throw "plugin does not support lan mode for this device yet - feel free to create a github issue"; + } + if ((apiKey = this.deviceMap[json.deviceid].apiKey)) { + let key = crypto.createHash('md5').update(Buffer.from(apiKey, 'utf8')).digest(), + iv = crypto.randomBytes(16), + enc = crypto.createCipheriv('aes-128-cbc', key, iv), + data = { + data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString('base64'), + deviceid: json.deviceid, + encrypt: true, + iv: iv.toString('base64'), + selfApikey: "123", + sequence: Date.now().toString() + }; + if (this.debugReqRes) { + let msg = JSON.stringify(json, null, 2).replace(json.apikey, "**hidden**").replace(json.apikey, "**hidden**").replace(json.deviceid, "**hidden**"); + this.log.warn("LAN mode message sent. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("LAN mode message sent."); + } + axios({ + method: "post", + url: "http://" + this.deviceMap[json.deviceid].ip + ":8081/zeroconf/" + suffix, + headers: { + Accept: "application/json", + "Content-Type": "application/json;charset=UTF-8" + }, + data + }).then(res => { + let body = res.data; + if (body.hasOwnProperty("error") && body.error === 0) { + resolve(); + } + throw body; + }).catch(err => { + reject(err); + }); + } + }); + } + receiveUpdate(f) { + this.emitter.addListener("update", f); + } +}; \ No newline at end of file diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js new file mode 100644 index 00000000..23f690d7 --- /dev/null +++ b/lib/eWeLinkWS.js @@ -0,0 +1,271 @@ +/* jshint esversion: 9, -W030, node: true */ +"use strict"; +const axios = require("axios"); +const constants = require("./constants"); +const eventemitter = require("events"); +const ws = require("ws"); +module.exports = class eWeLinkWS { + constructor(config, log, res) { + this.config = config; + this.log = log; + this.debug = this.config.debug || false; + this.debugReqRes = this.config.debugReqRes || false; + this.httpHost = res.httpHost; + this.aToken = res.aToken; + this.apiKey = res.apiKey; + this.wsIsOpen = false; + this.emitter = new eventemitter(); + this.delaySend = 0; + } + getHost() { + return new Promise((resolve, reject) => { + axios({ + method: "post", + url: "https://" + this.httpHost.replace("-api", "-disp") + "/dispatch/app", + headers: { + Authorization: "Bearer " + this.aToken, + "Content-Type": "application/json" + }, + data: { + appid: constants.appId, + nonce: Math.random().toString(36).substr(2, 8), + ts: Math.floor(new Date().getTime() / 1000), + version: 8 + } + }).then(res => { + let body = res.data; + if (!body.domain) { + throw "Server did not respond with a web socket host."; + } + if (this.debug) { + this.log("Web socket host received [%s].", body.domain); + } + this.wsHost = body.domain; + resolve(body.domain); + }).catch(err => { + reject(err); + }); + }); + } + login() { + this.ws = new ws("wss://" + this.wsHost + ":8080/api/ws"); + this.ws.on("open", () => { + this.wsIsOpen = true; + let payload = { + action: "userOnline", + apikey: this.apiKey, + appid: constants.appId, + at: this.aToken, + nonce: Math.random().toString(36).substr(2, 8), + sequence: Math.floor(new Date()), + ts: Math.floor(new Date() / 1000), + userAgent: "app", + version: 8 + }; + this.ws.send(JSON.stringify(payload)); + if (this.debugReqRes) { + let msg = JSON.stringify(payload, null, 2).replace(this.aToken, "**hidden**").replace(this.apiKey, "**hidden**"); + this.log.warn("Sending WS login request. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("Sending WS login request."); + } + }); + this.ws.on("message", m => { + if (m === "pong") { + return; + } + let device; + try { + device = JSON.parse(m); + } catch (e) { + this.log.warn("An error occured reading the web socket message [%s]", e); + return; + } + // for requestUpdate response + if (device.hasOwnProperty("deviceid") && device.hasOwnProperty("params") && device.hasOwnProperty("error") && device.error === 0) { + device.action = "update"; + } else if (device.hasOwnProperty("deviceid") && device.hasOwnProperty("error") && device.error === 504) { + device.action = "sysmsg"; + device.params = { + online: false + }; + } + // for external updates + if (device.hasOwnProperty("config") && device.config.hb && device.config.hbInterval && !this.hbInterval) { + this.hbInterval = setInterval(() => { + this.ws.send("ping"); + }, (device.config.hbInterval + 7) * 1000); + } else if (device.hasOwnProperty("action")) { + switch (device.action) { + case "sysmsg": + device.params.updateSource = "ws"; + let returnTemplate = { + deviceid: device.deviceid, + action: "sysmsg", + params: device.params + }; + if (this.debugReqRes) { + let msg = JSON.stringify(returnTemplate, null, 2).replace(device.deviceid, "**hidden**"); + this.log("WS message received.\n%s", msg); + } else if (this.debug) { + this.log("WS message received."); + } + this.emitter.emit("update", returnTemplate); + break; + case "update": + let params = device.params; + for (let param in params) { + if (params.hasOwnProperty(param)) { + if (!constants.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { + delete params[param]; + } + } + } + if (Object.keys(params).length > 0) { + params.updateSource = "ws"; + let returnTemplate = { + deviceid: device.deviceid, + action: "update", + params + }; + if (this.debugReqRes) { + let msg = JSON.stringify(returnTemplate, null, 2).replace(device.deviceid, "**hidden**"); + this.log("WS message received.\n%s", msg); + } else if (this.debug) { + this.log("WS message received."); + } + this.emitter.emit("update", returnTemplate); + } + break; + default: + this.log.warn("[%s] WS message has unknown action.\n" + JSON.stringify(device, null, 2), device.deviceid); + return; + } + } else if (device.hasOwnProperty("error") && device.error === 0) { + // *** Safe to ignore these messages *** \\ + } else { + if (this.debug) { + this.log.warn("WS unknown command received.\n" + JSON.stringify(device, null, 2)); + } + } + }); + this.ws.on("close", (e) => { + this.log.warn("Web socket closed - [%s].", e); + if (e.code !== 1000) { + this.log.warn("Web socket will try to reconnect in five seconds then try the command again."); + this.ws.removeAllListeners(); + setTimeout(() => { + this.login(); + }, 5000); + } else { + this.log.error("Please try restarting Homebridge so that this plugin can work again."); + } + this.wsIsOpen = false; + if (this.hbInterval) { + clearInterval(this.hbInterval); + this.hbInterval = null; + } + }); + this.ws.on("error", (e) => { + this.log.error("Web socket error - [%s].", e); + if (e.code === "ECONNREFUSED") { + this.log.warn("Web socket will try to reconnect in five seconds then try the command again."); + this.ws.removeAllListeners(); + setTimeout(() => { + this.login(); + }, 5000); + } else { + this.log.warn("If this was unexpected then please try restarting Homebridge."); + } + }); + } + sendUpdate(json, callback) { + json = { + ...json, + ...{ + action: "update", + sequence: Math.floor(new Date()), + userAgent: "app" + } + }; + let sendOperation = req => { + if (!this.wsIsOpen) { + setTimeout(() => { + sendOperation(req); + }, 280); + return; + } + if (this.ws) { + callback(); + this.ws.send(req); + if (this.debugReqRes) { + let msg = JSON.stringify(json, null, 2).replace(json.apikey, "**hidden**").replace(json.apiKey, "**hidden**").replace(json.deviceid, "**hidden**"); + this.log.warn("Web socket message sent. This text is yellow for clarity.\n%s", msg); + } + return; + } + this.delaySend = this.delaySend <= 0 ? 0 : this.delaySend -= 280; + }; + let string = JSON.stringify(json); + if (this.wsIsOpen) { + setTimeout(sendOperation, this.delaySend, string); + this.delaySend += 280; + } else { + this.log.warn("Web socket is currently reconnecting. Command will be resent."); + let interval, + waitToSend = req => { + if (this.wsIsOpen) { + clearInterval(interval); + sendOperation(req); + } + }; + interval = setInterval(waitToSend, 2500, string); + } + } + requestUpdate(accessory) { + let json = { + action: "query", + apikey: accessory.context.eweApiKey, + deviceid: accessory.context.eweDeviceId, + params: [], + sequence: Math.floor(new Date()), + ts: 0, + userAgent: "app" + }, + sendOperation = req => { + if (!this.wsIsOpen) { + setTimeout(() => { + sendOperation(req); + }, 280); + return; + } + if (this.ws) { + this.ws.send(req); + if (this.debugReqRes) { + let msg = JSON.stringify(json, null, 2).replace(json.apikey, "**hidden**").replace(json.apiKey, "**hidden**").replace(json.deviceid, "**hidden**"); + this.log.warn("Web socket message sent. This text is yellow for clarity.\n%s", msg); + } + return; + } + this.delaySend = this.delaySend <= 0 ? 0 : this.delaySend -= 280; + }, + string = JSON.stringify(json); + if (this.wsIsOpen) { + setTimeout(sendOperation, this.delaySend, string); + this.delaySend += 280; + } else { + this.log.warn("Web socket is currently reconnecting. Command will be resent."); + let interval, + waitToSend = req => { + if (this.wsIsOpen) { + clearInterval(interval); + sendOperation(req); + } + }; + interval = setInterval(waitToSend, 2500, string); + } + } + receiveUpdate(f) { + this.emitter.addListener("update", f); + } +}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 94d0313e..9420b343 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,360 +1,60 @@ { - "name": "homebridge-ewelink", - "version": "0.1.76", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "arpping": { - "version": "github:skydiver/arpping#ae65410343bdcbddb64b37ac9f674c65af1fe92c", - "from": "github:skydiver/arpping", - "requires": { - "child_process": "^1.0.2", - "os": "^0.1.1" - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "child_process": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/child_process/-/child_process-1.0.2.tgz", - "integrity": "sha1-sffn/HPSXn/R1FWtyU4UODAYK1o=" - }, - "chnl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/chnl/-/chnl-1.2.0.tgz", - "integrity": "sha512-g5gJb59edwCliFbX2j7G6sBfY4sX9YLy211yctONI2GRaiX0f2zIbKWmBm+sPqFNEpM7Ljzm7IJX/xrjiEbPrw==" - }, - "core-js": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", - "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" - }, - "crypto-js": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.0.0.tgz", - "integrity": "sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg==" - }, - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" - } - }, - "delay": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/delay/-/delay-4.4.0.tgz", - "integrity": "sha512-txgOrJu3OdtOfTiEOT2e76dJVfG/1dz2NZ4F0Pyt4UGZJryssMRp5vdM5wQoLwSOBNdrJv3F9PAhp/heqd7vrA==" - }, - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "requires": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "ewelink-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ewelink-api/-/ewelink-api-3.0.0.tgz", - "integrity": "sha512-W60dGUIPnV8b/ckCKRAi+0mYyIYil/YrkVrAknlf6CtnivHIVxvcQPUxQPOX6ctWzK10n+ACAh8V7uOok1rjMA==", - "requires": { - "arpping": "github:skydiver/arpping", - "crypto-js": "^4.0.0", - "delay": "^4.3.0", - "node-fetch": "^2.6.0", - "random": "^2.2.0", - "websocket": "^1.0.31", - "websocket-as-promised": "^1.0.1" - } - }, - "ext": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", - "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", - "requires": { - "type": "^2.0.0" + "name": "homebridge-ewelink", + "version": "2.19.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "requires": { + "follow-redirects": "1.5.10" + } }, - "dependencies": { - "type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", - "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==" - } - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" - }, - "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==" - }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" - }, - "is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "nan": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", - "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==" - }, - "next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" - }, - "node-fetch": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" - }, - "object-inspect": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", - "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==" - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "os": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/os/-/os-0.1.1.tgz", - "integrity": "sha1-IIhF6J4ZOtTZcUdLk5R3NqVtE/M=" - }, - "ow": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/ow/-/ow-0.4.0.tgz", - "integrity": "sha512-kJNzxUgVd6EF5LoGs+s2/etJPwjfRDLXPTCfEgV8At77sRrV+PSFA8lcoW2HF15Qd455mIR2Stee/2MzDiFBDA==" - }, - "ow-lite": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/ow-lite/-/ow-lite-0.0.2.tgz", - "integrity": "sha1-359QDmdAtlkKHpqWVzDUmo61l9E=" - }, - "promise-controller": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/promise-controller/-/promise-controller-1.0.0.tgz", - "integrity": "sha512-goA0zA9L91tuQbUmiMinSYqlyUtEgg4fxJcjYnLYOQnrktb4o4UqciXDNXiRUPiDBPACmsr1k8jDW4r7UDq9Qw==" - }, - "promise.prototype.finally": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/promise.prototype.finally/-/promise.prototype.finally-3.1.2.tgz", - "integrity": "sha512-A2HuJWl2opDH0EafgdjwEw7HysI8ff/n4lW4QEVBCUXFk9QeGecBWv0Deph0UmLe3tTNYegz8MOjsVuE6SMoJA==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.0", - "function-bind": "^1.1.1" - } - }, - "random": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/random/-/random-2.2.0.tgz", - "integrity": "sha512-4HBR4Xye4jJ41QBi6RfIaO1yKQpxVUZafQtdE6NvvjzirNlwWgsk3tkGLTbQtWUarF4ofZsUVEmWqB1TDQlkwA==", - "requires": { - "babel-runtime": "^6.26.0", - "ow": "^0.4.0", - "ow-lite": "^0.0.2", - "seedrandom": "^3.0.5" - } - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, - "seedrandom": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", - "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" - }, - "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "websocket": { - "version": "1.0.31", - "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.31.tgz", - "integrity": "sha512-VAouplvGKPiKFDTeCCO65vYHsyay8DqoBSlzIO3fayrfOgU94lQN5a1uWVnFrMLceTJw/+fQXR5PGbUVRaHshQ==", - "requires": { - "debug": "^2.2.0", - "es5-ext": "^0.10.50", - "nan": "^2.14.0", - "typedarray-to-buffer": "^3.1.5", - "yaeti": "^0.0.6" - } - }, - "websocket-as-promised": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/websocket-as-promised/-/websocket-as-promised-1.0.1.tgz", - "integrity": "sha512-+gBevna4yxisb8cigL8NxcS8s241cvfMeyy1fNFcFgBcX/6vknMT84MwMmBNLYmsYH2giVoxOSEiAeeb7txFOw==", - "requires": { - "chnl": "^1.0.0", - "promise-controller": "^1.0.0", - "promise.prototype.finally": "^3.1.1" + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node-dns-sd": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/node-dns-sd/-/node-dns-sd-0.4.1.tgz", + "integrity": "sha512-x+WSuMgvDBQv24OCq75YHcZj1SOzvP5fU4Tz+PBUiVvVBsfc+9XAHAuIftaCpf2nPLl+ys71uZoGr/v9fVDa6A==" + }, + "ws": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz", + "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==" } - }, - "yaeti": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", - "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" - } - } + } } diff --git a/package.json b/package.json index cb41333c..8a64e5a3 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,57 @@ { - "name": "homebridge-ewelink", - "version": "0.1.76", - "description": "homebridge-eWeLink is a Homebrige plugin to control Sonoff relays running OEM firmware", - "license": "MIT", - "keywords": [ - "homebridge-plugin", - "sonoff" - ], - "engines": { - "node": ">=0.12.0", - "homebridge": ">=0.2.0" - }, - "repository": { - "type": "git", - "url": "https://github.com/bwp91/homebridge-ewelink.git" - }, - "dependencies": { - "ewelink-api": "^3.0.0" - } + "name": "homebridge-ewelink", + "version": "2.19.1", + "author": "bwp91", + "contributors": [ + "gbro115", + "MrTomAsh", + "howanghk", + "LeJeko", + "aremishevsky-chegg", + "samkni", + "robsonfj", + "ramsesz", + "metarutaiga", + "janbuecker", + "jacopofranza", + "donavanbecker", + "dhutchison", + "danielk117", + "bassrock", + "VictorKrasnov", + "JuniorGenius", + "BobbySlope" + ], + "description": "homebridge-ewelink-sonoff is a Homebrige plugin to control Sonoff devices running OEM firmware.", + "license": "MIT", + "keywords": [ + "homebridge", + "homebridge-plugin", + "sonoff", + "ewelink" + ], + "engines": { + "node": ">=6.0.0", + "homebridge": ">=0.2.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/bwp91/homebridge-ewelink" + }, + "dependencies": { + "axios": "0.19.2", + "color-convert": "2.0.1", + "node-dns-sd": "0.4.1", + "ws": "7.3.1" + }, + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/bwp91" + }, + { + "type": "paypal", + "url": "https://www.paypal.me/BenPotter" + } + ] } From 227f2f29d54bfbb4c888cf723cb99b3576648bab Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sun, 16 Aug 2020 11:36:01 +0100 Subject: [PATCH 0010/3183] Update README.md --- README.md | 117 +----------------------------------------------------- 1 file changed, 1 insertion(+), 116 deletions(-) diff --git a/README.md b/README.md index fc4f06d7..1a70beb2 100644 --- a/README.md +++ b/README.md @@ -1,116 +1 @@ -### Changes from homebridge-ewelink-complete have been merged into the master - -The largest change here is to use evelink-api for all API needs rather than rewrite - -# About - -Homebridge plugin to control Sonoff relays with OEM firmware. It uses the same API as the iOS app to communicate with your devices. - -The platform will dynamically add/remove devices based on what is configured in your eWeLink account. - -It has been tested with the [Sonoff basic](http://sonoff.itead.cc/en/products/sonoff/sonoff-basic) relays. I have performed testing with up to two relays associated to my account. - -The plugin will only support one eWeLink account. - -It is possible to continute to use the OEM functionality (eWeLink app, Google Home integration); this plugin requires no modification to the relay's firmware. - -## Shortcomings - -The plugin uses the same credentials as the eWeLink app. In order to obtain the authenticationToken, you'll need to use Charles to inspect the traffic and grab the value from the Authorization header. See below for information on how to obtain this value. - -Also, the code is of suboptimal quality. It was a quick-and-dirty plugin; feel free to contribute & improve. - -## Steps to install / configure - -*Assuming that you've already downloaded the eWeLink app on your iOS device & have configured it:* - -1) Install the plugin -``` -sudo npm -g install homebridge-ewelink-complete -``` - -2) Add to the platforms[] section of config.json. Steps for obtaining the values for authenticationToken, apiHost, and webSocketApi can be found below. - -3) Restart Homebridge - -### Sample config.json - -``` -{ - "bridge": { - "name": "Homebridge", - "username": "XX:XX:XX:XX:XX:XX", - "port": 51826, - "pin": "123-45-678" - }, - - "description": "Your description here", - - "accessories": [ - ], - - "platforms": [ - { - "platform": "eWeLink", - "name": "eWeLink", - "phoneNumberOrEmail": "YOUR_ACCOUNT_EMAIL_OR_PHONE", - "accountPassword": "YOUR_ACCOUNT_PASSWORD", - "apiHost": "us-api.coolkit.cc:8080", - "webSocketApi": "us-long.coolkit.cc", - "debug": "true" - } ] -} -``` - -### A note on the authenticationToken - -The authentication token is generated every time your device's app logs in to the eWeLink service. Based on my limited testing, the session seems to persist for quite some time. - -You can only have one authentication token per user account. - -If you logout and login to the app again, you'll need to perform the above steps to get things working again. - -## Troubleshooting - -I've attempted to make the logging as useful as possible. If you have any suggestions, please open an issue on GitHub. I've also hidden most logging behind the debug parameter, please set to true or false accordingly - -## Sample logging - -``` -[12/13/2017, 9:39:05 PM] [eWeLink] A total of [1] accessories were loaded from the local cache -[12/13/2017, 9:39:05 PM] [eWeLink] Requesting a list of devices from eWeLink HTTPS API at [https://us-api.coolkit.cc:8080] -[12/13/2017, 9:39:06 PM] [eWeLink] eWeLink HTTPS API reports that there are a total of [1] devices registered -[12/13/2017, 9:39:06 PM] [eWeLink] Evaluating if devices need to be removed... -[12/13/2017, 9:39:06 PM] [eWeLink] Verifying that all cached devices are still registered with the API. Devices that are no longer registered with the API will be removed. -[12/13/2017, 9:39:06 PM] [eWeLink] Device [Fan] is regeistered with API. Nothing to do. -[12/13/2017, 9:39:06 PM] [eWeLink] Evaluating if new devices need to be added... -[12/13/2017, 9:39:06 PM] [eWeLink] Device with ID [XXXXXXX] is already configured. Ensuring that the configuration is current. -[12/13/2017, 9:39:06 PM] [eWeLink] Updating recorded Characteristic.On for [Fan] to [false]. No request will be sent to the device. -[12/13/2017, 9:39:06 PM] [eWeLink] Setting power state to [off] for device [Fan] -[12/13/2017, 9:39:06 PM] [eWeLink] API key retrieved from web service is [XXXXXXX] -[12/13/2017, 9:39:06 PM] [eWeLink] Connecting to the WebSocket API at [wss://us-long.coolkit.cc:8080/api/ws] -[12/13/2017, 9:39:06 PM] [eWeLink] Sending login request [{"action":"userOnline","userAgent":"app","version":6,"nonce":"151321914688000","apkVesrion":"1.8","os":"ios","at":"XXXXXXX","apikey":"xxxxxxx","ts":"1513219146","model":"iPhone10,6","romVersion":"11.1.2","sequence":1513219146880}] -[12/13/2017, 9:39:06 PM] [eWeLink] WebSocket messge received: {"error":0,"apikey":"xxxxxxx","config":{"hb":1,"hbInterval":145},"sequence":"1513219146880"} -``` - -*Hey Siri, turn on the fan* -``` -[12/13/2017, 9:39:09 PM] [eWeLink] Setting power state to [on] for device [Fan] -[12/13/2017, 9:39:09 PM] [eWeLink] WebSocket messge received: {"error":0,"deviceid":"XXXXXXX","apikey":"XXXXXXX","sequence":"1513219149620"} -[12/13/2017, 9:39:11 PM] [eWeLink] Setting power state to [off] for device [Fan] -[12/13/2017, 9:39:12 PM] [eWeLink] WebSocket messge received: {"error":0,"deviceid":"XXXXXXX","apikey":"XXXXXXX","sequence":"1513219151735"} -``` - -The plugin will also listen for announcements via a persistent web socket. This allows you to control the device from the likes of Google Home & have Homebridge be kept up-to-date - -*Hey Google, turn on the fan* -``` -[12/13/2017, 9:41:50 PM] [eWeLink] Update message received for device [XXXXXXX] -[12/13/2017, 9:41:50 PM] [eWeLink] Updating recorded Characteristic.On for [Fan] to [true]. No request will be sent to the device. -[12/13/2017, 9:41:50 PM] [eWeLink] Setting power state to [on] for device [Fan] -[12/13/2017, 9:41:50 PM] [eWeLink] WebSocket messge received: {"error":0,"deviceid":"XXXXXXX","apikey":"XXXXXXX","sequence":"1513219310003"} -``` -## Credits - -So many... needs updated. This is a fork of homebridge-ewelink - +Plugin update coming soon. From 8aa5141fb5fba65492c98265b949aeb1203f467d Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 17 Aug 2020 06:58:47 +0100 Subject: [PATCH 0011/3183] Update README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 1a70beb2..cf449835 100644 --- a/README.md +++ b/README.md @@ -1 +1,10 @@ +

+ Homebridge Verified +

+ + +# homebridge-ewelink-sonoff + + + Plugin update coming soon. From 9a235aec17bf57a7575f1a74ca63fc4d892742bf Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 17 Aug 2020 08:55:17 +0100 Subject: [PATCH 0012/3183] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cf449835..b4af0fec 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- Homebridge Verified + Homebridge Verified

From e5010696d51a3c6ad6b4c9b62c02cd189d420881 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 17 Aug 2020 08:55:53 +0100 Subject: [PATCH 0013/3183] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b4af0fec..a5b69dcb 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

-# homebridge-ewelink-sonoff +# homebridge-ewelink From 307b049208a804d18f7d229ad2ae44e01cafb7ec Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 17 Aug 2020 13:19:41 +0100 Subject: [PATCH 0014/3183] Update new-issue.md --- .github/ISSUE_TEMPLATE/new-issue.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/new-issue.md b/.github/ISSUE_TEMPLATE/new-issue.md index 44f070df..8f5f5df0 100644 --- a/.github/ISSUE_TEMPLATE/new-issue.md +++ b/.github/ISSUE_TEMPLATE/new-issue.md @@ -11,10 +11,20 @@ assignees: '' ... -**Which version of the package are you using?** +**Details of your setup.** +Do you use Homebridge or HOOBS? + +... + +Which version of Homebridge/HOOBS do you have? + +... + +Which version of this plugin (homebridge-ewelink-sonoff) do you have? ... **Please paste any relevant logs below. It helps if you can turn `debug` and `debugReqRes` in the package settings for more thorough logging.** +> If you are posting an error then it is helpful for me to also see the previous few lines as this can show the cause of the error. ... From dd9903f5220f1eeea524c6182c40419406fb8fc6 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 17 Aug 2020 13:19:56 +0100 Subject: [PATCH 0015/3183] Update new-issue.md --- .github/ISSUE_TEMPLATE/new-issue.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/new-issue.md b/.github/ISSUE_TEMPLATE/new-issue.md index 8f5f5df0..32cfb7df 100644 --- a/.github/ISSUE_TEMPLATE/new-issue.md +++ b/.github/ISSUE_TEMPLATE/new-issue.md @@ -20,7 +20,7 @@ Which version of Homebridge/HOOBS do you have? ... -Which version of this plugin (homebridge-ewelink-sonoff) do you have? +Which version of this plugin (homebridge-ewelink) do you have? ... From 44eec9875bb2bc9131a8c01d37c81a36fee478ae Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 17 Aug 2020 13:27:39 +0100 Subject: [PATCH 0016/3183] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a5b69dcb..e17ee9a1 100644 --- a/README.md +++ b/README.md @@ -7,4 +7,7 @@
-Plugin update coming soon. +This package will soon become the new home of [homebridge-ewelink-sonoff](https://github.com/bwp91/homebridge-ewelink-sonoff)! + +### Credit +To the original owner of this package @gbro115 for letting me take over. I will look after it as best as I can! From a99c3c3e65e5f371285bd554add10f405c6997d4 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 17 Aug 2020 16:19:46 +0100 Subject: [PATCH 0017/3183] Update FUNDING.yml --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index addfcd2d..9444c69e 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,2 +1,3 @@ patreon: bwp91 +ko_fi: bwp91 custom: ["https://www.paypal.me/BenPotter"] From ca47926ac14e6fdbb13e01ac5b64feb00f414186 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 17 Aug 2020 16:23:26 +0100 Subject: [PATCH 0018/3183] v rollback --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9420b343..7b3138f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.19.1", + "version": "2.19.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 8a64e5a3..c516fe57 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.19.1", + "version": "2.19.0", "author": "bwp91", "contributors": [ "gbro115", From cfd348deee2ee899ae9ab2d032fa6f34e7b7d91f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 17 Aug 2020 16:32:46 +0100 Subject: [PATCH 0019/3183] 2.19.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7b3138f9..9420b343 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.19.0", + "version": "2.19.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index c516fe57..8a64e5a3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.19.0", + "version": "2.19.1", "author": "bwp91", "contributors": [ "gbro115", From c536c2507203c7db3a089438f13ee1ff0815324f Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 17 Aug 2020 16:40:23 +0100 Subject: [PATCH 0020/3183] Update README.md --- README.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e17ee9a1..deb01fd4 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,18 @@

-# homebridge-ewelink +# homebridge-ewelink + [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) + [![Discord](https://img.shields.io/discord/432663330281226270?color=728ED5&logo=discord&label=discord)](https://discord.com/channels/432663330281226270/742733745743855627) + [![npm](https://img.shields.io/npm/dt/homebridge-ewelink-sonoff)](https://www.npmjs.com/package/homebridge-ewelink) + [![npm](https://img.shields.io/npm/v/homebridge-ewelink-sonoff?label=release)](https://www.npmjs.com/package/homebridge-ewelink) + [![npm](https://img.shields.io/npm/v/homebridge-ewelink-beta?label=beta)](https://www.npmjs.com/package/homebridge-ewelink-beta) + -This package will soon become the new home of [homebridge-ewelink-sonoff](https://github.com/bwp91/homebridge-ewelink-sonoff)! +## Documentation +Please refer to the [wiki](https://github.com/bwp91/homebridge-ewelink-sonoff/wiki) for documentation. -### Credit -To the original owner of this package @gbro115 for letting me take over. I will look after it as best as I can! +## Credit +To the original owner of this package @gbro115 for letting me take over. I will look after it as best as I can :) From e27c2d228975ec87034dd9aec418a450957ccb59 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 17 Aug 2020 16:55:25 +0100 Subject: [PATCH 0021/3183] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8a64e5a3..e33b50b4 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "JuniorGenius", "BobbySlope" ], - "description": "homebridge-ewelink-sonoff is a Homebrige plugin to control Sonoff devices running OEM firmware.", + "description": "Homebridge plugin to control eWeLink devices with original firmware.", "license": "MIT", "keywords": [ "homebridge", From 72000421e0e12dc4068236f001f6c4638c2aa6c2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 17 Aug 2020 17:25:03 +0100 Subject: [PATCH 0022/3183] Update config.schema.json --- config.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.schema.json b/config.schema.json index b8a7a5cf..90c72ece 100644 --- a/config.schema.json +++ b/config.schema.json @@ -2,7 +2,7 @@ "pluginAlias":"eWeLink", "pluginType":"platform", "singular":true, - "headerDisplay":"Homebridge plugin to control Sonoff devices with OEM firmware.", + "headerDisplay":"Homebridge plugin to control eWeLink devices with original firmware.", "footerDisplay":"If you have any suggestions, please open an issue on [GitHub](https://github.com/bwp91/homebridge-ewelink/issues).", "schema":{ "type":"object", From b75ec7243364d82eb519ebac7ca4190d4bc5069c Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 17 Aug 2020 17:37:26 +0100 Subject: [PATCH 0023/3183] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index deb01fd4..6f976a7a 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ ## Documentation -Please refer to the [wiki](https://github.com/bwp91/homebridge-ewelink-sonoff/wiki) for documentation. +Please refer to the [wiki](https://github.com/bwp91/homebridge-ewelink/wiki) for documentation. ## Credit To the original owner of this package @gbro115 for letting me take over. I will look after it as best as I can :) From 82b6fdf9151eccba656e9028d51364fdf47c8f93 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 17 Aug 2020 19:34:14 +0100 Subject: [PATCH 0024/3183] camera log entries --- lib/eWeLink.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 8cfdceec..eba46a71 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -166,6 +166,8 @@ class eWeLink { this.addAccessory(device, device.deviceid + "SWX", "zb_pri"); } else if (constants.devicesZB.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SWX", "zb_sub"); + } else if (device.extra.uiid === 87) { + this.log.warn("[%s] please consider using homebridge-camera-ffmpeg to use this camera.", device.name); } else { this.log.warn("[%s] could not be added as it is not supported by this plugin.", device.name); } @@ -239,7 +241,9 @@ class eWeLink { return; } } else { - this.log.warn("[%s] will not be refreshed as it wasn't found in Homebridge.", device.name); + if (device.extra.uiid !== 87) { + this.log.warn("[%s] will not be refreshed as it wasn't found in Homebridge.", device.name); + } return; } if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { @@ -655,7 +659,6 @@ class eWeLink { this.externalRFDeviceUpdate(accessory, newParams); return true; case "rf_sub": - return true; case "zb_pri": return true; case "zb_sub": @@ -1460,7 +1463,7 @@ class eWeLink { let oldState = accessory.getService(Service.ContactSensor).getCharacteristic(Characteristic.ContactSensorState).value, newState = params.switch === "on" ? 1 : 0, oAccessory = false; - accessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, newState); + accessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, newState); this.log("[%s] sent update that it was [%s] and is now [%s].", accessory.displayName, oldState ? "apart" : "joined", newState ? "apart" : "joined"); this.cusG.forEach(group => { if (group.sensorId === accessory.context.eweDeviceId && group.type === "garage") { From c2db874675578f4d768c31a5d8591837c235df7d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 17 Aug 2020 20:29:00 +0100 Subject: [PATCH 0025/3183] 2.19.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9420b343..386790ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.19.1", + "version": "2.19.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index e33b50b4..607d3323 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.19.1", + "version": "2.19.2", "author": "bwp91", "contributors": [ "gbro115", From 8d7ba03d6ef201e48136e5021ab71b1c586cd98b Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 17 Aug 2020 20:41:35 +0100 Subject: [PATCH 0026/3183] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6f976a7a..c8124630 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) [![Discord](https://img.shields.io/discord/432663330281226270?color=728ED5&logo=discord&label=discord)](https://discord.com/channels/432663330281226270/742733745743855627) - [![npm](https://img.shields.io/npm/dt/homebridge-ewelink-sonoff)](https://www.npmjs.com/package/homebridge-ewelink) - [![npm](https://img.shields.io/npm/v/homebridge-ewelink-sonoff?label=release)](https://www.npmjs.com/package/homebridge-ewelink) + [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) + [![npm](https://img.shields.io/npm/v/homebridge-ewelink?label=release)](https://www.npmjs.com/package/homebridge-ewelink) [![npm](https://img.shields.io/npm/v/homebridge-ewelink-beta?label=beta)](https://www.npmjs.com/package/homebridge-ewelink-beta) From 76f7b8bbfa0d6c58e713e4bcb0d255fda78c45e9 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 17 Aug 2020 21:12:45 +0100 Subject: [PATCH 0027/3183] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c8124630..633cb902 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- Homebridge Verified + Homebridge Verified

From e8db9d9846438abf2fa6e975a6d51b23e96f8d5a Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 17 Aug 2020 21:29:14 +0100 Subject: [PATCH 0028/3183] Set theme jekyll-theme-slate --- _config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 _config.yml diff --git a/_config.yml b/_config.yml new file mode 100644 index 00000000..c7418817 --- /dev/null +++ b/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-slate \ No newline at end of file From 36ca2782e763647cd50b58ec3c13f4c5e8c037ba Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 19 Aug 2020 14:32:18 +0100 Subject: [PATCH 0029/3183] remove button as now auto --- config.schema.json | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/config.schema.json b/config.schema.json index 90c72ece..95772b9f 100644 --- a/config.schema.json +++ b/config.schema.json @@ -195,12 +195,6 @@ "default":"motion", "description":"Select the type of sensor you would like to expose this as in Homebridge.", "oneOf":[ - { - "title":"Button", - "enum":[ - "button" - ] - }, { "title":"Motion", "enum":[ @@ -303,9 +297,9 @@ }, { "key":"bridgeSensors", - "title":"RF Bridge Devices", + "title":"RF Bridge Sensors", "expandable":true, - "add":"Add Another Device", + "add":"Add Another Sensor", "type":"array", "items":[ { From 098d2b90d58d2bb150a6d48a076483896a67b199 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 19 Aug 2020 21:24:43 +0100 Subject: [PATCH 0030/3183] issue #72 helper --- lib/eWeLink.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index eba46a71..9516058e 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -101,7 +101,12 @@ class eWeLink { } //*** Synchronise (add/refresh) devices between eWeLink and Homebridge ***\\ this.devicesInEwe.forEach(device => { - this.initialiseDevice(device); + if (device.hasOwnProperty("extra") && device.extra.hasOwnProperty("uiid")) { + this.initialiseDevice(device); + } else { + let deviceName = device.hasOwnProperty("name") ? device.name : "Unknown Device"; + this.log.warn("[%s] could not be synchronised due to missing uiid parameter.", deviceName); + } }); //*** Set up the ws listener for future external device updates ***\\ this.wsClient.receiveUpdate(device => { From 1f423035ad05fc4bef92e74b1bf9e421a9fe4fae Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 19 Aug 2020 21:25:19 +0100 Subject: [PATCH 0031/3183] 2.19.3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 386790ae..0077fce1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.19.2", + "version": "2.19.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 607d3323..83a1c664 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.19.2", + "version": "2.19.3", "author": "bwp91", "contributors": [ "gbro115", From 6a2b380605ab338b11c267f3e9f543735f7d4a74 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 19 Aug 2020 22:21:56 +0100 Subject: [PATCH 0032/3183] lan default --- config.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.schema.json b/config.schema.json index 95772b9f..a265ff91 100644 --- a/config.schema.json +++ b/config.schema.json @@ -44,7 +44,7 @@ "type":"string", "title":"Connection Mode", "required":true, - "default":"ws", + "default":"lan", "description":"Preferred method of updating devices. Devices that don't support LAN mode will use web socket.", "oneOf":[ { From 29cd09f93f8ad01d4ab92e319e22c2140eef0fba Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 20 Aug 2020 17:06:19 +0100 Subject: [PATCH 0033/3183] remove mode option --- config.schema.json | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/config.schema.json b/config.schema.json index a265ff91..8a6237d9 100644 --- a/config.schema.json +++ b/config.schema.json @@ -40,27 +40,6 @@ "description":"If enabled, HTTP, web socket and LAN mode messages will be added to the log. Not recommended for long-term use.", "default":false }, - "mode":{ - "type":"string", - "title":"Connection Mode", - "required":true, - "default":"lan", - "description":"Preferred method of updating devices. Devices that don't support LAN mode will use web socket.", - "oneOf":[ - { - "title":"LAN Mode (Recommended)", - "enum":[ - "lan" - ] - }, - { - "title":"Web Socket", - "enum":[ - "ws" - ] - } - ] - }, "hideDevFromHB":{ "type":"string", "title":"Hide Devices", @@ -266,7 +245,6 @@ "items":[ "debug", "debugReqRes", - "mode", "hideDevFromHB", "hideFromHB", "sensorTimeLength", From fa9c3f422e4dae90309ea914ca52e326364f6c6a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 20 Aug 2020 17:06:28 +0100 Subject: [PATCH 0034/3183] add camera uiid --- lib/constants.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/constants.js b/lib/constants.js index 27699ea5..3c557fca 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -14,6 +14,7 @@ module.exports = { devicesThermostat: [15], devicesFan: [34], devicesOutlet: [32], + devicesCamera: [87], devicesUSB: [77], devicesSCM: [78], devicesRFBridge: [28], From 387e98bcae9ceda49b9057f22f1c84d863ead5d8 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 20 Aug 2020 17:06:39 +0100 Subject: [PATCH 0035/3183] refactors --- lib/eWeLink.js | 1974 +++++++++++++++++++++----------------------- lib/eWeLinkHTTP.js | 46 +- lib/eWeLinkLAN.js | 43 +- lib/eWeLinkWS.js | 91 +- 4 files changed, 1056 insertions(+), 1098 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 9516058e..89352a12 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1,6 +1,6 @@ /* jshint esversion: 9, -W030, node: true */ "use strict"; -const constants = require("./constants"); +const cns = require("./constants"); const convert = require("color-convert"); const eWeLinkHTTP = require("./eWeLinkHTTP"); const eWeLinkWS = require("./eWeLinkWS"); @@ -12,23 +12,12 @@ class eWeLink { return; } if (!config || (!config.username || !config.password || !config.countryCode)) { - log.error("** Could not load " + constants.packageName + " **"); - log.warn("Make sure your eWeLink credentials are in the Homebridge configuration."); + log.error("🔴 Cannot load %s - please check your eWeLink credentials in the plugin settings.", cns.packageName); return; } this.log = log; this.config = config; this.api = api; - this.mode = this.config.mode || "lan"; - this.debug = this.config.debug || false; - this.debugReqRes = this.config.debugReqRes || false; - this.customHideChanFromHB = this.config.hideFromHB || ""; - this.customHideDvceFromHB = this.config.hideDevFromHB || ""; - this.customNameOverride = this.config.nameOverride || {}; - this.sensorTimeLength = this.config.sensorTimeLength || 2; - this.sensorTimeDifference = this.config.sensorTimeDifference || 120; - this.valveTimeLength = this.config.valveTimeLength || 120; - this.hideZBLDPress = this.config.hideZBLDPress || false; this.devicesInHB = new Map(); this.devicesInEwe = new Map(); this.cusG = new Map(); @@ -43,94 +32,78 @@ class eWeLink { }).then(res => { //*** Set up the web socket client ***\\ this.wsClient = new eWeLinkWS(this.config, this.log, res); return this.wsClient.getHost(); - }).then(res => { //*** Open web socket connection and get device list via HTTP ***\\ + }).then(() => { //*** Open web socket connection and get device list via HTTP ***\\ this.wsClient.login(); return this.httpClient.getDevices(); }).then(res => { //*** Get device IP addresses for LAN mode ***\\ + this.httpDevices = res + .filter(device => !(this.config.hideDevFromHB || "").includes(device.deviceid)) + .forEach(device => this.devicesInEwe.set(device.deviceid, device)); this.httpDevices = res; this.lanClient = new eWeLinkLAN(this.config, this.log, this.httpDevices); return this.lanClient.getHosts(); }).then(res => { //*** Set up the LAN mode listener ***\\ - this.lanDevices = res; + this.lanDevices = res.map; + this.lanDeviceOnline = res.count; return this.lanClient.startMonitor(); - }).then(res => { //*** Use the device list to refresh Homebridge accessories ***\\ + }).then(() => { //*** Use the device list to refresh Homebridge accessories ***\\ (() => { //*** Remove all Homebridge accessories if none found ***\\ if (Object.keys(this.httpDevices).length === 0 && Object.keys(this.lanDevices).length === 0) { - this.removeAllAccessories(); + Array.from(this.devicesInHB.values()).forEach(a => this.removeAccessory(a)); + this.devicesInHB.clear(); + this.log.warn("🟠 No devices were found registered to your eWeLink account so disabling plugin."); return; } - //*** Make a map of devices from eWeLink ***\\ - this.httpDevices.forEach(device => { - if (this.customHideDvceFromHB.includes(device.deviceid)) { - return; - } - this.devicesInEwe.set(device.deviceid, device); - }); //*** Make a map of custom groups from Homebridge config ***\\ - if (this.config.groups && Object.keys(this.config.groups).length > 0) { - this.config.groups.forEach(group => { - if (typeof group.deviceId !== "undefined" && this.devicesInEwe.has(group.deviceId.toLowerCase())) { - this.cusG.set(group.deviceId + "SWX", group); - } - }); + if (Object.keys(this.config.groups || []).length > 0) { + this.config.groups + .filter(g => g.hasOwnProperty("deviceId") && this.devicesInEwe.has(g.deviceId.toLowerCase())) + .forEach(g => this.cusG.set(g.deviceId + "SWX", g)); } //*** Make a map of RF Bridge custom sensors from Homebridge config ***\\ - if (this.config.bridgeSensors && Object.keys(this.config.bridgeSensors).length > 0) { - this.config.bridgeSensors.forEach(bridgeSensor => { - if (typeof bridgeSensor.deviceId !== "undefined" && this.devicesInEwe.has(bridgeSensor.deviceId.toLowerCase())) { - this.cusS.set(bridgeSensor.fullDeviceId, bridgeSensor); - } - }); + if (Object.keys(this.config.bridgeSensors || []).length > 0) { + this.config.bridgeSensors + .filter(s => s.hasOwnProperty("deviceId") && this.devicesInEwe.has(s.deviceId.toLowerCase())) + .forEach(s => this.cusS.set(s.fullDeviceId, s)); } //*** Logging always helps to see if everything is okay so far ***\\ this.log("[%s] eWeLink devices were loaded from the Homebridge cache.", this.devicesInHB.size); this.log("[%s] primary devices were loaded from your eWeLink account.", this.devicesInEwe.size); - this.log("[%s] primary devices were discovered on your local network.", Object.keys(this.lanDevices).length); + this.log("[%s] primary devices were discovered on your local network.", this.lanDeviceOnline); //*** Remove Homebridge accessories that don't appear in eWeLink ***\\ - if (this.devicesInHB.size > 0) { - this.devicesInHB.forEach(accessory => { - if (!this.devicesInEwe.has(accessory.context.eweDeviceId)) { - this.removeAccessory(accessory); - } - }); - } - //*** Disable plugin if no eWeLink devices ***\\ - if (this.devicesInEwe.size === 0) { - return; - } - //*** Synchronise (add/refresh) devices between eWeLink and Homebridge ***\\ - this.devicesInEwe.forEach(device => { - if (device.hasOwnProperty("extra") && device.extra.hasOwnProperty("uiid")) { - this.initialiseDevice(device); - } else { - let deviceName = device.hasOwnProperty("name") ? device.name : "Unknown Device"; - this.log.warn("[%s] could not be synchronised due to missing uiid parameter.", deviceName); + this.devicesInHB.forEach(accessory => { + if (!this.devicesInEwe.has(accessory.context.eweDeviceId)) { + this.removeAccessory(accessory); } }); - //*** Set up the ws listener for future external device updates ***\\ - this.wsClient.receiveUpdate(device => { - this.receiveDeviceUpdate(device); - }); - //*** Set up the lan listener for future external device updates ***\\ - this.lanClient.receiveUpdate(device => { - this.receiveDeviceUpdate(device); - }); - this.log("Synchronisation complete. Ready to go!"); - if (this.debugReqRes) { + //*** Synchronise devices between eWeLink and Homebridge and set up ws/lan listeners ***\\ + this.devicesInEwe.forEach(device => this.initialiseDevice(device)); + this.wsClient.receiveUpdate(device => this.receiveDeviceUpdate(device)); + this.lanClient.receiveUpdate(device => this.receiveDeviceUpdate(device)); + this.log("đŸŸĸ eWeLink setup complete. If you're enjoying this package please consider a ⭐ī¸ on GitHub!"); + if (this.config.debugReqRes) { this.log.warn("You have 'Request & Response Logging' enabled. This setting is not recommended for long-term use."); } })(); - }).catch(err => { - this.log.error("** eWeLink synchronisation error: **"); - this.log.warn(err); - this.log.error("** Plugin will not be loaded. **"); - }); + }).catch(err => this.log.error("🔴 Cannot load %s - %s", cns.packageName, err)); + }); + this.api.on('shutdown', () => { + this.lanClient.closeConnection(); + this.wsClient.closeConnection(); }); } initialiseDevice(device) { + if (!device.hasOwnProperty("extra") || !device.extra.hasOwnProperty("uiid")) { + let deviceName = device.hasOwnProperty("name") ? + device.name : + device.hasOwnProperty("deviceid") ? device.deviceid : "Unknown Device"; + this.log.warn("[%s] could not be synchronised due to missing uiid parameter.", deviceName); + return; + } let accessory; - //*** First add the device if it isn't already in Homebridge ***\\ + device.params.updateSource = "http"; + //*** First add the device if it isn't already in Homebridge. Yeah this code looks a mess :| ***\\ if (!this.devicesInHB.has(device.deviceid + "SWX") && !this.devicesInHB.has(device.deviceid + "SW0")) { if (device.extra.uiid === 2 && device.brandName === "coolkit" && device.productModel === "0285") { this.addAccessory(device, device.deviceid + "SWX", "valve"); @@ -138,141 +111,117 @@ class eWeLink { this.addAccessory(device, device.deviceid + "SWX", "blind"); } else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "garage") { this.addAccessory(device, device.deviceid + "SWX", "garage"); - } else if (constants.devicesSensor.includes(device.extra.uiid)) { + } else if (cns.devicesSensor.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SWX", "sensor"); - } else if (constants.devicesFan.includes(device.extra.uiid)) { + } else if (cns.devicesFan.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SWX", "fan"); - } else if (constants.devicesThermostat.includes(device.extra.uiid)) { + } else if (cns.devicesThermostat.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SWX", "thermostat"); - } else if (constants.devicesOutlet.includes(device.extra.uiid)) { + } else if (cns.devicesOutlet.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SWX", "outlet"); - } else if (constants.devicesUSB.includes(device.extra.uiid)) { + } else if (cns.devicesUSB.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SWX", "usb"); - } else if (constants.devicesSCM.includes(device.extra.uiid)) { + } else if (cns.devicesSCM.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SWX", "scm"); - } else if (constants.devicesSingleSwitch.includes(device.extra.uiid) && constants.devicesSingleSwitchLight.includes(device.productModel)) { + } else if (cns.devicesSingleSwitch.includes(device.extra.uiid) && cns.devicesSingleSwitchLight.includes(device.productModel)) { this.addAccessory(device, device.deviceid + "SWX", "light"); - } else if (constants.devicesMultiSwitch.includes(device.extra.uiid) && constants.devicesMultiSwitchLight.includes(device.productModel)) { - for (let i = 0; i <= constants.chansFromUiid[device.extra.uiid]; i++) { + } else if (cns.devicesMultiSwitch.includes(device.extra.uiid) && cns.devicesMultiSwitchLight.includes(device.productModel)) { + for (let i = 0; i <= cns.chansFromUiid[device.extra.uiid]; i++) { this.addAccessory(device, device.deviceid + "SW" + i, "light"); } - } else if (constants.devicesSingleSwitch.includes(device.extra.uiid)) { + } else if (cns.devicesSingleSwitch.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SWX", "switch"); - } else if (constants.devicesMultiSwitch.includes(device.extra.uiid)) { - for (let i = 0; i <= constants.chansFromUiid[device.extra.uiid]; i++) { + } else if (cns.devicesMultiSwitch.includes(device.extra.uiid)) { + for (let i = 0; i <= cns.chansFromUiid[device.extra.uiid]; i++) { this.addAccessory(device, device.deviceid + "SW" + i, "switch"); } - } else if (constants.devicesRFBridge.includes(device.extra.uiid)) { + } else if (cns.devicesRFBridge.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SW0", "rf_pri"); - for (let i = 1; i <= Object.keys(device.params.rfList).length; i++) { + for (let i = 1; i <= Object.keys(device.tags.zyx_info).length; i++) { this.addAccessory(device, device.deviceid + "SW" + i, "rf_sub"); } - } else if (constants.devicesZBBridge.includes(device.extra.uiid)) { + } else if (cns.devicesZBBridge.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SWX", "zb_pri"); - } else if (constants.devicesZB.includes(device.extra.uiid)) { + } else if (cns.devicesZB.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SWX", "zb_sub"); - } else if (device.extra.uiid === 87) { + } else if (cns.devicesCamera.includes(device.extra.uiid)) { this.log.warn("[%s] please consider using homebridge-camera-ffmpeg to use this camera.", device.name); + return; } else { - this.log.warn("[%s] could not be added as it is not supported by this plugin.", device.name); + this.log.warn("[%s] cannot be added as it is not supported by this plugin. Please make a GitHub issue request.", device.name); + return; } } //*** Next refresh the device ***\\ - if ((accessory = this.devicesInHB.get(device.deviceid + "SWX"))) { + if ((accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0"))) { + let isX = accessory.context.hbDeviceId.substr(-1) === "X", + isRfBridge = cns.devicesRFBridge.includes(accessory.context.eweUIID), + rfBridgeChange = false; accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); - accessory.context.reachableWAN = accessory.context.eweUIID !== 102 ? - device.online : - true; //*** DW2 offline sometimes (as battery powered?) ***\\ - accessory.context.reachableLAN = this.lanDevices[device.deviceid].ip || false; + accessory.context.reachableWAN = accessory.context.eweUIID !== 102 ? device.online : true; //*** DW2 ***\\ + accessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; let str = accessory.context.reachableLAN ? - "and locally with IP [" + accessory.context.reachableLAN + "]" : - (accessory.context.reachableWAN) ? - "but LAN mode unavailable as unsupported/shared device" : - "but LAN mode unavailable as device offline"; + "and locally with IP [" + this.lanDevices.get(device.deviceid).ip + "]" : + "but LAN mode unavailable as unsupported/shared device"; this.log("[%s] found in eWeLink %s.", accessory.displayName, str); - try { - this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - this.api.updatePlatformAccessories(constants.packageName, "eWeLink", [accessory]); - } catch (e) { - this.log.warn("[%s] online/offline status could not be updated - [%s].", accessory.displayName, e); - } - } else if ((accessory = this.devicesInHB.get(device.deviceid + "SW0"))) { - accessory.context.reachableLAN = this.lanDevices[device.deviceid].ip || false; - let str = accessory.context.reachableLAN ? - "and locally with IP [" + accessory.context.reachableLAN + "]" : - (accessory.context.reachableWAN) ? - "but LAN mode unavailable as unsupported/shared device" : - "but LAN mode unavailable as device offline"; - this.log("[%s] found in eWeLink %s.", accessory.displayName, str); - let isRf = constants.devicesRFBridge.includes(device.extra.uiid); - let rfCh = false; - for (let i = 0; i <= accessory.context.channelCount; i++) { - let oAccessory; - try { + this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + if (!isX) { + for (let i = 1; i <= accessory.context.channelCount; i++) { if (!this.devicesInHB.has(device.deviceid + "SW" + i)) { - if (i > 0 && this.customHideChanFromHB.includes(device.deviceid + "SW" + i) && constants.devicesHideable.includes(accessory.context.type)) { - continue; - } else { - this.addAccessory(device, device.deviceid + "SW" + i, "switch"); + if (cns.devicesHideable.includes(accessory.context.type)) { + if ((this.config.hideFromHB || "").includes(device.deviceid + "SW" + i)) { + continue; + } else { + this.addAccessory(device, device.deviceid + "SW" + i, "switch"); + } } } - oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); - if (i > 0 && this.customHideChanFromHB.includes(device.deviceid + "SW" + i) && constants.devicesHideable.includes(accessory.context.type)) { + let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); + if ((this.config.hideFromHB || "").includes(device.deviceid + "SW" + i) && cns.devicesHideable.includes(accessory.context.type)) { this.removeAccessory(oAccessory); continue; } - if (i > 0 && isRf) { + if (isRfBridge && oAccessory.context.sensorType !== "button") { let ct = this.cusS.has(oAccessory.context.hbDeviceId) ? this.cusS.get(oAccessory.context.hbDeviceId).type : "motion"; - if (ct !== oAccessory.context.sensorType) { - rfCh = true; + if (ct !== oAccessory.context.sensorType || typeof accessory.context.updated === "undefined") { + rfBridgeChange = true; } } oAccessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); oAccessory.context.reachableWAN = device.online; - oAccessory.context.reachableLAN = this.lanDevices[device.deviceid].ip || false; + oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); - this.api.updatePlatformAccessories(constants.packageName, "eWeLink", [oAccessory]); - } catch (e) {} - } - if (rfCh) { - this.log.warn("RF Bridge configuration changed. Devices will be removed and readded."); - try { - for (let i = 0; i <= accessory.context.channelCount; i++) { - let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); - this.removeAccessory(oAccessory); - } - this.initialiseDevice(device); - } catch (err) {} + } + } + if (rfBridgeChange) { + this.log.warn("[%s] bridge configuration changed - devices will be removed and readded.", accessory.displayName); + for (let i = 0; i <= accessory.context.channelCount; i++) { + let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); + this.removeAccessory(oAccessory); + } + this.initialiseDevice(device); return; } - } else { - if (device.extra.uiid !== 87) { - this.log.warn("[%s] will not be refreshed as it wasn't found in Homebridge.", device.name); + if (!this.refreshAccessory(accessory, device.params)) { + this.log.warn("[%s] could not be initialised. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.) [debug:%s:%s].", accessory.displayName, accessory.context.type, accessory.context.channelCount); } - return; - } - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - this.log.warn("[%s] will not be refreshed as it has been reported offline.", accessory.displayName); - return; - } - device.params.updateSource = "http"; - if (!this.refreshAccessory(accessory, device.params)) { - this.log.warn("[%s] could not be refreshed. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.). Debugging: [%s:%s:%s]", accessory.displayName, "initialise", accessory.context.type, accessory.context.channelCount); + } else { + this.log.warn("[%s] cannot be initialised as it wasn't found in Homebridge.", device.name); } } addAccessory(device, hbDeviceId, type) { - let channelCount = type === "rf_pri" ? Object.keys(device.params.rfList).length : constants.chansFromUiid[device.extra.uiid], + let channelCount = type === "rf_pri" ? Object.keys(device.tags.zyx_info).length : cns.chansFromUiid[device.extra.uiid], switchNumber = hbDeviceId.substr(-1).toString(), - newDeviceName = device.name; - if (["1", "2", "3", "4"].includes(switchNumber)) { + newDeviceName = type === "rf_sub" ? device.tags.zyx_info[switchNumber - 1].name : device.name; + if (["1", "2", "3", "4"].includes(switchNumber) && type !== "rf_sub") { newDeviceName += " SW" + switchNumber; - if (this.customHideChanFromHB.includes(hbDeviceId) && type === "switch") { + if ((this.config.hideFromHB || "").includes(hbDeviceId) && cns.devicesHideable.includes(type)) { this.log.warn("[%s] has not been added as per configuration", newDeviceName); return; } } - if (this.customNameOverride.hasOwnProperty(hbDeviceId)) { - newDeviceName = this.customNameOverride[hbDeviceId]; + if ((this.config.nameOverride || {}).hasOwnProperty(hbDeviceId)) { + newDeviceName = this.config.nameOverride[hbDeviceId]; } const accessory = new Accessory(newDeviceName, UUIDGen.generate(hbDeviceId).toString()); try { @@ -293,124 +242,150 @@ class eWeLink { type }; switch (type) { - case "valve": - ["A", "B"].forEach(v => { - accessory.addService(Service.Valve, "Valve " + v, "valve" + v.toLowerCase()) - .setCharacteristic(Characteristic.Active, 0) - .setCharacteristic(Characteristic.InUse, 0) - .setCharacteristic(Characteristic.ValveType, 1) - .setCharacteristic(Characteristic.SetDuration, this.valveTimeLength) - .addCharacteristic(Characteristic.RemainingDuration); - }); - break; - case "blind": - accessory.addService(Service.WindowCovering) - .setCharacteristic(Characteristic.CurrentPosition, 100) - .setCharacteristic(Characteristic.TargetPosition, 100) - .setCharacteristic(Characteristic.PositionState, 2); - break; - case "garage": - accessory.addService(Service.GarageDoorOpener) - .setCharacteristic(Characteristic.CurrentDoorState, 1) - .setCharacteristic(Characteristic.TargetDoorState, 1) - .setCharacteristic(Characteristic.ObstructionDetected, false); - break; - case "sensor": - accessory.addService(Service.ContactSensor) - .setCharacteristic(Characteristic.ContactSensorState, 0); - break; - case "fan": - accessory.addService(Service.Fanv2); - accessory.addService(Service.Lightbulb); - break; - case "thermostat": - accessory.addService(Service.Switch); - accessory.addService(Service.TemperatureSensor); - if (device.params.sensorType !== "DS18B20") { - accessory.addService(Service.HumiditySensor); - } - break; - case "outlet": - case "usb": - accessory.addService(Service.Outlet); - break; - case "light": - accessory.addService(Service.Lightbulb); - break; - case "switch": - case "scm": - accessory.addService(Service.Switch); - break; - case "rf_pri": - case "zb_pri": - break; - case "rf_sub": - accessory.context.sensorType = this.cusS.has(hbDeviceId) ? this.cusS.get(hbDeviceId).type : "motion"; - accessory.context.rfChl = parseInt(switchNumber) - 1; - switch (accessory.context.sensorType) { - case "button": - accessory.addService(Service.Switch); + case "valve": + ["A", "B"].forEach(v => { + accessory.addService(Service.Valve, "Valve " + v, "valve" + v.toLowerCase()) + .setCharacteristic(Characteristic.Active, 0) + .setCharacteristic(Characteristic.InUse, 0) + .setCharacteristic(Characteristic.ValveType, 1) + .setCharacteristic(Characteristic.SetDuration, (this.config.valveTimeLength || 120)) + .addCharacteristic(Characteristic.RemainingDuration); + }); break; - case "water": - accessory.addService(Service.LeakSensor); + case "blind": + accessory.addService(Service.WindowCovering) + .setCharacteristic(Characteristic.CurrentPosition, 100) + .setCharacteristic(Characteristic.TargetPosition, 100) + .setCharacteristic(Characteristic.PositionState, 2); break; - case "fire": - case "smoke": - accessory.addService(Service.SmokeSensor); + case "garage": + accessory.addService(Service.GarageDoorOpener) + .setCharacteristic(Characteristic.CurrentDoorState, 1) + .setCharacteristic(Characteristic.TargetDoorState, 1) + .setCharacteristic(Characteristic.ObstructionDetected, false); break; - case "co": - accessory.addService(Service.CarbonMonoxideSensor); + case "sensor": + accessory.addService(Service.ContactSensor); break; - case "co2": - accessory.addService(Service.CarbonDioxideSensor); + case "fan": + accessory.addService(Service.Fanv2); + accessory.addService(Service.Lightbulb); break; - case "contact": - accessory.addService(Service.ContactSensor); + case "thermostat": + accessory.addService(Service.Switch); + accessory.addService(Service.TemperatureSensor); + if (device.params.sensorType !== "DS18B20") { + accessory.addService(Service.HumiditySensor); + } break; - case "occupancy": - accessory.addService(Service.OccupancySensor); + case "outlet": + case "usb": + accessory.addService(Service.Outlet); break; - case "motion": - default: - accessory.addService(Service.MotionSensor); + case "light": + accessory.addService(Service.Lightbulb); break; - } - break; - case "zb_sub": - switch (device.extra.uiid) { - case 1000: //*** credit @tasict ***\\ - accessory.addService(Service.StatelessProgrammableSwitch); - if (this.hideZBLDPress) { - accessory.getService(Service.StatelessProgrammableSwitch) - .getCharacteristic(Characteristic.ProgrammableSwitchEvent) - .setProps({ - validValues: [0] - }); - } + case "switch": + case "scm": + accessory.addService(Service.Switch); break; - case 1770: - accessory.addService(Service.TemperatureSensor); - accessory.addService(Service.HumiditySensor); + case "rf_pri": + accessory.context.rfChlMap = {}; + accessory.context.updated = true; break; - case 2026: - accessory.addService(Service.MotionSensor); + case "zb_pri": break; - case 3026: - accessory.addService(Service.ContactSensor).setCharacteristic(Characteristic.ContactSensorState, 0); + case "rf_sub": + accessory.context.rfChls = {}; + switch (device.tags.zyx_info[parseInt(switchNumber) - 1].remote_type) { + case "1": + case "2": + case "3": + case "4": + accessory.context.sensorType = "button"; + break; + case "6": + accessory.context.sensorType = this.cusS.has(hbDeviceId) ? this.cusS.get(hbDeviceId).type : "motion"; + break; + case "5": + default: + throw "RF device type is not supported"; + } + let mAccessory = this.devicesInHB.get(device.deviceid + "SW0"); + device.tags.zyx_info[parseInt(switchNumber) - 1].buttonName.forEach(button => { + let rfChan, name; + Object.entries(button).forEach(([k, v]) => { + rfChan = k; + name = v; + }); + accessory.context.rfChls[rfChan] = name; + mAccessory.context.rfChlMap[rfChan] = switchNumber; + switch (accessory.context.sensorType) { + case "button": + accessory.addService(Service.Switch, name, "switch" + rfChan); + break; + case "water": + accessory.addService(Service.LeakSensor); + break; + case "fire": + case "smoke": + accessory.addService(Service.SmokeSensor); + break; + case "co": + accessory.addService(Service.CarbonMonoxideSensor); + break; + case "co2": + accessory.addService(Service.CarbonDioxideSensor); + break; + case "contact": + accessory.addService(Service.ContactSensor); + break; + case "occupancy": + accessory.addService(Service.OccupancySensor); + break; + case "motion": + default: + accessory.addService(Service.MotionSensor); + break; + } + this.devicesInHB.set(mAccessory.context.hbDeviceId, mAccessory); + }); + break; + case "zb_sub": //*** credit @tasict ***\\ + switch (device.extra.uiid) { + case 1000: + accessory.addService(Service.StatelessProgrammableSwitch); + if (this.config.hideZBLDPress) { + accessory.getService(Service.StatelessProgrammableSwitch) + .getCharacteristic(Characteristic.ProgrammableSwitchEvent) + .setProps({ + validValues: [0] + }); + } + break; + case 1770: + accessory.addService(Service.TemperatureSensor); + accessory.addService(Service.HumiditySensor); + break; + case 2026: + accessory.addService(Service.MotionSensor); + break; + case 3026: + accessory.addService(Service.ContactSensor); + break; + default: + throw "unsupported zigbee device type with uiid [" + device.extra.uiid + "]"; + } break; default: - throw "unsupported zigbee device type with uiid [" + device.extra.uiid + "]"; - } - break; - default: - throw "device is not supported by this plugin"; + throw "device is not supported by this plugin"; } this.devicesInHB.set(hbDeviceId, accessory); - this.api.registerPlatformAccessories(constants.packageName, "eWeLink", [accessory]); + this.api.registerPlatformAccessories(cns.packageName, "eWeLink", [accessory]); this.configureAccessory(accessory); this.log("[%s] has been added to Homebridge.", newDeviceName); - } catch (e) { - this.log.warn("[%s] could not be added as %s.", accessory.displayName, e); + } catch (err) { + this.log.warn("[%s] could not be added - %s.", newDeviceName, err); } } configureAccessory(accessory) { @@ -419,276 +394,272 @@ class eWeLink { } try { switch (accessory.context.type) { - case "valve": - ["A", "B"].forEach(v => { - accessory.getService("Valve " + v).getCharacteristic(Characteristic.Active) + case "valve": + ["A", "B"].forEach(v => { + accessory.getService("Valve " + v).getCharacteristic(Characteristic.Active) + .on("set", (value, callback) => { + accessory.getService("Valve " + v).getCharacteristic(Characteristic.Active).value !== value ? + this.internalValveUpdate(accessory, "Valve " + v, value, callback) : + callback(); + }); + accessory.getService("Valve " + v).getCharacteristic(Characteristic.SetDuration) + .on("set", (value, callback) => { + if (accessory.getService("Valve " + v).getCharacteristic(Characteristic.InUse).value) { + accessory.getService("Valve " + v).updateCharacteristic(Characteristic.RemainingDuration, value); + clearTimeout(accessory.getService("Valve " + v).timer); + accessory.getService("Valve " + v).timer = setTimeout(() => { + accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); + }, (value * 1000)); + } + callback(); + }); + }); + break; + case "blind": + accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.TargetPosition) + .setProps({ + minStep: 100 + }) .on("set", (value, callback) => { - accessory.getService("Valve " + v).getCharacteristic(Characteristic.Active).value !== value ? - this.internalValveUpdate(accessory, "Valve " + v, value, callback) : + accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.TargetPosition).value !== value ? + this.internalBlindUpdate(accessory, value, callback) : callback(); }); - accessory.getService("Valve " + v).getCharacteristic(Characteristic.SetDuration) + break; + case "garage": + accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.TargetDoorState) .on("set", (value, callback) => { - if (accessory.getService("Valve " + v).getCharacteristic(Characteristic.InUse).value) { - accessory.getService("Valve " + v).updateCharacteristic(Characteristic.RemainingDuration, value); - clearTimeout(accessory.getService("Valve " + v).timer); - accessory.getService("Valve " + v).timer = setTimeout(() => { - accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); - }, (value * 1000)); - } - callback(); + accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.TargetDoorState).value !== value ? + this.internalGarageUpdate(accessory, value, callback) : + callback(); }); - }); - break; - case "blind": - accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.TargetPosition) - .setProps({ - minStep: 100 - }) - .on("set", (value, callback) => { - accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.TargetPosition).value !== value ? - this.internalBlindUpdate(accessory, value, callback) : - callback(); - }); - break; - case "garage": - accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.TargetDoorState) - .on("set", (value, callback) => { - accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.TargetDoorState).value !== value ? - this.internalGarageUpdate(accessory, value, callback) : - callback(); - }); - break; - case "fan": - accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active) - .on("set", (value, callback) => { - accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active).value !== value ? - this.internalFanUpdate(accessory, "power", value, callback) : - callback(); - }); - accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.RotationSpeed) - .setProps({ - minStep: 33 - }) - .on("set", (value, callback) => { - accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.RotationSpeed).value !== value ? - this.internalFanUpdate(accessory, "speed", value, callback) : - callback(); - }); - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => { - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value !== value ? - this.internalFanUpdate(accessory, "light", value, callback) : - callback(); - }); - break; - case "thermostat": - accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => { - accessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value !== value ? - this.internalThermostatUpdate(accessory, value, callback) : - callback(); - }); - break; - case "outlet": - accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => { - accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value !== value ? - this.internalOutletUpdate(accessory, value, callback) : - callback(); - }); - break; - case "usb": - accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => { - accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value !== value ? - this.internalUSBUpdate(accessory, value, callback) : - callback(); - }); - break; - case "scm": - accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => { - accessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value !== value ? - this.internalSCMUpdate(accessory, value, callback) : - callback(); - }); - break; - case "light": - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => { - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value !== value ? - this.internalLightbulbUpdate(accessory, value, callback) : - callback(); - }); - if (constants.devicesBrightable.includes(accessory.context.eweUIID)) { - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Brightness) + break; + case "fan": + accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active) .on("set", (value, callback) => { - if (value > 0) { - if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { - this.internalLightbulbUpdate(accessory, true, callback); - } - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Brightness).value !== value ? - this.internalBrightnessUpdate(accessory, value, callback) : - callback(); - } else { - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value ? - this.internalLightbulbUpdate(accessory, false, callback) : - callback(); - } + accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active).value !== value ? + this.internalFanUpdate(accessory, "power", value, callback) : + callback(); }); - } else if (constants.devicesColourable.includes(accessory.context.eweUIID)) { - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Brightness) + accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.RotationSpeed) + .setProps({ + minStep: 33 + }) .on("set", (value, callback) => { - if (value > 0) { - if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { - this.internalLightbulbUpdate(accessory, true, callback); - } - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Brightness).value !== value ? - this.internalHSBUpdate(accessory, "bri", value, callback) : - callback(); - } else { - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value ? - this.internalLightbulbUpdate(accessory, false, callback) : - callback(); - } + accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.RotationSpeed).value !== value ? + this.internalFanUpdate(accessory, "speed", value, callback) : + callback(); }); - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Hue) + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) .on("set", (value, callback) => { - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Hue).value !== value ? - this.internalHSBUpdate(accessory, "hue", value, callback) : + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value !== value ? + this.internalFanUpdate(accessory, "light", value, callback) : callback(); }); - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Saturation) + break; + case "thermostat": + accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) .on("set", (value, callback) => { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Saturation, value); - callback(); + accessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value !== value ? + this.internalThermostatUpdate(accessory, value, callback) : + callback(); }); - } - break; - case "switch": - accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => { - accessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value !== value ? - this.internalSwitchUpdate(accessory, value, callback) : - callback(); - }); - break; - case "rf_sub": - if (accessory.context.sensorType === "button") { + break; + case "outlet": + accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) + .on("set", (value, callback) => { + accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value !== value ? + this.internalOutletUpdate(accessory, value, callback) : + callback(); + }); + break; + case "usb": + accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) + .on("set", (value, callback) => { + accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value !== value ? + this.internalUSBUpdate(accessory, value, callback) : + callback(); + }); + break; + case "scm": accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) .on("set", (value, callback) => { - this.internalRFDeviceUpdate(accessory, true, callback); + accessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value !== value ? + this.internalSCMUpdate(accessory, value, callback) : + callback(); }); - } - break; + break; + case "light": + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) + .on("set", (value, callback) => { + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value !== value ? + this.internalLightbulbUpdate(accessory, value, callback) : + callback(); + }); + if (cns.devicesBrightable.includes(accessory.context.eweUIID)) { + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Brightness) + .on("set", (value, callback) => { + if (value > 0) { + if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + this.internalLightbulbUpdate(accessory, true, callback); + } + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Brightness).value !== value ? + this.internalBrightnessUpdate(accessory, value, callback) : + callback(); + } else { + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value ? + this.internalLightbulbUpdate(accessory, false, callback) : + callback(); + } + }); + } else if (cns.devicesColourable.includes(accessory.context.eweUIID)) { + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Brightness) + .on("set", (value, callback) => { + if (value > 0) { + if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + this.internalLightbulbUpdate(accessory, true, callback); + } + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Brightness).value !== value ? + this.internalHSBUpdate(accessory, "bri", value, callback) : + callback(); + } else { + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value ? + this.internalLightbulbUpdate(accessory, false, callback) : + callback(); + } + }); + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Hue) + .on("set", (value, callback) => { + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Hue).value !== value ? + this.internalHSBUpdate(accessory, "hue", value, callback) : + callback(); + }); + accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Saturation) + .on("set", (value, callback) => { + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Saturation, value); + callback(); + }); + } + break; + case "switch": + accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) + .on("set", (value, callback) => { + accessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value !== value ? + this.internalSwitchUpdate(accessory, value, callback) : + callback(); + }); + break; + case "rf_sub": + accessory.context.rfChls = accessory.context.rfChls || {}; + if (accessory.context.sensorType === "button") { + Object.entries(accessory.context.rfChls).forEach(([k, v]) => { + accessory.getService(v).updateCharacteristic(Characteristic.On, false); + accessory.getService(v).getCharacteristic(Characteristic.On) + .on("set", (value, callback) => { + value ? + this.internalRFDeviceUpdate(accessory, k, callback) : + callback(); + }); + }); + } + break; } accessory.context.reachableWAN = true; accessory.context.reachableLAN = true; this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - this.api.updatePlatformAccessories(constants.packageName, "eWeLink", [accessory]); - } catch (e) { - this.log.warn("[%s] could not be refreshed - [%s].", accessory.displayName, e); + } catch (err) { + this.log.warn("[%s] could not be refreshed - [%s].", accessory.displayName, err); } } refreshAccessory(accessory, newParams) { switch (accessory.context.type) { - case "valve": - if (Array.isArray(newParams.switches)) { - this.externalValveUpdate(accessory, newParams); - } - return true; - case "blind": - if (Array.isArray(newParams.switches)) { - this.externalBlindUpdate(accessory, newParams); - } - return true; - case "garage": - if (newParams.hasOwnProperty("switch") || Array.isArray(newParams.switches)) { - this.externalGarageUpdate(accessory, newParams); - } - return true; - case "sensor": - if (newParams.hasOwnProperty("switch")) { - this.externalSensorUpdate(accessory, newParams); - } - return true; - case "fan": - if (Array.isArray(newParams.switches) || (newParams.hasOwnProperty("light") && newParams.hasOwnProperty("fan") && newParams.hasOwnProperty("speed"))) { - this.externalFanUpdate(accessory, newParams); - } - return true; - case "thermostat": - if (newParams.hasOwnProperty("currentTemperature") || newParams.hasOwnProperty("currentHumidity") || newParams.hasOwnProperty("switch") || newParams.hasOwnProperty("masterSwitch")) { - this.externalThermostatUpdate(accessory, newParams); - } - return true; - case "outlet": - if (newParams.hasOwnProperty("switch")) { - this.externalOutletUpdate(accessory, newParams); - } - return true; - case "usb": - if (Array.isArray(newParams.switches)) { - this.externalUSBUpdate(accessory, newParams); - } - return true; - case "scm": - if (Array.isArray(newParams.switches)) { - this.externalSCMUpdate(accessory, newParams); - } - return true; - case "light": - if (constants.devicesSingleSwitch.includes(accessory.context.eweUIID) && constants.devicesSingleSwitchLight.includes(accessory.context.eweModel)) { - if (newParams.hasOwnProperty("switch") || newParams.hasOwnProperty("state") || newParams.hasOwnProperty("bright") || newParams.hasOwnProperty("colorR") || newParams.hasOwnProperty("brightness") || newParams.hasOwnProperty("channel0") || newParams.hasOwnProperty("channel2") || newParams.hasOwnProperty("zyx_mode")) { - this.externalSingleLightUpdate(accessory, newParams); + case "valve": + if (Array.isArray(newParams.switches)) { + this.externalValveUpdate(accessory, newParams); } - } else if (constants.devicesMultiSwitch.includes(accessory.context.eweUIID) && constants.devicesMultiSwitchLight.includes(accessory.context.eweModel)) { + return true; + case "blind": if (Array.isArray(newParams.switches)) { - this.externalMultiLightUpdate(accessory, newParams); + this.externalBlindUpdate(accessory, newParams); } - } - return true; - case "switch": - if (constants.devicesSingleSwitch.includes(accessory.context.eweUIID)) { + return true; + case "garage": + if (newParams.hasOwnProperty("switch") || Array.isArray(newParams.switches)) { + this.externalGarageUpdate(accessory, newParams); + } + return true; + case "sensor": if (newParams.hasOwnProperty("switch")) { - this.externalSingleSwitchUpdate(accessory, newParams); + this.externalSensorUpdate(accessory, newParams); + } + return true; + case "fan": + if (Array.isArray(newParams.switches) || (newParams.hasOwnProperty("light") && newParams.hasOwnProperty("fan") && newParams.hasOwnProperty("speed"))) { + this.externalFanUpdate(accessory, newParams); + } + return true; + case "thermostat": + if (newParams.hasOwnProperty("currentTemperature") || newParams.hasOwnProperty("currentHumidity") || newParams.hasOwnProperty("switch") || newParams.hasOwnProperty("masterSwitch")) { + this.externalThermostatUpdate(accessory, newParams); + } + return true; + case "outlet": + if (newParams.hasOwnProperty("switch")) { + this.externalOutletUpdate(accessory, newParams); + } + return true; + case "usb": + if (Array.isArray(newParams.switches)) { + this.externalUSBUpdate(accessory, newParams); } - } else if (constants.devicesMultiSwitch.includes(accessory.context.eweUIID)) { + return true; + case "scm": if (Array.isArray(newParams.switches)) { - this.externalMultiSwitchUpdate(accessory, newParams); + this.externalSCMUpdate(accessory, newParams); } - } - return true; - case "rf_pri": - this.externalRFDeviceUpdate(accessory, newParams); - return true; - case "rf_sub": - case "zb_pri": - return true; - case "zb_sub": - this.externalZBDeviceUpdate(accessory, newParams); - return true; - default: - return false; + return true; + case "light": + if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID) && cns.devicesSingleSwitchLight.includes(accessory.context.eweModel)) { + if (newParams.hasOwnProperty("switch") || newParams.hasOwnProperty("state") || newParams.hasOwnProperty("bright") || newParams.hasOwnProperty("colorR") || newParams.hasOwnProperty("brightness") || newParams.hasOwnProperty("channel0") || newParams.hasOwnProperty("channel2") || newParams.hasOwnProperty("zyx_mode")) { + this.externalSingleLightUpdate(accessory, newParams); + } + } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID) && cns.devicesMultiSwitchLight.includes(accessory.context.eweModel)) { + if (Array.isArray(newParams.switches)) { + this.externalMultiLightUpdate(accessory, newParams); + } + } + return true; + case "switch": + if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID)) { + if (newParams.hasOwnProperty("switch")) { + this.externalSingleSwitchUpdate(accessory, newParams); + } + } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID)) { + if (Array.isArray(newParams.switches)) { + this.externalMultiSwitchUpdate(accessory, newParams); + } + } + return true; + case "rf_pri": + this.externalRFDeviceUpdate(accessory, newParams); + return true; + case "rf_sub": + case "zb_pri": + return true; + case "zb_sub": + this.externalZBDeviceUpdate(accessory, newParams); + return true; + default: + return false; } } removeAccessory(accessory) { try { this.devicesInHB.delete(accessory.context.hbDeviceId); - this.api.unregisterPlatformAccessories(constants.packageName, "eWeLink", [accessory]); - this.log("[%s] will be removed from Homebridge.", accessory.displayName); - } catch (e) { - this.log.warn("[%s] needed to be removed but couldn't - [%s].", accessory.displayName, e); - } - } - removeAllAccessories() { - try { - this.log.warn("[0] primary devices were loaded from your eWeLink account so any eWeLink devices in the Homebridge cache will be removed. This plugin will not load as there is no reason to continue."); - this.api.unregisterPlatformAccessories(constants.packageName, "eWeLink", Array.from(this.devicesInHB.values())); - this.devicesInHB.clear(); - } catch (e) { - this.log.warn("Accessories could not be removed from the Homebridge cache - [%s].", e); + this.api.unregisterPlatformAccessories(cns.packageName, "eWeLink", [accessory]); + this.log("[%s] has been removed from Homebridge.", accessory.displayName); + } catch (err) { + this.log.warn("[%s] needed to be removed but couldn't - [%s].", accessory.displayName, err); } } sendDeviceUpdate(accessory, params, callback) { @@ -697,95 +668,70 @@ class eWeLink { deviceid: accessory.context.eweDeviceId, params }; - switch (this.mode) { - case "lan": - default: - this.lanClient.sendUpdate(payload) - .then(res => { - callback(); - }) - .catch(err => { - if (accessory.context.reachableWAN) { - if (this.debug) { - this.log.warn("[%s] LAN update failed as %s. Trying web socket update.", accessory.displayName, err); - } - this.wsClient.sendUpdate(payload, callback); - setTimeout(() => { - this.wsClient.requestUpdate(accessory); - }, 2500); - } else { - this.log.error("[%s] could not be updated as it appears to be offline.", accessory.displayName); - callback("Device has failed to update"); + this.lanClient.sendUpdate(payload) + .then(res => { + callback(); + }) + .catch(err => { + if (accessory.context.reachableWAN) { + if (this.config.debug) { + this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); } - }); - break; - case "ws": - this.wsClient.sendUpdate(payload, callback); - setTimeout(() => { - this.wsClient.requestUpdate(accessory); - }, 2500); - break; - } + this.wsClient.sendUpdate(payload, callback); + setTimeout(() => { + this.wsClient.requestUpdate(accessory); + }, 3000); + } else { + this.log.error("[%s] could not be updated as it appears to be offline.", accessory.displayName); + callback("Device has failed to update"); + } + }); } receiveDeviceUpdate(device) { - let accessory; + let accessory, source = device.params.updateSource === "ws" ? "WS" : "LAN"; switch (device.action) { - case "sysmsg": - if (this.devicesInHB.has(device.deviceid + "SWX") || this.devicesInHB.has(device.deviceid + "SW0")) { - accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0"); - try { - if (accessory.context.reachableWAN !== device.params.online) { + case "sysmsg": + if ((accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0"))) { + let isX = accessory.context.hbDeviceId.substr(-1) === "X"; + if (source === "ws" && accessory.context.reachableWAN !== device.params.online) { accessory.context.reachableWAN = device.params.online; this.log("[%s] has been reported [%s].", accessory.displayName, accessory.context.reachableWAN ? "online" : "offline"); this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - this.api.updatePlatformAccessories(constants.packageName, "eWeLink", [accessory]); if (accessory.context.reachableWAN) { this.wsClient.requestUpdate(accessory); } } - } catch (e) { - this.log.warn("[%s] online/offline status could not be updated - [%s].", accessory.displayName, e); - } - if (this.devicesInHB.has(device.deviceid + "SW0")) { - let oAccessory; - for (let i = 1; i <= accessory.context.channelCount; i++) { - try { + if (!isX) { + for (let i = 1; i <= accessory.context.channelCount; i++) { if (this.devicesInHB.has(device.deviceid + "SW" + i)) { - oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); + let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); oAccessory.context.reachableWAN = device.params.online; this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); - this.api.updatePlatformAccessories(constants.packageName, "eWeLink", [oAccessory]); } - } catch (e) { - this.log.warn("[%s] online/offline status could not be updated - [%s].", oAccessory.displayName, e); } } } - } - break; - case "update": - let source = device.params.updateSource === "ws" ? "WS" : "LAN"; - if (this.devicesInHB.has(device.deviceid + "SWX") || this.devicesInHB.has(device.deviceid + "SW0")) { - accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0"); - if (source === "ws" && !accessory.context.reachableWAN) { - accessory.context.reachableWAN = true; - } - if (source === "lan" && !accessory.context.reachableLAN) { - accessory.context.reachableLAN = true; - } - if (this.debug) { - this.log("[%s] externally updated from above %s message and will be refreshed.", accessory.displayName, source); - } - if (this.refreshAccessory(accessory, device.params)) { - return; + break; + case "update": + if ((accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0"))) { + if (source === "ws" && !accessory.context.reachableWAN) { + accessory.context.reachableWAN = true; + } + if (source === "lan" && !accessory.context.reachableLAN) { + accessory.context.reachableLAN = true; + } + if (this.config.debug) { + this.log("[%s] externally updated from above %s message and will be refreshed.", accessory.displayName, source); + } + if (!this.refreshAccessory(accessory, device.params)) { + this.log.warn("[%s] cannot be refreshed. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.). [debug:%s:%s]", accessory.displayName, accessory.context.type, accessory.context.channelCount); + } + } else { + if (!(this.config.hideDevFromHB || "").includes(device.deviceid)) { + this.log.warn("[%s] Accessory received via %s update does not exist in Homebridge. If it's a new accessory please restart Homebridge so it is added.", device.deviceid, source); + } } - this.log.warn("[%s] cannot be refreshed. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.). Debugging: [%s:%s:%s]", accessory.displayName, "refresh", accessory.context.type, accessory.context.channelCount); - } else if (this.customHideDvceFromHB.includes(device.deviceid)) { - this.log.warn("[%s] %s update is for hidden accessory.", device.deviceid, source); - } else { - this.log.warn("[%s] Accessory received via %s update does not exist in Homebridge. If it's a new accessory please restart Homebridge so it is added.", device.deviceid, source); - } - break; + break; } } internalValveUpdate(accessory, valve, value, callback) { @@ -798,30 +744,30 @@ class eWeLink { .updateCharacteristic(Characteristic.Active, value) .updateCharacteristic(Characteristic.InUse, value); switch (value) { - case 0: - accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, 0); - clearTimeout(accessory.getService(valve).timer); - break; - case 1: - let timer = accessory.getService(valve).getCharacteristic(Characteristic.SetDuration).value; - accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, timer); - accessory.getService(valve).timer = setTimeout(() => { - accessory.getService(valve).setCharacteristic(Characteristic.Active, 0); - }, (timer * 1000)); - break; + case 0: + accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, 0); + clearTimeout(accessory.getService(valve).timer); + break; + case 1: + let timer = accessory.getService(valve).getCharacteristic(Characteristic.SetDuration).value; + accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, timer); + accessory.getService(valve).timer = setTimeout(() => { + accessory.getService(valve).setCharacteristic(Characteristic.Active, 0); + }, (timer * 1000)); + break; } params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; switch (valve) { - case "Valve A": - params.switches[0].switch = value ? "on" : "off"; - params.switches[1].switch = accessory.getService("Valve B").getCharacteristic(Characteristic.Active).value ? "on" : "off"; - break; - case "Valve B": - params.switches[0].switch = accessory.getService("Valve A").getCharacteristic(Characteristic.Active).value ? "on" : "off"; - params.switches[1].switch = value ? "on" : "off"; - break; - default: - throw "unknown valve [" + valve + "]"; + case "Valve A": + params.switches[0].switch = value ? "on" : "off"; + params.switches[1].switch = accessory.getService("Valve B").getCharacteristic(Characteristic.Active).value ? "on" : "off"; + break; + case "Valve B": + params.switches[0].switch = accessory.getService("Valve A").getCharacteristic(Characteristic.Active).value ? "on" : "off"; + params.switches[1].switch = value ? "on" : "off"; + break; + default: + throw "unknown valve [" + valve + "]"; } params.switches[2].switch = "off"; params.switches[3].switch = "off"; @@ -855,16 +801,16 @@ class eWeLink { return; } switch (blindConfig.setup) { - case "oneSwitch": - params.switch = "on"; - break; - case "twoSwitch": - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = value === 100 ? "on" : "off"; - params.switches[1].switch = value === 0 ? "on" : "off"; - break; + case "oneSwitch": + params.switch = "on"; + break; + case "twoSwitch": + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = value === 100 ? "on" : "off"; + params.switches[1].switch = value === 0 ? "on" : "off"; + break; } - this.sendDeviceUpdate(accessory, params, function () { + this.sendDeviceUpdate(accessory, params, function() { return; }); accessory.getService(Service.WindowCovering) @@ -873,15 +819,15 @@ class eWeLink { if (!blindConfig.inched || blindConfig.inched === "false") { setTimeout(() => { switch (blindConfig.setup) { - case "oneSwitch": - params.switch = "off"; - break; - case "twoSwitch": - params.switches[0].switch = "off"; - params.switches[1].switch = "off"; - break; + case "oneSwitch": + params.switch = "off"; + break; + case "twoSwitch": + params.switches[0].switch = "off"; + params.switches[1].switch = "off"; + break; } - this.sendDeviceUpdate(accessory, params, function () { + this.sendDeviceUpdate(accessory, params, function() { return; }); }, 500); @@ -928,16 +874,16 @@ class eWeLink { return; } switch (garageConfig.setup) { - case "oneSwitch": - params.switch = "on"; - break; - case "twoSwitch": - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = value === 0 ? "on" : "off"; - params.switches[1].switch = value === 1 ? "on" : "off"; - break; + case "oneSwitch": + params.switch = "on"; + break; + case "twoSwitch": + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = value === 0 ? "on" : "off"; + params.switches[1].switch = value === 1 ? "on" : "off"; + break; } - this.sendDeviceUpdate(accessory, params, function () { + this.sendDeviceUpdate(accessory, params, function() { return; }); accessory.getService(Service.GarageDoorOpener) @@ -946,15 +892,15 @@ class eWeLink { if (!garageConfig.inched || garageConfig.inched === "false") { setTimeout(() => { switch (garageConfig.setup) { - case "oneSwitch": - params.switch = "off"; - break; - case "twoSwitch": - params.switches[0].switch = "off"; - params.switches[1].switch = "off"; - break; + case "oneSwitch": + params.switch = "off"; + break; + case "twoSwitch": + params.switches[0].switch = "off"; + params.switches[1].switch = "off"; + break; } - this.sendDeviceUpdate(accessory, params, function () { + this.sendDeviceUpdate(accessory, params, function() { return; }); }, 500); @@ -981,21 +927,21 @@ class eWeLink { } let newPower, newSpeed, newLight; switch (type) { - case "power": - newPower = value; - newSpeed = value ? 33 : 0; - newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; - break; - case "speed": - newPower = value >= 33 ? 1 : 0; - newSpeed = value; - newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; - break; - case "light": - newPower = accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active).value; - newSpeed = accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.RotationSpeed).value; - newLight = value; - break; + case "power": + newPower = value; + newSpeed = value ? 33 : 0; + newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; + break; + case "speed": + newPower = value >= 33 ? 1 : 0; + newSpeed = value; + newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; + break; + case "light": + newPower = accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active).value; + newSpeed = accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.RotationSpeed).value; + newLight = value; + break; } accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, newLight); accessory.getService(Service.Fanv2) @@ -1008,7 +954,7 @@ class eWeLink { params.switches[1].switch = (newPower === 1 && newSpeed >= 33) ? "on" : "off"; params.switches[2].switch = (newPower === 1 && newSpeed >= 66 && newSpeed < 99) ? "on" : "off"; params.switches[3].switch = (newPower === 1 && newSpeed >= 99) ? "on" : "off"; - if (this.debug) { + if (this.config.debug) { this.log.warn("Fan Update - setting " + type + " to " + value); this.log("[%s] new stats: power [%s], speed [%s%], light [%s].", accessory.displayName, newPower, newSpeed, newLight); } @@ -1028,7 +974,7 @@ class eWeLink { switch: value ? "on" : "off", mainSwitch: value ? "on" : "off" }; - if (this.debug) { + if (this.config.debug) { this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); @@ -1047,7 +993,7 @@ class eWeLink { let params = { switch: value ? "on" : "off" }; - if (this.debug) { + if (this.config.debug) { this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); } accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); @@ -1065,7 +1011,7 @@ class eWeLink { switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches }; params.switches[0].switch = value ? "on" : "off"; - if (this.debug) { + if (this.config.debug) { this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); } accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); @@ -1083,7 +1029,7 @@ class eWeLink { switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches }; params.switches[0].switch = value ? "on" : "off"; - if (this.debug) { + if (this.config.debug) { this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); } accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); @@ -1099,62 +1045,62 @@ class eWeLink { } let oAccessory, params = {}; switch (accessory.context.switchNumber) { - case "X": - if (accessory.context.eweUIID === 22) { //*** B1 ***\\ - params.state = value ? "on" : "off"; - } else { - params.switch = value ? "on" : "off"; - } - if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); - break; - case "0": - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = value ? "on" : "off"; - params.switches[1].switch = value ? "on" : "off"; - params.switches[2].switch = value ? "on" : "off"; - params.switches[3].switch = value ? "on" : "off"; - if (this.debug) { - this.log("[%s] updating to turn group [%s].", accessory.displayName, value ? "on" : "off"); - } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); - for (let i = 1; i <= 4; i++) { - if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); - oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + case "X": + if (accessory.context.eweUIID === 22) { //*** B1 ***\\ + params.state = value ? "on" : "off"; + } else { + params.switch = value ? "on" : "off"; } - } - break; - case "1": - case "2": - case "3": - case "4": - if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); - let tAccessory, - masterState = "off"; - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; - for (let i = 1; i <= 4; i++) { - if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - i === parseInt(accessory.context.switchNumber) ? - params.switches[i - 1].switch = value ? "on" : "off" : - params.switches[i - 1].switch = tAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value ? "on" : "off"; - if (tAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { - masterState = "on"; + if (this.config.debug) { + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + break; + case "0": + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = value ? "on" : "off"; + params.switches[1].switch = value ? "on" : "off"; + params.switches[2].switch = value ? "on" : "off"; + params.switches[3].switch = value ? "on" : "off"; + if (this.config.debug) { + this.log("[%s] updating to turn group [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + for (let i = 1; i <= 4; i++) { + if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); + oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); } - } else { - params.switches[i - 1].switch = "off"; } - } - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, masterState === "on"); - break; - default: - throw "unknown switch number [" + accessory.context.switchNumber + "]"; + break; + case "1": + case "2": + case "3": + case "4": + if (this.config.debug) { + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + let tAccessory, + masterState = "off"; + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + for (let i = 1; i <= 4; i++) { + if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + i === parseInt(accessory.context.switchNumber) ? + params.switches[i - 1].switch = value ? "on" : "off" : + params.switches[i - 1].switch = tAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value ? "on" : "off"; + if (tAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + masterState = "on"; + } + } else { + params.switches[i - 1].switch = "off"; + } + } + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); + oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, masterState === "on"); + break; + default: + throw "unknown switch number [" + accessory.context.switchNumber + "]"; } this.sendDeviceUpdate(accessory, params, callback); } catch (err) { @@ -1177,19 +1123,19 @@ class eWeLink { params.switch = "on"; } switch (accessory.context.eweUIID) { - case 36: //*** KING-M4 ***\\ - params.bright = Math.round(value * 9 / 10 + 10); - break; - case 44: //*** D1 ***\\ - params.brightness = value; - params.mode = 0; - break; - default: - throw "unknown device UIID"; + case 36: //*** KING-M4 ***\\ + params.bright = Math.round(value * 9 / 10 + 10); + break; + case 44: //*** D1 ***\\ + params.brightness = value; + params.mode = 0; + break; + default: + throw "unknown device UIID"; } accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, value); } - if (this.debug) { + if (this.config.debug) { this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); } setTimeout(() => { @@ -1211,64 +1157,64 @@ class eWeLink { curHue = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Hue).value, curSat = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Saturation).value; switch (type) { - case "hue": - newRGB = convert.hsv.rgb(value, curSat, 100); - switch (accessory.context.eweUIID) { - case 22: //*** B1 ***\\ - params = { - zyx_mode: 2, - type: "middle", - channel0: "0", - channel1: "0", - channel2: newRGB[0].toString(), - channel3: newRGB[1].toString(), - channel4: newRGB[2].toString() - }; + case "hue": + newRGB = convert.hsv.rgb(value, curSat, 100); + switch (accessory.context.eweUIID) { + case 22: //*** B1 ***\\ + params = { + zyx_mode: 2, + type: "middle", + channel0: "0", + channel1: "0", + channel2: newRGB[0].toString(), + channel3: newRGB[1].toString(), + channel4: newRGB[2].toString() + }; + break; + case 59: //*** L1 ***\\ + params = { + mode: 1, + colorR: newRGB[0], + colorG: newRGB[1], + colorB: newRGB[2] + }; + break; + default: + throw "unknown device UIID"; + } + if (this.config.debug) { + this.log("[%s] updating hue to [%s°].", accessory.displayName, value); + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Hue, value); break; - case 59: //*** L1 ***\\ - params = { - mode: 1, - colorR: newRGB[0], - colorG: newRGB[1], - colorB: newRGB[2] - }; + case "bri": + switch (accessory.context.eweUIID) { + case 22: //*** B1 ***\\ + newRGB = convert.hsv.rgb(curHue, curSat, value); + params = { + zyx_mode: 2, + type: "middle", + channel0: "0", + channel1: "0", + channel2: newRGB[0].toString(), + channel3: newRGB[1].toString(), + channel4: newRGB[2].toString() + }; + break; + case 59: //*** L1 ***\\ + params = { + mode: 1, + bright: value + }; + break; + } + if (this.config.debug) { + this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, value); break; default: throw "unknown device UIID"; - } - if (this.debug) { - this.log("[%s] updating hue to [%s°].", accessory.displayName, value); - } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Hue, value); - break; - case "bri": - switch (accessory.context.eweUIID) { - case 22: //*** B1 ***\\ - newRGB = convert.hsv.rgb(curHue, curSat, value); - params = { - zyx_mode: 2, - type: "middle", - channel0: "0", - channel1: "0", - channel2: newRGB[0].toString(), - channel3: newRGB[1].toString(), - channel4: newRGB[2].toString() - }; - break; - case 59: //*** L1 ***\\ - params = { - mode: 1, - bright: value - }; - break; - } - if (this.debug) { - this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); - } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, value); - break; - default: - throw "unknown device UIID"; } setTimeout(() => { this.sendDeviceUpdate(accessory, params, callback); @@ -1286,58 +1232,58 @@ class eWeLink { } let oAccessory, params = {}; switch (accessory.context.switchNumber) { - case "X": - params.switch = value ? "on" : "off"; - if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); - break; - case "0": - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = value ? "on" : "off"; - params.switches[1].switch = value ? "on" : "off"; - params.switches[2].switch = value ? "on" : "off"; - params.switches[3].switch = value ? "on" : "off"; - if (this.debug) { - this.log("[%s] updating to turn group [%s].", accessory.displayName, value ? "on" : "off"); - } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); - for (let i = 1; i <= 4; i++) { - if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); - oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + case "X": + params.switch = value ? "on" : "off"; + if (this.config.debug) { + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } - } - break; - case "1": - case "2": - case "3": - case "4": - if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); - let tAccessory, - masterState = "off"; - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; - for (let i = 1; i <= 4; i++) { - if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - i === parseInt(accessory.context.switchNumber) ? - params.switches[i - 1].switch = value ? "on" : "off" : - params.switches[i - 1].switch = tAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value ? "on" : "off"; - if (tAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value) { - masterState = "on"; + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + break; + case "0": + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = value ? "on" : "off"; + params.switches[1].switch = value ? "on" : "off"; + params.switches[2].switch = value ? "on" : "off"; + params.switches[3].switch = value ? "on" : "off"; + if (this.config.debug) { + this.log("[%s] updating to turn group [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + for (let i = 1; i <= 4; i++) { + if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); + oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); } - } else { - params.switches[i - 1].switch = "off"; } - } - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, masterState === "on"); - break; - default: - throw "unknown switch number [" + accessory.context.switchNumber + "]"; + break; + case "1": + case "2": + case "3": + case "4": + if (this.config.debug) { + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + let tAccessory, + masterState = "off"; + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + for (let i = 1; i <= 4; i++) { + if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + i === parseInt(accessory.context.switchNumber) ? + params.switches[i - 1].switch = value ? "on" : "off" : + params.switches[i - 1].switch = tAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value ? "on" : "off"; + if (tAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value) { + masterState = "on"; + } + } else { + params.switches[i - 1].switch = "off"; + } + } + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); + oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, masterState === "on"); + break; + default: + throw "unknown switch number [" + accessory.context.switchNumber + "]"; } this.sendDeviceUpdate(accessory, params, callback); } catch (err) { @@ -1367,25 +1313,26 @@ class eWeLink { this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); } } - internalRFDeviceUpdate(accessory, value, callback) { + internalRFDeviceUpdate(accessory, rfChl, callback) { try { if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { throw "it is currently offline"; } + rfChl = parseInt(rfChl); let params = { cmd: "transmit", - rfChl: accessory.context.rfChl + rfChl }; - if (this.debug) { - this.log("[%s] mimicking RF button press.", accessory.displayName); + if (this.config.debug) { + this.log("[%s %s] mimicking RF button press.", accessory.displayName, accessory.context.rfChls[rfChl]); } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, true); + accessory.getService(accessory.context.rfChls[rfChl]).updateCharacteristic(Characteristic.On, true); this.sendDeviceUpdate(accessory, params, callback); setTimeout(() => { - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, false); - }, 500); + accessory.getService(accessory.context.rfChls[rfChl]).updateCharacteristic(Characteristic.On, false); + }, 3000); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + " " + name + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1400,20 +1347,20 @@ class eWeLink { throw "improper configuration"; } switch (blindConfig.setup) { - case "oneSwitch": - if (params.switch === "off") { - return; - } - nSte = accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.PositionState).value === 0 ? 1 : 0; - break; - case "twoSwitch": - if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { - return; - } - let switchUp = params.switches[0].switch === "on" ? -1 : 0, // matrix of numbers to get - switchDown = params.switches[1].switch === "on" ? 0 : 2; // ... the correct HomeKit value - nSte = switchUp + switchDown; - break; + case "oneSwitch": + if (params.switch === "off") { + return; + } + nSte = accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.PositionState).value === 0 ? 1 : 0; + break; + case "twoSwitch": + if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { + return; + } + let switchUp = params.switches[0].switch === "on" ? -1 : 0, // matrix of numbers to get + switchDown = params.switches[1].switch === "on" ? 0 : 2; // ... the correct HomeKit value + nSte = switchUp + switchDown; + break; } accessory.getService(Service.WindowCovering) .updateCharacteristic(Characteristic.PositionState, nSte) @@ -1437,18 +1384,18 @@ class eWeLink { throw "improper configuration"; } switch (garageConfig.setup) { - case "oneSwitch": - if (params.switch === "off" || garageConfig.sensorId) { - return; - } - nSte = [0, 2].includes(accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.CurrentDoorState).value) ? 3 : 2; - break; - case "twoSwitch": - if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { + case "oneSwitch": + if (params.switch === "off" || garageConfig.sensorId) { + return; + } + nSte = [0, 2].includes(accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.CurrentDoorState).value) ? 3 : 2; + break; + case "twoSwitch": + if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { + return; + } + // @TODO twoSwitch garage external update return; - } - // @TODO twoSwitch garage external update - return; } if (garageConfig.setup !== "oneSwitch" || !garageConfig.sensorId) { accessory.getService(Service.GarageDoorOpener) @@ -1474,22 +1421,22 @@ class eWeLink { if (group.sensorId === accessory.context.eweDeviceId && group.type === "garage") { if ((oAccessory = this.devicesInHB.get(group.deviceId + "SWX"))) { switch (newState) { - case 0: - oAccessory.getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.TargetDoorState, 1) - .updateCharacteristic(Characteristic.CurrentDoorState, 1); - this.log("[%s] updating to [closed] based on sensor.", oAccessory.displayName); - break; - case 1: - setTimeout(() => { + case 0: oAccessory.getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.TargetDoorState, 0) - .updateCharacteristic(Characteristic.CurrentDoorState, 0); - this.log("[%s] updating to [open] based on sensor.", oAccessory.displayName); - }, group.operationTime * 100); - break; - default: - throw "unknown sensor status received"; + .updateCharacteristic(Characteristic.TargetDoorState, 1) + .updateCharacteristic(Characteristic.CurrentDoorState, 1); + this.log("[%s] updating to [closed] based on sensor.", oAccessory.displayName); + break; + case 1: + setTimeout(() => { + oAccessory.getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.TargetDoorState, 0) + .updateCharacteristic(Characteristic.CurrentDoorState, 0); + this.log("[%s] updating to [open] based on sensor.", oAccessory.displayName); + }, group.operationTime * 100); + break; + default: + throw "unknown sensor status received"; } } } @@ -1504,21 +1451,21 @@ class eWeLink { if (Array.isArray(params.switches)) { light = params.switches[0].switch === "on"; switch (params.switches[1].switch+params.switches[2].switch+params.switches[3].switch) { - default: - status = 0; - speed = 0; - break; - case "onoffoff": - status = 1; - speed = 33; - break; - case "ononoff": - status = 1; - speed = 66; - break; - case "onoffon": - status = 1; - speed = 99; + default: + status = 0; + speed = 0; + break; + case "onoffoff": + status = 1; + speed = 33; + break; + case "ononoff": + status = 1; + speed = 66; + break; + case "onoffon": + status = 1; + speed = 99; } } else if (params.hasOwnProperty("light") && params.hasOwnProperty("fan") && params.hasOwnProperty("speed")) { light = params.light === "on"; @@ -1587,49 +1534,49 @@ class eWeLink { if (isOn) { accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, true); switch (accessory.context.eweUIID) { - case 36: // KING-M4 - if (params.hasOwnProperty("bright")) { - let nb = Math.round((params.bright - 10) * 10 / 9); // eWeLink scale is 10-100 and HomeKit scale is 0-100. - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, nb); - } - break; - case 44: // D1 - if (params.hasOwnProperty("brightness")) { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, params.brightness); - } - break; - case 22: // B1 - if (params.hasOwnProperty("zyx_mode")) { - mode = parseInt(params.zyx_mode); - } else if (params.hasOwnProperty("channel0") && (parseInt(params.channel0) + parseInt(params.channel1) > 0)) { - mode = 1; - } else { - mode = 2; - } - if (mode === 2) { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, true); - newColour = convert.rgb.hsv(parseInt(params.channel2), parseInt(params.channel3), parseInt(params.channel4)); - accessory.getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.Hue, newColour[0]) - .updateCharacteristic(Characteristic.Saturation, 100) - .updateCharacteristic(Characteristic.Brightness, 100); - } else if (mode === 1) { - throw "has been set to white mode which is not supported"; - } - break; - case 59: // L1 - if (params.hasOwnProperty("bright")) { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, params.bright); - } - if (params.hasOwnProperty("colorR")) { - newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB); - accessory.getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.Hue, newColour[0]) - .updateCharacteristic(Characteristic.Saturation, newColour[1]); - } - break; - default: - return; + case 36: // KING-M4 + if (params.hasOwnProperty("bright")) { + let nb = Math.round((params.bright - 10) * 10 / 9); // eWeLink scale is 10-100 and HomeKit scale is 0-100. + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, nb); + } + break; + case 44: // D1 + if (params.hasOwnProperty("brightness")) { + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, params.brightness); + } + break; + case 22: // B1 + if (params.hasOwnProperty("zyx_mode")) { + mode = parseInt(params.zyx_mode); + } else if (params.hasOwnProperty("channel0") && (parseInt(params.channel0) + parseInt(params.channel1) > 0)) { + mode = 1; + } else { + mode = 2; + } + if (mode === 2) { + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, true); + newColour = convert.rgb.hsv(parseInt(params.channel2), parseInt(params.channel3), parseInt(params.channel4)); + accessory.getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.Hue, newColour[0]) + .updateCharacteristic(Characteristic.Saturation, 100) + .updateCharacteristic(Characteristic.Brightness, 100); + } else if (mode === 1) { + throw "has been set to white mode which is not supported"; + } + break; + case 59: // L1 + if (params.hasOwnProperty("bright")) { + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, params.bright); + } + if (params.hasOwnProperty("colorR")) { + newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB); + accessory.getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.Hue, newColour[0]) + .updateCharacteristic(Characteristic.Saturation, newColour[1]); + } + break; + default: + return; } } else { accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, false); @@ -1683,95 +1630,86 @@ class eWeLink { } externalRFDeviceUpdate(accessory, params) { try { + if (params.updateSource === "http") { + return; + } let idToCheck = accessory.context.hbDeviceId.slice(0, -1), timeNow = new Date(); if (params.hasOwnProperty("cmd") && params.cmd === "transmit" && params.hasOwnProperty("rfChl")) { // RF Button let bAccessory; - if ((bAccessory = this.devicesInHB.get(idToCheck + (params.rfChl + 1)))) { - bAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, 1); + if ((bAccessory = this.devicesInHB.get(idToCheck + accessory.context.rfChlMap[params.rfChl]))) { + bAccessory.getService(bAccessory.context.rfChls[params.rfChl]).updateCharacteristic(Characteristic.On, 1); setTimeout(() => { - bAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, 0); - }, 500); + bAccessory.getService(bAccessory.context.rfChls[params.rfChl]).updateCharacteristic(Characteristic.On, 0); + }, 3000); } else { throw "rf button not found in Homebridge"; } - return; - } // else RF Sensor - for (let i = 1; i <= accessory.context.channelCount; i++) { - if (this.devicesInHB.has(idToCheck + i)) { - let oAccessory = this.devicesInHB.get(idToCheck + i); - if (params.hasOwnProperty("rfTrig" + (i - 1))) { - let timeOfMotion = new Date(params["rfTrig" + (i - 1)]), + } else if (params.hasOwnProperty("cmd") && params.cmd === "trigger") { // RF Sensor + let rfChan = Object.keys(params).filter(name => /rfTrig/.test(name)); + rfChan.forEach(chan => { + let chanNum = chan.substr(-1).toString(), + accessoryNum = accessory.context.rfChlMap[chanNum], + oAccessory; + if ((oAccessory = this.devicesInHB.get(idToCheck + accessoryNum))) { + let timeOfMotion = new Date(params[chan]), timeDifference = (timeNow.getTime() - timeOfMotion.getTime()) / 1000; - if (timeDifference < this.sensorTimeDifference) { + if (timeDifference < (this.config.sensorTimeDifference || 120)) { switch (oAccessory.context.sensorType) { - case "button": - break; - case "water": - oAccessory.getService(Service.LeakSensor).updateCharacteristic(Characteristic.LeakDetected, 1); - break; - case "fire": - case "smoke": - oAccessory.getService(Service.SmokeSensor).updateCharacteristic(Characteristic.SmokeDetected, 1); - break; - case "co": - oAccessory.getService(Service.CarbonMonoxideSensor).updateCharacteristic(Characteristic.CarbonMonoxideDetected, 1); - break; - case "co2": - oAccessory.getService(Service.CarbonDioxideSensor).updateCharacteristic(Characteristic.CarbonDioxideDetected, 1); - break; - case "contact": - oAccessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, 1); - break; - case "occupancy": - oAccessory.getService(Service.OccupancySensor).updateCharacteristic(Characteristic.OccupancyDetected, 1); - break; - case "motion": - default: - oAccessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, true); - break; + case "button": + break; + case "water": + oAccessory.getService(Service.LeakSensor).updateCharacteristic(Characteristic.LeakDetected, 1); + setTimeout(() => { + oAccessory.getService(Service.LeakSensor).updateCharacteristic(Characteristic.LeakDetected, 0); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + case "fire": + case "smoke": + oAccessory.getService(Service.SmokeSensor).updateCharacteristic(Characteristic.SmokeDetected, 1); + setTimeout(() => { + oAccessory.getService(Service.SmokeSensor).updateCharacteristic(Characteristic.SmokeDetected, 0); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + case "co": + oAccessory.getService(Service.CarbonMonoxideSensor).updateCharacteristic(Characteristic.CarbonMonoxideDetected, 1); + setTimeout(() => { + oAccessory.getService(Service.CarbonMonoxideSensor).updateCharacteristic(Characteristic.CarbonMonoxideDetected, 0); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + case "co2": + oAccessory.getService(Service.CarbonDioxideSensor).updateCharacteristic(Characteristic.CarbonDioxideDetected, 1); + setTimeout(() => { + oAccessory.getService(Service.CarbonDioxideSensor).updateCharacteristic(Characteristic.CarbonDioxideDetected, 0); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + case "contact": + oAccessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, 1); + setTimeout(() => { + oAccessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, 0); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + case "occupancy": + oAccessory.getService(Service.OccupancySensor).updateCharacteristic(Characteristic.OccupancyDetected, 1); + setTimeout(() => { + oAccessory.getService(Service.OccupancySensor).updateCharacteristic(Characteristic.OccupancyDetected, 0); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + case "motion": + default: + oAccessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, true); + setTimeout(() => { + oAccessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, false); + }, (this.config.sensorTimeLength || 2) * 1000); + break; } - if (this.debug) { + if (this.config.debug) { this.log("[%s] has detected [%s].", oAccessory.displayName, oAccessory.context.sensorType); } } } - } + }); } - setTimeout(() => { - for (let i = 1; i <= accessory.context.channelCount; i++) { - if (this.devicesInHB.has(idToCheck + i)) { - let oAccessory = this.devicesInHB.get(idToCheck + i); - switch (oAccessory.context.sensorType) { - case "button": - break; - case "water": - oAccessory.getService(Service.LeakSensor).updateCharacteristic(Characteristic.LeakDetected, 0); - break; - case "fire": - case "smoke": - oAccessory.getService(Service.SmokeSensor).updateCharacteristic(Characteristic.SmokeDetected, 0); - break; - case "co": - oAccessory.getService(Service.CarbonMonoxideSensor).updateCharacteristic(Characteristic.CarbonMonoxideDetected, 0); - break; - case "co2": - oAccessory.getService(Service.CarbonDioxideSensor).updateCharacteristic(Characteristic.CarbonDioxideDetected, 0); - break; - case "contact": - oAccessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, 0); - break; - case "occupancy": - oAccessory.getService(Service.OccupancySensor).updateCharacteristic(Characteristic.OccupancyDetected, 0); - break; - case "motion": - default: - oAccessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, false); - break; - } - } - } - }, this.sensorTimeLength * 1000); } catch (err) { this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); } @@ -1779,52 +1717,52 @@ class eWeLink { externalZBDeviceUpdate(accessory, params) { try { switch (accessory.context.eweUIID) { - case 1000: - if (params.hasOwnProperty("key")) { - if ([0, 1, 2].includes(params.key)) { - accessory.getService(Service.StatelessProgrammableSwitch).updateCharacteristic(Characteristic.ProgrammableSwitchEvent, params.key); //*** credit @tasict ***\\ - } else { - throw "unknown 'key' parameter received [" + params.key + "]"; + case 1000: + if (params.hasOwnProperty("key")) { + if ([0, 1, 2].includes(params.key)) { + accessory.getService(Service.StatelessProgrammableSwitch).updateCharacteristic(Characteristic.ProgrammableSwitchEvent, params.key); //*** credit @tasict ***\\ + } else { + throw "unknown 'key' parameter received [" + params.key + "]"; + } } - } - break; - case 1770: - if (params.hasOwnProperty("temperature")) { - let currentTemp = parseInt(params.temperature) / 100; - accessory.getService(Service.TemperatureSensor).updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); - } - if (params.hasOwnProperty("humidity")) { - let currentHumi = parseInt(params.humidity) / 100; - accessory.getService(Service.HumiditySensor).updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); - } - break; - case 2026: - if (params.hasOwnProperty("motion")) { - if ([0, 1].includes(params.lock)) { - accessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, params.motion); - } else { - throw "unknown 'motion' parameter received [" + params.motion + "]"; + break; + case 1770: + if (params.hasOwnProperty("temperature")) { + let currentTemp = parseInt(params.temperature) / 100; + accessory.getService(Service.TemperatureSensor).updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); } - } - break; - case 3026: - if (params.hasOwnProperty("lock")) { - if ([0, 1].includes(params.lock)) { - accessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, params.lock); - } else { - throw "unknown 'lock' parameter received [" + params.lock + "]"; + if (params.hasOwnProperty("humidity")) { + let currentHumi = parseInt(params.humidity) / 100; + accessory.getService(Service.HumiditySensor).updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); } - } - break; - default: - throw "unsupported zigbee device type"; + break; + case 2026: + if (params.hasOwnProperty("motion")) { + if ([0, 1].includes(params.lock)) { + accessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, params.motion); + } else { + throw "unknown 'motion' parameter received [" + params.motion + "]"; + } + } + break; + case 3026: + if (params.hasOwnProperty("lock")) { + if ([0, 1].includes(params.lock)) { + accessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, params.lock); + } else { + throw "unknown 'lock' parameter received [" + params.lock + "]"; + } + } + break; + default: + throw "unsupported zigbee device type"; } } catch (err) { this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); } } } -module.exports = function (homebridge) { +module.exports = function(homebridge) { Accessory = homebridge.platformAccessory; Service = homebridge.hap.Service; Characteristic = homebridge.hap.Characteristic; diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index f6c0c71d..f7701ed7 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -41,16 +41,16 @@ module.exports = class eWeLinkHTTP { let body = res.data; if (body.hasOwnProperty("error") && body.error === 10004 && body.hasOwnProperty("data") && body.data.hasOwnProperty("region")) { switch (body.data.region) { - case "eu": - case "us": - case "as": - this.httpHost = body.data.region + "-apia.coolkit.cc"; - break; - case "cn": - this.httpHost = "cn-apia.coolkit.cn"; - break; - default: - throw "No valid region received - [" + body.data.region + "]."; + case "eu": + case "us": + case "as": + this.httpHost = body.data.region + "-apia.coolkit.cc"; + break; + case "cn": + this.httpHost = "cn-apia.coolkit.cn"; + break; + default: + throw "No valid region received - [" + body.data.region + "]."; } if (this.debug) { this.log("New HTTP API host received [%s].", this.httpHost); @@ -82,16 +82,16 @@ module.exports = class eWeLinkHTTP { version: 8 }, dataToSign = []; - Object.keys(data).forEach(function (key) { + Object.keys(data).forEach(function(key) { dataToSign.push({ key: key, value: data[key] }); }); - dataToSign.sort(function (a, b) { + dataToSign.sort(function(a, b) { return a.key < b.key ? -1 : 1; }); - dataToSign = dataToSign.map(function (kv) { + dataToSign = dataToSign.map(function(kv) { return kv.key + "=" + kv.value; }).join("&"); dataToSign = crypto.createHmac("sha256", "6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM").update(dataToSign).digest("base64"); @@ -108,16 +108,16 @@ module.exports = class eWeLinkHTTP { throw "Server did not respond with a region.\n" + JSON.stringify(body, null, 2); } switch (body.region) { - case "eu": - case "us": - case "as": - this.httpHost = body.region + "-apia.coolkit.cc"; - break; - case "cn": - this.httpHost = "cn-apia.coolkit.cn"; - break; - default: - throw "No valid region received - [" + body.region + "]."; + case "eu": + case "us": + case "as": + this.httpHost = body.region + "-apia.coolkit.cc"; + break; + case "cn": + this.httpHost = "cn-apia.coolkit.cn"; + break; + default: + throw "No valid region received - [" + body.region + "]."; } if (this.debug) { this.log("HTTP API host received [%s].", this.httpHost); diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 9146dbe7..1032afa0 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -10,12 +10,13 @@ module.exports = class eWeLinkLAN { this.config = config; this.log = log; this.devices = devices; - let deviceMap = {}; + let deviceMap = new Map(); devices.forEach(device => { - deviceMap[device.deviceid] = { + deviceMap.set(device.deviceid, { apiKey: device.devicekey, - ip: false - }; + online: false, + ip: null + }); }); this.deviceMap = deviceMap; this.debug = this.config.debug || false; @@ -27,13 +28,22 @@ module.exports = class eWeLinkLAN { dns.discover({ name: "_ewelink._tcp.local" }).then(res => { + let onlineCount = 0; res.forEach(device => { - let a = device.fqdn.replace("._ewelink._tcp.local", "").replace("eWeLink_", ""); - if (this.deviceMap.hasOwnProperty(a)) { - this.deviceMap[a].ip = device.address; + let d, deviceId = device.fqdn.replace("._ewelink._tcp.local", "").replace("eWeLink_", ""); + if ((d = this.deviceMap.get(deviceId))) { + this.deviceMap.set(deviceId, { + apiKey: d.apiKey, + online: true, + ip: device.address + }); + onlineCount++; } }); - resolve(this.deviceMap); + resolve({ + map: this.deviceMap, + count: onlineCount + }); }).catch(err => { reject(err); }); @@ -100,7 +110,7 @@ module.exports = class eWeLinkLAN { } sendUpdate(json) { return new Promise((resolve, reject) => { - if (!this.deviceMap[json.deviceid].ip) { + if (!this.deviceMap.get(json.deviceid).online) { throw "device does not support LAN mode"; } let apiKey, suffix, params = {}; @@ -113,7 +123,7 @@ module.exports = class eWeLinkLAN { } else { throw "plugin does not support lan mode for this device yet - feel free to create a github issue"; } - if ((apiKey = this.deviceMap[json.deviceid].apiKey)) { + if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { let key = crypto.createHash('md5').update(Buffer.from(apiKey, 'utf8')).digest(), iv = crypto.randomBytes(16), enc = crypto.createCipheriv('aes-128-cbc', key, iv), @@ -133,18 +143,17 @@ module.exports = class eWeLinkLAN { } axios({ method: "post", - url: "http://" + this.deviceMap[json.deviceid].ip + ":8081/zeroconf/" + suffix, + url: "http://" + this.deviceMap.get(json.deviceid).ip + ":8081/zeroconf/" + suffix, headers: { Accept: "application/json", - "Content-Type": "application/json;charset=UTF-8" + "Content-Type": "application/json" }, data }).then(res => { - let body = res.data; - if (body.hasOwnProperty("error") && body.error === 0) { + if (res.data.hasOwnProperty("error") && res.data.error === 0) { resolve(); } - throw body; + throw res.data; }).catch(err => { reject(err); }); @@ -154,4 +163,8 @@ module.exports = class eWeLinkLAN { receiveUpdate(f) { this.emitter.addListener("update", f); } + closeConnection() { + dns.stopMonitoring(); + this.log("LAN monitoring stopped as part of Homebridge shutdown."); + } }; \ No newline at end of file diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 23f690d7..95aea46d 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -97,36 +97,12 @@ module.exports = class eWeLinkWS { }, (device.config.hbInterval + 7) * 1000); } else if (device.hasOwnProperty("action")) { switch (device.action) { - case "sysmsg": - device.params.updateSource = "ws"; - let returnTemplate = { - deviceid: device.deviceid, - action: "sysmsg", - params: device.params - }; - if (this.debugReqRes) { - let msg = JSON.stringify(returnTemplate, null, 2).replace(device.deviceid, "**hidden**"); - this.log("WS message received.\n%s", msg); - } else if (this.debug) { - this.log("WS message received."); - } - this.emitter.emit("update", returnTemplate); - break; - case "update": - let params = device.params; - for (let param in params) { - if (params.hasOwnProperty(param)) { - if (!constants.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { - delete params[param]; - } - } - } - if (Object.keys(params).length > 0) { - params.updateSource = "ws"; + case "sysmsg": + device.params.updateSource = "ws"; let returnTemplate = { deviceid: device.deviceid, - action: "update", - params + action: "sysmsg", + params: device.params }; if (this.debugReqRes) { let msg = JSON.stringify(returnTemplate, null, 2).replace(device.deviceid, "**hidden**"); @@ -135,11 +111,35 @@ module.exports = class eWeLinkWS { this.log("WS message received."); } this.emitter.emit("update", returnTemplate); - } - break; - default: - this.log.warn("[%s] WS message has unknown action.\n" + JSON.stringify(device, null, 2), device.deviceid); - return; + break; + case "update": + let params = device.params; + for (let param in params) { + if (params.hasOwnProperty(param)) { + if (!constants.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { + delete params[param]; + } + } + } + if (Object.keys(params).length > 0) { + params.updateSource = "ws"; + let returnTemplate = { + deviceid: device.deviceid, + action: "update", + params + }; + if (this.debugReqRes) { + let msg = JSON.stringify(returnTemplate, null, 2).replace(device.deviceid, "**hidden**"); + this.log("WS message received.\n%s", msg); + } else if (this.debug) { + this.log("WS message received."); + } + this.emitter.emit("update", returnTemplate); + } + break; + default: + this.log.warn("[%s] WS message has unknown action.\n" + JSON.stringify(device, null, 2), device.deviceid); + return; } } else if (device.hasOwnProperty("error") && device.error === 0) { // *** Safe to ignore these messages *** \\ @@ -149,22 +149,26 @@ module.exports = class eWeLinkWS { } } }); - this.ws.on("close", (e) => { - this.log.warn("Web socket closed - [%s].", e); - if (e.code !== 1000) { - this.log.warn("Web socket will try to reconnect in five seconds then try the command again."); - this.ws.removeAllListeners(); - setTimeout(() => { - this.login(); - }, 5000); + this.ws.on("close", (e, m) => { + if (m === "Stopping Homebridge") { + this.log("Web socket closed as part of Homebridge shutdown."); } else { - this.log.error("Please try restarting Homebridge so that this plugin can work again."); + this.log.warn("Web socket closed - [%s - %s].", e, m); + if (e !== 1000) { + this.log("Web socket will try to reconnect in five seconds."); + setTimeout(() => { + this.login(); + }, 5000); + } else { + this.log("Please try restarting Homebridge so that this plugin can work again."); + } } this.wsIsOpen = false; if (this.hbInterval) { clearInterval(this.hbInterval); this.hbInterval = null; } + this.ws.removeAllListeners(); }); this.ws.on("error", (e) => { this.log.error("Web socket error - [%s].", e); @@ -268,4 +272,7 @@ module.exports = class eWeLinkWS { receiveUpdate(f) { this.emitter.addListener("update", f); } + closeConnection() { + this.ws.close(1000, "Stopping Homebridge"); + } }; \ No newline at end of file From 65fc7549cc9aa1150e937b3cf4d59cd36a4cfe37 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 20 Aug 2020 17:08:50 +0100 Subject: [PATCH 0036/3183] 2.23.0-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0077fce1..8254df29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.19.3", + "version": "2.23.0-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 83a1c664..eb102db4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.19.3", + "version": "2.23.0-0", "author": "bwp91", "contributors": [ "gbro115", From acfa27e6c86b7d4666d06b6b382b2f38a1dba9c5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 20 Aug 2020 20:39:32 +0100 Subject: [PATCH 0037/3183] 2.23.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8254df29..9f311274 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.23.0-0", + "version": "2.23.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index eb102db4..1f11ab88 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.23.0-0", + "version": "2.23.0", "author": "bwp91", "contributors": [ "gbro115", From db010c5d0b872afdef3d7b7c729028954ce3777d Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Thu, 20 Aug 2020 23:04:59 +0100 Subject: [PATCH 0038/3183] Delete _config.yml --- _config.yml | 1 - 1 file changed, 1 deletion(-) delete mode 100644 _config.yml diff --git a/_config.yml b/_config.yml deleted file mode 100644 index c7418817..00000000 --- a/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-slate \ No newline at end of file From 5edc9ef42a58d4d46530deba8af0bb71c1d6bb39 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Thu, 20 Aug 2020 23:08:52 +0100 Subject: [PATCH 0039/3183] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 633cb902..f2df355c 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,9 @@ [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) [![Discord](https://img.shields.io/discord/432663330281226270?color=728ED5&logo=discord&label=discord)](https://discord.com/channels/432663330281226270/742733745743855627) [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) - [![npm](https://img.shields.io/npm/v/homebridge-ewelink?label=release)](https://www.npmjs.com/package/homebridge-ewelink) - [![npm](https://img.shields.io/npm/v/homebridge-ewelink-beta?label=beta)](https://www.npmjs.com/package/homebridge-ewelink-beta) + [![npm](https://img.shields.io/npm/v/homebridge-ewelink/release?label=release)](https://www.npmjs.com/package/homebridge-ewelink) + [![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://www.npmjs.com/package/homebridge-ewelink) + From f0d386db08af9d56ef380793213e4c2cce86f9db Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Thu, 20 Aug 2020 23:09:12 +0100 Subject: [PATCH 0040/3183] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f2df355c..bbcd2fef 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) [![Discord](https://img.shields.io/discord/432663330281226270?color=728ED5&logo=discord&label=discord)](https://discord.com/channels/432663330281226270/742733745743855627) [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) - [![npm](https://img.shields.io/npm/v/homebridge-ewelink/release?label=release)](https://www.npmjs.com/package/homebridge-ewelink) + [![npm](https://img.shields.io/npm/v/homebridge-ewelink/latest?label=release)](https://www.npmjs.com/package/homebridge-ewelink) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://www.npmjs.com/package/homebridge-ewelink) From f6b0531a6d7a85c647ad640ed2d0d29890b3edc1 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 21 Aug 2020 08:52:03 +0100 Subject: [PATCH 0041/3183] default ws for unsupported lan --- lib/constants.js | 1 + lib/eWeLink.js | 43 +++++++++++++++++++++++-------------------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/lib/constants.js b/lib/constants.js index 3c557fca..077cc40f 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -4,6 +4,7 @@ module.exports = { appId: "oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq", packageName: "homebridge-ewelink", devicesHideable: ["switch", "light", "valve"], + devicesNonLAN: [22, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], devicesSingleSwitchLight: ["T1 1C", "L1", "B1", "B1_R2", "TX1C", "D1", "D1R1", "KING-M4", "Slampher"], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 89352a12..c5f9bb29 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -307,7 +307,6 @@ class eWeLink { case "6": accessory.context.sensorType = this.cusS.has(hbDeviceId) ? this.cusS.get(hbDeviceId).type : "motion"; break; - case "5": default: throw "RF device type is not supported"; } @@ -343,7 +342,6 @@ class eWeLink { case "occupancy": accessory.addService(Service.OccupancySensor); break; - case "motion": default: accessory.addService(Service.MotionSensor); break; @@ -668,24 +666,30 @@ class eWeLink { deviceid: accessory.context.eweDeviceId, params }; - this.lanClient.sendUpdate(payload) - .then(res => { - callback(); - }) - .catch(err => { - if (accessory.context.reachableWAN) { - if (this.config.debug) { - this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); + if (cns.devicesNonLAN.includes(accessory.context.eweUIID)) { + if (accessory.context.reachableWAN) { + this.wsClient.sendUpdate(payload, callback); + } else { + this.log.error("[%s] could not be updated as it appears to be offline.", accessory.displayName); + callback("Device has failed to update"); + } + } else { + this.lanClient.sendUpdate(payload) + .then(res => { + callback(); + }) + .catch(err => { + if (accessory.context.reachableWAN) { + if (this.config.debug) { + this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); + } + this.wsClient.sendUpdate(payload, callback); + } else { + this.log.error("[%s] could not be updated as it appears to be offline.", accessory.displayName); + callback("Device has failed to update"); } - this.wsClient.sendUpdate(payload, callback); - setTimeout(() => { - this.wsClient.requestUpdate(accessory); - }, 3000); - } else { - this.log.error("[%s] could not be updated as it appears to be offline.", accessory.displayName); - callback("Device has failed to update"); - } - }); + }); + } } receiveDeviceUpdate(device) { let accessory, source = device.params.updateSource === "ws" ? "WS" : "LAN"; @@ -1695,7 +1699,6 @@ class eWeLink { oAccessory.getService(Service.OccupancySensor).updateCharacteristic(Characteristic.OccupancyDetected, 0); }, (this.config.sensorTimeLength || 2) * 1000); break; - case "motion": default: oAccessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, true); setTimeout(() => { From 514708fbaef362f0f846793d1ca90bd9a25e43e7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 21 Aug 2020 08:53:27 +0100 Subject: [PATCH 0042/3183] 2.23.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9f311274..7481fabd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.23.0", + "version": "2.23.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1f11ab88..c1aa9dee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.23.0", + "version": "2.23.1", "author": "bwp91", "contributors": [ "gbro115", From 1d6f1a4c59f39577dc0de7f87ee664ae4de4f330 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 21 Aug 2020 13:51:52 +0100 Subject: [PATCH 0043/3183] ws/lan refactor --- lib/eWeLink.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index c5f9bb29..87b1838a 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -666,28 +666,26 @@ class eWeLink { deviceid: accessory.context.eweDeviceId, params }; - if (cns.devicesNonLAN.includes(accessory.context.eweUIID)) { + let sendViaWS = () => { if (accessory.context.reachableWAN) { this.wsClient.sendUpdate(payload, callback); } else { this.log.error("[%s] could not be updated as it appears to be offline.", accessory.displayName); callback("Device has failed to update"); } + }; + if (cns.devicesNonLAN.includes(accessory.context.eweUIID) || !this.lanDevices.get(accessory.context.eweDeviceId).online) { + sendViaWS(); } else { this.lanClient.sendUpdate(payload) .then(res => { callback(); }) .catch(err => { - if (accessory.context.reachableWAN) { - if (this.config.debug) { - this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); - } - this.wsClient.sendUpdate(payload, callback); - } else { - this.log.error("[%s] could not be updated as it appears to be offline.", accessory.displayName); - callback("Device has failed to update"); + if (this.config.debug) { + this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); } + sendViaWS(); }); } } From dd78ff39f4a267d3da7d0d78e1bc47f3d9f7561c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 21 Aug 2020 13:52:23 +0100 Subject: [PATCH 0044/3183] 2.23.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7481fabd..39fb9235 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.23.1", + "version": "2.23.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index c1aa9dee..dea62940 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.23.1", + "version": "2.23.2", "author": "bwp91", "contributors": [ "gbro115", From 23884cc9575bc90315e85fe107febff969eaaca4 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 21 Aug 2020 23:36:49 +0100 Subject: [PATCH 0045/3183] config hide TH switch --- config.schema.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/config.schema.json b/config.schema.json index 8a6237d9..1ef46d3e 100644 --- a/config.schema.json +++ b/config.schema.json @@ -73,6 +73,12 @@ "default":"20", "maximum":999 }, + "hideTHSwitch":{ + "title":"Hide TH10/TH16 Switch", + "type":"boolean", + "description":"If enabled, the switch for the TH10/TH16 devices will be hidden from Homebridge.", + "default":false + }, "hideZBLDPress":{ "title":"Hide Double/Long Press", "type":"boolean", @@ -291,4 +297,4 @@ ] } ] -} \ No newline at end of file +} From 54c68c19b381e5620e288b805153bb92a352bdcb Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 21 Aug 2020 23:41:37 +0100 Subject: [PATCH 0046/3183] ability to hide th10/16 switch --- lib/eWeLink.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 87b1838a..89a16d67 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -272,7 +272,9 @@ class eWeLink { accessory.addService(Service.Lightbulb); break; case "thermostat": - accessory.addService(Service.Switch); + if (!this.config.hideTHSwitch) { + accessory.addService(Service.Switch); + } accessory.addService(Service.TemperatureSensor); if (device.params.sensorType !== "DS18B20") { accessory.addService(Service.HumiditySensor); @@ -1486,7 +1488,7 @@ class eWeLink { } externalThermostatUpdate(accessory, params) { try { - if (params.hasOwnProperty("switch") || params.hasOwnProperty("mainSwitch")) { + if (!this.config.hideTHSwitch && (params.hasOwnProperty("switch") || params.hasOwnProperty("mainSwitch"))) { let newState = params.hasOwnProperty("switch") ? params.switch === "on" : params.mainSwitch === "on"; accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, newState); } @@ -1769,4 +1771,4 @@ module.exports = function(homebridge) { Characteristic = homebridge.hap.Characteristic; UUIDGen = homebridge.hap.uuid; return eWeLink; -}; \ No newline at end of file +}; From 8743d0e81d7b976da86218d7a880f4af1788ab01 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 21 Aug 2020 23:44:02 +0100 Subject: [PATCH 0047/3183] hideTHSwitch visability --- config.schema.json | 1 + 1 file changed, 1 insertion(+) diff --git a/config.schema.json b/config.schema.json index 1ef46d3e..c41d0656 100644 --- a/config.schema.json +++ b/config.schema.json @@ -256,6 +256,7 @@ "sensorTimeLength", "sensorTimeDifference", "valveTimeLength", + "hideTHSwitch", "hideZBLDPress" ] }, From 344b03b5647668c187660e15ddb8fc4c317b5724 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sat, 22 Aug 2020 00:01:00 +0100 Subject: [PATCH 0048/3183] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bbcd2fef..31a356b8 100644 --- a/README.md +++ b/README.md @@ -17,5 +17,6 @@ ## Documentation Please refer to the [wiki](https://github.com/bwp91/homebridge-ewelink/wiki) for documentation. -## Credit -To the original owner of this package @gbro115 for letting me take over. I will look after it as best as I can :) +## Credits +- To the original owner of this package @gbro115 for letting me take over. I will look after it as best as I can :) +- More credits in the [wiki](https://github.com/bwp91/homebridge-ewelink/wiki/Credits). From d6d8f4fe1997044d7e72124c97651a75a4dd1689 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 22 Aug 2020 00:04:25 +0100 Subject: [PATCH 0049/3183] 2.24.0-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 39fb9235..16318a79 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.23.2", + "version": "2.24.0-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index dea62940..f27e3e2e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.23.2", + "version": "2.24.0-0", "author": "bwp91", "contributors": [ "gbro115", From e87441134623fac2d644ee78df757ddf5e9e5491 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 23 Aug 2020 13:05:25 +0100 Subject: [PATCH 0050/3183] hide th switch option --- lib/eWeLink.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 89a16d67..cb9464c2 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -458,12 +458,14 @@ class eWeLink { }); break; case "thermostat": - accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => { - accessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value !== value ? - this.internalThermostatUpdate(accessory, value, callback) : - callback(); - }); + if (!this.config.hideTHSwitch) { + accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) + .on("set", (value, callback) => { + accessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value !== value ? + this.internalThermostatUpdate(accessory, value, callback) : + callback(); + }); + } break; case "outlet": accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) @@ -1771,4 +1773,4 @@ module.exports = function(homebridge) { Characteristic = homebridge.hap.Characteristic; UUIDGen = homebridge.hap.uuid; return eWeLink; -}; +}; \ No newline at end of file From b352daf404d0c732871964dc4f974f5bce9cd4fc Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 23 Aug 2020 13:06:05 +0100 Subject: [PATCH 0051/3183] 2.24.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 16318a79..07fbec86 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.24.0-0", + "version": "2.24.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f27e3e2e..e03ce3b9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.24.0-0", + "version": "2.24.0", "author": "bwp91", "contributors": [ "gbro115", From 9cf948cac5c57880204ce6788430683bfcef4ee8 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 24 Aug 2020 19:46:44 +0200 Subject: [PATCH 0052/3183] Create codeql-analysis.yml --- .github/workflows/codeql-analysis.yml | 54 +++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000..7158717c --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,54 @@ +name: "CodeQL" + +on: + push: + branches: [master, ] + pull_request: + # The branches below must be a subset of the branches above + branches: [master] + schedule: + - cron: '0 1 * * 5' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 + + # If this run was triggered by a pull request event, then checkout + # the head of the pull request instead of the merge commit. + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + # Override language selection by uncommenting this and choosing your languages + # with: + # languages: go, javascript, csharp, python, cpp, java + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹī¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 From 4e50f266f526d1af85c29b9e58f16fa3f8c9b04a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 25 Aug 2020 16:29:53 +0100 Subject: [PATCH 0053/3183] improve lag --- lib/eWeLinkWS.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 95aea46d..cf35ae34 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -200,8 +200,8 @@ module.exports = class eWeLinkWS { return; } if (this.ws) { - callback(); this.ws.send(req); + callback(); if (this.debugReqRes) { let msg = JSON.stringify(json, null, 2).replace(json.apikey, "**hidden**").replace(json.apiKey, "**hidden**").replace(json.deviceid, "**hidden**"); this.log.warn("Web socket message sent. This text is yellow for clarity.\n%s", msg); From 50a6921cedd6bbc05be6ef3de223dc961c020228 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 25 Aug 2020 16:30:00 +0100 Subject: [PATCH 0054/3183] support for led device --- lib/constants.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/constants.js b/lib/constants.js index 077cc40f..653f547c 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -6,7 +6,7 @@ module.exports = { devicesHideable: ["switch", "light", "valve"], devicesNonLAN: [22, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], - devicesSingleSwitchLight: ["T1 1C", "L1", "B1", "B1_R2", "TX1C", "D1", "D1R1", "KING-M4", "Slampher"], + devicesSingleSwitchLight: ["T1 1C", "L1", "B1", "B1_R2", "TX1C", "D1", "D1R1", "KING-M4", "Slampher", "GTTA59"], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], devicesMultiSwitchLight: ["T1 2C", "T1 3C", "TX2C", "TX3C"], devicesBrightable: [36, 44], From e0d3f3812a361e4f0c77d598e14a98a4a47b9256 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 25 Aug 2020 16:33:58 +0100 Subject: [PATCH 0055/3183] 2.24.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 07fbec86..2732cb07 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.24.0", + "version": "2.24.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index e03ce3b9..9e42cfff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.24.0", + "version": "2.24.1", "author": "bwp91", "contributors": [ "gbro115", From 0eaa483317fbbcd38169a942506009f87eed8ba0 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 28 Aug 2020 13:11:28 +0100 Subject: [PATCH 0056/3183] callback position --- lib/eWeLink.js | 3 ++- lib/eWeLinkWS.js | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index cb9464c2..4d69b335 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -672,7 +672,8 @@ class eWeLink { }; let sendViaWS = () => { if (accessory.context.reachableWAN) { - this.wsClient.sendUpdate(payload, callback); + this.wsClient.sendUpdate(payload); + callback(); } else { this.log.error("[%s] could not be updated as it appears to be offline.", accessory.displayName); callback("Device has failed to update"); diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index cf35ae34..fb5ba293 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -183,7 +183,7 @@ module.exports = class eWeLinkWS { } }); } - sendUpdate(json, callback) { + sendUpdate(json) { json = { ...json, ...{ @@ -201,7 +201,6 @@ module.exports = class eWeLinkWS { } if (this.ws) { this.ws.send(req); - callback(); if (this.debugReqRes) { let msg = JSON.stringify(json, null, 2).replace(json.apikey, "**hidden**").replace(json.apiKey, "**hidden**").replace(json.deviceid, "**hidden**"); this.log.warn("Web socket message sent. This text is yellow for clarity.\n%s", msg); From 8859987af89637345ea864b12ef83c115962f341 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sun, 30 Aug 2020 14:56:47 +0100 Subject: [PATCH 0057/3183] Update README.md --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 31a356b8..003d8a37 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,8 @@ -## Documentation +### Documentation Please refer to the [wiki](https://github.com/bwp91/homebridge-ewelink/wiki) for documentation. -## Credits -- To the original owner of this package @gbro115 for letting me take over. I will look after it as best as I can :) -- More credits in the [wiki](https://github.com/bwp91/homebridge-ewelink/wiki/Credits). +### Credit +Thank you to the original owner of this package @gbro115 for letting me take over. I will look after it as best as I can :) From f4cdc7c23a1ec771a5c61dd81cefc81a3d4a1e3b Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sun, 30 Aug 2020 15:02:37 +0100 Subject: [PATCH 0058/3183] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 003d8a37..3aa9e0e0 100644 --- a/README.md +++ b/README.md @@ -5,17 +5,18 @@ # homebridge-ewelink + Homebridge plugin to control eWeLink devices with original firmware. + [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) [![Discord](https://img.shields.io/discord/432663330281226270?color=728ED5&logo=discord&label=discord)](https://discord.com/channels/432663330281226270/742733745743855627) [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/latest?label=release)](https://www.npmjs.com/package/homebridge-ewelink) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://www.npmjs.com/package/homebridge-ewelink) - ### Documentation Please refer to the [wiki](https://github.com/bwp91/homebridge-ewelink/wiki) for documentation. ### Credit -Thank you to the original owner of this package @gbro115 for letting me take over. I will look after it as best as I can :) +To the original owner of this package @gbro115 for letting me take over. I will look after it as best as I can :) From ee8674c0528219f447f33aae280ec712328903cd Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sun, 30 Aug 2020 15:23:00 +0100 Subject: [PATCH 0059/3183] Update README.md --- README.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3aa9e0e0..f0c86501 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,18 @@ -### Documentation -Please refer to the [wiki](https://github.com/bwp91/homebridge-ewelink/wiki) for documentation. - -### Credit -To the original owner of this package @gbro115 for letting me take over. I will look after it as best as I can :) +### Setup +* [Installation](https://github.com/bwp91/homebridge-ewelink/wiki/Installation) +* [Configuration](https://github.com/bwp91/homebridge-ewelink/wiki/Configuration) +* [Beta Version](https://github.com/bwp91/homebridge-ewelink/wiki/Beta-Version) +### Features +* [Supported Devices](https://github.com/bwp91/homebridge-ewelink/wiki/Supported-Devices) +* [Connection Methods](https://github.com/bwp91/homebridge-ewelink/wiki/Connection-Methods) +### How-to Guides +* [How to copy Homebridge logs](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-copy-Homebridge-logs) +* [How to enable/disable plugin extended logging](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-enable-disable-plugin-extended-logging) +* [How to set up RF Bridge sensors](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-RF-Bridge-sensors) +### About +* [Support Request](https://github.com/bwp91/homebridge-ewelink/issues) +* [Roadmap](https://github.com/bwp91/homebridge-ewelink/wiki/Roadmap) +* [Credits](https://github.com/bwp91/homebridge-ewelink/wiki/Credits) From 6b2518d4749ea98f879720bd58d97e0d4a7da63a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 5 Sep 2020 11:06:31 +0100 Subject: [PATCH 0060/3183] closeConnection checks --- lib/eWeLink.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 4d69b335..6940cc0a 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -89,8 +89,12 @@ class eWeLink { }).catch(err => this.log.error("🔴 Cannot load %s - %s", cns.packageName, err)); }); this.api.on('shutdown', () => { - this.lanClient.closeConnection(); - this.wsClient.closeConnection(); + if (this.lanClient) { + this.lanClient.closeConnection(); + } + if (this.wsClient) { + this.wsClient.closeConnection(); + } }); } initialiseDevice(device) { From 870a4304c862e937c5f9c663f1019a7b0c51bef0 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 5 Sep 2020 15:22:06 +0100 Subject: [PATCH 0061/3183] link to wiki --- config.schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.schema.json b/config.schema.json index c41d0656..9362768b 100644 --- a/config.schema.json +++ b/config.schema.json @@ -3,7 +3,7 @@ "pluginType":"platform", "singular":true, "headerDisplay":"Homebridge plugin to control eWeLink devices with original firmware.", - "footerDisplay":"If you have any suggestions, please open an issue on [GitHub](https://github.com/bwp91/homebridge-ewelink/issues).", + "footerDisplay":"For help and support please visit our [GitHub Wiki](https://github.com/bwp91/homebridge-ewelink/wiki).", "schema":{ "type":"object", "properties":{ @@ -298,4 +298,4 @@ ] } ] -} +} \ No newline at end of file From d077ba4a6c0d0a0ed8136268e9517f84198c63af Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 5 Sep 2020 15:22:16 +0100 Subject: [PATCH 0062/3183] remove package name --- lib/constants.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/constants.js b/lib/constants.js index 653f547c..1a11a419 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -2,7 +2,6 @@ "use strict"; module.exports = { appId: "oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq", - packageName: "homebridge-ewelink", devicesHideable: ["switch", "light", "valve"], devicesNonLAN: [22, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], From db052e3541fd04936b175627373aa7b318d375d9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 5 Sep 2020 15:22:19 +0100 Subject: [PATCH 0063/3183] remove package name --- index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/index.js b/index.js index 3083dd2d..624be64e 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,6 @@ /* jshint esversion: 9, -W030, node: true */ "use strict"; -const constants = require("./lib/constants"); module.exports = function (homebridge) { let eWeLink = require("./lib/eWeLink.js")(homebridge); - homebridge.registerPlatform(constants.packageName, "eWeLink", eWeLink, true); + homebridge.registerPlatform("homebridge-ewelink", "eWeLink", eWeLink, true); }; \ No newline at end of file From 2d90bbe787c1dc6fbb680d9e7b6a4b15c31eacc9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 5 Sep 2020 15:22:33 +0100 Subject: [PATCH 0064/3183] remove package name --- lib/eWeLink.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 6940cc0a..c780b194 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -12,7 +12,7 @@ class eWeLink { return; } if (!config || (!config.username || !config.password || !config.countryCode)) { - log.error("🔴 Cannot load %s - please check your eWeLink credentials in the plugin settings.", cns.packageName); + log.error("🔴 Cannot load homebridge-ewelink - please check your eWeLink credentials in the plugin settings."); return; } this.log = log; @@ -86,7 +86,7 @@ class eWeLink { this.log.warn("You have 'Request & Response Logging' enabled. This setting is not recommended for long-term use."); } })(); - }).catch(err => this.log.error("🔴 Cannot load %s - %s", cns.packageName, err)); + }).catch(err => this.log.error("🔴 Cannot load homebridge-ewelink - %s", err)); }); this.api.on('shutdown', () => { if (this.lanClient) { @@ -385,7 +385,7 @@ class eWeLink { throw "device is not supported by this plugin"; } this.devicesInHB.set(hbDeviceId, accessory); - this.api.registerPlatformAccessories(cns.packageName, "eWeLink", [accessory]); + this.api.registerPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); this.configureAccessory(accessory); this.log("[%s] has been added to Homebridge.", newDeviceName); } catch (err) { @@ -662,7 +662,7 @@ class eWeLink { removeAccessory(accessory) { try { this.devicesInHB.delete(accessory.context.hbDeviceId); - this.api.unregisterPlatformAccessories(cns.packageName, "eWeLink", [accessory]); + this.api.unregisterPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); this.log("[%s] has been removed from Homebridge.", accessory.displayName); } catch (err) { this.log.warn("[%s] needed to be removed but couldn't - [%s].", accessory.displayName, err); From a78de6c08a9da858be283445877e923698f6fd0e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 5 Sep 2020 15:25:25 +0100 Subject: [PATCH 0065/3183] 2.24.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2732cb07..c761890a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.24.1", + "version": "2.24.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 9e42cfff..0fc56a42 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.24.1", + "version": "2.24.2", "author": "bwp91", "contributors": [ "gbro115", From 0e1e9c57373221c44f8bb7fc6cb6ec95d7e570dc Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 5 Sep 2020 15:42:19 +0100 Subject: [PATCH 0066/3183] update axios dep --- package-lock.json | 30 +++++++----------------------- package.json | 2 +- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index c761890a..6aaae582 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,11 @@ "requires": true, "dependencies": { "axios": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", - "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz", + "integrity": "sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==", "requires": { - "follow-redirects": "1.5.10" + "follow-redirects": "^1.10.0" } }, "color-convert": { @@ -25,26 +25,10 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "requires": { - "debug": "=3.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", + "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==" }, "node-dns-sd": { "version": "0.4.1", diff --git a/package.json b/package.json index 0fc56a42..a8d8bcaf 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "url": "https://github.com/bwp91/homebridge-ewelink" }, "dependencies": { - "axios": "0.19.2", + "axios": "0.20.0", "color-convert": "2.0.1", "node-dns-sd": "0.4.1", "ws": "7.3.1" From 7163dd6f63b9a4f57870d22fc6dd56ece20da8fd Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 6 Sep 2020 01:10:17 +0100 Subject: [PATCH 0067/3183] lan receive msg bug --- lib/eWeLinkLAN.js | 294 +++++++++++++++++++++++----------------------- 1 file changed, 146 insertions(+), 148 deletions(-) diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 1032afa0..b50b901f 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -6,165 +6,163 @@ const crypto = require("crypto"); const dns = require("node-dns-sd"); const eventemitter = require("events"); module.exports = class eWeLinkLAN { - constructor(config, log, devices) { - this.config = config; - this.log = log; - this.devices = devices; - let deviceMap = new Map(); - devices.forEach(device => { - deviceMap.set(device.deviceid, { - apiKey: device.devicekey, - online: false, - ip: null - }); - }); - this.deviceMap = deviceMap; - this.debug = this.config.debug || false; - this.debugReqRes = this.config.debugReqRes || false; - this.emitter = new eventemitter(); - } - getHosts() { - return new Promise((resolve, reject) => { - dns.discover({ - name: "_ewelink._tcp.local" - }).then(res => { - let onlineCount = 0; - res.forEach(device => { - let d, deviceId = device.fqdn.replace("._ewelink._tcp.local", "").replace("eWeLink_", ""); - if ((d = this.deviceMap.get(deviceId))) { - this.deviceMap.set(deviceId, { - apiKey: d.apiKey, - online: true, - ip: device.address - }); - onlineCount++; - } + constructor(config, log, devices) { + this.config = config; + this.log = log; + this.devices = devices; + let deviceMap = new Map(); + devices.forEach(device => { + deviceMap.set(device.deviceid, { + apiKey: device.devicekey, + online: false, + ip: null }); - resolve({ - map: this.deviceMap, - count: onlineCount + }); + this.deviceMap = deviceMap; + this.debug = this.config.debug || false; + this.debugReqRes = this.config.debugReqRes || false; + this.emitter = new eventemitter(); + } + getHosts() { + return new Promise((resolve, reject) => { + dns.discover({ + name: "_ewelink._tcp.local" + }).then(res => { + let onlineCount = 0; + res.forEach(device => { + let d, deviceId = device.fqdn.replace("._ewelink._tcp.local", "").replace("eWeLink_", ""); + if ((d = this.deviceMap.get(deviceId))) { + this.deviceMap.set(deviceId, { + apiKey: d.apiKey, + online: true, + ip: device.address + }); + onlineCount++; + } + }); + resolve({ + map: this.deviceMap, + count: onlineCount + }); + }).catch(err => { + reject(err); }); - }).catch(err => { - reject(err); - }); - }); - } - startMonitor() { - dns.ondata = packet => { - if (packet.answers) { - packet.answers - .filter(value => value.name.includes("_ewelink._tcp.local")) - .forEach(value => { - if (value.type === "TXT") { - let rdata = value.rdata; - if (this.deviceMap.hasOwnProperty(rdata.id)) { - let deviceKey = this.deviceMap[rdata.id].apiKey, - data = rdata.data1 + - (rdata.hasOwnProperty("data2") ? rdata.data2 : "") + - (rdata.hasOwnProperty("data3") ? rdata.data3 : "") + - (rdata.hasOwnProperty("data4") ? rdata.data4 : ""), - key = crypto.createHash("md5").update(Buffer.from(deviceKey, "utf8")).digest(), - dText = crypto.createDecipheriv("aes-128-cbc", key, Buffer.from(rdata.iv, "base64")), - pText = Buffer.concat([dText.update(Buffer.from(data, "base64")), dText.final()]).toString("utf8"), - params; + }); + } + startMonitor() { + dns.ondata = packet => { + if (packet.answers) { + packet.answers + .filter(value => value.name.includes("_ewelink._tcp.local")) + .filter(value => value.type === "TXT") + .filter(value => this.deviceMap.has(value.rdata.id)) + .forEach(value => { + let rdata = value.rdata, + deviceKey = this.deviceMap.get(rdata.id).apiKey, + data = rdata.data1 + + (rdata.hasOwnProperty("data2") ? rdata.data2 : "") + + (rdata.hasOwnProperty("data3") ? rdata.data3 : "") + + (rdata.hasOwnProperty("data4") ? rdata.data4 : ""), + key = crypto.createHash("md5").update(Buffer.from(deviceKey, "utf8")).digest(), + dText = crypto.createDecipheriv("aes-128-cbc", key, Buffer.from(rdata.iv, "base64")), + pText = Buffer.concat([dText.update(Buffer.from(data, "base64")), dText.final()]).toString("utf8"), + params; try { - params = JSON.parse(pText); + params = JSON.parse(pText); } catch (e) { - this.log.warn("[%s] An error occured reading the LAN message [%s]", rdata.id, e); - return; + this.log.warn("[%s] An error occured reading the LAN message [%s]", rdata.id, e); + return; } for (let param in params) { - if (params.hasOwnProperty(param)) { - if (!constants.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { - delete params[param]; - } - } + if (params.hasOwnProperty(param)) { + if (!constants.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { + delete params[param]; + } + } } params.updateSource = "lan"; if (Object.keys(params).length > 0) { - let returnTemplate = { - deviceid: rdata.id, - action: "update", - params - }; - if (this.debugReqRes) { - let msg = JSON.stringify(returnTemplate, null, 2).replace(rdata.id, "**hidden**"); - this.log("LAN message received.\n%s", msg); - } else if (this.debug) { - this.log("LAN message received."); - } - this.emitter.emit("update", returnTemplate); + let returnTemplate = { + deviceid: rdata.id, + action: "update", + params + }; + if (this.debugReqRes) { + let msg = JSON.stringify(returnTemplate, null, 2).replace(rdata.id, "**hidden**"); + this.log("LAN message received.\n%s", msg); + } else if (this.debug) { + this.log("LAN message received."); + } + this.emitter.emit("update", returnTemplate); } - } - } - }); - } - }; - return new Promise((resolve, reject) => { - dns.startMonitoring().then(() => { - resolve(); - }).catch(err => { - reject(err); - }); - }); - } - sendUpdate(json) { - return new Promise((resolve, reject) => { - if (!this.deviceMap.get(json.deviceid).online) { - throw "device does not support LAN mode"; - } - let apiKey, suffix, params = {}; - if (json.params.hasOwnProperty("switches")) { - params.switches = json.params.switches; - suffix = "switches"; - } else if (json.params.hasOwnProperty("switch")) { - params.switch = json.params.switch; - suffix = "switch"; - } else { - throw "plugin does not support lan mode for this device yet - feel free to create a github issue"; - } - if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { - let key = crypto.createHash('md5').update(Buffer.from(apiKey, 'utf8')).digest(), - iv = crypto.randomBytes(16), - enc = crypto.createCipheriv('aes-128-cbc', key, iv), - data = { - data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString('base64'), - deviceid: json.deviceid, - encrypt: true, - iv: iv.toString('base64'), - selfApikey: "123", - sequence: Date.now().toString() - }; - if (this.debugReqRes) { - let msg = JSON.stringify(json, null, 2).replace(json.apikey, "**hidden**").replace(json.apikey, "**hidden**").replace(json.deviceid, "**hidden**"); - this.log.warn("LAN mode message sent. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("LAN mode message sent."); + }); } - axios({ - method: "post", - url: "http://" + this.deviceMap.get(json.deviceid).ip + ":8081/zeroconf/" + suffix, - headers: { - Accept: "application/json", - "Content-Type": "application/json" - }, - data - }).then(res => { - if (res.data.hasOwnProperty("error") && res.data.error === 0) { - resolve(); - } - throw res.data; + }; + return new Promise((resolve, reject) => { + dns.startMonitoring().then(() => { + resolve(); }).catch(err => { - reject(err); + reject(err); }); - } - }); - } - receiveUpdate(f) { - this.emitter.addListener("update", f); - } - closeConnection() { - dns.stopMonitoring(); - this.log("LAN monitoring stopped as part of Homebridge shutdown."); - } + }); + } + sendUpdate(json) { + return new Promise((resolve, reject) => { + if (!this.deviceMap.get(json.deviceid).online) { + throw "device does not support LAN mode"; + } + let apiKey, suffix, params = {}; + if (json.params.hasOwnProperty("switches")) { + params.switches = json.params.switches; + suffix = "switches"; + } else if (json.params.hasOwnProperty("switch")) { + params.switch = json.params.switch; + suffix = "switch"; + } else { + throw "plugin does not support lan mode for this device yet - feel free to create a github issue"; + } + if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { + let key = crypto.createHash('md5').update(Buffer.from(apiKey, 'utf8')).digest(), + iv = crypto.randomBytes(16), + enc = crypto.createCipheriv('aes-128-cbc', key, iv), + data = { + data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString('base64'), + deviceid: json.deviceid, + encrypt: true, + iv: iv.toString('base64'), + selfApikey: "123", + sequence: Date.now().toString() + }; + if (this.debugReqRes) { + let msg = JSON.stringify(json, null, 2).replace(json.apikey, "**hidden**").replace(json.apikey, "**hidden**").replace(json.deviceid, "**hidden**"); + this.log.warn("LAN mode message sent. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("LAN mode message sent."); + } + axios({ + method: "post", + url: "http://" + this.deviceMap.get(json.deviceid).ip + ":8081/zeroconf/" + suffix, + headers: { + Accept: "application/json", + "Content-Type": "application/json" + }, + data + }).then(res => { + if (res.data.hasOwnProperty("error") && res.data.error === 0) { + resolve(); + } + throw res.data; + }).catch(err => { + reject(err); + }); + } + }); + } + receiveUpdate(f) { + this.emitter.addListener("update", f); + } + closeConnection() { + dns.stopMonitoring(); + this.log("LAN monitoring stopped as part of Homebridge shutdown."); + } }; \ No newline at end of file From 722a754d29c521cf1d8f74f0bbe3afdc13b98295 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 6 Sep 2020 01:13:47 +0100 Subject: [PATCH 0068/3183] formatting --- lib/eWeLinkLAN.js | 306 +++++++++++++++++++++++----------------------- 1 file changed, 153 insertions(+), 153 deletions(-) diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index b50b901f..098be312 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -6,163 +6,163 @@ const crypto = require("crypto"); const dns = require("node-dns-sd"); const eventemitter = require("events"); module.exports = class eWeLinkLAN { - constructor(config, log, devices) { - this.config = config; - this.log = log; - this.devices = devices; - let deviceMap = new Map(); - devices.forEach(device => { - deviceMap.set(device.deviceid, { - apiKey: device.devicekey, - online: false, - ip: null + constructor(config, log, devices) { + this.config = config; + this.log = log; + this.devices = devices; + let deviceMap = new Map(); + devices.forEach(device => { + deviceMap.set(device.deviceid, { + apiKey: device.devicekey, + online: false, + ip: null + }); + }); + this.deviceMap = deviceMap; + this.debug = this.config.debug || false; + this.debugReqRes = this.config.debugReqRes || false; + this.emitter = new eventemitter(); + } + getHosts() { + return new Promise((resolve, reject) => { + dns.discover({ + name: "_ewelink._tcp.local" + }).then(res => { + let onlineCount = 0; + res.forEach(device => { + let d, deviceId = device.fqdn.replace("._ewelink._tcp.local", "").replace("eWeLink_", ""); + if ((d = this.deviceMap.get(deviceId))) { + this.deviceMap.set(deviceId, { + apiKey: d.apiKey, + online: true, + ip: device.address + }); + onlineCount++; + } }); - }); - this.deviceMap = deviceMap; - this.debug = this.config.debug || false; - this.debugReqRes = this.config.debugReqRes || false; - this.emitter = new eventemitter(); - } - getHosts() { - return new Promise((resolve, reject) => { - dns.discover({ - name: "_ewelink._tcp.local" - }).then(res => { - let onlineCount = 0; - res.forEach(device => { - let d, deviceId = device.fqdn.replace("._ewelink._tcp.local", "").replace("eWeLink_", ""); - if ((d = this.deviceMap.get(deviceId))) { - this.deviceMap.set(deviceId, { - apiKey: d.apiKey, - online: true, - ip: device.address - }); - onlineCount++; - } - }); - resolve({ - map: this.deviceMap, - count: onlineCount - }); - }).catch(err => { - reject(err); + resolve({ + map: this.deviceMap, + count: onlineCount }); - }); - } - startMonitor() { - dns.ondata = packet => { - if (packet.answers) { - packet.answers - .filter(value => value.name.includes("_ewelink._tcp.local")) - .filter(value => value.type === "TXT") - .filter(value => this.deviceMap.has(value.rdata.id)) - .forEach(value => { - let rdata = value.rdata, - deviceKey = this.deviceMap.get(rdata.id).apiKey, - data = rdata.data1 + - (rdata.hasOwnProperty("data2") ? rdata.data2 : "") + - (rdata.hasOwnProperty("data3") ? rdata.data3 : "") + - (rdata.hasOwnProperty("data4") ? rdata.data4 : ""), - key = crypto.createHash("md5").update(Buffer.from(deviceKey, "utf8")).digest(), - dText = crypto.createDecipheriv("aes-128-cbc", key, Buffer.from(rdata.iv, "base64")), - pText = Buffer.concat([dText.update(Buffer.from(data, "base64")), dText.final()]).toString("utf8"), - params; - try { - params = JSON.parse(pText); - } catch (e) { - this.log.warn("[%s] An error occured reading the LAN message [%s]", rdata.id, e); - return; - } - for (let param in params) { - if (params.hasOwnProperty(param)) { - if (!constants.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { - delete params[param]; - } - } - } - params.updateSource = "lan"; - if (Object.keys(params).length > 0) { - let returnTemplate = { - deviceid: rdata.id, - action: "update", - params - }; - if (this.debugReqRes) { - let msg = JSON.stringify(returnTemplate, null, 2).replace(rdata.id, "**hidden**"); - this.log("LAN message received.\n%s", msg); - } else if (this.debug) { - this.log("LAN message received."); - } - this.emitter.emit("update", returnTemplate); + }).catch(err => { + reject(err); + }); + }); + } + startMonitor() { + dns.ondata = packet => { + if (packet.answers) { + packet.answers + .filter(value => value.name.includes("_ewelink._tcp.local")) + .filter(value => value.type === "TXT") + .filter(value => this.deviceMap.has(value.rdata.id)) + .forEach(value => { + let rdata = value.rdata, + deviceKey = this.deviceMap.get(rdata.id).apiKey, + data = rdata.data1 + + (rdata.hasOwnProperty("data2") ? rdata.data2 : "") + + (rdata.hasOwnProperty("data3") ? rdata.data3 : "") + + (rdata.hasOwnProperty("data4") ? rdata.data4 : ""), + key = crypto.createHash("md5").update(Buffer.from(deviceKey, "utf8")).digest(), + dText = crypto.createDecipheriv("aes-128-cbc", key, Buffer.from(rdata.iv, "base64")), + pText = Buffer.concat([dText.update(Buffer.from(data, "base64")), dText.final()]).toString("utf8"), + params; + try { + params = JSON.parse(pText); + } catch (e) { + this.log.warn("[%s] An error occured reading the LAN message [%s]", rdata.id, e); + return; + } + for (let param in params) { + if (params.hasOwnProperty(param)) { + if (!constants.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { + delete params[param]; } - }); + } + } + params.updateSource = "lan"; + if (Object.keys(params).length > 0) { + let returnTemplate = { + deviceid: rdata.id, + action: "update", + params + }; + if (this.debugReqRes) { + let msg = JSON.stringify(returnTemplate, null, 2).replace(rdata.id, "**hidden**"); + this.log("LAN message received.\n%s", msg); + } else if (this.debug) { + this.log("LAN message received."); + } + this.emitter.emit("update", returnTemplate); + } + }); + } + }; + return new Promise((resolve, reject) => { + dns.startMonitoring().then(() => { + resolve(); + }).catch(err => { + reject(err); + }); + }); + } + sendUpdate(json) { + return new Promise((resolve, reject) => { + if (!this.deviceMap.get(json.deviceid).online) { + throw "device does not support LAN mode"; + } + let apiKey, suffix, params = {}; + if (json.params.hasOwnProperty("switches")) { + params.switches = json.params.switches; + suffix = "switches"; + } else if (json.params.hasOwnProperty("switch")) { + params.switch = json.params.switch; + suffix = "switch"; + } else { + throw "plugin does not support lan mode for this device yet - feel free to create a github issue"; + } + if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { + let key = crypto.createHash('md5').update(Buffer.from(apiKey, 'utf8')).digest(), + iv = crypto.randomBytes(16), + enc = crypto.createCipheriv('aes-128-cbc', key, iv), + data = { + data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString('base64'), + deviceid: json.deviceid, + encrypt: true, + iv: iv.toString('base64'), + selfApikey: "123", + sequence: Date.now().toString() + }; + if (this.debugReqRes) { + let msg = JSON.stringify(json, null, 2).replace(json.apikey, "**hidden**").replace(json.apikey, "**hidden**").replace(json.deviceid, "**hidden**"); + this.log.warn("LAN mode message sent. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("LAN mode message sent."); } - }; - return new Promise((resolve, reject) => { - dns.startMonitoring().then(() => { - resolve(); + axios({ + method: "post", + url: "http://" + this.deviceMap.get(json.deviceid).ip + ":8081/zeroconf/" + suffix, + headers: { + Accept: "application/json", + "Content-Type": "application/json" + }, + data + }).then(res => { + if (res.data.hasOwnProperty("error") && res.data.error === 0) { + resolve(); + } + throw res.data; }).catch(err => { - reject(err); + reject(err); }); - }); - } - sendUpdate(json) { - return new Promise((resolve, reject) => { - if (!this.deviceMap.get(json.deviceid).online) { - throw "device does not support LAN mode"; - } - let apiKey, suffix, params = {}; - if (json.params.hasOwnProperty("switches")) { - params.switches = json.params.switches; - suffix = "switches"; - } else if (json.params.hasOwnProperty("switch")) { - params.switch = json.params.switch; - suffix = "switch"; - } else { - throw "plugin does not support lan mode for this device yet - feel free to create a github issue"; - } - if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { - let key = crypto.createHash('md5').update(Buffer.from(apiKey, 'utf8')).digest(), - iv = crypto.randomBytes(16), - enc = crypto.createCipheriv('aes-128-cbc', key, iv), - data = { - data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString('base64'), - deviceid: json.deviceid, - encrypt: true, - iv: iv.toString('base64'), - selfApikey: "123", - sequence: Date.now().toString() - }; - if (this.debugReqRes) { - let msg = JSON.stringify(json, null, 2).replace(json.apikey, "**hidden**").replace(json.apikey, "**hidden**").replace(json.deviceid, "**hidden**"); - this.log.warn("LAN mode message sent. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("LAN mode message sent."); - } - axios({ - method: "post", - url: "http://" + this.deviceMap.get(json.deviceid).ip + ":8081/zeroconf/" + suffix, - headers: { - Accept: "application/json", - "Content-Type": "application/json" - }, - data - }).then(res => { - if (res.data.hasOwnProperty("error") && res.data.error === 0) { - resolve(); - } - throw res.data; - }).catch(err => { - reject(err); - }); - } - }); - } - receiveUpdate(f) { - this.emitter.addListener("update", f); - } - closeConnection() { - dns.stopMonitoring(); - this.log("LAN monitoring stopped as part of Homebridge shutdown."); - } + } + }); + } + receiveUpdate(f) { + this.emitter.addListener("update", f); + } + closeConnection() { + dns.stopMonitoring(); + this.log("LAN monitoring stopped as part of Homebridge shutdown."); + } }; \ No newline at end of file From ada5c535e49ee35bab65466a0954cfaae5c91a50 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 6 Sep 2020 01:25:13 +0100 Subject: [PATCH 0069/3183] close lan/ws on error --- lib/eWeLink.js | 10 +++++++++- lib/eWeLinkLAN.js | 2 +- lib/eWeLinkWS.js | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index c780b194..38b8fdc4 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -86,7 +86,15 @@ class eWeLink { this.log.warn("You have 'Request & Response Logging' enabled. This setting is not recommended for long-term use."); } })(); - }).catch(err => this.log.error("🔴 Cannot load homebridge-ewelink - %s", err)); + }).catch(err => { + this.log.error("🔴 Cannot load homebridge-ewelink - %s", err) + if (this.lanClient) { + this.lanClient.closeConnection(); + } + if (this.wsClient) { + this.wsClient.closeConnection(); + } + }); }); this.api.on('shutdown', () => { if (this.lanClient) { diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 098be312..7a22f442 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -163,6 +163,6 @@ module.exports = class eWeLinkLAN { } closeConnection() { dns.stopMonitoring(); - this.log("LAN monitoring stopped as part of Homebridge shutdown."); + this.log("LAN monitoring gracefully stopped."); } }; \ No newline at end of file diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index fb5ba293..73180031 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -151,7 +151,7 @@ module.exports = class eWeLinkWS { }); this.ws.on("close", (e, m) => { if (m === "Stopping Homebridge") { - this.log("Web socket closed as part of Homebridge shutdown."); + this.log("Web socket gracefully closed."); } else { this.log.warn("Web socket closed - [%s - %s].", e, m); if (e !== 1000) { From 204420cea8712b90538a99d1e3bce41491628575 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 6 Sep 2020 01:26:42 +0100 Subject: [PATCH 0070/3183] 2.24.3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6aaae582..e19dacd6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.24.2", + "version": "2.24.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a8d8bcaf..ea228f70 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.24.2", + "version": "2.24.3", "author": "bwp91", "contributors": [ "gbro115", From bb7c39b940dce94a71e9ae2b32e0165f7df55799 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sun, 6 Sep 2020 15:54:44 +0100 Subject: [PATCH 0071/3183] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f0c86501..501eea7f 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ * [How to copy Homebridge logs](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-copy-Homebridge-logs) * [How to enable/disable plugin extended logging](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-enable-disable-plugin-extended-logging) * [How to set up RF Bridge sensors](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-RF-Bridge-sensors) +* [How to set up Sonoff Camera (GK-200MP2-B)](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-Sonoff-Camera) ### About * [Support Request](https://github.com/bwp91/homebridge-ewelink/issues) * [Roadmap](https://github.com/bwp91/homebridge-ewelink/wiki/Roadmap) From 05951ebbbbf7735b51ae66b796b72e35a7d56a97 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 6 Sep 2020 16:28:24 +0100 Subject: [PATCH 0072/3183] garagedoor fix attempt --- lib/eWeLink.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 38b8fdc4..2eb7de37 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -439,6 +439,7 @@ class eWeLink { }); break; case "garage": + accessory.context.inUse = false; accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.TargetDoorState) .on("set", (value, callback) => { accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.TargetDoorState).value !== value ? @@ -865,6 +866,10 @@ class eWeLink { } internalGarageUpdate(accessory, value, callback) { try { + if (accessory.context.inUse) { + throw "it is currently in use"; + } + accessory.context.inUse = true; if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { throw "it is currently offline"; } @@ -928,9 +933,11 @@ class eWeLink { setTimeout(() => { accessory.getService(Service.GarageDoorOpener) .updateCharacteristic(Characteristic.CurrentDoorState, value === 0 ? 0 : 1); + accessory.context.inUse = false; callback(); }, parseInt(garageConfig.operationTime) * 100); } else { + accessory.context.inUse = false; callback(); } } catch (err) { @@ -1395,6 +1402,10 @@ class eWeLink { } externalGarageUpdate(accessory, params) { try { + if (accessory.context.inUse) { + throw "it is currently in use"; + } + accessory.context.inUse = true; let garageConfig, nSte; if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; @@ -1425,6 +1436,7 @@ class eWeLink { .updateCharacteristic(Characteristic.CurrentDoorState, nSte - 2); }, parseInt(garageConfig.operationTime) * 100); } + accessory.context.inUse = false; } catch (err) { this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); } From b459a73051bc25e445f3e895b6d1e3eb7a66cb88 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 6 Sep 2020 16:29:40 +0100 Subject: [PATCH 0073/3183] 2.24.4-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index e19dacd6..d6087665 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.24.3", + "version": "2.24.4-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index ea228f70..16e7198d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.24.3", + "version": "2.24.4-0", "author": "bwp91", "contributors": [ "gbro115", From 8fe8af13fefd0f73b0f191643c9295ab68a873a1 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sun, 6 Sep 2020 17:59:09 +0100 Subject: [PATCH 0074/3183] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 501eea7f..cbd907d0 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,8 @@ ### Setup -* [Installation](https://github.com/bwp91/homebridge-ewelink/wiki/Installation) +* [Installation (Homebridge)](https://github.com/bwp91/homebridge-ewelink/wiki/Installation-(Homebridge)) +* [Installation (HOOBS)](https://github.com/bwp91/homebridge-ewelink/wiki/Installation-(HOOBS)) * [Configuration](https://github.com/bwp91/homebridge-ewelink/wiki/Configuration) * [Beta Version](https://github.com/bwp91/homebridge-ewelink/wiki/Beta-Version) ### Features From 0fe6611e678da03c34345d67b3e9ccbf667d9de1 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 6 Sep 2020 18:06:57 +0100 Subject: [PATCH 0075/3183] added kofi link --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index 16e7198d..a9cca3b7 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,10 @@ "ws": "7.3.1" }, "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/bwp91" + }, { "type": "patreon", "url": "https://www.patreon.com/bwp91" From 9d95d70a998e4e4ef62a1791a3664c678c192329 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 7 Sep 2020 11:13:34 +0100 Subject: [PATCH 0076/3183] rename variable --- lib/eWeLink.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 2eb7de37..2c3c4aea 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -44,7 +44,7 @@ class eWeLink { return this.lanClient.getHosts(); }).then(res => { //*** Set up the LAN mode listener ***\\ this.lanDevices = res.map; - this.lanDeviceOnline = res.count; + this.lanDevicesOnline = res.count; return this.lanClient.startMonitor(); }).then(() => { //*** Use the device list to refresh Homebridge accessories ***\\ (() => { @@ -70,7 +70,7 @@ class eWeLink { //*** Logging always helps to see if everything is okay so far ***\\ this.log("[%s] eWeLink devices were loaded from the Homebridge cache.", this.devicesInHB.size); this.log("[%s] primary devices were loaded from your eWeLink account.", this.devicesInEwe.size); - this.log("[%s] primary devices were discovered on your local network.", this.lanDeviceOnline); + this.log("[%s] primary devices were discovered on your local network.", this.lanDevicesOnline); //*** Remove Homebridge accessories that don't appear in eWeLink ***\\ this.devicesInHB.forEach(accessory => { if (!this.devicesInEwe.has(accessory.context.eweDeviceId)) { From 71a4000b42d563de4d16926daf5d2268ec8385cf Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 7 Sep 2020 11:13:57 +0100 Subject: [PATCH 0077/3183] feat: ip address update --- lib/eWeLinkLAN.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 7a22f442..e6db8410 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -58,15 +58,25 @@ module.exports = class eWeLinkLAN { .filter(value => this.deviceMap.has(value.rdata.id)) .forEach(value => { let rdata = value.rdata, - deviceKey = this.deviceMap.get(rdata.id).apiKey, + deviceInfo = this.deviceMap.get(rdata.id), data = rdata.data1 + (rdata.hasOwnProperty("data2") ? rdata.data2 : "") + (rdata.hasOwnProperty("data3") ? rdata.data3 : "") + (rdata.hasOwnProperty("data4") ? rdata.data4 : ""), - key = crypto.createHash("md5").update(Buffer.from(deviceKey, "utf8")).digest(), + key = crypto.createHash("md5").update(Buffer.from(deviceInfo.apiKey, "utf8")).digest(), dText = crypto.createDecipheriv("aes-128-cbc", key, Buffer.from(rdata.iv, "base64")), pText = Buffer.concat([dText.update(Buffer.from(data, "base64")), dText.final()]).toString("utf8"), params; + if (packet.address !== deviceInfo.ip) { + this.deviceMap.set(rdata.id, { + apiKey: deviceInfo.apiKey, + online: true, + ip: packet.address + }); + if (this.debug) { + this.log.warn("[%s] updating IP address to [%s].", rdata.id, packet.address); + } + } try { params = JSON.parse(pText); } catch (e) { From 058982df175fe0359eba1219b142f3a0d7ce4630 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 7 Sep 2020 13:10:32 +0100 Subject: [PATCH 0078/3183] garage door bug fix? --- lib/eWeLink.js | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 2c3c4aea..298a1ca6 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -87,7 +87,7 @@ class eWeLink { } })(); }).catch(err => { - this.log.error("🔴 Cannot load homebridge-ewelink - %s", err) + this.log.error("🔴 Cannot load homebridge-ewelink - %s", err); if (this.lanClient) { this.lanClient.closeConnection(); } @@ -157,7 +157,7 @@ class eWeLink { } else if (cns.devicesZB.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SWX", "zb_sub"); } else if (cns.devicesCamera.includes(device.extra.uiid)) { - this.log.warn("[%s] please consider using homebridge-camera-ffmpeg to use this camera.", device.name); + this.log.warn("[%s] please see \"https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-Sonoff-Camera\".", device.name); return; } else { this.log.warn("[%s] cannot be added as it is not supported by this plugin. Please make a GitHub issue request.", device.name); @@ -172,6 +172,7 @@ class eWeLink { accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); accessory.context.reachableWAN = accessory.context.eweUIID !== 102 ? device.online : true; //*** DW2 ***\\ accessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; + accessory.context.inUse = false; let str = accessory.context.reachableLAN ? "and locally with IP [" + this.lanDevices.get(device.deviceid).ip + "]" : "but LAN mode unavailable as unsupported/shared device"; @@ -439,7 +440,6 @@ class eWeLink { }); break; case "garage": - accessory.context.inUse = false; accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.TargetDoorState) .on("set", (value, callback) => { accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.TargetDoorState).value !== value ? @@ -866,13 +866,16 @@ class eWeLink { } internalGarageUpdate(accessory, value, callback) { try { - if (accessory.context.inUse) { - throw "it is currently in use"; - } - accessory.context.inUse = true; if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { throw "it is currently offline"; } + if (accessory.context.inUse) { + let str = "[" + accessory.displayName + "] skipping update as it is currently moving."; + this.log.warn(str); + callback(str); + return; + } + accessory.context.inUse = true; let garageConfig; if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; @@ -894,6 +897,7 @@ class eWeLink { accessory.getService(Service.GarageDoorOpener) .updateCharacteristic(Characteristic.TargetDoorState, value) .updateCharacteristic(Characteristic.CurrentDoorState, value); + accessory.context.inUse = false; callback(); return; } @@ -941,6 +945,7 @@ class eWeLink { callback(); } } catch (err) { + accessory.context.inUse = false; let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); @@ -1403,7 +1408,9 @@ class eWeLink { externalGarageUpdate(accessory, params) { try { if (accessory.context.inUse) { - throw "it is currently in use"; + let str = "[" + accessory.displayName + "] skipping update as it is currently moving."; + this.log.warn(str); + return; } accessory.context.inUse = true; let garageConfig, nSte; @@ -1416,15 +1423,18 @@ class eWeLink { switch (garageConfig.setup) { case "oneSwitch": if (params.switch === "off" || garageConfig.sensorId) { + accessory.context.inUse = false; return; } nSte = [0, 2].includes(accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.CurrentDoorState).value) ? 3 : 2; break; case "twoSwitch": if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { + accessory.context.inUse = false; return; } // @TODO twoSwitch garage external update + accessory.context.inUse = false; return; } if (garageConfig.setup !== "oneSwitch" || !garageConfig.sensorId) { @@ -1438,6 +1448,7 @@ class eWeLink { } accessory.context.inUse = false; } catch (err) { + accessory.context.inUse = false; this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); } } From e441e76347db9c8c5d1a48f01ea2561f54b11bce Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 7 Sep 2020 13:11:31 +0100 Subject: [PATCH 0079/3183] 2.24.4-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index d6087665..d082ba02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.24.4-0", + "version": "2.24.4-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a9cca3b7..1a370dc4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.24.4-0", + "version": "2.24.4-1", "author": "bwp91", "contributors": [ "gbro115", From 238a32a47a1f6ee73bfdfa1a987feb5157e4787b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 7 Sep 2020 18:04:28 +0100 Subject: [PATCH 0080/3183] remove inching setting --- config.schema.json | 7 ------- 1 file changed, 7 deletions(-) diff --git a/config.schema.json b/config.schema.json index 9362768b..5d56f513 100644 --- a/config.schema.json +++ b/config.schema.json @@ -143,12 +143,6 @@ "description":"Total time in deciseconds to fully open/close the blind/door. Count the time in seconds and multiply by 10, for example 100 for 10 seconds or 75 for 7.5 seconds.", "default":100 }, - "inched":{ - "title":"Device Inching", - "type":"boolean", - "description":"If device inching is already setup in your eWeLink account then set this to true. Otherwise this plugin will send an 'off' command after half a second to mimic the inching behaviour.", - "default":true - }, "sensorId":{ "type":"string", "title":"Sensor", @@ -274,7 +268,6 @@ "groups[].deviceId", "groups[].setup", "groups[].operationTime", - "groups[].inched", "groups[].sensorId" ] } From a15195d92bacbf8a07dead1a435954578aa02e99 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 7 Sep 2020 18:04:43 +0100 Subject: [PATCH 0081/3183] consistency in text --- lib/eWeLinkLAN.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index e6db8410..8a2d82d3 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -145,9 +145,9 @@ module.exports = class eWeLinkLAN { }; if (this.debugReqRes) { let msg = JSON.stringify(json, null, 2).replace(json.apikey, "**hidden**").replace(json.apikey, "**hidden**").replace(json.deviceid, "**hidden**"); - this.log.warn("LAN mode message sent. This text is yellow for clarity.\n%s", msg); + this.log.warn("LAN message sent. This text is yellow for clarity.\n%s", msg); } else if (this.debug) { - this.log("LAN mode message sent."); + this.log("LAN message sent."); } axios({ method: "post", From 3cf55cfca10eb62b817631b9d62601e112b8b926 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 7 Sep 2020 18:35:30 +0100 Subject: [PATCH 0082/3183] garage door rewrites --- lib/eWeLink.js | 103 +++++++++++++++---------------------------------- 1 file changed, 31 insertions(+), 72 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 298a1ca6..9b149e63 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -810,13 +810,13 @@ class eWeLink { if (blindConfig.type !== "blind" || !["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { throw "improper configuration"; } - let pSte, params = {}; + let oldPos, params = {}; value = value >= 50 ? 100 : 0; - pSte = accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.PositionState).value; - if (value === pSte * 100) { + oldPos = accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.PositionState).value; + if (value === oldPos * 100) { accessory.getService(Service.WindowCovering) .updateCharacteristic(Characteristic.TargetPosition, value) - .updateCharacteristic(Characteristic.PositionState, pSte); + .updateCharacteristic(Characteristic.PositionState, oldPos); callback(); return; } @@ -836,22 +836,6 @@ class eWeLink { accessory.getService(Service.WindowCovering) .updateCharacteristic(Characteristic.TargetPosition, value) .updateCharacteristic(Characteristic.PositionState, (value / 100)); - if (!blindConfig.inched || blindConfig.inched === "false") { - setTimeout(() => { - switch (blindConfig.setup) { - case "oneSwitch": - params.switch = "off"; - break; - case "twoSwitch": - params.switches[0].switch = "off"; - params.switches[1].switch = "off"; - break; - } - this.sendDeviceUpdate(accessory, params, function() { - return; - }); - }, 500); - } setTimeout(() => { accessory.getService(Service.WindowCovering) .updateCharacteristic(Characteristic.CurrentPosition, value) @@ -866,16 +850,10 @@ class eWeLink { } internalGarageUpdate(accessory, value, callback) { try { + accessory.context.inUse = true; if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { throw "it is currently offline"; } - if (accessory.context.inUse) { - let str = "[" + accessory.displayName + "] skipping update as it is currently moving."; - this.log.warn(str); - callback(str); - return; - } - accessory.context.inUse = true; let garageConfig; if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; @@ -885,65 +863,45 @@ class eWeLink { } let sensorDefinition = garageConfig.sensorId || false, sAccessory = false, - pSte, + oldPos, + newPos = value, params = {}; if (sensorDefinition && !(sAccessory = this.devicesInHB.get(garageConfig.sensorId + "SWX"))) { throw "defined sensor doesn't exist"; } - this.log("[%s] has received request to [%s].", accessory.displayName, value === 0 ? "open" : "close"); - pSte = sAccessory ? - sAccessory.getService(Service.ContactSensor).getCharacteristic(Characteristic.ContactSensorState).value === 0 ? 1 : 0 : [0, 2].includes(accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.CurrentDoorState).value) ? 0 : 1; - if (value === pSte) { - accessory.getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.TargetDoorState, value) - .updateCharacteristic(Characteristic.CurrentDoorState, value); + this.log("[%s] has received request to [%s].", accessory.displayName, newPos === 0 ? "open" : "close"); + oldPos = sAccessory ? + sAccessory.getService(Service.ContactSensor).getCharacteristic(Characteristic.ContactSensorState).value === 0 ? 1 : 0 : + accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.CurrentDoorState).value; + if (newPos === (oldPos % 2)) { accessory.context.inUse = false; callback(); return; } + accessory.getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.TargetDoorState, newPos) + .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2); switch (garageConfig.setup) { case "oneSwitch": params.switch = "on"; break; case "twoSwitch": params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = value === 0 ? "on" : "off"; - params.switches[1].switch = value === 1 ? "on" : "off"; + params.switches[0].switch = newPos === 0 ? "on" : "off"; + params.switches[1].switch = newPos === 1 ? "on" : "off"; break; } this.sendDeviceUpdate(accessory, params, function() { return; }); - accessory.getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.TargetDoorState, value) - .updateCharacteristic(Characteristic.CurrentDoorState, value === 0 ? 2 : 3); - if (!garageConfig.inched || garageConfig.inched === "false") { - setTimeout(() => { - switch (garageConfig.setup) { - case "oneSwitch": - params.switch = "off"; - break; - case "twoSwitch": - params.switches[0].switch = "off"; - params.switches[1].switch = "off"; - break; - } - this.sendDeviceUpdate(accessory, params, function() { - return; - }); - }, 500); - } - if (!sAccessory) { - setTimeout(() => { + setTimeout(() => { + if (!sAccessory) { accessory.getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.CurrentDoorState, value === 0 ? 0 : 1); - accessory.context.inUse = false; - callback(); - }, parseInt(garageConfig.operationTime) * 100); - } else { + .updateCharacteristic(Characteristic.CurrentDoorState, newPos === 0 ? 0 : 1); + } accessory.context.inUse = false; - callback(); - } + }, parseInt(garageConfig.operationTime) * 100); + callback(); } catch (err) { accessory.context.inUse = false; let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; @@ -1408,12 +1366,14 @@ class eWeLink { externalGarageUpdate(accessory, params) { try { if (accessory.context.inUse) { - let str = "[" + accessory.displayName + "] skipping update as it is currently moving."; + let str = "[" + accessory.displayName + "] ignoring update as it is already moving."; this.log.warn(str); return; } accessory.context.inUse = true; - let garageConfig, nSte; + let garageConfig, + oldPos = accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.CurrentDoorState).value, + newPos = [0, 2].includes(oldPos) ? 3 : 2; if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } @@ -1426,7 +1386,6 @@ class eWeLink { accessory.context.inUse = false; return; } - nSte = [0, 2].includes(accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.CurrentDoorState).value) ? 3 : 2; break; case "twoSwitch": if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { @@ -1437,13 +1396,13 @@ class eWeLink { accessory.context.inUse = false; return; } - if (garageConfig.setup !== "oneSwitch" || !garageConfig.sensorId) { + if (!garageConfig.sensorId) { accessory.getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.CurrentDoorState, nSte) - .updateCharacteristic(Characteristic.TargetDoorState, nSte - 2); + .updateCharacteristic(Characteristic.CurrentDoorState, newPos) + .updateCharacteristic(Characteristic.TargetDoorState, newPos - 2); setTimeout(() => { accessory.getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.CurrentDoorState, nSte - 2); + .updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2); }, parseInt(garageConfig.operationTime) * 100); } accessory.context.inUse = false; From 4e09194256c315b5b84183b0217380a40485c5ad Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 7 Sep 2020 20:42:12 +0100 Subject: [PATCH 0083/3183] more garage improvements --- lib/eWeLink.js | 70 ++++++++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 9b149e63..d6462e40 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -851,6 +851,7 @@ class eWeLink { internalGarageUpdate(accessory, value, callback) { try { accessory.context.inUse = true; + accessory.context.state = value; if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { throw "it is currently offline"; } @@ -865,7 +866,8 @@ class eWeLink { sAccessory = false, oldPos, newPos = value, - params = {}; + params = {}, + wsDelay = 0; if (sensorDefinition && !(sAccessory = this.devicesInHB.get(garageConfig.sensorId + "SWX"))) { throw "defined sensor doesn't exist"; } @@ -878,29 +880,39 @@ class eWeLink { callback(); return; } - accessory.getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.TargetDoorState, newPos) - .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2); - switch (garageConfig.setup) { - case "oneSwitch": - params.switch = "on"; - break; - case "twoSwitch": - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = newPos === 0 ? "on" : "off"; - params.switches[1].switch = newPos === 1 ? "on" : "off"; - break; + if (garageConfig.setup === "oneSwitch" && [2, 3].includes(oldPos)) { + accessory.getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.CurrentDoorState, oldPos * 2 % 3 + 2); + wsDelay = 1500; } - this.sendDeviceUpdate(accessory, params, function() { - return; - }); setTimeout(() => { - if (!sAccessory) { + // final check to continue + if (accessory.context.state === newPos) { accessory.getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.CurrentDoorState, newPos === 0 ? 0 : 1); + .updateCharacteristic(Characteristic.TargetDoorState, newPos) + .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2); + switch (garageConfig.setup) { + case "oneSwitch": + params.switch = "on"; + break; + case "twoSwitch": + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = newPos === 0 ? "on" : "off"; + params.switches[1].switch = newPos === 1 ? "on" : "off"; + break; + } + this.sendDeviceUpdate(accessory, params, function() { + return; + }); + setTimeout(() => { + if (!sAccessory) { + accessory.getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.CurrentDoorState, newPos === 0 ? 0 : 1); + } + accessory.context.inUse = false; + }, parseInt(garageConfig.operationTime) * 100); } - accessory.context.inUse = false; - }, parseInt(garageConfig.operationTime) * 100); + }, wsDelay); callback(); } catch (err) { accessory.context.inUse = false; @@ -1365,12 +1377,6 @@ class eWeLink { } externalGarageUpdate(accessory, params) { try { - if (accessory.context.inUse) { - let str = "[" + accessory.displayName + "] ignoring update as it is already moving."; - this.log.warn(str); - return; - } - accessory.context.inUse = true; let garageConfig, oldPos = accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.CurrentDoorState).value, newPos = [0, 2].includes(oldPos) ? 3 : 2; @@ -1383,19 +1389,20 @@ class eWeLink { switch (garageConfig.setup) { case "oneSwitch": if (params.switch === "off" || garageConfig.sensorId) { - accessory.context.inUse = false; return; } break; case "twoSwitch": if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { - accessory.context.inUse = false; return; } // @TODO twoSwitch garage external update - accessory.context.inUse = false; return; } + if (accessory.context.inUse) { + return; + } + accessory.context.inUse = true; if (!garageConfig.sensorId) { accessory.getService(Service.GarageDoorOpener) .updateCharacteristic(Characteristic.CurrentDoorState, newPos) @@ -1405,7 +1412,10 @@ class eWeLink { .updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2); }, parseInt(garageConfig.operationTime) * 100); } - accessory.context.inUse = false; + setTimeout(() => { + accessory.context.inUse = false; + }, parseInt(garageConfig.operationTime) * 100); + } catch (err) { accessory.context.inUse = false; this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); From 726b759357dd8a9724aed4ae1a87aed7f23fd356 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 7 Sep 2020 20:43:11 +0100 Subject: [PATCH 0084/3183] 2.25.0-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index d082ba02..6b2b69da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.24.4-1", + "version": "2.25.0-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1a370dc4..fa68bb8d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.24.4-1", + "version": "2.25.0-0", "author": "bwp91", "contributors": [ "gbro115", From df03e5f2309350239d014f178e0377f9846648d2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 7 Sep 2020 21:37:45 +0100 Subject: [PATCH 0085/3183] initial lock support --- config.schema.json | 8 ++++- lib/eWeLink.js | 83 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 82 insertions(+), 9 deletions(-) diff --git a/config.schema.json b/config.schema.json index 5d56f513..65074d0d 100644 --- a/config.schema.json +++ b/config.schema.json @@ -88,7 +88,7 @@ "groups":{ "type":"array", "title":"Custom Groups", - "description":"You can group channels of Sonoff devices to simulate another HomeKit accessory instead of having each switch separately. Currently only blinds and garage doors are supported.", + "description":"You can group channels of Sonoff devices to simulate another HomeKit accessory instead of having each switch separately. Currently only blinds, garage doors and locks are supported.", "items":{ "type":"object", "properties":{ @@ -109,6 +109,12 @@ "enum":[ "garage" ] + }, + { + "title":"Lock", + "enum":[ + "lock" + ] } ] }, diff --git a/lib/eWeLink.js b/lib/eWeLink.js index d6462e40..87220176 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -123,6 +123,8 @@ class eWeLink { this.addAccessory(device, device.deviceid + "SWX", "blind"); } else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "garage") { this.addAccessory(device, device.deviceid + "SWX", "garage"); + } else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "lock") { + this.addAccessory(device, device.deviceid + "SWX", "lock"); } else if (cns.devicesSensor.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SWX", "sensor"); } else if (cns.devicesFan.includes(device.extra.uiid)) { @@ -277,6 +279,11 @@ class eWeLink { .setCharacteristic(Characteristic.TargetDoorState, 1) .setCharacteristic(Characteristic.ObstructionDetected, false); break; + case "lock": + accessory.addService(Service.LockMechanism) + .setCharacteristic(Characteristic.LockCurrentState, 1) + .setCharacteristic(Characteristic.LockTargetState, 1); + break; case "sensor": accessory.addService(Service.ContactSensor); break; @@ -447,6 +454,14 @@ class eWeLink { callback(); }); break; + case "lock": + accessory.getService(Service.LockMechanism).getCharacteristic(Characteristic.LockTargetState) + .on("set", (value, callback) => { + accessory.getService(Service.LockMechanism).getCharacteristic(Characteristic.LockTargetState).value !== value ? + this.internalLockUpdate(accessory, value, callback) : + callback(); + }); + break; case "fan": accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active) .on("set", (value, callback) => { @@ -603,6 +618,11 @@ class eWeLink { this.externalGarageUpdate(accessory, newParams); } return true; + case "lock": + if (newParams.hasOwnProperty("switch")) { + this.externalLockUpdate(accessory, newParams); + } + return true; case "sensor": if (newParams.hasOwnProperty("switch")) { this.externalSensorUpdate(accessory, newParams); @@ -850,8 +870,6 @@ class eWeLink { } internalGarageUpdate(accessory, value, callback) { try { - accessory.context.inUse = true; - accessory.context.state = value; if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { throw "it is currently offline"; } @@ -862,6 +880,8 @@ class eWeLink { if (garageConfig.type !== "garage" || !["oneSwitch", "twoSwitch"].includes(garageConfig.setup)) { throw "improper configuration"; } + accessory.context.inUse = true; + accessory.context.state = value; let sensorDefinition = garageConfig.sensorId || false, sAccessory = false, oldPos, @@ -921,6 +941,36 @@ class eWeLink { callback(str); } } + internalLockUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let lockConfig; + if (!(lockConfig = this.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; + } + if (lockConfig.type !== "lock") { + throw "improper configuration"; + } + accessory.context.inUse = true; + let params = {}; + this.log("[%s] has received request to [%s].", accessory.displayName, value === 0 ? "unlock" : "lock"); + accessory.getService(Service.LockMechanism) + .updateCharacteristic(Characteristic.LockTargetState, value); + params.switch = "on"; + this.sendDeviceUpdate(accessory, params, callback); + setTimeout(() => { + accessory.context.inUse = false; + accessory.getService(Service.LockMechanism) + .updateCharacteristic(Characteristic.LockCurrentState, value); + }, 3000); + } catch (err) { + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } internalFanUpdate(accessory, type, value, callback) { try { if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { @@ -1388,20 +1438,17 @@ class eWeLink { } switch (garageConfig.setup) { case "oneSwitch": - if (params.switch === "off" || garageConfig.sensorId) { + if (params.switch === "off" || garageConfig.sensorId || accessory.context.inUse) { return; } break; case "twoSwitch": - if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { + if ((params.switches[0].switch === "off" && params.switches[1].switch === "off") || accessory.context.inUse) { return; } // @TODO twoSwitch garage external update return; } - if (accessory.context.inUse) { - return; - } accessory.context.inUse = true; if (!garageConfig.sensorId) { accessory.getService(Service.GarageDoorOpener) @@ -1415,12 +1462,32 @@ class eWeLink { setTimeout(() => { accessory.context.inUse = false; }, parseInt(garageConfig.operationTime) * 100); - } catch (err) { accessory.context.inUse = false; this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); } } + externalLockUpdate(accessory, params) { + try { + let lockConfig, + oldPos = accessory.getService(Service.LockMechanism).getCharacteristic(Characteristic.LockCurrentState).value, + newPos = oldPos === 0 ? 1 : 0; + if (!(lockConfig = this.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; + } + if (lockConfig.type !== "lock") { + throw "improper configuration"; + } + if (params.switch === "off" || accessory.context.inUse) { + return; + } + accessory.getService(Service.LockMechanism) + .updateCharacteristic(Characteristic.LockCurrentState, newPos) + .updateCharacteristic(Characteristic.LockTargetState, newPos); + } catch (err) { + this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + } + } externalSensorUpdate(accessory, params) { try { let oldState = accessory.getService(Service.ContactSensor).getCharacteristic(Characteristic.ContactSensorState).value, From b51e09f7e0772851d888074f5c9963007eee86a6 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 7 Sep 2020 21:38:23 +0100 Subject: [PATCH 0086/3183] 2.25.0-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6b2b69da..f64d553a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.25.0-0", + "version": "2.25.0-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index fa68bb8d..1cdcd8e8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.25.0-0", + "version": "2.25.0-1", "author": "bwp91", "contributors": [ "gbro115", From c6cef109b8ff8b25c27702f52a4bdb6aeda5ee57 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 7 Sep 2020 22:59:01 +0100 Subject: [PATCH 0087/3183] changes to lock --- lib/eWeLink.js | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 87220176..f97540fd 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -456,11 +456,7 @@ class eWeLink { break; case "lock": accessory.getService(Service.LockMechanism).getCharacteristic(Characteristic.LockTargetState) - .on("set", (value, callback) => { - accessory.getService(Service.LockMechanism).getCharacteristic(Characteristic.LockTargetState).value !== value ? - this.internalLockUpdate(accessory, value, callback) : - callback(); - }); + .on("set", (value, callback) => this.internalLockUpdate(accessory, value, callback)); break; case "fan": accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active) @@ -906,7 +902,6 @@ class eWeLink { wsDelay = 1500; } setTimeout(() => { - // final check to continue if (accessory.context.state === newPos) { accessory.getService(Service.GarageDoorOpener) .updateCharacteristic(Characteristic.TargetDoorState, newPos) @@ -946,7 +941,7 @@ class eWeLink { if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { throw "it is currently offline"; } - let lockConfig; + let lockConfig, params = {}; if (!(lockConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } @@ -954,18 +949,20 @@ class eWeLink { throw "improper configuration"; } accessory.context.inUse = true; - let params = {}; - this.log("[%s] has received request to [%s].", accessory.displayName, value === 0 ? "unlock" : "lock"); + this.log("[%s] has received request to unlock.", accessory.displayName); accessory.getService(Service.LockMechanism) - .updateCharacteristic(Characteristic.LockTargetState, value); + .updateCharacteristic(Characteristic.LockTargetState, 0) + .updateCharacteristic(Characteristic.LockCurrentState, 0); params.switch = "on"; this.sendDeviceUpdate(accessory, params, callback); setTimeout(() => { - accessory.context.inUse = false; accessory.getService(Service.LockMechanism) - .updateCharacteristic(Characteristic.LockCurrentState, value); - }, 3000); + .updateCharacteristic(Characteristic.LockTargetState, 1) + .updateCharacteristic(Characteristic.LockCurrentState, 1); + accessory.context.inUse = false; + }, parseInt(lockConfig.operationTime) * 100); } catch (err) { + accessory.context.inUse = false; let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); @@ -1469,9 +1466,7 @@ class eWeLink { } externalLockUpdate(accessory, params) { try { - let lockConfig, - oldPos = accessory.getService(Service.LockMechanism).getCharacteristic(Characteristic.LockCurrentState).value, - newPos = oldPos === 0 ? 1 : 0; + let lockConfig; if (!(lockConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } @@ -1481,10 +1476,18 @@ class eWeLink { if (params.switch === "off" || accessory.context.inUse) { return; } + accessory.context.inUse = true; accessory.getService(Service.LockMechanism) - .updateCharacteristic(Characteristic.LockCurrentState, newPos) - .updateCharacteristic(Characteristic.LockTargetState, newPos); + .updateCharacteristic(Characteristic.LockCurrentState, 0) + .updateCharacteristic(Characteristic.LockTargetState, 0); + setTimeout(() => { + accessory.getService(Service.LockMechanism) + .updateCharacteristic(Characteristic.LockCurrentState, 1) + .updateCharacteristic(Characteristic.LockTargetState, 1); + accessory.context.inUse = false; + }, parseInt(lockConfig.operationTime) * 100); } catch (err) { + accessory.context.inUse = false; this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); } } From 9d3d76428c3029be135da751211019e0e4f7ca69 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 7 Sep 2020 23:20:56 +0100 Subject: [PATCH 0088/3183] #82 fix? --- lib/eWeLink.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index f97540fd..ded8ce26 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -729,9 +729,9 @@ class eWeLink { case "sysmsg": if ((accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0"))) { let isX = accessory.context.hbDeviceId.substr(-1) === "X"; - if (source === "ws" && accessory.context.reachableWAN !== device.params.online) { + if (source === "WS" && accessory.context.reachableWAN !== device.params.online) { accessory.context.reachableWAN = device.params.online; - this.log("[%s] has been reported [%s].", accessory.displayName, accessory.context.reachableWAN ? "online" : "offline"); + this.log("[%s] has been reported [%s] via [WS].", accessory.displayName, accessory.context.reachableWAN ? "online" : "offline"); this.devicesInHB.set(accessory.context.hbDeviceId, accessory); if (accessory.context.reachableWAN) { this.wsClient.requestUpdate(accessory); @@ -750,11 +750,13 @@ class eWeLink { break; case "update": if ((accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0"))) { - if (source === "ws" && !accessory.context.reachableWAN) { + if (source === "WS" && !accessory.context.reachableWAN) { accessory.context.reachableWAN = true; + this.log("[%s] has been reported [online] via [WS].", accessory.displayName); } - if (source === "lan" && !accessory.context.reachableLAN) { + if (source === "LAN" && !accessory.context.reachableLAN) { accessory.context.reachableLAN = true; + this.log("[%s] has been reported [online] via [LAN].", accessory.displayName); } if (this.config.debug) { this.log("[%s] externally updated from above %s message and will be refreshed.", accessory.displayName, source); From bb784067f196c39742a584e1ac45efc3101b5b16 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 7 Sep 2020 23:22:48 +0100 Subject: [PATCH 0089/3183] 2.25.0-2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f64d553a..13f0eb35 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.25.0-1", + "version": "2.25.0-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1cdcd8e8..bbe0307b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.25.0-1", + "version": "2.25.0-2", "author": "bwp91", "contributors": [ "gbro115", From 6d52c26eba25b8109071eeaa04f45c3299931d1b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 8 Sep 2020 07:42:23 +0100 Subject: [PATCH 0090/3183] log text consistency --- lib/eWeLinkWS.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 73180031..eb50d15e 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -203,7 +203,9 @@ module.exports = class eWeLinkWS { this.ws.send(req); if (this.debugReqRes) { let msg = JSON.stringify(json, null, 2).replace(json.apikey, "**hidden**").replace(json.apiKey, "**hidden**").replace(json.deviceid, "**hidden**"); - this.log.warn("Web socket message sent. This text is yellow for clarity.\n%s", msg); + this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("WS message sent."); } return; } @@ -246,7 +248,9 @@ module.exports = class eWeLinkWS { this.ws.send(req); if (this.debugReqRes) { let msg = JSON.stringify(json, null, 2).replace(json.apikey, "**hidden**").replace(json.apiKey, "**hidden**").replace(json.deviceid, "**hidden**"); - this.log.warn("Web socket message sent. This text is yellow for clarity.\n%s", msg); + this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("WS message sent."); } return; } From 6e33f28e984285066abb5cda76b3dc0a0eb764b4 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 8 Sep 2020 07:50:46 +0100 Subject: [PATCH 0091/3183] rename groups to custom types --- config.schema.json | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/config.schema.json b/config.schema.json index 65074d0d..4175f7cb 100644 --- a/config.schema.json +++ b/config.schema.json @@ -87,16 +87,21 @@ }, "groups":{ "type":"array", - "title":"Custom Groups", - "description":"You can group channels of Sonoff devices to simulate another HomeKit accessory instead of having each switch separately. Currently only blinds, garage doors and locks are supported.", + "title":"Custom Device Types", + "description":"You can use this setting to set up custom device types within Homebridge. Currently only blinds, garage doors and locks are supported.", "items":{ "type":"object", "properties":{ + "deviceId":{ + "type":"string", + "title":"Device ID", + "description":"Device ID from your eWeLink app (ten digits normally in the format 1000******)." + }, "type":{ "type":"string", "title":"Type", "default":"null", - "description":"A description of this group.", + "description":"The new type for this device.", "oneOf":[ { "title":"Blind", @@ -118,16 +123,11 @@ } ] }, - "deviceId":{ - "type":"string", - "title":"Device ID", - "description":"Device ID from your eWeLink app (ten digits normally in the format 1000******)." - }, "setup":{ "type":"string", "title":"Device Setup", "default":"null", - "description":"The device setup.", + "description":"The device setup. Please ignore this setting for locks", "oneOf":[ { "title":"One Switch - for up and down", @@ -146,13 +146,13 @@ "operationTime":{ "type":"number", "title":"Operation Time", - "description":"Total time in deciseconds to fully open/close the blind/door. Count the time in seconds and multiply by 10, for example 100 for 10 seconds or 75 for 7.5 seconds.", + "description":"For blinds and garage doors this is the total time in deciseconds to fully open/close the device. For locks this is the time to show the Home app tile as unlocked. Count the time in seconds and multiply by 10, for example 100 for 10 seconds or 75 for 7.5 seconds.", "default":100 }, "sensorId":{ "type":"string", "title":"Sensor", - "description":"A Sonoff DW2 sensor can be used for a 'one switch' setup. This is to determine the current open/closed state of this device. Please enter the 10 digit device ID. Otherwise leave this blank." + "description":"A Sonoff DW2 sensor can optionally be used for blinds and garage doors. This is to determine the current open/closed state of the device. Please enter the 10 digit device ID. Otherwise leave this blank." } } } @@ -263,15 +263,15 @@ { "key":"groups", "expandable":true, - "title":"Custom Groups", - "add":"Add Another Group", + "title":"Custom Device Types", + "add":"Add Another Type", "type":"array", "items":[ { "type":"fieldset", "items":[ - "groups[].type", "groups[].deviceId", + "groups[].type", "groups[].setup", "groups[].operationTime", "groups[].sensorId" From fa43686eecfc88e8250778a2fd33898cb489e18c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 8 Sep 2020 09:16:03 +0100 Subject: [PATCH 0092/3183] add updateSource to params --- lib/constants.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/constants.js b/lib/constants.js index 1a11a419..354c4736 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -20,7 +20,7 @@ module.exports = { devicesRFBridge: [28], devicesZBBridge: [66], devicesZB: [1000, 1770, 2026, 3026], - paramsToKeep: ["bright", "brightness", "channel", "cmd", "colorB", "colorG", "colorR", "currentHumidity", "currentTemperature", "fan", "humidity", "key", "light", "lock", "mainSwitch", "mode", "online", "rfChl", "rfList", "rfTrig", "sensorType", "speed", "state", "switch", "switches", "temperature", "type", "zyx_mode"], + paramsToKeep: ["bright", "brightness", "channel", "cmd", "colorB", "colorG", "colorR", "currentHumidity", "currentTemperature", "fan", "humidity", "key", "light", "lock", "mainSwitch", "mode", "online", "rfChl", "rfList", "rfTrig", "sensorType", "speed", "state", "switch", "switches", "temperature", "type", "updateSource", "zyx_mode"], chansFromUiid: { 1: 1, // "SOCKET" \\ 20, MINI, BASIC, S26 2: 2, // "SOCKET_2" \\ From 16c22a26fd5b15fb27b78266a0354d60bcba4c60 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 8 Sep 2020 09:16:22 +0100 Subject: [PATCH 0093/3183] updateSource changes --- lib/eWeLinkLAN.js | 2 +- lib/eWeLinkWS.js | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 8a2d82d3..89e1a337 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -90,7 +90,7 @@ module.exports = class eWeLinkLAN { } } } - params.updateSource = "lan"; + params.updateSource = "LAN"; if (Object.keys(params).length > 0) { let returnTemplate = { deviceid: rdata.id, diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index eb50d15e..8afe3926 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -96,9 +96,9 @@ module.exports = class eWeLinkWS { this.ws.send("ping"); }, (device.config.hbInterval + 7) * 1000); } else if (device.hasOwnProperty("action")) { + device.params.updateSource = "WS"; switch (device.action) { case "sysmsg": - device.params.updateSource = "ws"; let returnTemplate = { deviceid: device.deviceid, action: "sysmsg", @@ -113,20 +113,18 @@ module.exports = class eWeLinkWS { this.emitter.emit("update", returnTemplate); break; case "update": - let params = device.params; - for (let param in params) { - if (params.hasOwnProperty(param)) { + for (let param in device.params) { + if (device.params.hasOwnProperty(param)) { if (!constants.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { - delete params[param]; + delete device.params[param]; } } } - if (Object.keys(params).length > 0) { - params.updateSource = "ws"; + if (Object.keys(device.params).length > 0) { let returnTemplate = { deviceid: device.deviceid, action: "update", - params + params: device.params }; if (this.debugReqRes) { let msg = JSON.stringify(returnTemplate, null, 2).replace(device.deviceid, "**hidden**"); From b7b5947d7fbff9f692106db8c4a37ae912ea2107 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 8 Sep 2020 10:34:49 +0100 Subject: [PATCH 0094/3183] updates --- lib/constants.js | 3 +- lib/eWeLink.js | 322 ++++++++++++++++++---------------------------- lib/eWeLinkLAN.js | 2 +- lib/eWeLinkWS.js | 3 +- 4 files changed, 129 insertions(+), 201 deletions(-) diff --git a/lib/constants.js b/lib/constants.js index 354c4736..534514f0 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -20,7 +20,8 @@ module.exports = { devicesRFBridge: [28], devicesZBBridge: [66], devicesZB: [1000, 1770, 2026, 3026], - paramsToKeep: ["bright", "brightness", "channel", "cmd", "colorB", "colorG", "colorR", "currentHumidity", "currentTemperature", "fan", "humidity", "key", "light", "lock", "mainSwitch", "mode", "online", "rfChl", "rfList", "rfTrig", "sensorType", "speed", "state", "switch", "switches", "temperature", "type", "updateSource", "zyx_mode"], + allowedGroups: ["blind", "garage", "lock"], + paramsToKeep: ["bright", "brightness", "channel", "cmd", "colorB", "colorG", "colorR", "currentHumidity", "currentTemperature", "fan", "humidity", "key", "light", "lock", "mainSwitch", "mode", "online", "rfChl", "rfList", "rfTrig", "sensorType", "speed", "state", "switch", "switches", "temperature", "type", "zyx_mode"], chansFromUiid: { 1: 1, // "SOCKET" \\ 20, MINI, BASIC, S26 2: 2, // "SOCKET_2" \\ diff --git a/lib/eWeLink.js b/lib/eWeLink.js index ded8ce26..ddf238bb 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -37,6 +37,8 @@ class eWeLink { return this.httpClient.getDevices(); }).then(res => { //*** Get device IP addresses for LAN mode ***\\ this.httpDevices = res + .filter(device => device.hasOwnProperty("extra")) + .filter(device => device.extra.hasOwnProperty("uiid")) .filter(device => !(this.config.hideDevFromHB || "").includes(device.deviceid)) .forEach(device => this.devicesInEwe.set(device.deviceid, device)); this.httpDevices = res; @@ -59,6 +61,7 @@ class eWeLink { if (Object.keys(this.config.groups || []).length > 0) { this.config.groups .filter(g => g.hasOwnProperty("deviceId") && this.devicesInEwe.has(g.deviceId.toLowerCase())) + .filter(g => g.hasOwnProperty("type") && cns.allowedGroups.includes(g.type)) .forEach(g => this.cusG.set(g.deviceId + "SWX", g)); } //*** Make a map of RF Bridge custom sensors from Homebridge config ***\\ @@ -106,15 +109,8 @@ class eWeLink { }); } initialiseDevice(device) { - if (!device.hasOwnProperty("extra") || !device.extra.hasOwnProperty("uiid")) { - let deviceName = device.hasOwnProperty("name") ? - device.name : - device.hasOwnProperty("deviceid") ? device.deviceid : "Unknown Device"; - this.log.warn("[%s] could not be synchronised due to missing uiid parameter.", deviceName); - return; - } let accessory; - device.params.updateSource = "http"; + device.params.updateSource = "HTTP"; //*** First add the device if it isn't already in Homebridge. Yeah this code looks a mess :| ***\\ if (!this.devicesInHB.has(device.deviceid + "SWX") && !this.devicesInHB.has(device.deviceid + "SW0")) { if (device.extra.uiid === 2 && device.brandName === "coolkit" && device.productModel === "0285") { @@ -231,7 +227,7 @@ class eWeLink { if (["1", "2", "3", "4"].includes(switchNumber) && type !== "rf_sub") { newDeviceName += " SW" + switchNumber; if ((this.config.hideFromHB || "").includes(hbDeviceId) && cns.devicesHideable.includes(type)) { - this.log.warn("[%s] has not been added as per configuration", newDeviceName); + this.log.warn("[%s] will not be added as per configuration.", newDeviceName); return; } } @@ -440,19 +436,11 @@ class eWeLink { .setProps({ minStep: 100 }) - .on("set", (value, callback) => { - accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.TargetPosition).value !== value ? - this.internalBlindUpdate(accessory, value, callback) : - callback(); - }); + .on("set", (value, callback) => this.internalBlindUpdate(accessory, value, callback)); break; case "garage": accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.TargetDoorState) - .on("set", (value, callback) => { - accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.TargetDoorState).value !== value ? - this.internalGarageUpdate(accessory, value, callback) : - callback(); - }); + .on("set", (value, callback) => this.internalGarageUpdate(accessory, value, callback)); break; case "lock": accessory.getService(Service.LockMechanism).getCharacteristic(Characteristic.LockTargetState) @@ -460,82 +448,48 @@ class eWeLink { break; case "fan": accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active) - .on("set", (value, callback) => { - accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active).value !== value ? - this.internalFanUpdate(accessory, "power", value, callback) : - callback(); - }); + .on("set", (value, callback) => this.internalFanUpdate(accessory, "power", value, callback)); accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.RotationSpeed) .setProps({ minStep: 33 }) - .on("set", (value, callback) => { - accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.RotationSpeed).value !== value ? - this.internalFanUpdate(accessory, "speed", value, callback) : - callback(); - }); + .on("set", (value, callback) => this.internalFanUpdate(accessory, "speed", value, callback)); accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => { - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value !== value ? - this.internalFanUpdate(accessory, "light", value, callback) : - callback(); - }); + .on("set", (value, callback) => this.internalFanUpdate(accessory, "light", value, callback)); break; case "thermostat": if (!this.config.hideTHSwitch) { accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => { - accessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value !== value ? - this.internalThermostatUpdate(accessory, value, callback) : - callback(); - }); + .on("set", (value, callback) => this.internalThermostatUpdate(accessory, value, callback)); } break; case "outlet": accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => { - accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value !== value ? - this.internalOutletUpdate(accessory, value, callback) : - callback(); - }); + .on("set", (value, callback) => this.internalOutletUpdate(accessory, value, callback)); break; case "usb": accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => { - accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value !== value ? - this.internalUSBUpdate(accessory, value, callback) : - callback(); - }); + .on("set", (value, callback) => this.internalUSBUpdate(accessory, value, callback)); break; case "scm": accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => { - accessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value !== value ? - this.internalSCMUpdate(accessory, value, callback) : - callback(); - }); + .on("set", (value, callback) => this.internalSCMUpdate(accessory, value, callback)); break; case "light": accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => { - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value !== value ? - this.internalLightbulbUpdate(accessory, value, callback) : - callback(); - }); + .on("set", (value, callback) => this.internalLightbulbUpdate(accessory, value, callback)); if (cns.devicesBrightable.includes(accessory.context.eweUIID)) { accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Brightness) .on("set", (value, callback) => { if (value > 0) { if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { - this.internalLightbulbUpdate(accessory, true, callback); + this.internalLightbulbUpdate(accessory, true, function() { + return; + }); } - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Brightness).value !== value ? - this.internalBrightnessUpdate(accessory, value, callback) : - callback(); + this.internalBrightnessUpdate(accessory, value, callback); } else { - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value ? - this.internalLightbulbUpdate(accessory, false, callback) : - callback(); + this.internalLightbulbUpdate(accessory, false, callback); } }); } else if (cns.devicesColourable.includes(accessory.context.eweUIID)) { @@ -543,37 +497,24 @@ class eWeLink { .on("set", (value, callback) => { if (value > 0) { if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { - this.internalLightbulbUpdate(accessory, true, callback); + this.internalLightbulbUpdate(accessory, true, function() { + return; + }); } - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Brightness).value !== value ? - this.internalHSBUpdate(accessory, "bri", value, callback) : - callback(); + this.internalHSBUpdate(accessory, "bri", value, callback); } else { - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value ? - this.internalLightbulbUpdate(accessory, false, callback) : - callback(); + this.internalLightbulbUpdate(accessory, false, callback); } }); accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Hue) - .on("set", (value, callback) => { - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Hue).value !== value ? - this.internalHSBUpdate(accessory, "hue", value, callback) : - callback(); - }); + .on("set", (value, callback) => this.internalHSBUpdate(accessory, "hue", value, callback)); accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Saturation) - .on("set", (value, callback) => { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Saturation, value); - callback(); - }); + .on("set", (value, callback) => callback()); } break; case "switch": accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => { - accessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value !== value ? - this.internalSwitchUpdate(accessory, value, callback) : - callback(); - }); + .on("set", (value, callback) => this.internalSwitchUpdate(accessory, value, callback)); break; case "rf_sub": accessory.context.rfChls = accessory.context.rfChls || {}; @@ -582,9 +523,7 @@ class eWeLink { accessory.getService(v).updateCharacteristic(Characteristic.On, false); accessory.getService(v).getCharacteristic(Characteristic.On) .on("set", (value, callback) => { - value ? - this.internalRFDeviceUpdate(accessory, k, callback) : - callback(); + value ? this.internalRFDeviceUpdate(accessory, k, callback) : callback(); }); }); } @@ -708,13 +647,11 @@ class eWeLink { callback("Device has failed to update"); } }; - if (cns.devicesNonLAN.includes(accessory.context.eweUIID) || !this.lanDevices.get(accessory.context.eweDeviceId).online) { + if (cns.devicesNonLAN.includes(accessory.context.eweUIID) || !accessory.context.reachableLAN) { sendViaWS(); } else { this.lanClient.sendUpdate(payload) - .then(res => { - callback(); - }) + .then(res => callback()) .catch(err => { if (this.config.debug) { this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); @@ -724,12 +661,12 @@ class eWeLink { } } receiveDeviceUpdate(device) { - let accessory, source = device.params.updateSource === "ws" ? "WS" : "LAN"; + let accessory; switch (device.action) { case "sysmsg": if ((accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0"))) { let isX = accessory.context.hbDeviceId.substr(-1) === "X"; - if (source === "WS" && accessory.context.reachableWAN !== device.params.online) { + if (device.params.updateSource === "WS" && accessory.context.reachableWAN !== device.params.online) { accessory.context.reachableWAN = device.params.online; this.log("[%s] has been reported [%s] via [WS].", accessory.displayName, accessory.context.reachableWAN ? "online" : "offline"); this.devicesInHB.set(accessory.context.hbDeviceId, accessory); @@ -750,23 +687,23 @@ class eWeLink { break; case "update": if ((accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0"))) { - if (source === "WS" && !accessory.context.reachableWAN) { + if (device.params.updateSource === "WS" && !accessory.context.reachableWAN) { accessory.context.reachableWAN = true; this.log("[%s] has been reported [online] via [WS].", accessory.displayName); } - if (source === "LAN" && !accessory.context.reachableLAN) { + if (device.params.updateSource === "LAN" && !accessory.context.reachableLAN) { accessory.context.reachableLAN = true; this.log("[%s] has been reported [online] via [LAN].", accessory.displayName); } if (this.config.debug) { - this.log("[%s] externally updated from above %s message and will be refreshed.", accessory.displayName, source); + this.log("[%s] externally updated from above %s message and will be refreshed.", accessory.displayName, device.params.updateSource); } if (!this.refreshAccessory(accessory, device.params)) { this.log.warn("[%s] cannot be refreshed. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.). [debug:%s:%s]", accessory.displayName, accessory.context.type, accessory.context.channelCount); } } else { if (!(this.config.hideDevFromHB || "").includes(device.deviceid)) { - this.log.warn("[%s] Accessory received via %s update does not exist in Homebridge. If it's a new accessory please restart Homebridge so it is added.", device.deviceid, source); + this.log.warn("[%s] Accessory received via %s update does not exist in Homebridge. If it's a new accessory please restart Homebridge so it is added.", device.deviceid, device.params.updateSource); } } break; @@ -924,7 +861,7 @@ class eWeLink { setTimeout(() => { if (!sAccessory) { accessory.getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.CurrentDoorState, newPos === 0 ? 0 : 1); + .updateCharacteristic(Characteristic.CurrentDoorState, newPos); } accessory.context.inUse = false; }, parseInt(garageConfig.operationTime) * 100); @@ -1360,7 +1297,7 @@ class eWeLink { } }); } catch (err) { - this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } internalRFDeviceUpdate(accessory, rfChl, callback) { @@ -1421,7 +1358,7 @@ class eWeLink { .updateCharacteristic(Characteristic.CurrentPosition, nSte * 100); }, parseInt(blindConfig.operationTime) * 100); } catch (err) { - this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalGarageUpdate(accessory, params) { @@ -1463,7 +1400,7 @@ class eWeLink { }, parseInt(garageConfig.operationTime) * 100); } catch (err) { accessory.context.inUse = false; - this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalLockUpdate(accessory, params) { @@ -1490,7 +1427,7 @@ class eWeLink { }, parseInt(lockConfig.operationTime) * 100); } catch (err) { accessory.context.inUse = false; - this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalSensorUpdate(accessory, params) { @@ -1525,7 +1462,7 @@ class eWeLink { } }); } catch (err) { - this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalFanUpdate(accessory, params) { @@ -1562,7 +1499,7 @@ class eWeLink { .updateCharacteristic(Characteristic.Active, status) .updateCharacteristic(Characteristic.RotationSpeed, speed); } catch (err) { - this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalThermostatUpdate(accessory, params) { @@ -1580,28 +1517,28 @@ class eWeLink { accessory.getService(Service.HumiditySensor).updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); } } catch (err) { - this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalOutletUpdate(accessory, params) { try { accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switch === "on"); } catch (err) { - this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalUSBUpdate(accessory, params) { try { accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); } catch (err) { - this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalSCMUpdate(accessory, params) { try { accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); } catch (err) { - this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalSingleLightUpdate(accessory, params) { @@ -1665,7 +1602,7 @@ class eWeLink { accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, false); } } catch (err) { - this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalMultiLightUpdate(accessory, params) { @@ -1683,14 +1620,14 @@ class eWeLink { } accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, primaryState); } catch (err) { - this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalSingleSwitchUpdate(accessory, params) { try { accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switch === "on"); } catch (err) { - this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalMultiSwitchUpdate(accessory, params) { @@ -1708,12 +1645,12 @@ class eWeLink { } accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState); } catch (err) { - this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalRFDeviceUpdate(accessory, params) { try { - if (params.updateSource === "http") { + if (params.updateSource === "HTTP") { return; } let idToCheck = accessory.context.hbDeviceId.slice(0, -1), @@ -1729,83 +1666,80 @@ class eWeLink { throw "rf button not found in Homebridge"; } } else if (params.hasOwnProperty("cmd") && params.cmd === "trigger") { // RF Sensor - let rfChan = Object.keys(params).filter(name => /rfTrig/.test(name)); - rfChan.forEach(chan => { - let chanNum = chan.substr(-1).toString(), - accessoryNum = accessory.context.rfChlMap[chanNum], - oAccessory; - if ((oAccessory = this.devicesInHB.get(idToCheck + accessoryNum))) { - let timeOfMotion = new Date(params[chan]), - timeDifference = (timeNow.getTime() - timeOfMotion.getTime()) / 1000; - if (timeDifference < (this.config.sensorTimeDifference || 120)) { - switch (oAccessory.context.sensorType) { - case "button": - break; - case "water": - oAccessory.getService(Service.LeakSensor).updateCharacteristic(Characteristic.LeakDetected, 1); - setTimeout(() => { - oAccessory.getService(Service.LeakSensor).updateCharacteristic(Characteristic.LeakDetected, 0); - }, (this.config.sensorTimeLength || 2) * 1000); - break; - case "fire": - case "smoke": - oAccessory.getService(Service.SmokeSensor).updateCharacteristic(Characteristic.SmokeDetected, 1); - setTimeout(() => { - oAccessory.getService(Service.SmokeSensor).updateCharacteristic(Characteristic.SmokeDetected, 0); - }, (this.config.sensorTimeLength || 2) * 1000); - break; - case "co": - oAccessory.getService(Service.CarbonMonoxideSensor).updateCharacteristic(Characteristic.CarbonMonoxideDetected, 1); - setTimeout(() => { - oAccessory.getService(Service.CarbonMonoxideSensor).updateCharacteristic(Characteristic.CarbonMonoxideDetected, 0); - }, (this.config.sensorTimeLength || 2) * 1000); - break; - case "co2": - oAccessory.getService(Service.CarbonDioxideSensor).updateCharacteristic(Characteristic.CarbonDioxideDetected, 1); - setTimeout(() => { - oAccessory.getService(Service.CarbonDioxideSensor).updateCharacteristic(Characteristic.CarbonDioxideDetected, 0); - }, (this.config.sensorTimeLength || 2) * 1000); - break; - case "contact": - oAccessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, 1); - setTimeout(() => { - oAccessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, 0); - }, (this.config.sensorTimeLength || 2) * 1000); - break; - case "occupancy": - oAccessory.getService(Service.OccupancySensor).updateCharacteristic(Characteristic.OccupancyDetected, 1); - setTimeout(() => { - oAccessory.getService(Service.OccupancySensor).updateCharacteristic(Characteristic.OccupancyDetected, 0); - }, (this.config.sensorTimeLength || 2) * 1000); - break; - default: - oAccessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, true); - setTimeout(() => { - oAccessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, false); - }, (this.config.sensorTimeLength || 2) * 1000); - break; - } - if (this.config.debug) { - this.log("[%s] has detected [%s].", oAccessory.displayName, oAccessory.context.sensorType); + Object.keys(params) + .filter(name => /rfTrig/.test(name)) + .forEach(chan => { + let chanNum = chan.substr(-1).toString(), + accessoryNum = accessory.context.rfChlMap[chanNum], + oAccessory; + if ((oAccessory = this.devicesInHB.get(idToCheck + accessoryNum))) { + let timeOfMotion = new Date(params[chan]), + timeDifference = (timeNow.getTime() - timeOfMotion.getTime()) / 1000; + if (timeDifference < (this.config.sensorTimeDifference || 120)) { + switch (oAccessory.context.sensorType) { + case "button": + break; + case "water": + oAccessory.getService(Service.LeakSensor).updateCharacteristic(Characteristic.LeakDetected, 1); + setTimeout(() => { + oAccessory.getService(Service.LeakSensor).updateCharacteristic(Characteristic.LeakDetected, 0); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + case "fire": + case "smoke": + oAccessory.getService(Service.SmokeSensor).updateCharacteristic(Characteristic.SmokeDetected, 1); + setTimeout(() => { + oAccessory.getService(Service.SmokeSensor).updateCharacteristic(Characteristic.SmokeDetected, 0); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + case "co": + oAccessory.getService(Service.CarbonMonoxideSensor).updateCharacteristic(Characteristic.CarbonMonoxideDetected, 1); + setTimeout(() => { + oAccessory.getService(Service.CarbonMonoxideSensor).updateCharacteristic(Characteristic.CarbonMonoxideDetected, 0); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + case "co2": + oAccessory.getService(Service.CarbonDioxideSensor).updateCharacteristic(Characteristic.CarbonDioxideDetected, 1); + setTimeout(() => { + oAccessory.getService(Service.CarbonDioxideSensor).updateCharacteristic(Characteristic.CarbonDioxideDetected, 0); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + case "contact": + oAccessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, 1); + setTimeout(() => { + oAccessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, 0); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + case "occupancy": + oAccessory.getService(Service.OccupancySensor).updateCharacteristic(Characteristic.OccupancyDetected, 1); + setTimeout(() => { + oAccessory.getService(Service.OccupancySensor).updateCharacteristic(Characteristic.OccupancyDetected, 0); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + default: + oAccessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, true); + setTimeout(() => { + oAccessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, false); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + } + if (this.config.debug) { + this.log("[%s] has detected [%s].", oAccessory.displayName, oAccessory.context.sensorType); + } } } - } - }); + }); } } catch (err) { - this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalZBDeviceUpdate(accessory, params) { - try { + try { //*** credit @tasict ***\\ switch (accessory.context.eweUIID) { case 1000: - if (params.hasOwnProperty("key")) { - if ([0, 1, 2].includes(params.key)) { - accessory.getService(Service.StatelessProgrammableSwitch).updateCharacteristic(Characteristic.ProgrammableSwitchEvent, params.key); //*** credit @tasict ***\\ - } else { - throw "unknown 'key' parameter received [" + params.key + "]"; - } + if (params.hasOwnProperty("key") && [0, 1, 2].includes(params.key)) { + accessory.getService(Service.StatelessProgrammableSwitch).updateCharacteristic(Characteristic.ProgrammableSwitchEvent, params.key); } break; case 1770: @@ -1819,28 +1753,20 @@ class eWeLink { } break; case 2026: - if (params.hasOwnProperty("motion")) { - if ([0, 1].includes(params.lock)) { - accessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, params.motion); - } else { - throw "unknown 'motion' parameter received [" + params.motion + "]"; - } + if (params.hasOwnProperty("motion") && [0, 1].includes(params.lock)) { + accessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, params.motion); } break; case 3026: - if (params.hasOwnProperty("lock")) { - if ([0, 1].includes(params.lock)) { - accessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, params.lock); - } else { - throw "unknown 'lock' parameter received [" + params.lock + "]"; - } + if (params.hasOwnProperty("lock") && [0, 1].includes(params.lock)) { + accessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, params.lock); } break; default: - throw "unsupported zigbee device type"; + throw "unsupported zigbee device type [" + accessory.context.eweUIID + "]. Please create an issue on GitHub"; } } catch (err) { - this.log.warn("[%s] could not be updated - [%s].", accessory.displayName, err); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } } diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 89e1a337..4582825b 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -90,8 +90,8 @@ module.exports = class eWeLinkLAN { } } } - params.updateSource = "LAN"; if (Object.keys(params).length > 0) { + params.updateSource = "LAN"; let returnTemplate = { deviceid: rdata.id, action: "update", diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 8afe3926..0052d5d6 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -96,9 +96,9 @@ module.exports = class eWeLinkWS { this.ws.send("ping"); }, (device.config.hbInterval + 7) * 1000); } else if (device.hasOwnProperty("action")) { - device.params.updateSource = "WS"; switch (device.action) { case "sysmsg": + device.params.updateSource = "WS"; let returnTemplate = { deviceid: device.deviceid, action: "sysmsg", @@ -121,6 +121,7 @@ module.exports = class eWeLinkWS { } } if (Object.keys(device.params).length > 0) { + device.params.updateSource = "WS"; let returnTemplate = { deviceid: device.deviceid, action: "update", From 69ea1e39b60c4dac434d9f3fd53297db145ef43c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 8 Sep 2020 11:24:57 +0100 Subject: [PATCH 0095/3183] small changes --- lib/eWeLink.js | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index ddf238bb..969e215a 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -205,7 +205,7 @@ class eWeLink { } } if (rfBridgeChange) { - this.log.warn("[%s] bridge configuration changed - devices will be removed and readded.", accessory.displayName); + this.log.warn("[%s] bridge configuration changed so devices will be removed and readded.", accessory.displayName); for (let i = 0; i <= accessory.context.channelCount; i++) { let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); this.removeAccessory(oAccessory); @@ -390,18 +390,18 @@ class eWeLink { accessory.addService(Service.ContactSensor); break; default: - throw "unsupported zigbee device type with uiid [" + device.extra.uiid + "]"; + throw "unsupported zigbee device type [" + device.extra.uiid + "]. Please create an issue on GitHub"; } break; default: - throw "device is not supported by this plugin"; + throw "device is not supported by this plugin. Please create an issue on GitHub"; } this.devicesInHB.set(hbDeviceId, accessory); this.api.registerPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); this.configureAccessory(accessory); this.log("[%s] has been added to Homebridge.", newDeviceName); } catch (err) { - this.log.warn("[%s] could not be added - %s.", newDeviceName, err); + this.log.warn("[%s] could not be added as %s.", newDeviceName, err); } } configureAccessory(accessory) { @@ -533,7 +533,7 @@ class eWeLink { accessory.context.reachableLAN = true; this.devicesInHB.set(accessory.context.hbDeviceId, accessory); } catch (err) { - this.log.warn("[%s] could not be refreshed - [%s].", accessory.displayName, err); + this.log.warn("[%s] could not be refreshed as %s.", accessory.displayName, err); } } refreshAccessory(accessory, newParams) { @@ -629,7 +629,7 @@ class eWeLink { this.api.unregisterPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); this.log("[%s] has been removed from Homebridge.", accessory.displayName); } catch (err) { - this.log.warn("[%s] needed to be removed but couldn't - [%s].", accessory.displayName, err); + this.log.warn("[%s] needed to be removed but couldn't as %s.", accessory.displayName, err); } } sendDeviceUpdate(accessory, params, callback) { @@ -651,7 +651,7 @@ class eWeLink { sendViaWS(); } else { this.lanClient.sendUpdate(payload) - .then(res => callback()) + .then(() => callback()) .catch(err => { if (this.config.debug) { this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); @@ -666,12 +666,18 @@ class eWeLink { case "sysmsg": if ((accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0"))) { let isX = accessory.context.hbDeviceId.substr(-1) === "X"; - if (device.params.updateSource === "WS" && accessory.context.reachableWAN !== device.params.online) { - accessory.context.reachableWAN = device.params.online; - this.log("[%s] has been reported [%s] via [WS].", accessory.displayName, accessory.context.reachableWAN ? "online" : "offline"); - this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory); + if (device.params.updateSource === "WS") { + if (accessory.context.reachableWAN !== device.params.online) { + accessory.context.reachableWAN = device.params.online; + this.log("[%s] has been reported [%s] via [WS].", accessory.displayName, accessory.context.reachableWAN ? "online" : "offline"); + this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory); + } + } else { + if (this.debug) { + this.log("[%s] Nothing to update from above WS message.", accessory.displayName); + } } } if (!isX) { @@ -822,7 +828,7 @@ class eWeLink { oldPos, newPos = value, params = {}, - wsDelay = 0; + delay = 0; if (sensorDefinition && !(sAccessory = this.devicesInHB.get(garageConfig.sensorId + "SWX"))) { throw "defined sensor doesn't exist"; } @@ -836,9 +842,8 @@ class eWeLink { return; } if (garageConfig.setup === "oneSwitch" && [2, 3].includes(oldPos)) { - accessory.getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.CurrentDoorState, oldPos * 2 % 3 + 2); - wsDelay = 1500; + accessory.getService(Service.GarageDoorOpener).updateCharacteristic(Characteristic.CurrentDoorState, oldPos * 2 % 3 + 2); + delay = 1500; } setTimeout(() => { if (accessory.context.state === newPos) { @@ -860,13 +865,12 @@ class eWeLink { }); setTimeout(() => { if (!sAccessory) { - accessory.getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.CurrentDoorState, newPos); + accessory.getService(Service.GarageDoorOpener).updateCharacteristic(Characteristic.CurrentDoorState, newPos); } accessory.context.inUse = false; }, parseInt(garageConfig.operationTime) * 100); } - }, wsDelay); + }, delay); callback(); } catch (err) { accessory.context.inUse = false; @@ -1762,8 +1766,6 @@ class eWeLink { accessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, params.lock); } break; - default: - throw "unsupported zigbee device type [" + accessory.context.eweUIID + "]. Please create an issue on GitHub"; } } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); From 4e1a204ec89f73b91a79f43eeb4d838b78fd0366 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 8 Sep 2020 11:26:02 +0100 Subject: [PATCH 0096/3183] 2.25.0-3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 13f0eb35..2a277e50 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.25.0-2", + "version": "2.25.0-3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index bbe0307b..42c59d5b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.25.0-2", + "version": "2.25.0-3", "author": "bwp91", "contributors": [ "gbro115", From 0f60d15462b848fcad41ea2a219b2cfc277049ec Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 8 Sep 2020 16:28:12 +0100 Subject: [PATCH 0097/3183] 2.25.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2a277e50..41e52d3d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.25.0-3", + "version": "2.25.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 42c59d5b..f2e18280 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.25.0-3", + "version": "2.25.0", "author": "bwp91", "contributors": [ "gbro115", From 100e71094040a0e069e4c5926a10161a7e15af98 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 9 Sep 2020 06:42:44 +0100 Subject: [PATCH 0098/3183] bug: rf bridge with no devices --- lib/eWeLink.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 969e215a..6e9fb4db 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -221,7 +221,7 @@ class eWeLink { } } addAccessory(device, hbDeviceId, type) { - let channelCount = type === "rf_pri" ? Object.keys(device.tags.zyx_info).length : cns.chansFromUiid[device.extra.uiid], + let channelCount = type === "rf_pri" ? Object.keys(device.tags.zyx_info || []).length : cns.chansFromUiid[device.extra.uiid], switchNumber = hbDeviceId.substr(-1).toString(), newDeviceName = type === "rf_sub" ? device.tags.zyx_info[switchNumber - 1].name : device.name; if (["1", "2", "3", "4"].includes(switchNumber) && type !== "rf_sub") { From d616b3d14c62bc9efd6b0b101b77352b78c99ab4 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 9 Sep 2020 06:43:31 +0100 Subject: [PATCH 0099/3183] bug: can't close if not open #85 --- lib/eWeLinkWS.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 0052d5d6..a44b1431 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -275,6 +275,8 @@ module.exports = class eWeLinkWS { this.emitter.addListener("update", f); } closeConnection() { - this.ws.close(1000, "Stopping Homebridge"); + if (this.ws && this.wsIsOpen) { + this.ws.close(1000, "Stopping Homebridge"); + } } }; \ No newline at end of file From a441bf4dc28964d02ae5d2769b81ef4b5b9a1e93 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 9 Sep 2020 06:43:58 +0100 Subject: [PATCH 0100/3183] feat: custom ip definition --- lib/eWeLinkLAN.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 4582825b..f43869b7 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -10,12 +10,13 @@ module.exports = class eWeLinkLAN { this.config = config; this.log = log; this.devices = devices; + this.ipOverrides = this.config.ipOverride || {}; let deviceMap = new Map(); devices.forEach(device => { deviceMap.set(device.deviceid, { apiKey: device.devicekey, - online: false, - ip: null + online: this.ipOverrides.hasOwnProperty(device.deviceid) ? true : false, + ip: this.ipOverrides.hasOwnProperty(device.deviceid) ? this.ipOverrides[device.deviceid] : null }); }); this.deviceMap = deviceMap; @@ -32,11 +33,13 @@ module.exports = class eWeLinkLAN { res.forEach(device => { let d, deviceId = device.fqdn.replace("._ewelink._tcp.local", "").replace("eWeLink_", ""); if ((d = this.deviceMap.get(deviceId))) { - this.deviceMap.set(deviceId, { - apiKey: d.apiKey, - online: true, - ip: device.address - }); + if (!this.ipOverrides.hasOwnProperty(deviceId)) { + this.deviceMap.set(deviceId, { + apiKey: d.apiKey, + online: true, + ip: device.address + }); + } onlineCount++; } }); @@ -67,7 +70,7 @@ module.exports = class eWeLinkLAN { dText = crypto.createDecipheriv("aes-128-cbc", key, Buffer.from(rdata.iv, "base64")), pText = Buffer.concat([dText.update(Buffer.from(data, "base64")), dText.final()]).toString("utf8"), params; - if (packet.address !== deviceInfo.ip) { + if (packet.address !== deviceInfo.ip && !this.ipOverrides.hasOwnProperty(rdata.id)) { this.deviceMap.set(rdata.id, { apiKey: deviceInfo.apiKey, online: true, From cc4c55c664745f331f755f8891764cd4a7a9023a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 9 Sep 2020 06:56:30 +0100 Subject: [PATCH 0101/3183] 2.25.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 41e52d3d..ca38ffdb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.25.0", + "version": "2.25.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f2e18280..d6d5a820 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.25.0", + "version": "2.25.1", "author": "bwp91", "contributors": [ "gbro115", From 77305516003e311ffc1a76d3e94cb52682e292f6 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 9 Sep 2020 20:00:33 +0100 Subject: [PATCH 0102/3183] bugs definition --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index d6d5a820..04d63730 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,9 @@ "type": "git", "url": "https://github.com/bwp91/homebridge-ewelink" }, + "bugs": { + "url": "https://github.com/bwp91/homebridge-ewelink/issues" + }, "dependencies": { "axios": "0.20.0", "color-convert": "2.0.1", From 782806340b9364a0f7154011bce55ce0c623f05b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 9 Sep 2020 20:04:04 +0100 Subject: [PATCH 0103/3183] garage and rf bug fixes --- lib/eWeLink.js | 190 ++++++++++++++++++++++++------------------------- 1 file changed, 95 insertions(+), 95 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 6e9fb4db..397cee30 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -22,91 +22,91 @@ class eWeLink { this.devicesInEwe = new Map(); this.cusG = new Map(); this.cusS = new Map(); - this.api.on("didFinishLaunching", () => { - this.log("Plugin has finished initialising. Starting synchronisation with eWeLink account."); - //*** Set up HTTP client and get the user HTTP host ***\\ - this.httpClient = new eWeLinkHTTP(this.config, this.log); - this.httpClient.getHost() - .then(res => { //*** Use the HTTP API host to log into eWeLink ***\\ - return this.httpClient.login(); - }).then(res => { //*** Set up the web socket client ***\\ - this.wsClient = new eWeLinkWS(this.config, this.log, res); - return this.wsClient.getHost(); - }).then(() => { //*** Open web socket connection and get device list via HTTP ***\\ - this.wsClient.login(); - return this.httpClient.getDevices(); - }).then(res => { //*** Get device IP addresses for LAN mode ***\\ - this.httpDevices = res - .filter(device => device.hasOwnProperty("extra")) - .filter(device => device.extra.hasOwnProperty("uiid")) - .filter(device => !(this.config.hideDevFromHB || "").includes(device.deviceid)) - .forEach(device => this.devicesInEwe.set(device.deviceid, device)); - this.httpDevices = res; - this.lanClient = new eWeLinkLAN(this.config, this.log, this.httpDevices); - return this.lanClient.getHosts(); - }).then(res => { //*** Set up the LAN mode listener ***\\ - this.lanDevices = res.map; - this.lanDevicesOnline = res.count; - return this.lanClient.startMonitor(); - }).then(() => { //*** Use the device list to refresh Homebridge accessories ***\\ - (() => { - //*** Remove all Homebridge accessories if none found ***\\ - if (Object.keys(this.httpDevices).length === 0 && Object.keys(this.lanDevices).length === 0) { - Array.from(this.devicesInHB.values()).forEach(a => this.removeAccessory(a)); - this.devicesInHB.clear(); - this.log.warn("🟠 No devices were found registered to your eWeLink account so disabling plugin."); - return; - } - //*** Make a map of custom groups from Homebridge config ***\\ - if (Object.keys(this.config.groups || []).length > 0) { - this.config.groups - .filter(g => g.hasOwnProperty("deviceId") && this.devicesInEwe.has(g.deviceId.toLowerCase())) - .filter(g => g.hasOwnProperty("type") && cns.allowedGroups.includes(g.type)) - .forEach(g => this.cusG.set(g.deviceId + "SWX", g)); - } - //*** Make a map of RF Bridge custom sensors from Homebridge config ***\\ - if (Object.keys(this.config.bridgeSensors || []).length > 0) { - this.config.bridgeSensors - .filter(s => s.hasOwnProperty("deviceId") && this.devicesInEwe.has(s.deviceId.toLowerCase())) - .forEach(s => this.cusS.set(s.fullDeviceId, s)); - } - //*** Logging always helps to see if everything is okay so far ***\\ - this.log("[%s] eWeLink devices were loaded from the Homebridge cache.", this.devicesInHB.size); - this.log("[%s] primary devices were loaded from your eWeLink account.", this.devicesInEwe.size); - this.log("[%s] primary devices were discovered on your local network.", this.lanDevicesOnline); - //*** Remove Homebridge accessories that don't appear in eWeLink ***\\ - this.devicesInHB.forEach(accessory => { - if (!this.devicesInEwe.has(accessory.context.eweDeviceId)) { - this.removeAccessory(accessory); + this.api + .on("didFinishLaunching", () => { + this.log("Plugin has finished initialising. Starting synchronisation with eWeLink account."); + //*** Set up HTTP client and get the user HTTP host ***\\ + this.httpClient = new eWeLinkHTTP(this.config, this.log); + this.httpClient.getHost() + .then(res => { //*** Use the HTTP API host to log into eWeLink ***\\ + return this.httpClient.login(); + }).then(res => { //*** Set up the web socket client ***\\ + this.wsClient = new eWeLinkWS(this.config, this.log, res); + return this.wsClient.getHost(); + }).then(() => { //*** Open web socket connection and get device list via HTTP ***\\ + this.wsClient.login(); + return this.httpClient.getDevices(); + }).then(res => { //*** Get device IP addresses for LAN mode ***\\ + this.httpDevices = res + .filter(device => device.hasOwnProperty("extra") && device.extra.hasOwnProperty("uiid")) + .filter(device => !(this.config.hideDevFromHB || "").includes(device.deviceid)) + .forEach(device => this.devicesInEwe.set(device.deviceid, device)); + this.httpDevices = res; + this.lanClient = new eWeLinkLAN(this.config, this.log, this.httpDevices); + return this.lanClient.getHosts(); + }).then(res => { //*** Set up the LAN mode listener ***\\ + this.lanDevices = res.map; + this.lanDevicesOnline = res.count; + return this.lanClient.startMonitor(); + }).then(() => { //*** Use the device list to refresh Homebridge accessories ***\\ + (() => { + //*** Remove all Homebridge accessories if none found ***\\ + if (Object.keys(this.httpDevices).length === 0 && Object.keys(this.lanDevices).length === 0) { + Array.from(this.devicesInHB.values()).forEach(a => this.removeAccessory(a)); + this.devicesInHB.clear(); + this.log.warn("🟠 No devices were found registered to your eWeLink account so disabling plugin."); + return; } - }); - //*** Synchronise devices between eWeLink and Homebridge and set up ws/lan listeners ***\\ - this.devicesInEwe.forEach(device => this.initialiseDevice(device)); - this.wsClient.receiveUpdate(device => this.receiveDeviceUpdate(device)); - this.lanClient.receiveUpdate(device => this.receiveDeviceUpdate(device)); - this.log("đŸŸĸ eWeLink setup complete. If you're enjoying this package please consider a ⭐ī¸ on GitHub!"); - if (this.config.debugReqRes) { - this.log.warn("You have 'Request & Response Logging' enabled. This setting is not recommended for long-term use."); + //*** Make a map of custom groups from Homebridge config ***\\ + if (Object.keys(this.config.groups || []).length > 0) { + this.config.groups + .filter(g => g.hasOwnProperty("deviceId") && this.devicesInEwe.has(g.deviceId.toLowerCase())) + .filter(g => g.hasOwnProperty("type") && cns.allowedGroups.includes(g.type)) + .forEach(g => this.cusG.set(g.deviceId + "SWX", g)); + } + //*** Make a map of RF Bridge custom sensors from Homebridge config ***\\ + if (Object.keys(this.config.bridgeSensors || []).length > 0) { + this.config.bridgeSensors + .filter(s => s.hasOwnProperty("deviceId") && this.devicesInEwe.has(s.deviceId.toLowerCase())) + .forEach(s => this.cusS.set(s.fullDeviceId, s)); + } + //*** Logging always helps to see if everything is okay so far ***\\ + this.log("[%s] eWeLink devices were loaded from the Homebridge cache.", this.devicesInHB.size); + this.log("[%s] primary devices were loaded from your eWeLink account.", this.devicesInEwe.size); + this.log("[%s] primary devices were discovered on your local network.", this.lanDevicesOnline); + //*** Remove Homebridge accessories that don't appear in eWeLink ***\\ + this.devicesInHB.forEach(accessory => { + if (!this.devicesInEwe.has(accessory.context.eweDeviceId)) { + this.removeAccessory(accessory); + } + }); + //*** Synchronise devices between eWeLink and Homebridge and set up ws/lan listeners ***\\ + this.devicesInEwe.forEach(device => this.initialiseDevice(device)); + this.wsClient.receiveUpdate(device => this.receiveDeviceUpdate(device)); + this.lanClient.receiveUpdate(device => this.receiveDeviceUpdate(device)); + this.log("đŸŸĸ eWeLink setup complete. If you're enjoying this package please consider a ⭐ī¸ on GitHub!"); + if (this.config.debugReqRes) { + this.log.warn("You have 'Request & Response Logging' enabled. This setting is not recommended for long-term use."); + } + })(); + }).catch(err => { + this.log.error("🔴 Cannot load homebridge-ewelink - %s", err); + if (this.lanClient) { + this.lanClient.closeConnection(); } - })(); - }).catch(err => { - this.log.error("🔴 Cannot load homebridge-ewelink - %s", err); - if (this.lanClient) { - this.lanClient.closeConnection(); - } - if (this.wsClient) { - this.wsClient.closeConnection(); - } - }); - }); - this.api.on('shutdown', () => { - if (this.lanClient) { - this.lanClient.closeConnection(); - } - if (this.wsClient) { - this.wsClient.closeConnection(); - } - }); + if (this.wsClient) { + this.wsClient.closeConnection(); + } + }); + }) + .on('shutdown', () => { + if (this.lanClient) { + this.lanClient.closeConnection(); + } + if (this.wsClient) { + this.wsClient.closeConnection(); + } + }); } initialiseDevice(device) { let accessory; @@ -147,8 +147,10 @@ class eWeLink { } } else if (cns.devicesRFBridge.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SW0", "rf_pri"); - for (let i = 1; i <= Object.keys(device.tags.zyx_info).length; i++) { - this.addAccessory(device, device.deviceid + "SW" + i, "rf_sub"); + if (Object.keys((device.tags && device.tags.zyx_info) || []).length > 0) { + for (let i = 1; i <= Object.keys(device.tags.zyx_info).length; i++) { + this.addAccessory(device, device.deviceid + "SW" + i, "rf_sub"); + } } } else if (cns.devicesZBBridge.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SWX", "zb_pri"); @@ -221,7 +223,7 @@ class eWeLink { } } addAccessory(device, hbDeviceId, type) { - let channelCount = type === "rf_pri" ? Object.keys(device.tags.zyx_info || []).length : cns.chansFromUiid[device.extra.uiid], + let channelCount = type === "rf_pri" ? Object.keys((device.tags && device.tags.zyx_info) || []).length : cns.chansFromUiid[device.extra.uiid], switchNumber = hbDeviceId.substr(-1).toString(), newDeviceName = type === "rf_sub" ? device.tags.zyx_info[switchNumber - 1].name : device.name; if (["1", "2", "3", "4"].includes(switchNumber) && type !== "rf_sub") { @@ -832,7 +834,6 @@ class eWeLink { if (sensorDefinition && !(sAccessory = this.devicesInHB.get(garageConfig.sensorId + "SWX"))) { throw "defined sensor doesn't exist"; } - this.log("[%s] has received request to [%s].", accessory.displayName, newPos === 0 ? "open" : "close"); oldPos = sAccessory ? sAccessory.getService(Service.ContactSensor).getCharacteristic(Characteristic.ContactSensorState).value === 0 ? 1 : 0 : accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.CurrentDoorState).value; @@ -1376,18 +1377,20 @@ class eWeLink { if (garageConfig.type !== "garage" || !["oneSwitch", "twoSwitch"].includes(garageConfig.setup)) { throw "improper configuration"; } + if (accessory.context.inUse || garageConfig.sensorId) { + return; + } switch (garageConfig.setup) { case "oneSwitch": - if (params.switch === "off" || garageConfig.sensorId || accessory.context.inUse) { + if (params.switch === "off") { return; } break; case "twoSwitch": - if ((params.switches[0].switch === "off" && params.switches[1].switch === "off") || accessory.context.inUse) { + if (params.switches[0].switch === params.switches[1].switch || params.switches[oldPos % 2].switch === "on") { return; } - // @TODO twoSwitch garage external update - return; + break; } accessory.context.inUse = true; if (!garageConfig.sensorId) { @@ -1440,7 +1443,6 @@ class eWeLink { newState = params.switch === "on" ? 1 : 0, oAccessory = false; accessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, newState); - this.log("[%s] sent update that it was [%s] and is now [%s].", accessory.displayName, oldState ? "apart" : "joined", newState ? "apart" : "joined"); this.cusG.forEach(group => { if (group.sensorId === accessory.context.eweDeviceId && group.type === "garage") { if ((oAccessory = this.devicesInHB.get(group.deviceId + "SWX"))) { @@ -1449,18 +1451,16 @@ class eWeLink { oAccessory.getService(Service.GarageDoorOpener) .updateCharacteristic(Characteristic.TargetDoorState, 1) .updateCharacteristic(Characteristic.CurrentDoorState, 1); - this.log("[%s] updating to [closed] based on sensor.", oAccessory.displayName); break; case 1: setTimeout(() => { oAccessory.getService(Service.GarageDoorOpener) .updateCharacteristic(Characteristic.TargetDoorState, 0) .updateCharacteristic(Characteristic.CurrentDoorState, 0); - this.log("[%s] updating to [open] based on sensor.", oAccessory.displayName); }, group.operationTime * 100); break; default: - throw "unknown sensor status received"; + throw "unknown sensor status received [" + newState + "]"; } } } From 069c3d4aca80865b5a71a58ecdd036d2eeebd8ae Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 9 Sep 2020 20:13:43 +0100 Subject: [PATCH 0104/3183] unused var --- lib/eWeLink.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 397cee30..a5e87086 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1439,8 +1439,7 @@ class eWeLink { } externalSensorUpdate(accessory, params) { try { - let oldState = accessory.getService(Service.ContactSensor).getCharacteristic(Characteristic.ContactSensorState).value, - newState = params.switch === "on" ? 1 : 0, + let newState = params.switch === "on" ? 1 : 0, oAccessory = false; accessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, newState); this.cusG.forEach(group => { From 76050162243c895cd9757ecd1e5eab221d9eaabe Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 9 Sep 2020 20:15:16 +0100 Subject: [PATCH 0105/3183] 2.25.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index ca38ffdb..d7a67f06 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.25.1", + "version": "2.25.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 04d63730..17650b7e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.25.1", + "version": "2.25.2", "author": "bwp91", "contributors": [ "gbro115", From 140f355b975fc429f489354b920fa7c64cdadf27 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 10 Sep 2020 10:54:31 +0100 Subject: [PATCH 0106/3183] Update package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 17650b7e..7e070066 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "keywords": [ "homebridge", "homebridge-plugin", + "homekit", "sonoff", "ewelink" ], From f694e1b622c36f39a26542c1a0944499faf6b670 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 11 Sep 2020 00:07:26 +0100 Subject: [PATCH 0107/3183] params per device type --- lib/constants.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/constants.js b/lib/constants.js index 534514f0..0a53039b 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -5,23 +5,39 @@ module.exports = { devicesHideable: ["switch", "light", "valve"], devicesNonLAN: [22, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], - devicesSingleSwitchLight: ["T1 1C", "L1", "B1", "B1_R2", "TX1C", "D1", "D1R1", "KING-M4", "Slampher", "GTTA59"], + devicesSingleSwitchParams: ["switch"], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], + devicesMultiSwitchParams: ["switches"], + devicesSingleSwitchLight: ["T1 1C", "L1", "B1", "B1_R2", "TX1C", "D1", "D1R1", "KING-M4", "Slampher", "GTTA59"], + devicesSingleSwitchLightParams: ["switch", "state", "bright", "colorR", "brightness", "channel0", "channel2", "xyz_mode"], devicesMultiSwitchLight: ["T1 2C", "T1 3C", "TX2C", "TX3C"], + devicesMultiSwitchLightParams: ["switches"], devicesBrightable: [36, 44], devicesColourable: [22, 59], devicesSensor: [102], + devicesSensorParams: ["switch"], devicesThermostat: [15], + devicesThermostatParams: ["currentTemperature", "currentHumidity", "switch", "masterSwitch"], devicesFan: [34], + devicesFanParams: ["switches", "light", "fan", "speed"], devicesOutlet: [32], + devicesOutletParams: ["switch", "power", "voltage", "current"], devicesCamera: [87], devicesUSB: [77], + devicesUSBParams: ["switches"], devicesSCM: [78], + devicesSCMParams: ["switches"], devicesRFBridge: [28], + devicesRFBridgeParams: ["cmd"], devicesZBBridge: [66], + devicesZBBridgeParams: ["key", "temperature", "humidity", "motion", "lock"], devicesZB: [1000, 1770, 2026, 3026], + devicesValveParams: ["switches"], + devicesBlindParams: ["switch", "switches"], + devicesGarageParams: ["switch", "switches"], + devicesLockParams: ["switch"], allowedGroups: ["blind", "garage", "lock"], - paramsToKeep: ["bright", "brightness", "channel", "cmd", "colorB", "colorG", "colorR", "currentHumidity", "currentTemperature", "fan", "humidity", "key", "light", "lock", "mainSwitch", "mode", "online", "rfChl", "rfList", "rfTrig", "sensorType", "speed", "state", "switch", "switches", "temperature", "type", "zyx_mode"], + paramsToKeep: ["bright", "brightness", "channel", "cmd", "colorB", "colorG", "colorR", "current", "currentHumidity", "currentTemperature", "fan", "humidity", "key", "light", "lock", "mainSwitch", "mode", "online", "power", "rfChl", "rfList", "rfTrig", "sensorType", "speed", "state", "switch", "switches", "temperature", "type", "voltage", "zyx_mode"], chansFromUiid: { 1: 1, // "SOCKET" \\ 20, MINI, BASIC, S26 2: 2, // "SOCKET_2" \\ From 4b823fa632718e1290ed510f582a55cd6ffa4d2d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 11 Sep 2020 00:07:43 +0100 Subject: [PATCH 0108/3183] deps for power readings --- package-lock.json | 575 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 + 2 files changed, 577 insertions(+) diff --git a/package-lock.json b/package-lock.json index d7a67f06..0e0ca51e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,61 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "agent-base": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.1.tgz", + "integrity": "sha512-01q25QQDwLSsyfhrKbn8yuur+JNw0H+0Y4JiGIKd3z9aYk/w/2kxD/Upc+t2ZBBSUNff50VjPsSW2YxM8QYKVg==", + "requires": { + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + }, "axios": { "version": "0.20.0", "resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz", @@ -12,6 +67,48 @@ "follow-redirects": "^1.10.0" } }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, + "bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -25,20 +122,498 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" + }, + "dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "fakegato-history": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/fakegato-history/-/fakegato-history-0.5.6.tgz", + "integrity": "sha512-LlsOkiw9LntVlRlBkssD5ozhEkQzYuEJUlvXk5YAgBQcWzk19PQ5g+NoKfs6SRY1qAeC1onb65hes4mCvY+JmA==", + "requires": { + "debug": "^2.2.0", + "googleapis": ">39.1.0", + "moment": "*" + } + }, + "fast-text-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", + "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" + }, "follow-redirects": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==" }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "gaxios": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.1.0.tgz", + "integrity": "sha512-DDTn3KXVJJigtz+g0J3vhcfbDbKtAroSTxauWsdnP57sM5KZ3d2c/3D9RKFJ86s43hfw6WULg6TXYw/AYiBlpA==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + } + }, + "gcp-metadata": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.4.tgz", + "integrity": "sha512-5J/GIH0yWt/56R3dNaNWPGQ/zXsZOddYECfJaqxFWgrZ9HC2Kvc5vl9upOgUUHKzURjAVf2N+f6tEJiojqXUuA==", + "requires": { + "gaxios": "^3.0.0", + "json-bigint": "^1.0.0" + } + }, + "google-auth-library": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.6.tgz", + "integrity": "sha512-fWYdRdg55HSJoRq9k568jJA1lrhg9i2xgfhVIMJbskUmbDpJGHsbv9l41DGhCDXM21F9Kn4kUwdysgxSYBYJUw==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^3.0.0", + "gcp-metadata": "^4.1.0", + "gtoken": "^5.0.0", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + } + }, + "google-p12-pem": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.3.tgz", + "integrity": "sha512-wS0ek4ZtFx/ACKYF3JhyGe5kzH7pgiQ7J5otlumqR9psmWMYc+U9cErKlCYVYHoUaidXHdZ2xbo34kB+S+24hA==", + "requires": { + "node-forge": "^0.10.0" + } + }, + "googleapis": { + "version": "59.0.0", + "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-59.0.0.tgz", + "integrity": "sha512-GV/E4KRN89a4GxSk7D7cwUfRYgcJHR05sOgm/WGdwc/u8dxNXG5lWmz9gF5ZwFGk2yKtVxL4VZNn4zBuZ6rmGg==", + "requires": { + "google-auth-library": "^6.0.0", + "googleapis-common": "^4.4.0" + } + }, + "googleapis-common": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-4.4.0.tgz", + "integrity": "sha512-Bgrs8/1OZQFFIfVuX38L9t48rPAkVUXttZy6NzhhXxFOEMSHgfFIjxou7RIXOkBHxmx2pVwct9WjKkbnqMYImQ==", + "requires": { + "extend": "^3.0.2", + "gaxios": "^3.0.0", + "google-auth-library": "^6.0.0", + "qs": "^6.7.0", + "url-template": "^2.0.8", + "uuid": "^8.0.0" + } + }, + "gtoken": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.3.tgz", + "integrity": "sha512-Nyd1wZCMRc2dj/mAD0LlfQLcAO06uKdpKJXvK85SGrF5+5+Bpfil9u/2aw35ltvEHjvl0h5FMKN5knEU+9JrOg==", + "requires": { + "gaxios": "^3.0.0", + "google-p12-pem": "^3.0.0", + "jws": "^4.0.0", + "mime": "^2.2.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "homebridge-lib": { + "version": "4.7.14", + "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-4.7.14.tgz", + "integrity": "sha512-8eUGTVrCRd7WHwEH49CgqYUu2q9WjeTVDnEA5WXL2ZvPevTMCck5GcVIXtvVWxr9we8Ay0ybFp0N5RRlrIzH/g==", + "requires": { + "bonjour": "^3.5.0", + "chalk": "^4.1.0", + "debug": "^4.1.1", + "semver": "^7.3.2" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==" + }, + "is-callable": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.1.tgz", + "integrity": "sha512-wliAfSzx6V+6WfMOmus1xy0XvSgf/dlStkvTfq7F0g4bOIW0PSUbnyse3NhDwdyYS1ozfUtAAySqTws3z9Eqgg==" + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" + }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, + "jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "mime": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" + }, + "moment": { + "version": "2.27.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz", + "integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" + }, "node-dns-sd": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/node-dns-sd/-/node-dns-sd-0.4.1.tgz", "integrity": "sha512-x+WSuMgvDBQv24OCq75YHcZj1SOzvP5fU4Tz+PBUiVvVBsfc+9XAHAuIftaCpf2nPLl+ys71uZoGr/v9fVDa6A==" }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" + }, + "object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==" + }, + "object-is": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz", + "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" + }, + "regexp.prototype.flags": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", + "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" + }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" + }, + "uuid": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.0.tgz", + "integrity": "sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==" + }, "ws": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz", "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } } diff --git a/package.json b/package.json index 7e070066..21d8fd47 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,8 @@ "dependencies": { "axios": "0.20.0", "color-convert": "2.0.1", + "fakegato-history": "0.5.6", + "homebridge-lib": "4.7.14", "node-dns-sd": "0.4.1", "ws": "7.3.1" }, From 5cba7192f8d496cb90dd92469a8ac19053532f1d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 11 Sep 2020 00:08:01 +0100 Subject: [PATCH 0109/3183] code formatting --- lib/eWeLinkHTTP.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index f7701ed7..4756c48b 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -145,9 +145,7 @@ module.exports = class eWeLinkHTTP { } let deviceList = []; if (body.data.thingList && body.data.thingList.length > 0) { - body.data.thingList.forEach(device => { - deviceList.push(device.itemData); - }); + body.data.thingList.forEach(device => deviceList.push(device.itemData)); } resolve(deviceList); }).catch(err => { From c549111b91770a41e9325c496aeee167b39c1ffb Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 11 Sep 2020 00:09:32 +0100 Subject: [PATCH 0110/3183] eve readings --- lib/eWeLink.js | 64 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index a5e87086..55212147 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -5,7 +5,9 @@ const convert = require("color-convert"); const eWeLinkHTTP = require("./eWeLinkHTTP"); const eWeLinkWS = require("./eWeLinkWS"); const eWeLinkLAN = require("./eWeLinkLAN"); -let Accessory, Service, Characteristic, UUIDGen; +const fakegato = require("fakegato-history"); +const hbLib = require("homebridge-lib"); +let Accessory, Characteristic, EveService, EveHistoryService, Service, UUIDGen; class eWeLink { constructor(log, config, api) { if (!log || !api) { @@ -299,6 +301,11 @@ class eWeLink { } break; case "outlet": + accessory.addService(Service.Outlet); + accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.Voltage); + accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.CurrentConsumption); + accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.ElectricCurrent); + break; case "usb": accessory.addService(Service.Outlet); break; @@ -541,85 +548,89 @@ class eWeLink { refreshAccessory(accessory, newParams) { switch (accessory.context.type) { case "valve": - if (Array.isArray(newParams.switches)) { + if (Object.keys(newParams).some(v => cns.devicesValveParams.includes(v)) && Array.isArray(newParams.switches)) { this.externalValveUpdate(accessory, newParams); } return true; case "blind": - if (Array.isArray(newParams.switches)) { + if (Object.keys(newParams).some(v => cns.devicesBlindParams.includes(v)) && Array.isArray(newParams.switches)) { this.externalBlindUpdate(accessory, newParams); } return true; case "garage": - if (newParams.hasOwnProperty("switch") || Array.isArray(newParams.switches)) { + if (Object.keys(newParams).some(v => cns.devicesGarageParams.includes(v)) && Array.isArray(newParams.switches)) { this.externalGarageUpdate(accessory, newParams); } return true; case "lock": - if (newParams.hasOwnProperty("switch")) { + if (Object.keys(newParams).some(v => cns.devicesLockParams.includes(v))) { this.externalLockUpdate(accessory, newParams); } return true; case "sensor": - if (newParams.hasOwnProperty("switch")) { + if (Object.keys(newParams).some(v => cns.devicesSensorParams.includes(v))) { this.externalSensorUpdate(accessory, newParams); } return true; case "fan": - if (Array.isArray(newParams.switches) || (newParams.hasOwnProperty("light") && newParams.hasOwnProperty("fan") && newParams.hasOwnProperty("speed"))) { + if (Object.keys(newParams).some(v => cns.devicesFanParams.includes(v))) { this.externalFanUpdate(accessory, newParams); } return true; case "thermostat": - if (newParams.hasOwnProperty("currentTemperature") || newParams.hasOwnProperty("currentHumidity") || newParams.hasOwnProperty("switch") || newParams.hasOwnProperty("masterSwitch")) { + if (Object.keys(newParams).some(v => cns.devicesThermostatParams.includes(v))) { this.externalThermostatUpdate(accessory, newParams); } return true; case "outlet": - if (newParams.hasOwnProperty("switch")) { + if (Object.keys(newParams).some(v => cns.devicesOutletParams.includes(v))) { this.externalOutletUpdate(accessory, newParams); } return true; case "usb": - if (Array.isArray(newParams.switches)) { + if (Object.keys(newParams).some(v => cns.devicesUSBParams.includes(v)) && Array.isArray(newParams.switches)) { this.externalUSBUpdate(accessory, newParams); } return true; case "scm": - if (Array.isArray(newParams.switches)) { + if (Object.keys(newParams).some(v => cns.devicesSCMParams.includes(v)) && Array.isArray(newParams.switches)) { this.externalSCMUpdate(accessory, newParams); } return true; case "light": if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID) && cns.devicesSingleSwitchLight.includes(accessory.context.eweModel)) { - if (newParams.hasOwnProperty("switch") || newParams.hasOwnProperty("state") || newParams.hasOwnProperty("bright") || newParams.hasOwnProperty("colorR") || newParams.hasOwnProperty("brightness") || newParams.hasOwnProperty("channel0") || newParams.hasOwnProperty("channel2") || newParams.hasOwnProperty("zyx_mode")) { + if (Object.keys(newParams).some(v => cns.devicesSingleSwitchLightParams.includes(v))) { this.externalSingleLightUpdate(accessory, newParams); } } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID) && cns.devicesMultiSwitchLight.includes(accessory.context.eweModel)) { - if (Array.isArray(newParams.switches)) { + if (Object.keys(newParams).some(v => cns.devicesMultiSwitchLightParams.includes(v)) && Array.isArray(newParams.switches)) { this.externalMultiLightUpdate(accessory, newParams); } } return true; case "switch": if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID)) { - if (newParams.hasOwnProperty("switch")) { + if (Object.keys(newParams).some(v => cns.devicesSingleSwitchParams.includes(v))) { this.externalSingleSwitchUpdate(accessory, newParams); } } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID)) { - if (Array.isArray(newParams.switches)) { + if (Object.keys(newParams).some(v => cns.devicesMultiSwitchParams.includes(v)) && Array.isArray(newParams.switches)) { this.externalMultiSwitchUpdate(accessory, newParams); } } return true; case "rf_pri": - this.externalRFDeviceUpdate(accessory, newParams); + if (Object.keys(newParams).some(v => cns.devicesRFBridgeParams.includes(v))) { + this.externalRFDeviceUpdate(accessory, newParams); + } return true; case "rf_sub": case "zb_pri": return true; case "zb_sub": - this.externalZBDeviceUpdate(accessory, newParams); + if (Object.keys(newParams).some(v => cns.devicesZBBridgeParams.includes(v))) { + this.externalZBDeviceUpdate(accessory, newParams); + } return true; default: return false; @@ -988,7 +999,7 @@ class eWeLink { if (this.config.debug) { this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); + accessory.getService(Outlet).updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { callback("[" + accessory.displayName + "] " + err + "."); @@ -1525,7 +1536,18 @@ class eWeLink { } externalOutletUpdate(accessory, params) { try { - accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switch === "on"); + if (params.hasOwnProperty("switch")) { + accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switch === "on"); + } + if (params.hasOwnProperty("power")) { + accessory.getService(Service.Outlet).updateCharacteristic(EveService.Characteristics.CurrentConsumption, parseFloat(params.power)); + } + if (params.hasOwnProperty("voltage")) { + accessory.getService(Service.Outlet).updateCharacteristic(EveService.Characteristics.Voltage, parseFloat(params.voltage)); + } + if (params.hasOwnProperty("current")) { + accessory.getService(Service.Outlet).updateCharacteristic(EveService.Characteristics.ElectricCurrent, parseFloat(params.current)); + } } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } @@ -1773,8 +1795,10 @@ class eWeLink { } module.exports = function(homebridge) { Accessory = homebridge.platformAccessory; - Service = homebridge.hap.Service; Characteristic = homebridge.hap.Characteristic; + EveService = new hbLib.EveHomeKitTypes(homebridge); + EveHistoryService = fakegato(homebridge); + Service = homebridge.hap.Service; UUIDGen = homebridge.hap.uuid; return eWeLink; }; \ No newline at end of file From 671a970241975eebbc970de85ed3c2699d77d5e1 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 11 Sep 2020 00:12:23 +0100 Subject: [PATCH 0111/3183] 2.26.0-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0e0ca51e..873013f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.25.2", + "version": "2.26.0-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 21d8fd47..06f177bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.25.2", + "version": "2.26.0-0", "author": "bwp91", "contributors": [ "gbro115", From 74aeae4a564420da4f963b6e1f0a64c665860f88 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 11 Sep 2020 00:22:59 +0100 Subject: [PATCH 0112/3183] outlet type line 1001 --- lib/eWeLink.js | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 55212147..9db0619b 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -30,9 +30,8 @@ class eWeLink { //*** Set up HTTP client and get the user HTTP host ***\\ this.httpClient = new eWeLinkHTTP(this.config, this.log); this.httpClient.getHost() - .then(res => { //*** Use the HTTP API host to log into eWeLink ***\\ - return this.httpClient.login(); - }).then(res => { //*** Set up the web socket client ***\\ + .then(() => this.httpClient.login()) + .then(res => { //*** Set up the web socket client ***\\ this.wsClient = new eWeLinkWS(this.config, this.log, res); return this.wsClient.getHost(); }).then(() => { //*** Open web socket connection and get device list via HTTP ***\\ @@ -999,7 +998,7 @@ class eWeLink { if (this.config.debug) { this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory.getService(Outlet).updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { callback("[" + accessory.displayName + "] " + err + "."); @@ -1141,9 +1140,7 @@ class eWeLink { if (this.config.debug) { this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); } - setTimeout(() => { - this.sendDeviceUpdate(accessory, params, callback); - }, 250); + setTimeout(() => this.sendDeviceUpdate(accessory, params, callback), 250); } catch (err) { let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); @@ -1219,9 +1216,7 @@ class eWeLink { default: throw "unknown device UIID"; } - setTimeout(() => { - this.sendDeviceUpdate(accessory, params, callback); - }, 250); + setTimeout(() => this.sendDeviceUpdate(accessory, params, callback), 250); } catch (err) { let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); @@ -1331,9 +1326,7 @@ class eWeLink { } accessory.getService(accessory.context.rfChls[rfChl]).updateCharacteristic(Characteristic.On, true); this.sendDeviceUpdate(accessory, params, callback); - setTimeout(() => { - accessory.getService(accessory.context.rfChls[rfChl]).updateCharacteristic(Characteristic.On, false); - }, 3000); + setTimeout(() => accessory.getService(accessory.context.rfChls[rfChl]).updateCharacteristic(Characteristic.On, false), 3000); } catch (err) { let str = "[" + accessory.displayName + " " + name + "] could not be updated as " + err + "."; this.log.error(str); @@ -1409,8 +1402,7 @@ class eWeLink { .updateCharacteristic(Characteristic.CurrentDoorState, newPos) .updateCharacteristic(Characteristic.TargetDoorState, newPos - 2); setTimeout(() => { - accessory.getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2); + accessory.getService(Service.GarageDoorOpener).updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2); }, parseInt(garageConfig.operationTime) * 100); } setTimeout(() => { @@ -1684,9 +1676,7 @@ class eWeLink { let bAccessory; if ((bAccessory = this.devicesInHB.get(idToCheck + accessory.context.rfChlMap[params.rfChl]))) { bAccessory.getService(bAccessory.context.rfChls[params.rfChl]).updateCharacteristic(Characteristic.On, 1); - setTimeout(() => { - bAccessory.getService(bAccessory.context.rfChls[params.rfChl]).updateCharacteristic(Characteristic.On, 0); - }, 3000); + setTimeout(() => bAccessory.getService(bAccessory.context.rfChls[params.rfChl]).updateCharacteristic(Characteristic.On, 0), 3000); } else { throw "rf button not found in Homebridge"; } From bb1eb3cfc2b6077f8f05891c737a742c513202f8 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 11 Sep 2020 14:08:18 +0100 Subject: [PATCH 0113/3183] Update index.js --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 624be64e..4902dd17 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,6 @@ /* jshint esversion: 9, -W030, node: true */ "use strict"; module.exports = function (homebridge) { - let eWeLink = require("./lib/eWeLink.js")(homebridge); + const eWeLink = require("./lib/eWeLink.js")(homebridge); homebridge.registerPlatform("homebridge-ewelink", "eWeLink", eWeLink, true); }; \ No newline at end of file From c967ba8b677a3476a04f33b8cd0baf2758a0a257 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 11 Sep 2020 14:09:13 +0100 Subject: [PATCH 0114/3183] refactoring --- lib/eWeLink.js | 182 ++++++++++++++++++++++++++----------------------- 1 file changed, 98 insertions(+), 84 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 9db0619b..b5c6ff68 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1,20 +1,20 @@ /* jshint esversion: 9, -W030, node: true */ "use strict"; -const cns = require("./constants"); -const convert = require("color-convert"); -const eWeLinkHTTP = require("./eWeLinkHTTP"); -const eWeLinkWS = require("./eWeLinkWS"); -const eWeLinkLAN = require("./eWeLinkLAN"); -const fakegato = require("fakegato-history"); -const hbLib = require("homebridge-lib"); let Accessory, Characteristic, EveService, EveHistoryService, Service, UUIDGen; +const cns = require("./constants"), + convert = require("color-convert"), + eWeLinkHTTP = require("./eWeLinkHTTP"), + eWeLinkWS = require("./eWeLinkWS"), + eWeLinkLAN = require("./eWeLinkLAN"), + fakegato = require("fakegato-history"), + hbLib = require("homebridge-lib"); class eWeLink { constructor(log, config, api) { - if (!log || !api) { - return; - } - if (!config || (!config.username || !config.password || !config.countryCode)) { - log.error("🔴 Cannot load homebridge-ewelink - please check your eWeLink credentials in the plugin settings."); + if (!log || !api || !config) return; + if (!config.username || !config.password || !config.countryCode) { + log.error("************** Cannot load homebridge-ewelink **************"); + log.error("Your eWeLink credentials missing from the Homebridge config."); + log.error("************************************************************"); return; } this.log = log; @@ -24,6 +24,7 @@ class eWeLink { this.devicesInEwe = new Map(); this.cusG = new Map(); this.cusS = new Map(); + this.eveLogPath = this.api.user.persistPath() + "/homebridge-ewelink"; this.api .on("didFinishLaunching", () => { this.log("Plugin has finished initialising. Starting synchronisation with eWeLink account."); @@ -40,10 +41,9 @@ class eWeLink { }).then(res => { //*** Get device IP addresses for LAN mode ***\\ this.httpDevices = res .filter(device => device.hasOwnProperty("extra") && device.extra.hasOwnProperty("uiid")) - .filter(device => !(this.config.hideDevFromHB || "").includes(device.deviceid)) - .forEach(device => this.devicesInEwe.set(device.deviceid, device)); - this.httpDevices = res; + .filter(device => !(this.config.hideDevFromHB || "").includes(device.deviceid)); this.lanClient = new eWeLinkLAN(this.config, this.log, this.httpDevices); + this.httpDevices.forEach(device => this.devicesInEwe.set(device.deviceid, device)); return this.lanClient.getHosts(); }).then(res => { //*** Set up the LAN mode listener ***\\ this.lanDevices = res.map; @@ -55,14 +55,16 @@ class eWeLink { if (Object.keys(this.httpDevices).length === 0 && Object.keys(this.lanDevices).length === 0) { Array.from(this.devicesInHB.values()).forEach(a => this.removeAccessory(a)); this.devicesInHB.clear(); - this.log.warn("🟠 No devices were found registered to your eWeLink account so disabling plugin."); + this.log.warn("******* Not loading homebridge-ewelink *******"); + this.log.warn("No devices were found in your eWeLink account."); + this.log.warn("**********************************************"); return; } //*** Make a map of custom groups from Homebridge config ***\\ if (Object.keys(this.config.groups || []).length > 0) { this.config.groups - .filter(g => g.hasOwnProperty("deviceId") && this.devicesInEwe.has(g.deviceId.toLowerCase())) .filter(g => g.hasOwnProperty("type") && cns.allowedGroups.includes(g.type)) + .filter(g => g.hasOwnProperty("deviceId") && this.devicesInEwe.has(g.deviceId.toLowerCase())) .forEach(g => this.cusG.set(g.deviceId + "SWX", g)); } //*** Make a map of RF Bridge custom sensors from Homebridge config ***\\ @@ -76,42 +78,35 @@ class eWeLink { this.log("[%s] primary devices were loaded from your eWeLink account.", this.devicesInEwe.size); this.log("[%s] primary devices were discovered on your local network.", this.lanDevicesOnline); //*** Remove Homebridge accessories that don't appear in eWeLink ***\\ - this.devicesInHB.forEach(accessory => { - if (!this.devicesInEwe.has(accessory.context.eweDeviceId)) { - this.removeAccessory(accessory); + this.devicesInHB.forEach(a => { + if (!this.devicesInEwe.has(a.context.eweDeviceId)) { + this.removeAccessory(a); } }); //*** Synchronise devices between eWeLink and Homebridge and set up ws/lan listeners ***\\ - this.devicesInEwe.forEach(device => this.initialiseDevice(device)); - this.wsClient.receiveUpdate(device => this.receiveDeviceUpdate(device)); - this.lanClient.receiveUpdate(device => this.receiveDeviceUpdate(device)); - this.log("đŸŸĸ eWeLink setup complete. If you're enjoying this package please consider a ⭐ī¸ on GitHub!"); + this.devicesInEwe.forEach(d => this.initialiseDevice(d)); + this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); + this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); + this.log("eWeLink setup complete. If you're enjoying this package please consider a ⭐ī¸ on GitHub :)."); if (this.config.debugReqRes) { this.log.warn("You have 'Request & Response Logging' enabled. This setting is not recommended for long-term use."); } })(); }).catch(err => { - this.log.error("🔴 Cannot load homebridge-ewelink - %s", err); - if (this.lanClient) { - this.lanClient.closeConnection(); - } - if (this.wsClient) { - this.wsClient.closeConnection(); - } + this.log.error("************** Cannot load homebridge-ewelink **************"); + this.log.error(err); + this.log.error("************************************************************"); + if (this.lanClient) this.lanClient.closeConnection(); + if (this.wsClient) this.wsClient.closeConnection(); }); }) .on('shutdown', () => { - if (this.lanClient) { - this.lanClient.closeConnection(); - } - if (this.wsClient) { - this.wsClient.closeConnection(); - } + if (this.lanClient) this.lanClient.closeConnection(); + if (this.wsClient) this.wsClient.closeConnection(); }); } initialiseDevice(device) { let accessory; - device.params.updateSource = "HTTP"; //*** First add the device if it isn't already in Homebridge. Yeah this code looks a mess :| ***\\ if (!this.devicesInHB.has(device.deviceid + "SWX") && !this.devicesInHB.has(device.deviceid + "SW0")) { if (device.extra.uiid === 2 && device.brandName === "coolkit" && device.productModel === "0285") { @@ -170,8 +165,9 @@ class eWeLink { let isX = accessory.context.hbDeviceId.substr(-1) === "X", isRfBridge = cns.devicesRFBridge.includes(accessory.context.eweUIID), rfBridgeChange = false; - accessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); - accessory.context.reachableWAN = accessory.context.eweUIID !== 102 ? device.online : true; //*** DW2 ***\\ + accessory.getService(Service.AccessoryInformation) + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); + accessory.context.reachableWAN = accessory.context.eweUIID !== 102 ? device.online : true; accessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; accessory.context.inUse = false; let str = accessory.context.reachableLAN ? @@ -197,11 +193,10 @@ class eWeLink { } if (isRfBridge && oAccessory.context.sensorType !== "button") { let ct = this.cusS.has(oAccessory.context.hbDeviceId) ? this.cusS.get(oAccessory.context.hbDeviceId).type : "motion"; - if (ct !== oAccessory.context.sensorType || typeof accessory.context.updated === "undefined") { - rfBridgeChange = true; - } + if (ct !== oAccessory.context.sensorType) rfBridgeChange = true; } - oAccessory.getService(Service.AccessoryInformation).setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); + oAccessory.getService(Service.AccessoryInformation) + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); oAccessory.context.reachableWAN = device.online; oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); @@ -224,13 +219,15 @@ class eWeLink { } } addAccessory(device, hbDeviceId, type) { - let channelCount = type === "rf_pri" ? Object.keys((device.tags && device.tags.zyx_info) || []).length : cns.chansFromUiid[device.extra.uiid], - switchNumber = hbDeviceId.substr(-1).toString(), - newDeviceName = type === "rf_sub" ? device.tags.zyx_info[switchNumber - 1].name : device.name; + let switchNumber = hbDeviceId.substr(-1).toString(), + newDeviceName = type === "rf_sub" ? device.tags.zyx_info[switchNumber - 1].name : device.name, + channelCount = type === "rf_pri" ? + Object.keys((device.tags && device.tags.zyx_info) || []).length : + cns.chansFromUiid[device.extra.uiid]; if (["1", "2", "3", "4"].includes(switchNumber) && type !== "rf_sub") { newDeviceName += " SW" + switchNumber; if ((this.config.hideFromHB || "").includes(hbDeviceId) && cns.devicesHideable.includes(type)) { - this.log.warn("[%s] will not be added as per configuration.", newDeviceName); + this.log("[%s] will not be added as per configuration.", newDeviceName); return; } } @@ -291,18 +288,15 @@ class eWeLink { accessory.addService(Service.Lightbulb); break; case "thermostat": - if (!this.config.hideTHSwitch) { - accessory.addService(Service.Switch); - } + if (!this.config.hideTHSwitch) accessory.addService(Service.Switch); accessory.addService(Service.TemperatureSensor); - if (device.params.sensorType !== "DS18B20") { - accessory.addService(Service.HumiditySensor); - } + if (device.params.sensorType !== "DS18B20") accessory.addService(Service.HumiditySensor); break; case "outlet": accessory.addService(Service.Outlet); accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.Voltage); accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.CurrentConsumption); + accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.TotalConsumption); accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.ElectricCurrent); break; case "usb": @@ -317,7 +311,6 @@ class eWeLink { break; case "rf_pri": accessory.context.rfChlMap = {}; - accessory.context.updated = true; break; case "zb_pri": break; @@ -334,20 +327,20 @@ class eWeLink { accessory.context.sensorType = this.cusS.has(hbDeviceId) ? this.cusS.get(hbDeviceId).type : "motion"; break; default: - throw "RF device type is not supported"; + throw "unsupported rf device type [" + device.tags.zyx_info[parseInt(switchNumber) - 1].remote_type + "]. Please create an issue on GitHub"; } let mAccessory = this.devicesInHB.get(device.deviceid + "SW0"); device.tags.zyx_info[parseInt(switchNumber) - 1].buttonName.forEach(button => { - let rfChan, name; - Object.entries(button).forEach(([k, v]) => { - rfChan = k; - name = v; + let rfData; + Object.entries(button).forEach(([k, v]) => rfData = { + rfChan: k, + name: v }); - accessory.context.rfChls[rfChan] = name; - mAccessory.context.rfChlMap[rfChan] = switchNumber; + accessory.context.rfChls[rfData.rfChan] = rfData.name; + mAccessory.context.rfChlMap[rfData.rfChan] = switchNumber; switch (accessory.context.sensorType) { case "button": - accessory.addService(Service.Switch, name, "switch" + rfChan); + accessory.addService(Service.Switch, rfData.name, "switch" + rfData.rfChan); break; case "water": accessory.addService(Service.LeakSensor); @@ -413,19 +406,15 @@ class eWeLink { } } configureAccessory(accessory) { - if (!this.log) { - return; - } + if (!this.log) return; try { + accessory.context.reachableWAN = true; + accessory.context.reachableLAN = true; switch (accessory.context.type) { case "valve": ["A", "B"].forEach(v => { accessory.getService("Valve " + v).getCharacteristic(Characteristic.Active) - .on("set", (value, callback) => { - accessory.getService("Valve " + v).getCharacteristic(Characteristic.Active).value !== value ? - this.internalValveUpdate(accessory, "Valve " + v, value, callback) : - callback(); - }); + .on("set", (value, callback) => this.internalValveUpdate(accessory, "Valve " + v, value, callback)); accessory.getService("Valve " + v).getCharacteristic(Characteristic.SetDuration) .on("set", (value, callback) => { if (accessory.getService("Valve " + v).getCharacteristic(Characteristic.InUse).value) { @@ -433,7 +422,7 @@ class eWeLink { clearTimeout(accessory.getService("Valve " + v).timer); accessory.getService("Valve " + v).timer = setTimeout(() => { accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); - }, (value * 1000)); + }, value * 1000); } callback(); }); @@ -441,10 +430,10 @@ class eWeLink { break; case "blind": accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.TargetPosition) + .on("set", (value, callback) => this.internalBlindUpdate(accessory, value, callback)) .setProps({ minStep: 100 - }) - .on("set", (value, callback) => this.internalBlindUpdate(accessory, value, callback)); + }); break; case "garage": accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.TargetDoorState) @@ -458,10 +447,10 @@ class eWeLink { accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active) .on("set", (value, callback) => this.internalFanUpdate(accessory, "power", value, callback)); accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.RotationSpeed) + .on("set", (value, callback) => this.internalFanUpdate(accessory, "speed", value, callback)) .setProps({ minStep: 33 - }) - .on("set", (value, callback) => this.internalFanUpdate(accessory, "speed", value, callback)); + }); accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) .on("set", (value, callback) => this.internalFanUpdate(accessory, "light", value, callback)); break; @@ -474,6 +463,12 @@ class eWeLink { case "outlet": accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) .on("set", (value, callback) => this.internalOutletUpdate(accessory, value, callback)); + accessory.log = this.log; + accessory.eveLogger = new EveHistoryService("energy", accessory, { + storage: "fs", + path: this.eveLogPath + }); + accessory.context.totalEnergyTemp = 0; break; case "usb": accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) @@ -537,8 +532,6 @@ class eWeLink { } break; } - accessory.context.reachableWAN = true; - accessory.context.reachableLAN = true; this.devicesInHB.set(accessory.context.hbDeviceId, accessory); } catch (err) { this.log.warn("[%s] could not be refreshed as %s.", accessory.displayName, err); @@ -683,9 +676,7 @@ class eWeLink { accessory.context.reachableWAN = device.params.online; this.log("[%s] has been reported [%s] via [WS].", accessory.displayName, accessory.context.reachableWAN ? "online" : "offline"); this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory); - } + if (accessory.context.reachableWAN) this.wsClient.requestUpdate(accessory); } else { if (this.debug) { this.log("[%s] Nothing to update from above WS message.", accessory.displayName); @@ -1533,6 +1524,31 @@ class eWeLink { } if (params.hasOwnProperty("power")) { accessory.getService(Service.Outlet).updateCharacteristic(EveService.Characteristics.CurrentConsumption, parseFloat(params.power)); + accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.OutletInUse, parseFloat(params.power) > 0); + if (accessory.eveLogger.isHistoryLoaded()) { + let extraPersistedData = accessory.eveLogger.getExtraPersistedData(); + if (extraPersistedData !== undefined) { + let totalEnergy = extraPersistedData.totalenergy + accessory.context.totalEnergyTemp + parseFloat(params.power) * (30000 / 1000) / 3600 / 1000; + accessory.eveLogger.setExtraPersistedData({ + totalEnergy, + lastReset: extraPersistedData.lastReset + }); + } else { + let totalEnergy = accessory.context.totalEnergyTemp + parseFloat(params.power) * (30000 / 1000) / 3600 / 1000; + accessory.eveLogger.setExtraPersistedData({ + totalEnergy, + lastReset: 0 + }); + } + accessory.context.totalEnergyTemp = 0; + } else { + accessory.context.totalEnergyTemp += parseFloat(params.power) * (30000 / 1000) / 3600 / 1000; + let totalEnergy = accessory.context.totalEnergyTemp; + } + accessory.eveLogger.addEntry({ + time: Math.floor((new Date()).getTime() / 1000), + power: parseFloat(params.power) + }); } if (params.hasOwnProperty("voltage")) { accessory.getService(Service.Outlet).updateCharacteristic(EveService.Characteristics.Voltage, parseFloat(params.voltage)); @@ -1667,9 +1683,7 @@ class eWeLink { } externalRFDeviceUpdate(accessory, params) { try { - if (params.updateSource === "HTTP") { - return; - } + if (!params.hasOwnProperty("updateSource")) return; let idToCheck = accessory.context.hbDeviceId.slice(0, -1), timeNow = new Date(); if (params.hasOwnProperty("cmd") && params.cmd === "transmit" && params.hasOwnProperty("rfChl")) { // RF Button From 05da65457b40afea4b6bad83b05bb200c5f3073c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 11 Sep 2020 14:10:01 +0100 Subject: [PATCH 0115/3183] 2.26.0-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 873013f6..976b4433 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.26.0-0", + "version": "2.26.0-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 06f177bb..2ffd7773 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.26.0-0", + "version": "2.26.0-1", "author": "bwp91", "contributors": [ "gbro115", From 157bba8ebf8933a90e3d6550845283426fa94aab Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 12 Sep 2020 13:37:04 +0100 Subject: [PATCH 0116/3183] add correcting-inteval dep --- package-lock.json | 5 +++++ package.json | 1 + 2 files changed, 6 insertions(+) diff --git a/package-lock.json b/package-lock.json index 976b4433..529f274a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -122,6 +122,11 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "correcting-interval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/correcting-interval/-/correcting-interval-2.0.0.tgz", + "integrity": "sha1-iTdklFcN+C7axTQRHV8n/z6gstM=" + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", diff --git a/package.json b/package.json index 2ffd7773..fba6c4dd 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "dependencies": { "axios": "0.20.0", "color-convert": "2.0.1", + "correcting-interval": "2.0.0", "fakegato-history": "0.5.6", "homebridge-lib": "4.7.14", "node-dns-sd": "0.4.1", From 6622c561a84e3ce00e7afcb34018a1c04c4e58a0 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 12 Sep 2020 13:37:48 +0100 Subject: [PATCH 0117/3183] EVE temp/power logging --- lib/eWeLink.js | 125 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 101 insertions(+), 24 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index b5c6ff68..338f40ba 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -3,6 +3,7 @@ let Accessory, Characteristic, EveService, EveHistoryService, Service, UUIDGen; const cns = require("./constants"), convert = require("color-convert"), + corrInterval = require("correcting-interval"), eWeLinkHTTP = require("./eWeLinkHTTP"), eWeLinkWS = require("./eWeLinkWS"), eWeLinkLAN = require("./eWeLinkLAN"), @@ -24,7 +25,7 @@ class eWeLink { this.devicesInEwe = new Map(); this.cusG = new Map(); this.cusS = new Map(); - this.eveLogPath = this.api.user.persistPath() + "/homebridge-ewelink"; + this.eveLogPath = this.api.user.storagePath() + "/persist/"; this.api .on("didFinishLaunching", () => { this.log("Plugin has finished initialising. Starting synchronisation with eWeLink account."); @@ -291,13 +292,32 @@ class eWeLink { if (!this.config.hideTHSwitch) accessory.addService(Service.Switch); accessory.addService(Service.TemperatureSensor); if (device.params.sensorType !== "DS18B20") accessory.addService(Service.HumiditySensor); + accessory.log = this.log; + accessory.eveLogger = new EveHistoryService("weather", accessory, { + storage: "fs", + path: this.eveLogPath + }); break; case "outlet": accessory.addService(Service.Outlet); accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.Voltage); accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.CurrentConsumption); - accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.TotalConsumption); accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.ElectricCurrent); + accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.TotalConsumption); + accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.ResetTotal); + accessory.context = { + ...accessory.context, + ...{ + extraPersistedData: {}, + lastReset: 0, + totalEnergy: 0, + totalEnergyTemp: 0 + } + }; + accessory.eveLogger = new EveHistoryService("energy", accessory, { + storage: "fs", + path: this.eveLogPath + }); break; case "usb": accessory.addService(Service.Outlet); @@ -459,6 +479,23 @@ class eWeLink { accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) .on("set", (value, callback) => this.internalThermostatUpdate(accessory, value, callback)); } + accessory.log = this.log; + accessory.eveLogger = new EveHistoryService("weather", accessory, { + storage: "fs", + path: this.eveLogPath + }); + corrInterval.setCorrectingInterval(() => { + let currentTemp = accessory.getService(Service.TemperatureSensor).getCharacteristic(Characteristic.CurrentTemperature).value, + dataToAdd = { + time: Date.now(), + temp: currentTemp + }; + if (accessory.getService(Service.HumiditySensor)) { + dataToAdd.humidity = accessory.getService(Service.HumiditySensor).getCharacteristic(Characteristic.CurrentRelativeHumidity).value; + } + this.log.warn("[%s] 10 minute inteval recorded [%s°C].", accessory.displayName, currentTemp); + accessory.eveLogger.addEntry(dataToAdd); + }, 60000); break; case "outlet": accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) @@ -468,7 +505,60 @@ class eWeLink { storage: "fs", path: this.eveLogPath }); - accessory.context.totalEnergyTemp = 0; + corrInterval.setCorrectingInterval(() => { + let currentWatt = accessory.getService(Service.Outlet) + .getCharacteristic(EveService.Characteristics.CurrentConsumption).value; + this.log.warn("[%s] 10 minute inteval recorded [%sW].", accessory.displayName, currentWatt); + if (accessory.eveLogger.isHistoryLoaded()) { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.totalEnergy = accessory.context.extraPersistedData.totalenergy + accessory.context.totalEnergyTemp + currentWatt * 10 / 3600 / 1000; + accessory.eveLogger.setExtraPersistedData({ + totalenergy: accessory.context.totalEnergy, + lastReset: accessory.context.extraPersistedData.lastReset + }); + } else { + accessory.context.totalEnergy = accessory.context.totalEnergyTemp + currentWatt * 10 / 3600 / 1000; + accessory.eveLogger.setExtraPersistedData({ + totalenergy: accessory.context.totalEnergy, + lastReset: 0 + }); + } + accessory.context.totalEnergytemp = 0; + } else { + accessory.context.totalEnergyTemp += currentWatt * 10 / 3600 / 1000; + accessory.context.totalEnergy = accessory.context.totalEnergyTemp; + } + accessory.eveLogger.addEntry({ + time: Date.now(), + power: currentWatt + }); + }, 60000); + accessory.getService(Service.Outlet).getCharacteristic(EveService.Characteristics.TotalConsumption) + .on("get", callback => { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.totalPower = accessory.context.extraPersistedData.totalPower; + } + callback(null, accessory.context.totalPower); + }); + accessory.getService(Service.Outlet).getCharacteristic(EveService.Characteristics.ResetTotal) + .on("set", (value, callback) => { + accessory.context.totalPower = 0; + accessory.context.lastReset = value; + accessory.eveLogger.setExtraPersistedData({ + totalPower: 0, + lastReset: value + }); + callback(); + }) + .on("get", callback => { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.lastReset = accessory.context.extraPersistedData.lastReset; + } + callback(null, accessory.context.lastReset); + }); break; case "usb": accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) @@ -1505,14 +1595,21 @@ class eWeLink { let newState = params.hasOwnProperty("switch") ? params.switch === "on" : params.mainSwitch === "on"; accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, newState); } + let eveLog = false; if (params.hasOwnProperty("currentTemperature") && accessory.getService(Service.TemperatureSensor)) { let currentTemp = params.currentTemperature !== "unavailable" ? params.currentTemperature : 0; accessory.getService(Service.TemperatureSensor).updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); + eveLog = { + time: Date.now(), + temp: currentTemp + }; } if (params.hasOwnProperty("currentHumidity") && accessory.getService(Service.HumiditySensor)) { let currentHumi = params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; accessory.getService(Service.HumiditySensor).updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); + eveLog.humidity = currentHumi; } + if (eveLog) accessory.eveLogger.addEntry(eveLog); } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } @@ -1525,28 +1622,8 @@ class eWeLink { if (params.hasOwnProperty("power")) { accessory.getService(Service.Outlet).updateCharacteristic(EveService.Characteristics.CurrentConsumption, parseFloat(params.power)); accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.OutletInUse, parseFloat(params.power) > 0); - if (accessory.eveLogger.isHistoryLoaded()) { - let extraPersistedData = accessory.eveLogger.getExtraPersistedData(); - if (extraPersistedData !== undefined) { - let totalEnergy = extraPersistedData.totalenergy + accessory.context.totalEnergyTemp + parseFloat(params.power) * (30000 / 1000) / 3600 / 1000; - accessory.eveLogger.setExtraPersistedData({ - totalEnergy, - lastReset: extraPersistedData.lastReset - }); - } else { - let totalEnergy = accessory.context.totalEnergyTemp + parseFloat(params.power) * (30000 / 1000) / 3600 / 1000; - accessory.eveLogger.setExtraPersistedData({ - totalEnergy, - lastReset: 0 - }); - } - accessory.context.totalEnergyTemp = 0; - } else { - accessory.context.totalEnergyTemp += parseFloat(params.power) * (30000 / 1000) / 3600 / 1000; - let totalEnergy = accessory.context.totalEnergyTemp; - } accessory.eveLogger.addEntry({ - time: Math.floor((new Date()).getTime() / 1000), + time: Date.now(), power: parseFloat(params.power) }); } From f26836d8bdbbe266d5adfb377779d5cb1da588b3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 12 Sep 2020 13:52:42 +0100 Subject: [PATCH 0118/3183] energy typo --- lib/eWeLink.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 338f40ba..7dbc5f6f 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -538,13 +538,13 @@ class eWeLink { .on("get", callback => { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalPower = accessory.context.extraPersistedData.totalPower; + accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower; } - callback(null, accessory.context.totalPower); + callback(null, accessory.context.totalEnergy); }); accessory.getService(Service.Outlet).getCharacteristic(EveService.Characteristics.ResetTotal) .on("set", (value, callback) => { - accessory.context.totalPower = 0; + accessory.context.totalEnergy = 0; accessory.context.lastReset = value; accessory.eveLogger.setExtraPersistedData({ totalPower: 0, From 55e1e17c72500ce2c5398973c71246ac011160e6 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 12 Sep 2020 13:53:17 +0100 Subject: [PATCH 0119/3183] 2.26.0-2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 529f274a..9f86cb85 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.26.0-1", + "version": "2.26.0-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index fba6c4dd..92c69284 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.26.0-1", + "version": "2.26.0-2", "author": "bwp91", "contributors": [ "gbro115", From 2e3457c80a5bf6ad396fd38ed37918631f76993d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 12 Sep 2020 14:31:10 +0100 Subject: [PATCH 0120/3183] eve log bugs --- lib/eWeLink.js | 54 +++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 7dbc5f6f..fd806aa3 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -493,7 +493,6 @@ class eWeLink { if (accessory.getService(Service.HumiditySensor)) { dataToAdd.humidity = accessory.getService(Service.HumiditySensor).getCharacteristic(Characteristic.CurrentRelativeHumidity).value; } - this.log.warn("[%s] 10 minute inteval recorded [%s°C].", accessory.displayName, currentTemp); accessory.eveLogger.addEntry(dataToAdd); }, 60000); break; @@ -506,9 +505,9 @@ class eWeLink { path: this.eveLogPath }); corrInterval.setCorrectingInterval(() => { - let currentWatt = accessory.getService(Service.Outlet) - .getCharacteristic(EveService.Characteristics.CurrentConsumption).value; - this.log.warn("[%s] 10 minute inteval recorded [%sW].", accessory.displayName, currentWatt); + let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value, + currentWatt = isOn ? accessory.getService(Service.Outlet) + .getCharacteristic(EveService.Characteristics.CurrentConsumption).value : 0; if (accessory.eveLogger.isHistoryLoaded()) { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); if (accessory.context.extraPersistedData !== undefined) { @@ -1371,27 +1370,6 @@ class eWeLink { callback(str); } } - externalValveUpdate(accessory, params) { - try { - ["A", "B"].forEach((v, k) => { - accessory.getService("Valve " + v) - .updateCharacteristic(Characteristic.Active, params.switches[k].switch === "on") - .updateCharacteristic(Characteristic.InUse, params.switches[k].switch === "on"); - if (params.switches[k].switch === "on") { - let timer = accessory.getService("Valve " + v).getCharacteristic(Characteristic.SetDuration).value; - accessory.getService("Valve " + v).updateCharacteristic(Characteristic.RemainingDuration, timer); - accessory.getService("Valve " + v).timer = setTimeout(() => { - accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); - }, (timer * 1000)); - } else { - accessory.getService("Valve " + v).updateCharacteristic(Characteristic.RemainingDuration, 0); - clearTimeout(accessory.getService("Valve " + v).timer); - } - }); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } internalRFDeviceUpdate(accessory, rfChl, callback) { try { if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { @@ -1414,6 +1392,27 @@ class eWeLink { callback(str); } } + externalValveUpdate(accessory, params) { + try { + ["A", "B"].forEach((v, k) => { + accessory.getService("Valve " + v) + .updateCharacteristic(Characteristic.Active, params.switches[k].switch === "on") + .updateCharacteristic(Characteristic.InUse, params.switches[k].switch === "on"); + if (params.switches[k].switch === "on") { + let timer = accessory.getService("Valve " + v).getCharacteristic(Characteristic.SetDuration).value; + accessory.getService("Valve " + v).updateCharacteristic(Characteristic.RemainingDuration, timer); + accessory.getService("Valve " + v).timer = setTimeout(() => { + accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); + }, (timer * 1000)); + } else { + accessory.getService("Valve " + v).updateCharacteristic(Characteristic.RemainingDuration, 0); + clearTimeout(accessory.getService("Valve " + v).timer); + } + }); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } externalBlindUpdate(accessory, params) { try { let blindConfig, nSte; @@ -1601,7 +1600,7 @@ class eWeLink { accessory.getService(Service.TemperatureSensor).updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); eveLog = { time: Date.now(), - temp: currentTemp + temp: parseFloat(currentTemp) }; } if (params.hasOwnProperty("currentHumidity") && accessory.getService(Service.HumiditySensor)) { @@ -1622,9 +1621,10 @@ class eWeLink { if (params.hasOwnProperty("power")) { accessory.getService(Service.Outlet).updateCharacteristic(EveService.Characteristics.CurrentConsumption, parseFloat(params.power)); accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.OutletInUse, parseFloat(params.power) > 0); + let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value; accessory.eveLogger.addEntry({ time: Date.now(), - power: parseFloat(params.power) + power: isOn ? parseFloat(params.power) : 0 }); } if (params.hasOwnProperty("voltage")) { From c85d865a3f01e9244ce78b54df14e3cbee21975f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 12 Sep 2020 14:49:22 +0100 Subject: [PATCH 0121/3183] eve final changes --- lib/eWeLink.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index fd806aa3..5c70de5f 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -485,16 +485,15 @@ class eWeLink { path: this.eveLogPath }); corrInterval.setCorrectingInterval(() => { - let currentTemp = accessory.getService(Service.TemperatureSensor).getCharacteristic(Characteristic.CurrentTemperature).value, - dataToAdd = { - time: Date.now(), - temp: currentTemp - }; + let dataToAdd = { + time: Date.now(), + temp: accessory.getService(Service.TemperatureSensor).getCharacteristic(Characteristic.CurrentTemperature).value + }; if (accessory.getService(Service.HumiditySensor)) { dataToAdd.humidity = accessory.getService(Service.HumiditySensor).getCharacteristic(Characteristic.CurrentRelativeHumidity).value; } accessory.eveLogger.addEntry(dataToAdd); - }, 60000); + }, 600000); break; case "outlet": accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) @@ -532,7 +531,7 @@ class eWeLink { time: Date.now(), power: currentWatt }); - }, 60000); + }, 600000); accessory.getService(Service.Outlet).getCharacteristic(EveService.Characteristics.TotalConsumption) .on("get", callback => { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); From 23d53138e1ca9761234377b553f548f7dd236bd6 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 12 Sep 2020 15:12:44 +0100 Subject: [PATCH 0122/3183] eve log timer to 5 mins --- lib/eWeLink.js | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 5c70de5f..2ef060cb 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -292,11 +292,6 @@ class eWeLink { if (!this.config.hideTHSwitch) accessory.addService(Service.Switch); accessory.addService(Service.TemperatureSensor); if (device.params.sensorType !== "DS18B20") accessory.addService(Service.HumiditySensor); - accessory.log = this.log; - accessory.eveLogger = new EveHistoryService("weather", accessory, { - storage: "fs", - path: this.eveLogPath - }); break; case "outlet": accessory.addService(Service.Outlet); @@ -314,10 +309,6 @@ class eWeLink { totalEnergyTemp: 0 } }; - accessory.eveLogger = new EveHistoryService("energy", accessory, { - storage: "fs", - path: this.eveLogPath - }); break; case "usb": accessory.addService(Service.Outlet); @@ -482,6 +473,7 @@ class eWeLink { accessory.log = this.log; accessory.eveLogger = new EveHistoryService("weather", accessory, { storage: "fs", + minutes: 5, path: this.eveLogPath }); corrInterval.setCorrectingInterval(() => { @@ -493,7 +485,7 @@ class eWeLink { dataToAdd.humidity = accessory.getService(Service.HumiditySensor).getCharacteristic(Characteristic.CurrentRelativeHumidity).value; } accessory.eveLogger.addEntry(dataToAdd); - }, 600000); + }, 300000); break; case "outlet": accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) @@ -501,6 +493,7 @@ class eWeLink { accessory.log = this.log; accessory.eveLogger = new EveHistoryService("energy", accessory, { storage: "fs", + minutes: 5, path: this.eveLogPath }); corrInterval.setCorrectingInterval(() => { @@ -531,7 +524,7 @@ class eWeLink { time: Date.now(), power: currentWatt }); - }, 600000); + }, 300000); accessory.getService(Service.Outlet).getCharacteristic(EveService.Characteristics.TotalConsumption) .on("get", callback => { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); From 9e6f378e862de843871666419b1c03468d46aac5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 12 Sep 2020 15:30:39 +0100 Subject: [PATCH 0123/3183] eve logging directory --- lib/eWeLink.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 2ef060cb..4a1676ae 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -25,7 +25,7 @@ class eWeLink { this.devicesInEwe = new Map(); this.cusG = new Map(); this.cusS = new Map(); - this.eveLogPath = this.api.user.storagePath() + "/persist/"; + this.eveLogPath = this.api.user.storagePath() + "/homebridge-ewelink/"; this.api .on("didFinishLaunching", () => { this.log("Plugin has finished initialising. Starting synchronisation with eWeLink account."); From 82bf6886274a2e8c80c599582614e2ccbcd50875 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 12 Sep 2020 15:31:12 +0100 Subject: [PATCH 0124/3183] 2.26.0-3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9f86cb85..3075e4c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.26.0-2", + "version": "2.26.0-3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 92c69284..a27267fd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.26.0-2", + "version": "2.26.0-3", "author": "bwp91", "contributors": [ "gbro115", From a9c91778cf0d029a007f32bb31bc6c3280d449d9 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sat, 12 Sep 2020 17:01:46 +0100 Subject: [PATCH 0125/3183] Create dependabot.yml --- .github/dependabot.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..8abca405 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "npm" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "daily" From 7e867251c0386c30b22176102263c32c5356f811 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 12 Sep 2020 18:51:57 +0100 Subject: [PATCH 0126/3183] typos --- lib/eWeLink.js | 7 ++++--- lib/eWeLinkHTTP.js | 6 +++--- lib/eWeLinkLAN.js | 10 +++++----- lib/eWeLinkWS.js | 8 ++++---- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 4a1676ae..27fa8ad0 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -13,14 +13,15 @@ class eWeLink { constructor(log, config, api) { if (!log || !api || !config) return; if (!config.username || !config.password || !config.countryCode) { - log.error("************** Cannot load homebridge-ewelink **************"); - log.error("Your eWeLink credentials missing from the Homebridge config."); - log.error("************************************************************"); + log.error("**************** Cannot load homebridge-ewelink ****************"); + log.error("Your eWeLink credentials are missing from the Homebridge config."); + log.error("****************************************************************"); return; } this.log = log; this.config = config; this.api = api; + this.debug = this.config.debug || false; this.devicesInHB = new Map(); this.devicesInEwe = new Map(); this.cusG = new Map(); diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 4756c48b..6df6fbb9 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -1,8 +1,8 @@ /* jshint esversion: 9, -W030, node: true */ "use strict"; -const axios = require("axios"); -const constants = require("./constants"); -const crypto = require("crypto"); +const axios = require("axios"), + constants = require("./constants"), + crypto = require("crypto"); module.exports = class eWeLinkHTTP { constructor(config, log) { this.config = config; diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index f43869b7..f6ff9188 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -1,10 +1,10 @@ /* jshint esversion: 9, -W030, node: true */ "use strict"; -const axios = require("axios"); -const constants = require("./constants"); -const crypto = require("crypto"); -const dns = require("node-dns-sd"); -const eventemitter = require("events"); +const axios = require("axios"), + constants = require("./constants"), + crypto = require("crypto"), + dns = require("node-dns-sd"), + eventemitter = require("events"); module.exports = class eWeLinkLAN { constructor(config, log, devices) { this.config = config; diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index a44b1431..9cb70c1c 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -1,9 +1,9 @@ /* jshint esversion: 9, -W030, node: true */ "use strict"; -const axios = require("axios"); -const constants = require("./constants"); -const eventemitter = require("events"); -const ws = require("ws"); +const axios = require("axios"), + constants = require("./constants"), + eventemitter = require("events"), + ws = require("ws"); module.exports = class eWeLinkWS { constructor(config, log, res) { this.config = config; From aaa15f6451a891a6ab263eca800ab75f3a640394 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sun, 13 Sep 2020 10:23:09 +0100 Subject: [PATCH 0127/3183] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cbd907d0..6db17853 100644 --- a/README.md +++ b/README.md @@ -24,10 +24,11 @@ * [Supported Devices](https://github.com/bwp91/homebridge-ewelink/wiki/Supported-Devices) * [Connection Methods](https://github.com/bwp91/homebridge-ewelink/wiki/Connection-Methods) ### How-to Guides -* [How to copy Homebridge logs](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-copy-Homebridge-logs) -* [How to enable/disable plugin extended logging](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-enable-disable-plugin-extended-logging) * [How to set up RF Bridge sensors](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-RF-Bridge-sensors) * [How to set up Sonoff Camera (GK-200MP2-B)](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-Sonoff-Camera) +* [How to copy Homebridge logs](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-copy-Homebridge-logs) +* [How to enable/disable plugin extended logging](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-enable-disable-plugin-extended-logging) +* [How to remove an accessory from the cache](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-remove-an-accessory-from-the-cache) ### About * [Support Request](https://github.com/bwp91/homebridge-ewelink/issues) * [Roadmap](https://github.com/bwp91/homebridge-ewelink/wiki/Roadmap) From 6256c4c9c2eb59db88afaa47a3a7debd6d5a289a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 13 Sep 2020 10:34:32 +0100 Subject: [PATCH 0128/3183] log check and outlet fix --- lib/eWeLink.js | 49 ++++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 27fa8ad0..2c596ad9 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -90,7 +90,7 @@ class eWeLink { this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); this.log("eWeLink setup complete. If you're enjoying this package please consider a ⭐ī¸ on GitHub :)."); - if (this.config.debugReqRes) { + if (this.config.debugReqRes || false) { this.log.warn("You have 'Request & Response Logging' enabled. This setting is not recommended for long-term use."); } })(); @@ -497,6 +497,17 @@ class eWeLink { minutes: 5, path: this.eveLogPath }); + if (!accessory.context.hasOwnProperty("lastReset")) { + accessory.context = { + ...accessory.context, + ...{ + extraPersistedData: {}, + lastReset: 0, + totalEnergy: 0, + totalEnergyTemp: 0 + } + }; + } corrInterval.setCorrectingInterval(() => { let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value, currentWatt = isOn ? accessory.getService(Service.Outlet) @@ -740,7 +751,7 @@ class eWeLink { this.lanClient.sendUpdate(payload) .then(() => callback()) .catch(err => { - if (this.config.debug) { + if (this.debug) { this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); } sendViaWS(); @@ -786,7 +797,7 @@ class eWeLink { accessory.context.reachableLAN = true; this.log("[%s] has been reported [online] via [LAN].", accessory.displayName); } - if (this.config.debug) { + if (this.debug) { this.log("[%s] externally updated from above %s message and will be refreshed.", accessory.displayName, device.params.updateSource); } if (!this.refreshAccessory(accessory, device.params)) { @@ -1029,7 +1040,7 @@ class eWeLink { params.switches[1].switch = (newPower === 1 && newSpeed >= 33) ? "on" : "off"; params.switches[2].switch = (newPower === 1 && newSpeed >= 66 && newSpeed < 99) ? "on" : "off"; params.switches[3].switch = (newPower === 1 && newSpeed >= 99) ? "on" : "off"; - if (this.config.debug) { + if (this.debug) { this.log.warn("Fan Update - setting " + type + " to " + value); this.log("[%s] new stats: power [%s], speed [%s%], light [%s].", accessory.displayName, newPower, newSpeed, newLight); } @@ -1049,7 +1060,7 @@ class eWeLink { switch: value ? "on" : "off", mainSwitch: value ? "on" : "off" }; - if (this.config.debug) { + if (this.debug) { this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); @@ -1068,7 +1079,7 @@ class eWeLink { let params = { switch: value ? "on" : "off" }; - if (this.config.debug) { + if (this.debug) { this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); } accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); @@ -1086,7 +1097,7 @@ class eWeLink { switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches }; params.switches[0].switch = value ? "on" : "off"; - if (this.config.debug) { + if (this.debug) { this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); } accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); @@ -1104,7 +1115,7 @@ class eWeLink { switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches }; params.switches[0].switch = value ? "on" : "off"; - if (this.config.debug) { + if (this.debug) { this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); } accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); @@ -1126,7 +1137,7 @@ class eWeLink { } else { params.switch = value ? "on" : "off"; } - if (this.config.debug) { + if (this.debug) { this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); @@ -1137,7 +1148,7 @@ class eWeLink { params.switches[1].switch = value ? "on" : "off"; params.switches[2].switch = value ? "on" : "off"; params.switches[3].switch = value ? "on" : "off"; - if (this.config.debug) { + if (this.debug) { this.log("[%s] updating to turn group [%s].", accessory.displayName, value ? "on" : "off"); } accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); @@ -1152,7 +1163,7 @@ class eWeLink { case "2": case "3": case "4": - if (this.config.debug) { + if (this.debug) { this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); @@ -1210,7 +1221,7 @@ class eWeLink { } accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, value); } - if (this.config.debug) { + if (this.debug) { this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); } setTimeout(() => this.sendDeviceUpdate(accessory, params, callback), 250); @@ -1255,7 +1266,7 @@ class eWeLink { default: throw "unknown device UIID"; } - if (this.config.debug) { + if (this.debug) { this.log("[%s] updating hue to [%s°].", accessory.displayName, value); } accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Hue, value); @@ -1281,7 +1292,7 @@ class eWeLink { }; break; } - if (this.config.debug) { + if (this.debug) { this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); } accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, value); @@ -1305,7 +1316,7 @@ class eWeLink { switch (accessory.context.switchNumber) { case "X": params.switch = value ? "on" : "off"; - if (this.config.debug) { + if (this.debug) { this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); @@ -1316,7 +1327,7 @@ class eWeLink { params.switches[1].switch = value ? "on" : "off"; params.switches[2].switch = value ? "on" : "off"; params.switches[3].switch = value ? "on" : "off"; - if (this.config.debug) { + if (this.debug) { this.log("[%s] updating to turn group [%s].", accessory.displayName, value ? "on" : "off"); } accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); @@ -1331,7 +1342,7 @@ class eWeLink { case "2": case "3": case "4": - if (this.config.debug) { + if (this.debug) { this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); @@ -1373,7 +1384,7 @@ class eWeLink { cmd: "transmit", rfChl }; - if (this.config.debug) { + if (this.debug) { this.log("[%s %s] mimicking RF button press.", accessory.displayName, accessory.context.rfChls[rfChl]); } accessory.getService(accessory.context.rfChls[rfChl]).updateCharacteristic(Characteristic.On, true); @@ -1822,7 +1833,7 @@ class eWeLink { }, (this.config.sensorTimeLength || 2) * 1000); break; } - if (this.config.debug) { + if (this.debug) { this.log("[%s] has detected [%s].", oAccessory.displayName, oAccessory.context.sensorType); } } From 6404f83cf4b91c9fcc22e0200a352ef8fc571ee6 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 13 Sep 2020 11:08:22 +0100 Subject: [PATCH 0129/3183] 2.26.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3075e4c5..cdf0592f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.26.0-3", + "version": "2.26.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a27267fd..638621b7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.26.0-3", + "version": "2.26.0", "author": "bwp91", "contributors": [ "gbro115", From c76cf88d0b4d5d824f6049b6614d47a8f4929b1c Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sun, 13 Sep 2020 11:13:53 +0100 Subject: [PATCH 0130/3183] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6db17853..0225eb9e 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,6 @@ * [How to enable/disable plugin extended logging](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-enable-disable-plugin-extended-logging) * [How to remove an accessory from the cache](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-remove-an-accessory-from-the-cache) ### About -* [Support Request](https://github.com/bwp91/homebridge-ewelink/issues) +* [Support Request](https://github.com/bwp91/homebridge-ewelink/issues/new/choose) * [Roadmap](https://github.com/bwp91/homebridge-ewelink/wiki/Roadmap) * [Credits](https://github.com/bwp91/homebridge-ewelink/wiki/Credits) From 808d5c46ae207b90b1835822eab9fd81b627c08f Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 14 Sep 2020 16:29:24 +0100 Subject: [PATCH 0131/3183] Create config.yml --- .github/ISSUE_TEMPLATE/config.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..d4cc064a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Test + url: https://github.community/ + about: Please ask and answer questions here. From 0f50118d443dcd169d85a12cd8aebfe2e4fd6a83 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 14 Sep 2020 16:33:10 +0100 Subject: [PATCH 0132/3183] Update config.yml --- .github/ISSUE_TEMPLATE/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index d4cc064a..2194a932 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: false contact_links: - - name: Test - url: https://github.community/ - about: Please ask and answer questions here. + - name: Homebridge Discord + url: https://discord.gg/Z8jmyvb + about: Chat to me on Discord - my username is bwp91. From 5cb0d109cfbfe74aa09f0f8beecb14ade83f6f18 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 14 Sep 2020 16:35:17 +0100 Subject: [PATCH 0133/3183] Create feedback.md --- .github/ISSUE_TEMPLATE/feedback.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/feedback.md diff --git a/.github/ISSUE_TEMPLATE/feedback.md b/.github/ISSUE_TEMPLATE/feedback.md new file mode 100644 index 00000000..31941559 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feedback.md @@ -0,0 +1,9 @@ +--- +name: Feedback +about: Give feedback that I might have asked for. +title: '' +labels: '' +assignees: '' + +--- + From 1a047f21232fddbb5ee217e9e2f48e1e3dd1e940 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 14 Sep 2020 16:35:51 +0100 Subject: [PATCH 0134/3183] Update feature-request.md --- .github/ISSUE_TEMPLATE/feature-request.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md index 47b2c95b..5ba9ddfc 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -1,6 +1,6 @@ --- name: Feature Request -about: I have an idea for the package! +about: I have an idea for the package or have a device that isn't supported. title: '' labels: '' assignees: '' From e2fb269c652a0910cdc374a0095300948155bb9d Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 14 Sep 2020 16:36:21 +0100 Subject: [PATCH 0135/3183] Update new-issue.md --- .github/ISSUE_TEMPLATE/new-issue.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/new-issue.md b/.github/ISSUE_TEMPLATE/new-issue.md index 32cfb7df..fb970abc 100644 --- a/.github/ISSUE_TEMPLATE/new-issue.md +++ b/.github/ISSUE_TEMPLATE/new-issue.md @@ -1,6 +1,6 @@ --- name: New Issue -about: I have a problem with the package! +about: I have a problem with the package or it's showing an error. title: '' labels: '' assignees: '' From 0bcba58c6713ac14bee6d6ed6acfe30beabb5228 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 14 Sep 2020 20:24:59 +0100 Subject: [PATCH 0136/3183] zb motion sensor bug --- lib/constants.js | 4 ++-- lib/eWeLink.js | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/constants.js b/lib/constants.js index 0a53039b..34ce9a38 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -30,14 +30,14 @@ module.exports = { devicesRFBridge: [28], devicesRFBridgeParams: ["cmd"], devicesZBBridge: [66], - devicesZBBridgeParams: ["key", "temperature", "humidity", "motion", "lock"], + devicesZBBridgeParams: ["key", "temperature", "humidity", "motion", "lock", "trigTime"], devicesZB: [1000, 1770, 2026, 3026], devicesValveParams: ["switches"], devicesBlindParams: ["switch", "switches"], devicesGarageParams: ["switch", "switches"], devicesLockParams: ["switch"], allowedGroups: ["blind", "garage", "lock"], - paramsToKeep: ["bright", "brightness", "channel", "cmd", "colorB", "colorG", "colorR", "current", "currentHumidity", "currentTemperature", "fan", "humidity", "key", "light", "lock", "mainSwitch", "mode", "online", "power", "rfChl", "rfList", "rfTrig", "sensorType", "speed", "state", "switch", "switches", "temperature", "type", "voltage", "zyx_mode"], + paramsToKeep: ["bright", "brightness", "channel", "cmd", "colorB", "colorG", "colorR", "current", "currentHumidity", "currentTemperature", "fan", "humidity", "key", "light", "lock", "mainSwitch", "mode", "motion", "online", "power", "rfChl", "rfList", "rfTrig", "sensorType", "speed", "state", "switch", "switches", "temperature", "trigTime", "type", "voltage", "zyx_mode"], chansFromUiid: { 1: 1, // "SOCKET" \\ 20, MINI, BASIC, S26 2: 2, // "SOCKET_2" \\ diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 2c596ad9..ec37aeca 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1863,8 +1863,16 @@ class eWeLink { } break; case 2026: - if (params.hasOwnProperty("motion") && [0, 1].includes(params.lock)) { - accessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, params.motion); + if (params.hasOwnProperty("motion") && params.motion === 1 && params.hasOwnProperty("trigTime")) { + let timeNow = new Date(), + timeDifference = (timeNow.getTime() - params.trigTime) / 1000; + if (timeDifference < (this.config.sensorTimeDifference || 120)) { + accessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, 1); + setTimeout(() => { + accessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, 0); + }, (this.config.sensorTimeLength || 2) * 1000); + } + break; } break; case 3026: From ae1aacb589e8d3ba6c57c15bfcec15c1a05b9c92 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 14 Sep 2020 20:26:32 +0100 Subject: [PATCH 0137/3183] 2.26.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index cdf0592f..81baac0a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.26.0", + "version": "2.26.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 638621b7..a572eac9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.26.0", + "version": "2.26.1", "author": "bwp91", "contributors": [ "gbro115", From 5d15ea647689a825927d5386d4353ca3dadc5b02 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 14 Sep 2020 23:17:13 +0100 Subject: [PATCH 0138/3183] implement sliders --- config.schema.json | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/config.schema.json b/config.schema.json index 4175f7cb..b3ce4afe 100644 --- a/config.schema.json +++ b/config.schema.json @@ -56,22 +56,25 @@ "type":"integer", "title":"Sensor Length", "description":"The number of seconds which the sensor tile in the Home app will light up for if a sensor detects something.", - "default":"2", - "maximum":999 + "default":60, + "minimum":1, + "maximum":120 }, "sensorTimeDifference":{ "type":"integer", "title":"Sensor Lag", "description":"An offset in seconds to ignore any notifications if they is a delay between a sensor detecting something and Homebridge receiving the notification.", - "default":"120", - "maximum":999 + "default":120, + "minimum":10, + "maximum":300 }, "valveTimeLength":{ "type":"integer", "title":"Valve Duration", "description":"The default number of seconds that irrigation valves will run for.", - "default":"20", - "maximum":999 + "default":20, + "minimum": 10, + "maximum":1800 }, "hideTHSwitch":{ "title":"Hide TH10/TH16 Switch", @@ -147,7 +150,9 @@ "type":"number", "title":"Operation Time", "description":"For blinds and garage doors this is the total time in deciseconds to fully open/close the device. For locks this is the time to show the Home app tile as unlocked. Count the time in seconds and multiply by 10, for example 100 for 10 seconds or 75 for 7.5 seconds.", - "default":100 + "default":100, + "minimum":10, + "maximum":600 }, "sensorId":{ "type":"string", From bf9d4ca1e7143a4fdf7a10b5f3a07311aeaeb102 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 14 Sep 2020 23:17:40 +0100 Subject: [PATCH 0139/3183] eve for zb temp sensor --- lib/eWeLink.js | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index ec37aeca..50335be5 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -624,6 +624,24 @@ class eWeLink { }); } break; + case "zb_sub": + if (accessory.context.eweUIID === 1770) { + accessory.log = this.log; + accessory.eveLogger = new EveHistoryService("weather", accessory, { + storage: "fs", + minutes: 5, + path: this.eveLogPath + }); + corrInterval.setCorrectingInterval(() => { + let dataToAdd = { + time: Date.now(), + temp: accessory.getService(Service.TemperatureSensor).getCharacteristic(Characteristic.CurrentTemperature).value, + humidity: accessory.getService(Service.HumiditySensor).getCharacteristic(Characteristic.CurrentRelativeHumidity).value + }; + accessory.eveLogger.addEntry(dataToAdd); + }, 300000); + } + break; } this.devicesInHB.set(accessory.context.hbDeviceId, accessory); } catch (err) { @@ -1598,21 +1616,22 @@ class eWeLink { let newState = params.hasOwnProperty("switch") ? params.switch === "on" : params.mainSwitch === "on"; accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, newState); } - let eveLog = false; + let eveLog = { + time: Date.now() + }; if (params.hasOwnProperty("currentTemperature") && accessory.getService(Service.TemperatureSensor)) { let currentTemp = params.currentTemperature !== "unavailable" ? params.currentTemperature : 0; accessory.getService(Service.TemperatureSensor).updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); - eveLog = { - time: Date.now(), - temp: parseFloat(currentTemp) - }; + eveLog.temp = parseFloat(currentTemp); } if (params.hasOwnProperty("currentHumidity") && accessory.getService(Service.HumiditySensor)) { let currentHumi = params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; accessory.getService(Service.HumiditySensor).updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); - eveLog.humidity = currentHumi; + eveLog.humidity = parseFloat(currentHumi); + } + if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { + accessory.eveLogger.addEntry(eveLog); } - if (eveLog) accessory.eveLogger.addEntry(eveLog); } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } @@ -1853,13 +1872,21 @@ class eWeLink { } break; case 1770: + let eveLog = { + time: Date.now() + }; if (params.hasOwnProperty("temperature")) { let currentTemp = parseInt(params.temperature) / 100; accessory.getService(Service.TemperatureSensor).updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); + eveLog.temp = parseFloat(currentTemp); } if (params.hasOwnProperty("humidity")) { let currentHumi = parseInt(params.humidity) / 100; accessory.getService(Service.HumiditySensor).updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); + eveLog.humidity = parseFloat(currentHumi); + } + if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { + accessory.eveLogger.addEntry(eveLog); } break; case 2026: From fe1c23d2933dbbc12fa673a5c7b584a2a0bc2153 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 15 Sep 2020 06:54:51 +0100 Subject: [PATCH 0140/3183] number -> integer --- config.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.schema.json b/config.schema.json index b3ce4afe..664f3935 100644 --- a/config.schema.json +++ b/config.schema.json @@ -147,7 +147,7 @@ ] }, "operationTime":{ - "type":"number", + "type":"integer", "title":"Operation Time", "description":"For blinds and garage doors this is the total time in deciseconds to fully open/close the device. For locks this is the time to show the Home app tile as unlocked. Count the time in seconds and multiply by 10, for example 100 for 10 seconds or 75 for 7.5 seconds.", "default":100, From 0e5c58d86a03c10f61ae8b49603d06f698babca5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 15 Sep 2020 06:56:08 +0100 Subject: [PATCH 0141/3183] 2.26.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 81baac0a..89e609db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.26.1", + "version": "2.26.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a572eac9..5e90fe89 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.26.1", + "version": "2.26.2", "author": "bwp91", "contributors": [ "gbro115", From 05bf298fa9f220694e0d7458cef72d4a1683e1bd Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 15 Sep 2020 08:10:48 +0100 Subject: [PATCH 0142/3183] allow battery parameter --- lib/constants.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/constants.js b/lib/constants.js index 34ce9a38..464ac8ab 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -30,14 +30,14 @@ module.exports = { devicesRFBridge: [28], devicesRFBridgeParams: ["cmd"], devicesZBBridge: [66], - devicesZBBridgeParams: ["key", "temperature", "humidity", "motion", "lock", "trigTime"], + devicesZBBridgeParams: ["key", "temperature", "humidity", "motion", "lock", "trigTime", "battery"], devicesZB: [1000, 1770, 2026, 3026], devicesValveParams: ["switches"], devicesBlindParams: ["switch", "switches"], devicesGarageParams: ["switch", "switches"], devicesLockParams: ["switch"], allowedGroups: ["blind", "garage", "lock"], - paramsToKeep: ["bright", "brightness", "channel", "cmd", "colorB", "colorG", "colorR", "current", "currentHumidity", "currentTemperature", "fan", "humidity", "key", "light", "lock", "mainSwitch", "mode", "motion", "online", "power", "rfChl", "rfList", "rfTrig", "sensorType", "speed", "state", "switch", "switches", "temperature", "trigTime", "type", "voltage", "zyx_mode"], + paramsToKeep: ["battery", "bright", "brightness", "channel", "cmd", "colorB", "colorG", "colorR", "current", "currentHumidity", "currentTemperature", "fan", "humidity", "key", "light", "lock", "mainSwitch", "mode", "motion", "online", "power", "rfChl", "rfList", "rfTrig", "sensorType", "speed", "state", "switch", "switches", "temperature", "trigTime", "type", "voltage", "zyx_mode"], chansFromUiid: { 1: 1, // "SOCKET" \\ 20, MINI, BASIC, S26 2: 2, // "SOCKET_2" \\ From 20340fd2f0be88eef1170c1cdfa0598f131748e6 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 15 Sep 2020 08:12:18 +0100 Subject: [PATCH 0143/3183] battery service for zb devices --- lib/eWeLink.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 50335be5..f4b62df6 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1865,6 +1865,11 @@ class eWeLink { } externalZBDeviceUpdate(accessory, params) { try { //*** credit @tasict ***\\ + if (params.hasOwnProperty("battery")) { + let batteryService = accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); + batteryService.updateCharacteristic(Characteristic.BatteryLevel, params.battery); + batteryService.updateCharacteristic(Characteristic.StatusLowBattery, params.battery <= 25); + } switch (accessory.context.eweUIID) { case 1000: if (params.hasOwnProperty("key") && [0, 1, 2].includes(params.key)) { From c9800aa437deef9613ddf08cccf311849b5b6d96 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 15 Sep 2020 09:47:24 +0100 Subject: [PATCH 0144/3183] clarify device format --- config.schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.schema.json b/config.schema.json index 664f3935..a6d6cd98 100644 --- a/config.schema.json +++ b/config.schema.json @@ -98,7 +98,7 @@ "deviceId":{ "type":"string", "title":"Device ID", - "description":"Device ID from your eWeLink app (ten digits normally in the format 1000******)." + "description":"Device ID from your eWeLink app (ten digits normally in the format 1000ab23cd)." }, "type":{ "type":"string", @@ -157,7 +157,7 @@ "sensorId":{ "type":"string", "title":"Sensor", - "description":"A Sonoff DW2 sensor can optionally be used for blinds and garage doors. This is to determine the current open/closed state of the device. Please enter the 10 digit device ID. Otherwise leave this blank." + "description":"A Sonoff DW2 sensor can optionally be used for blinds and garage doors. This is to determine the current open/closed state of the device. Please enter the 10 digit device ID (normally in the format 1000ab23cd). Otherwise leave this blank." } } } From 80c82f6c07a1c92bbc1b1f832f217ff3fcef6d47 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 15 Sep 2020 10:32:36 +0100 Subject: [PATCH 0145/3183] Update constants.js --- lib/constants.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/constants.js b/lib/constants.js index 464ac8ab..3543d717 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -15,7 +15,7 @@ module.exports = { devicesBrightable: [36, 44], devicesColourable: [22, 59], devicesSensor: [102], - devicesSensorParams: ["switch"], + devicesSensorParams: ["switch", "battery", "type"], devicesThermostat: [15], devicesThermostatParams: ["currentTemperature", "currentHumidity", "switch", "masterSwitch"], devicesFan: [34], From 31754a36a9fcf20eea37be3bf316f010f4055ccb Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 15 Sep 2020 10:33:15 +0100 Subject: [PATCH 0146/3183] DW2 battery --- lib/eWeLink.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index f4b62df6..8dec569e 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -109,6 +109,7 @@ class eWeLink { } initialiseDevice(device) { let accessory; + // if (device.extra.uiid === 102) this.log.warn(device); //*** First add the device if it isn't already in Homebridge. Yeah this code looks a mess :| ***\\ if (!this.devicesInHB.has(device.deviceid + "SWX") && !this.devicesInHB.has(device.deviceid + "SW0")) { if (device.extra.uiid === 2 && device.brandName === "coolkit" && device.productModel === "0285") { @@ -381,6 +382,7 @@ class eWeLink { }); break; case "zb_sub": //*** credit @tasict ***\\ + accessory.addService(Service.BatteryService); switch (device.extra.uiid) { case 1000: accessory.addService(Service.StatelessProgrammableSwitch); @@ -944,7 +946,10 @@ class eWeLink { params = {}, delay = 0; if (sensorDefinition && !(sAccessory = this.devicesInHB.get(garageConfig.sensorId + "SWX"))) { - throw "defined sensor doesn't exist"; + throw "defined DW2 sensor doesn't exist"; + } + if (sAccessory.context.type !== "sensor") { + throw "defined DW2 sensor isn't a sensor"; } oldPos = sAccessory ? sAccessory.getService(Service.ContactSensor).getCharacteristic(Characteristic.ContactSensorState).value === 0 ? 1 : 0 : @@ -1547,6 +1552,11 @@ class eWeLink { let newState = params.switch === "on" ? 1 : 0, oAccessory = false; accessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, newState); + if (params.hasOwnProperty("battery")) { + let batteryService = accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); + batteryService.updateCharacteristic(Characteristic.BatteryLevel, params.battery); + batteryService.updateCharacteristic(Characteristic.StatusLowBattery, params.battery <= 25); + } this.cusG.forEach(group => { if (group.sensorId === accessory.context.eweDeviceId && group.type === "garage") { if ((oAccessory = this.devicesInHB.get(group.deviceId + "SWX"))) { From 81e566d75802c6443bff8a9936949fa4a7efc2d9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 15 Sep 2020 10:48:04 +0100 Subject: [PATCH 0147/3183] appSecret to constants --- lib/constants.js | 3 ++- lib/eWeLinkHTTP.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/constants.js b/lib/constants.js index 3543d717..0751d683 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -1,7 +1,8 @@ /* jshint esversion: 9, -W030, node: true */ "use strict"; module.exports = { - appId: "oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq", + appId: "Uw83EKZFxdif7XFXEsrpduz5YyjP7nTl", // "oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq" + appSecret: "mXLOjea0woSMvK9gw7Fjsy7YlFO4iSu6", // "6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM" devicesHideable: ["switch", "light", "valve"], devicesNonLAN: [22, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 6df6fbb9..0382542b 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -24,7 +24,7 @@ module.exports = class eWeLinkHTTP { } else if (this.debug) { this.log("Sending HTTP login request."); } - let dataToSign = crypto.createHmac("sha256", "6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM").update(JSON.stringify(data)).digest("base64"); + let dataToSign = crypto.createHmac("sha256", constants.appSecret).update(JSON.stringify(data)).digest("base64"); return new Promise((resolve, reject) => { axios({ url: "https://" + this.httpHost + "/v2/user/login", From c9ce9c77993e542394fbc1fca4b5e90b935b4e1b Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Tue, 15 Sep 2020 12:55:11 +0100 Subject: [PATCH 0148/3183] Create stale.yml --- .github/stale.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 00000000..89b61309 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,16 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 7 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 7 +# Issues with these labels will never be considered stale +exemptLabels: +# Label to use when marking an issue as stale +staleLabel: inactive +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as inactive because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: > + This issue has been automatically closed. From 1b6f9c4560a9e10a890c4c55befc8ca9b02a25b4 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Tue, 15 Sep 2020 16:23:53 +0100 Subject: [PATCH 0149/3183] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0225eb9e..60323284 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) [![Discord](https://img.shields.io/discord/432663330281226270?color=728ED5&logo=discord&label=discord)](https://discord.com/channels/432663330281226270/742733745743855627) - [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) + [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) + [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/latest?label=release)](https://www.npmjs.com/package/homebridge-ewelink) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://www.npmjs.com/package/homebridge-ewelink) From bb1be253518800f38ff67aab154e10b45bc928d6 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 15 Sep 2020 16:25:56 +0100 Subject: [PATCH 0150/3183] prettier code --- .prettier.ignore | 5 + .prettierrc.json | 4 + config.schema.json | 558 +++--- index.js | 6 +- lib/constants.js | 316 ++-- lib/eWeLink.js | 4061 +++++++++++++++++++++++--------------------- lib/eWeLinkHTTP.js | 316 ++-- lib/eWeLinkLAN.js | 365 ++-- lib/eWeLinkWS.js | 551 +++--- package-lock.json | 1248 +++++++------- package.json | 135 +- 11 files changed, 3955 insertions(+), 3610 deletions(-) create mode 100644 .prettier.ignore create mode 100644 .prettierrc.json diff --git a/.prettier.ignore b/.prettier.ignore new file mode 100644 index 00000000..45fb205e --- /dev/null +++ b/.prettier.ignore @@ -0,0 +1,5 @@ +.DS_Store +.nova +.github +.npm +node_modules/ \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 00000000..163a0a7e --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,4 @@ +{ + "arrowParens": "avoid", + "printWidth": 120 +} diff --git a/config.schema.json b/config.schema.json index a6d6cd98..ee24e05b 100644 --- a/config.schema.json +++ b/config.schema.json @@ -1,305 +1,269 @@ { - "pluginAlias":"eWeLink", - "pluginType":"platform", - "singular":true, - "headerDisplay":"Homebridge plugin to control eWeLink devices with original firmware.", - "footerDisplay":"For help and support please visit our [GitHub Wiki](https://github.com/bwp91/homebridge-ewelink/wiki).", - "schema":{ - "type":"object", - "properties":{ - "name":{ - "type":"string", - "default":"eWeLink" - }, - "countryCode":{ - "type":"string", - "title":"Country Code", - "description":"The telephone country code linked to your eWeLink account (without the +)." - }, - "username":{ - "type":"string", - "title":"Username", - "description":"The phone number or email address linked to your eWeLink account. If you use a phone number please enter the country code (with the +), for example +8613185260282." - }, - "password":{ - "type":"string", - "title":"Password", - "description":"The password for your eWeLink account." - }, - "debug":{ - "title":"Debug Logging", - "type":"boolean", - "required":true, - "description":"If enabled, more information will be added to the Homebridge log.", - "default":false - }, - "debugReqRes":{ - "title":"Request & Response Logging", - "type":"boolean", - "required":true, - "description":"If enabled, HTTP, web socket and LAN mode messages will be added to the log. Not recommended for long-term use.", - "default":false - }, - "hideDevFromHB":{ - "type":"string", - "title":"Hide Devices", - "description":"A list of eWeLink devices to hide from Homebridge. For example '10009553c8' or multiple devices separated with a comma '10009553c8,10009553c9'.", - "default":"" - }, - "hideFromHB":{ - "type":"string", - "title":"Hide Device Channels", - "description":"A list of device channels to hide from Homebridge. For example '10009553c8SW1' or multiple channels separated with a comma '10009553c8SW1,10009553c9SW2'. Only channels from switches, lights and irrigation valves can be hidden.", - "default":"" - }, - "sensorTimeLength":{ - "type":"integer", - "title":"Sensor Length", - "description":"The number of seconds which the sensor tile in the Home app will light up for if a sensor detects something.", - "default":60, - "minimum":1, - "maximum":120 - }, - "sensorTimeDifference":{ - "type":"integer", - "title":"Sensor Lag", - "description":"An offset in seconds to ignore any notifications if they is a delay between a sensor detecting something and Homebridge receiving the notification.", - "default":120, - "minimum":10, - "maximum":300 - }, - "valveTimeLength":{ - "type":"integer", - "title":"Valve Duration", - "description":"The default number of seconds that irrigation valves will run for.", - "default":20, - "minimum": 10, - "maximum":1800 - }, - "hideTHSwitch":{ - "title":"Hide TH10/TH16 Switch", - "type":"boolean", - "description":"If enabled, the switch for the TH10/TH16 devices will be hidden from Homebridge.", - "default":false - }, - "hideZBLDPress":{ - "title":"Hide Double/Long Press", - "type":"boolean", - "description":"If enabled, double and long press options will be hidden for the ZigBee button.", - "default":false - }, - "groups":{ - "type":"array", - "title":"Custom Device Types", - "description":"You can use this setting to set up custom device types within Homebridge. Currently only blinds, garage doors and locks are supported.", - "items":{ - "type":"object", - "properties":{ - "deviceId":{ - "type":"string", - "title":"Device ID", - "description":"Device ID from your eWeLink app (ten digits normally in the format 1000ab23cd)." - }, - "type":{ - "type":"string", - "title":"Type", - "default":"null", - "description":"The new type for this device.", - "oneOf":[ - { - "title":"Blind", - "enum":[ - "blind" - ] - }, - { - "title":"Garage Door", - "enum":[ - "garage" - ] - }, - { - "title":"Lock", - "enum":[ - "lock" - ] - } - ] - }, - "setup":{ - "type":"string", - "title":"Device Setup", - "default":"null", - "description":"The device setup. Please ignore this setting for locks", - "oneOf":[ - { - "title":"One Switch - for up and down", - "enum":[ - "oneSwitch" - ] - }, - { - "title":"Two Switches - one for up and one for down", - "enum":[ - "twoSwitch" - ] - } - ] - }, - "operationTime":{ - "type":"integer", - "title":"Operation Time", - "description":"For blinds and garage doors this is the total time in deciseconds to fully open/close the device. For locks this is the time to show the Home app tile as unlocked. Count the time in seconds and multiply by 10, for example 100 for 10 seconds or 75 for 7.5 seconds.", - "default":100, - "minimum":10, - "maximum":600 - }, - "sensorId":{ - "type":"string", - "title":"Sensor", - "description":"A Sonoff DW2 sensor can optionally be used for blinds and garage doors. This is to determine the current open/closed state of the device. Please enter the 10 digit device ID (normally in the format 1000ab23cd). Otherwise leave this blank." - } - } - } - }, - "bridgeSensors":{ - "type":"array", - "title":"Sensors", - "description":"You can expose different types of sensors connected to your RF Bridge in HomeKit.", - "items":{ - "type":"object", - "properties":{ - "deviceId":{ - "type":"string", - "title":"RF Bridge Device ID", - "description":"Device ID of your RF Bridge from your eWeLink app (10 digits normally in the format 1000******)." - }, - "fullDeviceId":{ - "type":"string", - "title":"Sensor Device ID", - "description":"Device ID of the sensor from Homebridge (13 digits normally in the format 1000******SW*)." - }, - "type":{ - "type":"string", - "title":"Sensor Type", - "default":"motion", - "description":"Select the type of sensor you would like to expose this as in Homebridge.", - "oneOf":[ - { - "title":"Motion", - "enum":[ - "motion" - ] - }, - { - "title":"Smoke/Fire", - "enum":[ - "smoke" - ] - }, - { - "title":"Water/Leak", - "enum":[ - "water" - ] - }, - { - "title":"Carbon Monoxide", - "enum":[ - "co" - ] - }, - { - "title":"Carbon Dioxide", - "enum":[ - "co2" - ] - }, - { - "title":"Occupancy", - "enum":[ - "occupancy" - ] - }, - { - "title":"Contact", - "enum":[ - "contact" - ] - } - ] - } - } - } - } + "pluginAlias": "eWeLink", + "pluginType": "platform", + "singular": true, + "headerDisplay": "Homebridge plugin to control eWeLink devices with original firmware.", + "footerDisplay": "For help and support please visit our [GitHub Wiki](https://github.com/bwp91/homebridge-ewelink/wiki).", + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "default": "eWeLink" }, - "required":[ - "countryCode", - "username", - "password" - ] - }, - "layout":[ - { - "type":"fieldset", - "items":[ - "countryCode", - "username", - "password" - ] + "countryCode": { + "type": "string", + "title": "Country Code", + "description": "The telephone country code linked to your eWeLink account (without the +)." + }, + "username": { + "type": "string", + "title": "Username", + "description": "The phone number or email address linked to your eWeLink account. If you use a phone number please enter the country code (with the +), for example +8613185260282." + }, + "password": { + "type": "string", + "title": "Password", + "description": "The password for your eWeLink account." + }, + "debug": { + "title": "Debug Logging", + "type": "boolean", + "required": true, + "description": "If enabled, more information will be added to the Homebridge log.", + "default": false + }, + "debugReqRes": { + "title": "Request & Response Logging", + "type": "boolean", + "required": true, + "description": "If enabled, HTTP, web socket and LAN mode messages will be added to the log. Not recommended for long-term use.", + "default": false + }, + "hideDevFromHB": { + "type": "string", + "title": "Hide Devices", + "description": "A list of eWeLink devices to hide from Homebridge. For example '10009553c8' or multiple devices separated with a comma '10009553c8,10009553c9'.", + "default": "" }, - { - "type":"fieldset", - "title":"Optional", - "description":"Only adjust these settings if you know what you are doing.", - "expandable":true, - "items":[ - "debug", - "debugReqRes", - "hideDevFromHB", - "hideFromHB", - "sensorTimeLength", - "sensorTimeDifference", - "valveTimeLength", - "hideTHSwitch", - "hideZBLDPress" - ] + "hideFromHB": { + "type": "string", + "title": "Hide Device Channels", + "description": "A list of device channels to hide from Homebridge. For example '10009553c8SW1' or multiple channels separated with a comma '10009553c8SW1,10009553c9SW2'. Only channels from switches, lights and irrigation valves can be hidden.", + "default": "" }, - { - "key":"groups", - "expandable":true, - "title":"Custom Device Types", - "add":"Add Another Type", - "type":"array", - "items":[ - { - "type":"fieldset", - "items":[ - "groups[].deviceId", - "groups[].type", - "groups[].setup", - "groups[].operationTime", - "groups[].sensorId" - ] + "sensorTimeLength": { + "type": "integer", + "title": "Sensor Length", + "description": "The number of seconds which the sensor tile in the Home app will light up for if a sensor detects something.", + "default": 60, + "minimum": 1, + "maximum": 120 + }, + "sensorTimeDifference": { + "type": "integer", + "title": "Sensor Lag", + "description": "An offset in seconds to ignore any notifications if they is a delay between a sensor detecting something and Homebridge receiving the notification.", + "default": 120, + "minimum": 10, + "maximum": 300 + }, + "valveTimeLength": { + "type": "integer", + "title": "Valve Duration", + "description": "The default number of seconds that irrigation valves will run for.", + "default": 20, + "minimum": 10, + "maximum": 1800 + }, + "hideTHSwitch": { + "title": "Hide TH10/TH16 Switch", + "type": "boolean", + "description": "If enabled, the switch for the TH10/TH16 devices will be hidden from Homebridge.", + "default": false + }, + "hideZBLDPress": { + "title": "Hide Double/Long Press", + "type": "boolean", + "description": "If enabled, double and long press options will be hidden for the ZigBee button.", + "default": false + }, + "groups": { + "type": "array", + "title": "Custom Device Types", + "description": "You can use this setting to set up custom device types within Homebridge. Currently only blinds, garage doors and locks are supported.", + "items": { + "type": "object", + "properties": { + "deviceId": { + "type": "string", + "title": "Device ID", + "description": "Device ID from your eWeLink app (ten digits normally in the format 1000ab23cd)." + }, + "type": { + "type": "string", + "title": "Type", + "default": "null", + "description": "The new type for this device.", + "oneOf": [ + { + "title": "Blind", + "enum": ["blind"] + }, + { + "title": "Garage Door", + "enum": ["garage"] + }, + { + "title": "Lock", + "enum": ["lock"] + } + ] + }, + "setup": { + "type": "string", + "title": "Device Setup", + "default": "null", + "description": "The device setup. Please ignore this setting for locks", + "oneOf": [ + { + "title": "One Switch - for up and down", + "enum": ["oneSwitch"] + }, + { + "title": "Two Switches - one for up and one for down", + "enum": ["twoSwitch"] + } + ] + }, + "operationTime": { + "type": "integer", + "title": "Operation Time", + "description": "For blinds and garage doors this is the total time in deciseconds to fully open/close the device. For locks this is the time to show the Home app tile as unlocked. Count the time in seconds and multiply by 10, for example 100 for 10 seconds or 75 for 7.5 seconds.", + "default": 100, + "minimum": 10, + "maximum": 600 + }, + "sensorId": { + "type": "string", + "title": "Sensor", + "description": "A Sonoff DW2 sensor can optionally be used for blinds and garage doors. This is to determine the current open/closed state of the device. Please enter the 10 digit device ID (normally in the format 1000ab23cd). Otherwise leave this blank." } - ] + } + } }, - { - "key":"bridgeSensors", - "title":"RF Bridge Sensors", - "expandable":true, - "add":"Add Another Sensor", - "type":"array", - "items":[ - { - "type":"fieldset", - "items":[ - "bridgeSensors[].deviceId", - "bridgeSensors[].fullDeviceId", - "bridgeSensors[].type" - ] + "bridgeSensors": { + "type": "array", + "title": "Sensors", + "description": "You can expose different types of sensors connected to your RF Bridge in HomeKit.", + "items": { + "type": "object", + "properties": { + "deviceId": { + "type": "string", + "title": "RF Bridge Device ID", + "description": "Device ID of your RF Bridge from your eWeLink app (10 digits normally in the format 1000******)." + }, + "fullDeviceId": { + "type": "string", + "title": "Sensor Device ID", + "description": "Device ID of the sensor from Homebridge (13 digits normally in the format 1000******SW*)." + }, + "type": { + "type": "string", + "title": "Sensor Type", + "default": "motion", + "description": "Select the type of sensor you would like to expose this as in Homebridge.", + "oneOf": [ + { + "title": "Motion", + "enum": ["motion"] + }, + { + "title": "Smoke/Fire", + "enum": ["smoke"] + }, + { + "title": "Water/Leak", + "enum": ["water"] + }, + { + "title": "Carbon Monoxide", + "enum": ["co"] + }, + { + "title": "Carbon Dioxide", + "enum": ["co2"] + }, + { + "title": "Occupancy", + "enum": ["occupancy"] + }, + { + "title": "Contact", + "enum": ["contact"] + } + ] } - ] + } + } } - ] -} \ No newline at end of file + }, + "required": ["countryCode", "username", "password"] + }, + "layout": [ + { + "type": "fieldset", + "items": ["countryCode", "username", "password"] + }, + { + "type": "fieldset", + "title": "Optional", + "description": "Only adjust these settings if you know what you are doing.", + "expandable": true, + "items": [ + "debug", + "debugReqRes", + "hideDevFromHB", + "hideFromHB", + "sensorTimeLength", + "sensorTimeDifference", + "valveTimeLength", + "hideTHSwitch", + "hideZBLDPress" + ] + }, + { + "key": "groups", + "expandable": true, + "title": "Custom Device Types", + "add": "Add Another Type", + "type": "array", + "items": [ + { + "type": "fieldset", + "items": [ + "groups[].deviceId", + "groups[].type", + "groups[].setup", + "groups[].operationTime", + "groups[].sensorId" + ] + } + ] + }, + { + "key": "bridgeSensors", + "title": "RF Bridge Sensors", + "expandable": true, + "add": "Add Another Sensor", + "type": "array", + "items": [ + { + "type": "fieldset", + "items": ["bridgeSensors[].deviceId", "bridgeSensors[].fullDeviceId", "bridgeSensors[].type"] + } + ] + } + ] +} diff --git a/index.js b/index.js index 4902dd17..d25bb094 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,6 @@ /* jshint esversion: 9, -W030, node: true */ "use strict"; module.exports = function (homebridge) { - const eWeLink = require("./lib/eWeLink.js")(homebridge); - homebridge.registerPlatform("homebridge-ewelink", "eWeLink", eWeLink, true); -}; \ No newline at end of file + const eWeLink = require("./lib/eWeLink.js")(homebridge); + homebridge.registerPlatform("homebridge-ewelink", "eWeLink", eWeLink, true); +}; diff --git a/lib/constants.js b/lib/constants.js index 0751d683..c8a8f17f 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -1,138 +1,184 @@ /* jshint esversion: 9, -W030, node: true */ "use strict"; module.exports = { - appId: "Uw83EKZFxdif7XFXEsrpduz5YyjP7nTl", // "oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq" - appSecret: "mXLOjea0woSMvK9gw7Fjsy7YlFO4iSu6", // "6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM" - devicesHideable: ["switch", "light", "valve"], - devicesNonLAN: [22, 59, 102], - devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], - devicesSingleSwitchParams: ["switch"], - devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], - devicesMultiSwitchParams: ["switches"], - devicesSingleSwitchLight: ["T1 1C", "L1", "B1", "B1_R2", "TX1C", "D1", "D1R1", "KING-M4", "Slampher", "GTTA59"], - devicesSingleSwitchLightParams: ["switch", "state", "bright", "colorR", "brightness", "channel0", "channel2", "xyz_mode"], - devicesMultiSwitchLight: ["T1 2C", "T1 3C", "TX2C", "TX3C"], - devicesMultiSwitchLightParams: ["switches"], - devicesBrightable: [36, 44], - devicesColourable: [22, 59], - devicesSensor: [102], - devicesSensorParams: ["switch", "battery", "type"], - devicesThermostat: [15], - devicesThermostatParams: ["currentTemperature", "currentHumidity", "switch", "masterSwitch"], - devicesFan: [34], - devicesFanParams: ["switches", "light", "fan", "speed"], - devicesOutlet: [32], - devicesOutletParams: ["switch", "power", "voltage", "current"], - devicesCamera: [87], - devicesUSB: [77], - devicesUSBParams: ["switches"], - devicesSCM: [78], - devicesSCMParams: ["switches"], - devicesRFBridge: [28], - devicesRFBridgeParams: ["cmd"], - devicesZBBridge: [66], - devicesZBBridgeParams: ["key", "temperature", "humidity", "motion", "lock", "trigTime", "battery"], - devicesZB: [1000, 1770, 2026, 3026], - devicesValveParams: ["switches"], - devicesBlindParams: ["switch", "switches"], - devicesGarageParams: ["switch", "switches"], - devicesLockParams: ["switch"], - allowedGroups: ["blind", "garage", "lock"], - paramsToKeep: ["battery", "bright", "brightness", "channel", "cmd", "colorB", "colorG", "colorR", "current", "currentHumidity", "currentTemperature", "fan", "humidity", "key", "light", "lock", "mainSwitch", "mode", "motion", "online", "power", "rfChl", "rfList", "rfTrig", "sensorType", "speed", "state", "switch", "switches", "temperature", "trigTime", "type", "voltage", "zyx_mode"], - chansFromUiid: { - 1: 1, // "SOCKET" \\ 20, MINI, BASIC, S26 - 2: 2, // "SOCKET_2" \\ - 3: 3, // "SOCKET_3" \\ - 4: 4, // "SOCKET_4", \\ - 5: 1, // "SOCKET_POWER" \\ - 6: 1, // "SWITCH" \\ T1 1C, TX1C - 7: 2, // "SWITCH_2" \\ T1 2C, TX2C - 8: 3, // "SWITCH_3" \\ T1 3C, TX3C - 9: 4, // "SWITCH_4" \\ - 10: 0, // "OSPF" \\ - 11: 0, // "CURTAIN" \\ King Q4 Cover - 12: 0, // "EW-RE" \\ - 13: 0, // "FIREPLACE" \\ - 14: 1, // "SWITCH_CHANGE" \\ - 15: 1, // "THERMOSTAT" \\ TH10, TH16 - 16: 0, // "COLD_WARM_LED" \\ - 17: 0, // "THREE_GEAR_FAN" \\ - 18: 0, // "SENSORS_CENTER" \\ - 19: 0, // "HUMIDIFIER" \\ - 22: 1, // "RGB_BALL_LIGHT" \\ B1, B1_R2 - 23: 0, // "NEST_THERMOSTAT" \\ - 24: 1, // "GSM_SOCKET" \\ - 25: 0, // "AROMATHERAPY", \\ Diffuser - 26: 0, // "RuiMiTeWenKongQi" \\ - 27: 1, // "GSM_UNLIMIT_SOCKET" \\ - 28: 1, // "RF_BRIDGE" \\ RFBridge, RF_Bridge - 29: 2, // "GSM_SOCKET_2" \\ - 30: 3, // "GSM_SOCKET_3" \\ - 31: 4, // "GSM_SOCKET_4" \\ - 32: 1, // "POWER_DETECTION_SOCKET" \\ Pow_R2 POW - 33: 0, // "LIGHT_BELT", \\ - 34: 4, // "FAN_LIGHT" \\ iFan02, iFan - 35: 0, // "EZVIZ_CAMERA", \\ - 36: 1, // "SINGLE_CHANNEL_DIMMER_SWITCH" \\ KING-M4 - 38: 0, // "HOME_KIT_BRIDGE", \\ - 40: 0, // "FUJIN_OPS" \\ - 41: 4, // "CUN_YOU_DOOR" \\ - 42: 0, // "SMART_BEDSIDE_AND_NEW_RGB_BALL_LIGHT" \\ - 43: 0, // "?" \\ - 44: 1, // "SNOFF_LIGHT" \\ D1 - 45: 0, // "DOWN_CEILING_LIGHT" \\ - 46: 0, // "AIR_CLEANER" \\ - 49: 0, // "MACHINE_BED" \\ - 51: 0, // "COLD_WARM_DESK_LIGHT" \\ - 52: 0, // "DOUBLE_COLOR_DEMO_LIGHT" \\ - 53: 0, // "ELECTRIC_FAN_WITH_LAMP" \\ - 55: 0, // "SWEEPING_ROBOT" \\ - 56: 0, // "RGB_BALL_LIGHT_4" \\ - 57: 0, // "MONOCHROMATIC_BALL_LIGHT" \\ - 59: 1, // "MUSIC_LIGHT_BELT" \\ L1 - 60: 0, // "NEW_HUMIDIFIER" \\ - 61: 0, // "KAI_WEI_ROUTER" \\ - 62: 0, // "MEARICAMERA" \\ - 64: 0, // "HeatingTable" \\ - 65: 0, // "CustomCamera" \\ - 66: 0, // "ZIGBEE_MAIN_DEVICE" \\ - 67: 0, // "RollingDoor" \\ - 68: 0, // "KOOCHUWAH" \\ - 69: 0, // "ATMOSPHERE_LAMP" \\ - 76: 0, // "YI_GE_ER_LAMP" \\ - 77: 4, // "SINGLE_SOCKET_MULTIPLE" \\ (1 socket device using data structure of four :() - 78: 4, // "SINGLE_SWITCH_MULTIPLE" \\ (1 switch device using data structure of four :() - 79: 0, // "CHRISTMAS_LIGHT" \\ - 80: 0, // "HANYUAN_AIR_CONDITION" \\ - 81: 1, // "GSM_SOCKET_NO_FLOW" \\ - 82: 2, // "GSM_SOCKET_2_NO_FLOW" \\ - 83: 3, // "GSM_SOCKET_3_NO_FLOW" \\ - 84: 4, // "GSM_SOCKET_4_NO_FLOW" \\ - 86: 0, // "CLEAR_BOOT" \\ - 87: 0, // "EWELINK_IOT_CAMERA" \\ GK-200MP2B - 88: 0, // "YK_INFRARED" \\ - 89: 0, // "SMART_OPEN_MACHINE" \\ - 90: 0, // "GSM_RFBridge" \\ - 91: 0, // "ROLLING_DOOR_91" \\ - 93: 0, // "HTHD_AIR_CLEANER" \\ - 94: 0, // "YIAN_ELECTRIC_PROTECT" \\ - 98: 0, // "DOORBELL_RFBRIDGE" \\ - 102: 1, // "DOOR_MAGNETIC" \\ OPL-DMA, DW2 - 103: 0, // "WOTEWODE_TEM_LIGHT" \\ - 104: 0, // "WOTEWODE_RGB_TEM_LIGHT" \\ - 107: 0, // "GSM_SOCKET_NO_FLOW" \\ - 109: 0, // "YK_INFRARED_2" \\ - 1000: 1, // "ZIGBEE_WIRELESS_SWITCH" \\ - 1001: 0, // "BLADELESS_FAN" \\ - 1002: 0, // "NEW_HUMIDIFIER" \\ - 1003: 0, // "WARM_AIR_BLOWER" \\ - 1256: 1, // "ZIGBEE_SINGLE_SWITCH" \\ - 1770: 1, // "ZIGBEE_TEMPERATURE_SENSOR" \\ - 2026: 1, // "ZIGBEE_MOBILE_SENSOR" \\ - 2256: 2, // "ZIGBEE_SWITCH_2" \\ - 3026: 1, // "ZIGBEE_DOOR_AND_WINDOW_SENSOR" \\ - 3256: 3, // "ZIGBEE_SWITCH_3" \\ - 4026: 1, // "ZIGBEE_WATER_SENSOR" \\ - 4256: 4, // "ZIGBEE_SWITCH_4" \\ - } -}; \ No newline at end of file + // appId: "Uw83EKZFxdif7XFXEsrpduz5YyjP7nTl", + appId: "oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq", + // appSecret: "mXLOjea0woSMvK9gw7Fjsy7YlFO4iSu6", + appSecret: "6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM", + devicesHideable: ["switch", "light", "valve"], + devicesNonLAN: [22, 59, 102], + devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], + devicesSingleSwitchParams: ["switch"], + devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], + devicesMultiSwitchParams: ["switches"], + devicesSingleSwitchLight: ["T1 1C", "L1", "B1", "B1_R2", "TX1C", "D1", "D1R1", "KING-M4", "Slampher", "GTTA59"], + devicesSingleSwitchLightParams: [ + "switch", + "state", + "bright", + "colorR", + "brightness", + "channel0", + "channel2", + "xyz_mode", + ], + devicesMultiSwitchLight: ["T1 2C", "T1 3C", "TX2C", "TX3C"], + devicesMultiSwitchLightParams: ["switches"], + devicesBrightable: [36, 44], + devicesColourable: [22, 59], + devicesSensor: [102], + devicesSensorParams: ["switch", "battery", "type"], + devicesThermostat: [15], + devicesThermostatParams: ["currentTemperature", "currentHumidity", "switch", "masterSwitch"], + devicesFan: [34], + devicesFanParams: ["switches", "light", "fan", "speed"], + devicesOutlet: [32], + devicesOutletParams: ["switch", "power", "voltage", "current"], + devicesCamera: [87], + devicesUSB: [77], + devicesUSBParams: ["switches"], + devicesSCM: [78], + devicesSCMParams: ["switches"], + devicesRFBridge: [28], + devicesRFBridgeParams: ["cmd"], + devicesZBBridge: [66], + devicesZBBridgeParams: ["key", "temperature", "humidity", "motion", "lock", "trigTime", "battery"], + devicesZB: [1000, 1770, 2026, 3026], + devicesValveParams: ["switches"], + devicesBlindParams: ["switch", "switches"], + devicesGarageParams: ["switch", "switches"], + devicesLockParams: ["switch"], + allowedGroups: ["blind", "garage", "lock"], + paramsToKeep: [ + "battery", + "bright", + "brightness", + "channel", + "cmd", + "colorB", + "colorG", + "colorR", + "current", + "currentHumidity", + "currentTemperature", + "fan", + "humidity", + "key", + "light", + "lock", + "mainSwitch", + "mode", + "motion", + "online", + "power", + "rfChl", + "rfList", + "rfTrig", + "sensorType", + "speed", + "state", + "switch", + "switches", + "temperature", + "trigTime", + "type", + "voltage", + "zyx_mode", + ], + chansFromUiid: { + 1: 1, // "SOCKET" \\ 20, MINI, BASIC, S26 + 2: 2, // "SOCKET_2" \\ + 3: 3, // "SOCKET_3" \\ + 4: 4, // "SOCKET_4", \\ + 5: 1, // "SOCKET_POWER" \\ + 6: 1, // "SWITCH" \\ T1 1C, TX1C + 7: 2, // "SWITCH_2" \\ T1 2C, TX2C + 8: 3, // "SWITCH_3" \\ T1 3C, TX3C + 9: 4, // "SWITCH_4" \\ + 10: 0, // "OSPF" \\ + 11: 0, // "CURTAIN" \\ King Q4 Cover + 12: 0, // "EW-RE" \\ + 13: 0, // "FIREPLACE" \\ + 14: 1, // "SWITCH_CHANGE" \\ + 15: 1, // "THERMOSTAT" \\ TH10, TH16 + 16: 0, // "COLD_WARM_LED" \\ + 17: 0, // "THREE_GEAR_FAN" \\ + 18: 0, // "SENSORS_CENTER" \\ + 19: 0, // "HUMIDIFIER" \\ + 22: 1, // "RGB_BALL_LIGHT" \\ B1, B1_R2 + 23: 0, // "NEST_THERMOSTAT" \\ + 24: 1, // "GSM_SOCKET" \\ + 25: 0, // "AROMATHERAPY", \\ Diffuser + 26: 0, // "RuiMiTeWenKongQi" \\ + 27: 1, // "GSM_UNLIMIT_SOCKET" \\ + 28: 1, // "RF_BRIDGE" \\ RFBridge, RF_Bridge + 29: 2, // "GSM_SOCKET_2" \\ + 30: 3, // "GSM_SOCKET_3" \\ + 31: 4, // "GSM_SOCKET_4" \\ + 32: 1, // "POWER_DETECTION_SOCKET" \\ Pow_R2 POW + 33: 0, // "LIGHT_BELT", \\ + 34: 4, // "FAN_LIGHT" \\ iFan02, iFan + 35: 0, // "EZVIZ_CAMERA", \\ + 36: 1, // "SINGLE_CHANNEL_DIMMER_SWITCH" \\ KING-M4 + 38: 0, // "HOME_KIT_BRIDGE", \\ + 40: 0, // "FUJIN_OPS" \\ + 41: 4, // "CUN_YOU_DOOR" \\ + 42: 0, // "SMART_BEDSIDE_AND_NEW_RGB_BALL_LIGHT" \\ + 43: 0, // "?" \\ + 44: 1, // "SNOFF_LIGHT" \\ D1 + 45: 0, // "DOWN_CEILING_LIGHT" \\ + 46: 0, // "AIR_CLEANER" \\ + 49: 0, // "MACHINE_BED" \\ + 51: 0, // "COLD_WARM_DESK_LIGHT" \\ + 52: 0, // "DOUBLE_COLOR_DEMO_LIGHT" \\ + 53: 0, // "ELECTRIC_FAN_WITH_LAMP" \\ + 55: 0, // "SWEEPING_ROBOT" \\ + 56: 0, // "RGB_BALL_LIGHT_4" \\ + 57: 0, // "MONOCHROMATIC_BALL_LIGHT" \\ + 59: 1, // "MUSIC_LIGHT_BELT" \\ L1 + 60: 0, // "NEW_HUMIDIFIER" \\ + 61: 0, // "KAI_WEI_ROUTER" \\ + 62: 0, // "MEARICAMERA" \\ + 64: 0, // "HeatingTable" \\ + 65: 0, // "CustomCamera" \\ + 66: 0, // "ZIGBEE_MAIN_DEVICE" \\ + 67: 0, // "RollingDoor" \\ + 68: 0, // "KOOCHUWAH" \\ + 69: 0, // "ATMOSPHERE_LAMP" \\ + 76: 0, // "YI_GE_ER_LAMP" \\ + 77: 4, // "SINGLE_SOCKET_MULTIPLE" \\ (1 socket device using data structure of four :() + 78: 4, // "SINGLE_SWITCH_MULTIPLE" \\ (1 switch device using data structure of four :() + 79: 0, // "CHRISTMAS_LIGHT" \\ + 80: 0, // "HANYUAN_AIR_CONDITION" \\ + 81: 1, // "GSM_SOCKET_NO_FLOW" \\ + 82: 2, // "GSM_SOCKET_2_NO_FLOW" \\ + 83: 3, // "GSM_SOCKET_3_NO_FLOW" \\ + 84: 4, // "GSM_SOCKET_4_NO_FLOW" \\ + 86: 0, // "CLEAR_BOOT" \\ + 87: 0, // "EWELINK_IOT_CAMERA" \\ GK-200MP2B + 88: 0, // "YK_INFRARED" \\ + 89: 0, // "SMART_OPEN_MACHINE" \\ + 90: 0, // "GSM_RFBridge" \\ + 91: 0, // "ROLLING_DOOR_91" \\ + 93: 0, // "HTHD_AIR_CLEANER" \\ + 94: 0, // "YIAN_ELECTRIC_PROTECT" \\ + 98: 0, // "DOORBELL_RFBRIDGE" \\ + 102: 1, // "DOOR_MAGNETIC" \\ OPL-DMA, DW2 + 103: 0, // "WOTEWODE_TEM_LIGHT" \\ + 104: 0, // "WOTEWODE_RGB_TEM_LIGHT" \\ + 107: 0, // "GSM_SOCKET_NO_FLOW" \\ + 109: 0, // "YK_INFRARED_2" \\ + 1000: 1, // "ZIGBEE_WIRELESS_SWITCH" \\ + 1001: 0, // "BLADELESS_FAN" \\ + 1002: 0, // "NEW_HUMIDIFIER" \\ + 1003: 0, // "WARM_AIR_BLOWER" \\ + 1256: 1, // "ZIGBEE_SINGLE_SWITCH" \\ + 1770: 1, // "ZIGBEE_TEMPERATURE_SENSOR" \\ + 2026: 1, // "ZIGBEE_MOBILE_SENSOR" \\ + 2256: 2, // "ZIGBEE_SWITCH_2" \\ + 3026: 1, // "ZIGBEE_DOOR_AND_WINDOW_SENSOR" \\ + 3256: 3, // "ZIGBEE_SWITCH_3" \\ + 4026: 1, // "ZIGBEE_WATER_SENSOR" \\ + 4256: 4, // "ZIGBEE_SWITCH_4" \\ + }, +}; diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 8dec569e..5b87acf8 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -2,1938 +2,2203 @@ "use strict"; let Accessory, Characteristic, EveService, EveHistoryService, Service, UUIDGen; const cns = require("./constants"), - convert = require("color-convert"), - corrInterval = require("correcting-interval"), - eWeLinkHTTP = require("./eWeLinkHTTP"), - eWeLinkWS = require("./eWeLinkWS"), - eWeLinkLAN = require("./eWeLinkLAN"), - fakegato = require("fakegato-history"), - hbLib = require("homebridge-lib"); + convert = require("color-convert"), + corrInterval = require("correcting-interval"), + eWeLinkHTTP = require("./eWeLinkHTTP"), + eWeLinkWS = require("./eWeLinkWS"), + eWeLinkLAN = require("./eWeLinkLAN"), + fakegato = require("fakegato-history"), + hbLib = require("homebridge-lib"); class eWeLink { - constructor(log, config, api) { - if (!log || !api || !config) return; - if (!config.username || !config.password || !config.countryCode) { - log.error("**************** Cannot load homebridge-ewelink ****************"); - log.error("Your eWeLink credentials are missing from the Homebridge config."); - log.error("****************************************************************"); - return; - } - this.log = log; - this.config = config; - this.api = api; - this.debug = this.config.debug || false; - this.devicesInHB = new Map(); - this.devicesInEwe = new Map(); - this.cusG = new Map(); - this.cusS = new Map(); - this.eveLogPath = this.api.user.storagePath() + "/homebridge-ewelink/"; - this.api - .on("didFinishLaunching", () => { - this.log("Plugin has finished initialising. Starting synchronisation with eWeLink account."); - //*** Set up HTTP client and get the user HTTP host ***\\ - this.httpClient = new eWeLinkHTTP(this.config, this.log); - this.httpClient.getHost() - .then(() => this.httpClient.login()) - .then(res => { //*** Set up the web socket client ***\\ - this.wsClient = new eWeLinkWS(this.config, this.log, res); - return this.wsClient.getHost(); - }).then(() => { //*** Open web socket connection and get device list via HTTP ***\\ - this.wsClient.login(); - return this.httpClient.getDevices(); - }).then(res => { //*** Get device IP addresses for LAN mode ***\\ - this.httpDevices = res - .filter(device => device.hasOwnProperty("extra") && device.extra.hasOwnProperty("uiid")) - .filter(device => !(this.config.hideDevFromHB || "").includes(device.deviceid)); - this.lanClient = new eWeLinkLAN(this.config, this.log, this.httpDevices); - this.httpDevices.forEach(device => this.devicesInEwe.set(device.deviceid, device)); - return this.lanClient.getHosts(); - }).then(res => { //*** Set up the LAN mode listener ***\\ - this.lanDevices = res.map; - this.lanDevicesOnline = res.count; - return this.lanClient.startMonitor(); - }).then(() => { //*** Use the device list to refresh Homebridge accessories ***\\ - (() => { - //*** Remove all Homebridge accessories if none found ***\\ - if (Object.keys(this.httpDevices).length === 0 && Object.keys(this.lanDevices).length === 0) { - Array.from(this.devicesInHB.values()).forEach(a => this.removeAccessory(a)); - this.devicesInHB.clear(); - this.log.warn("******* Not loading homebridge-ewelink *******"); - this.log.warn("No devices were found in your eWeLink account."); - this.log.warn("**********************************************"); - return; - } - //*** Make a map of custom groups from Homebridge config ***\\ - if (Object.keys(this.config.groups || []).length > 0) { - this.config.groups - .filter(g => g.hasOwnProperty("type") && cns.allowedGroups.includes(g.type)) - .filter(g => g.hasOwnProperty("deviceId") && this.devicesInEwe.has(g.deviceId.toLowerCase())) - .forEach(g => this.cusG.set(g.deviceId + "SWX", g)); - } - //*** Make a map of RF Bridge custom sensors from Homebridge config ***\\ - if (Object.keys(this.config.bridgeSensors || []).length > 0) { - this.config.bridgeSensors - .filter(s => s.hasOwnProperty("deviceId") && this.devicesInEwe.has(s.deviceId.toLowerCase())) - .forEach(s => this.cusS.set(s.fullDeviceId, s)); - } - //*** Logging always helps to see if everything is okay so far ***\\ - this.log("[%s] eWeLink devices were loaded from the Homebridge cache.", this.devicesInHB.size); - this.log("[%s] primary devices were loaded from your eWeLink account.", this.devicesInEwe.size); - this.log("[%s] primary devices were discovered on your local network.", this.lanDevicesOnline); - //*** Remove Homebridge accessories that don't appear in eWeLink ***\\ - this.devicesInHB.forEach(a => { - if (!this.devicesInEwe.has(a.context.eweDeviceId)) { - this.removeAccessory(a); - } - }); - //*** Synchronise devices between eWeLink and Homebridge and set up ws/lan listeners ***\\ - this.devicesInEwe.forEach(d => this.initialiseDevice(d)); - this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); - this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); - this.log("eWeLink setup complete. If you're enjoying this package please consider a ⭐ī¸ on GitHub :)."); - if (this.config.debugReqRes || false) { - this.log.warn("You have 'Request & Response Logging' enabled. This setting is not recommended for long-term use."); - } - })(); - }).catch(err => { - this.log.error("************** Cannot load homebridge-ewelink **************"); - this.log.error(err); - this.log.error("************************************************************"); - if (this.lanClient) this.lanClient.closeConnection(); - if (this.wsClient) this.wsClient.closeConnection(); - }); - }) - .on('shutdown', () => { + constructor(log, config, api) { + if (!log || !api || !config) return; + if (!config.username || !config.password || !config.countryCode) { + log.error("**************** Cannot load homebridge-ewelink ****************"); + log.error("Your eWeLink credentials are missing from the Homebridge config."); + log.error("****************************************************************"); + return; + } + this.log = log; + this.config = config; + this.api = api; + this.debug = this.config.debug || false; + this.devicesInHB = new Map(); + this.devicesInEwe = new Map(); + this.cusG = new Map(); + this.cusS = new Map(); + this.eveLogPath = this.api.user.storagePath() + "/homebridge-ewelink/"; + this.api + .on("didFinishLaunching", () => { + this.log("Plugin has finished initialising. Starting synchronisation with eWeLink account."); + //*** Set up HTTP client and get the user HTTP host ***\\ + this.httpClient = new eWeLinkHTTP(this.config, this.log); + this.httpClient + .getHost() + .then(() => this.httpClient.login()) + .then(res => { + //*** Set up the web socket client ***\\ + this.wsClient = new eWeLinkWS(this.config, this.log, res); + return this.wsClient.getHost(); + }) + .then(() => { + //*** Open web socket connection and get device list via HTTP ***\\ + this.wsClient.login(); + return this.httpClient.getDevices(); + }) + .then(res => { + //*** Get device IP addresses for LAN mode ***\\ + this.httpDevices = res + .filter(device => device.hasOwnProperty("extra") && device.extra.hasOwnProperty("uiid")) + .filter(device => !(this.config.hideDevFromHB || "").includes(device.deviceid)); + this.lanClient = new eWeLinkLAN(this.config, this.log, this.httpDevices); + this.httpDevices.forEach(device => this.devicesInEwe.set(device.deviceid, device)); + return this.lanClient.getHosts(); + }) + .then(res => { + //*** Set up the LAN mode listener ***\\ + this.lanDevices = res.map; + this.lanDevicesOnline = res.count; + return this.lanClient.startMonitor(); + }) + .then(() => { + //*** Use the device list to refresh Homebridge accessories ***\\ + (() => { + //*** Remove all Homebridge accessories if none found ***\\ + if (Object.keys(this.httpDevices).length === 0 && Object.keys(this.lanDevices).length === 0) { + Array.from(this.devicesInHB.values()).forEach(a => this.removeAccessory(a)); + this.devicesInHB.clear(); + this.log.warn("******* Not loading homebridge-ewelink *******"); + this.log.warn("No devices were found in your eWeLink account."); + this.log.warn("**********************************************"); + return; + } + //*** Make a map of custom groups from Homebridge config ***\\ + if (Object.keys(this.config.groups || []).length > 0) { + this.config.groups + .filter(g => g.hasOwnProperty("type") && cns.allowedGroups.includes(g.type)) + .filter(g => g.hasOwnProperty("deviceId") && this.devicesInEwe.has(g.deviceId.toLowerCase())) + .forEach(g => this.cusG.set(g.deviceId + "SWX", g)); + } + //*** Make a map of RF Bridge custom sensors from Homebridge config ***\\ + if (Object.keys(this.config.bridgeSensors || []).length > 0) { + this.config.bridgeSensors + .filter(s => s.hasOwnProperty("deviceId") && this.devicesInEwe.has(s.deviceId.toLowerCase())) + .forEach(s => this.cusS.set(s.fullDeviceId, s)); + } + //*** Logging always helps to see if everything is okay so far ***\\ + this.log("[%s] eWeLink devices were loaded from the Homebridge cache.", this.devicesInHB.size); + this.log("[%s] primary devices were loaded from your eWeLink account.", this.devicesInEwe.size); + this.log("[%s] primary devices were discovered on your local network.", this.lanDevicesOnline); + //*** Remove Homebridge accessories that don't appear in eWeLink ***\\ + this.devicesInHB.forEach(a => { + if (!this.devicesInEwe.has(a.context.eweDeviceId)) { + this.removeAccessory(a); + } + }); + //*** Synchronise devices between eWeLink and Homebridge and set up ws/lan listeners ***\\ + this.devicesInEwe.forEach(d => this.initialiseDevice(d)); + this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); + this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); + this.log("eWeLink setup complete. If you're enjoying this package please consider a ⭐ī¸ on GitHub :)."); + if (this.config.debugReqRes || false) { + this.log.warn( + "You have 'Request & Response Logging' enabled. This setting is not recommended for long-term use." + ); + } + })(); + }) + .catch(err => { + this.log.error("************** Cannot load homebridge-ewelink **************"); + this.log.error(err); + this.log.error("************************************************************"); if (this.lanClient) this.lanClient.closeConnection(); if (this.wsClient) this.wsClient.closeConnection(); - }); - } - initialiseDevice(device) { - let accessory; - // if (device.extra.uiid === 102) this.log.warn(device); - //*** First add the device if it isn't already in Homebridge. Yeah this code looks a mess :| ***\\ - if (!this.devicesInHB.has(device.deviceid + "SWX") && !this.devicesInHB.has(device.deviceid + "SW0")) { - if (device.extra.uiid === 2 && device.brandName === "coolkit" && device.productModel === "0285") { - this.addAccessory(device, device.deviceid + "SWX", "valve"); - } else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "blind") { - this.addAccessory(device, device.deviceid + "SWX", "blind"); - } else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "garage") { - this.addAccessory(device, device.deviceid + "SWX", "garage"); - } else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "lock") { - this.addAccessory(device, device.deviceid + "SWX", "lock"); - } else if (cns.devicesSensor.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SWX", "sensor"); - } else if (cns.devicesFan.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SWX", "fan"); - } else if (cns.devicesThermostat.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SWX", "thermostat"); - } else if (cns.devicesOutlet.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SWX", "outlet"); - } else if (cns.devicesUSB.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SWX", "usb"); - } else if (cns.devicesSCM.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SWX", "scm"); - } else if (cns.devicesSingleSwitch.includes(device.extra.uiid) && cns.devicesSingleSwitchLight.includes(device.productModel)) { - this.addAccessory(device, device.deviceid + "SWX", "light"); - } else if (cns.devicesMultiSwitch.includes(device.extra.uiid) && cns.devicesMultiSwitchLight.includes(device.productModel)) { - for (let i = 0; i <= cns.chansFromUiid[device.extra.uiid]; i++) { - this.addAccessory(device, device.deviceid + "SW" + i, "light"); - } - } else if (cns.devicesSingleSwitch.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SWX", "switch"); - } else if (cns.devicesMultiSwitch.includes(device.extra.uiid)) { - for (let i = 0; i <= cns.chansFromUiid[device.extra.uiid]; i++) { - this.addAccessory(device, device.deviceid + "SW" + i, "switch"); - } - } else if (cns.devicesRFBridge.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SW0", "rf_pri"); - if (Object.keys((device.tags && device.tags.zyx_info) || []).length > 0) { - for (let i = 1; i <= Object.keys(device.tags.zyx_info).length; i++) { - this.addAccessory(device, device.deviceid + "SW" + i, "rf_sub"); - } + }); + }) + .on("shutdown", () => { + if (this.lanClient) this.lanClient.closeConnection(); + if (this.wsClient) this.wsClient.closeConnection(); + }); + } + initialiseDevice(device) { + let accessory; + // if (device.extra.uiid === 102) this.log.warn(device); + //*** First add the device if it isn't already in Homebridge. Yeah this code looks a mess :| ***\\ + if (!this.devicesInHB.has(device.deviceid + "SWX") && !this.devicesInHB.has(device.deviceid + "SW0")) { + if (device.extra.uiid === 2 && device.brandName === "coolkit" && device.productModel === "0285") { + this.addAccessory(device, device.deviceid + "SWX", "valve"); + } else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "blind") { + this.addAccessory(device, device.deviceid + "SWX", "blind"); + } else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "garage") { + this.addAccessory(device, device.deviceid + "SWX", "garage"); + } else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "lock") { + this.addAccessory(device, device.deviceid + "SWX", "lock"); + } else if (cns.devicesSensor.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SWX", "sensor"); + } else if (cns.devicesFan.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SWX", "fan"); + } else if (cns.devicesThermostat.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SWX", "thermostat"); + } else if (cns.devicesOutlet.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SWX", "outlet"); + } else if (cns.devicesUSB.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SWX", "usb"); + } else if (cns.devicesSCM.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SWX", "scm"); + } else if ( + cns.devicesSingleSwitch.includes(device.extra.uiid) && + cns.devicesSingleSwitchLight.includes(device.productModel) + ) { + this.addAccessory(device, device.deviceid + "SWX", "light"); + } else if ( + cns.devicesMultiSwitch.includes(device.extra.uiid) && + cns.devicesMultiSwitchLight.includes(device.productModel) + ) { + for (let i = 0; i <= cns.chansFromUiid[device.extra.uiid]; i++) { + this.addAccessory(device, device.deviceid + "SW" + i, "light"); + } + } else if (cns.devicesSingleSwitch.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SWX", "switch"); + } else if (cns.devicesMultiSwitch.includes(device.extra.uiid)) { + for (let i = 0; i <= cns.chansFromUiid[device.extra.uiid]; i++) { + this.addAccessory(device, device.deviceid + "SW" + i, "switch"); + } + } else if (cns.devicesRFBridge.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SW0", "rf_pri"); + if (Object.keys((device.tags && device.tags.zyx_info) || []).length > 0) { + for (let i = 1; i <= Object.keys(device.tags.zyx_info).length; i++) { + this.addAccessory(device, device.deviceid + "SW" + i, "rf_sub"); + } + } + } else if (cns.devicesZBBridge.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SWX", "zb_pri"); + } else if (cns.devicesZB.includes(device.extra.uiid)) { + this.addAccessory(device, device.deviceid + "SWX", "zb_sub"); + } else if (cns.devicesCamera.includes(device.extra.uiid)) { + this.log.warn( + '[%s] please see "https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-Sonoff-Camera".', + device.name + ); + return; + } else { + this.log.warn( + "[%s] cannot be added as it is not supported by this plugin. Please make a GitHub issue request.", + device.name + ); + return; + } + } + //*** Next refresh the device ***\\ + if ((accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0"))) { + let isX = accessory.context.hbDeviceId.substr(-1) === "X", + isRfBridge = cns.devicesRFBridge.includes(accessory.context.eweUIID), + rfBridgeChange = false; + accessory + .getService(Service.AccessoryInformation) + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); + accessory.context.reachableWAN = accessory.context.eweUIID !== 102 ? device.online : true; + accessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; + accessory.context.inUse = false; + let str = accessory.context.reachableLAN + ? "and locally with IP [" + this.lanDevices.get(device.deviceid).ip + "]" + : "but LAN mode unavailable as unsupported/shared device"; + this.log("[%s] found in eWeLink %s.", accessory.displayName, str); + this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + if (!isX) { + for (let i = 1; i <= accessory.context.channelCount; i++) { + if (!this.devicesInHB.has(device.deviceid + "SW" + i)) { + if (cns.devicesHideable.includes(accessory.context.type)) { + if ((this.config.hideFromHB || "").includes(device.deviceid + "SW" + i)) { + continue; + } else { + this.addAccessory(device, device.deviceid + "SW" + i, "switch"); + } } - } else if (cns.devicesZBBridge.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SWX", "zb_pri"); - } else if (cns.devicesZB.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SWX", "zb_sub"); - } else if (cns.devicesCamera.includes(device.extra.uiid)) { - this.log.warn("[%s] please see \"https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-Sonoff-Camera\".", device.name); - return; - } else { - this.log.warn("[%s] cannot be added as it is not supported by this plugin. Please make a GitHub issue request.", device.name); - return; - } - } - //*** Next refresh the device ***\\ - if ((accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0"))) { - let isX = accessory.context.hbDeviceId.substr(-1) === "X", - isRfBridge = cns.devicesRFBridge.includes(accessory.context.eweUIID), - rfBridgeChange = false; - accessory.getService(Service.AccessoryInformation) + } + let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); + if ( + (this.config.hideFromHB || "").includes(device.deviceid + "SW" + i) && + cns.devicesHideable.includes(accessory.context.type) + ) { + this.removeAccessory(oAccessory); + continue; + } + if (isRfBridge && oAccessory.context.sensorType !== "button") { + let ct = this.cusS.has(oAccessory.context.hbDeviceId) + ? this.cusS.get(oAccessory.context.hbDeviceId).type + : "motion"; + if (ct !== oAccessory.context.sensorType) rfBridgeChange = true; + } + oAccessory + .getService(Service.AccessoryInformation) .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); - accessory.context.reachableWAN = accessory.context.eweUIID !== 102 ? device.online : true; - accessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; - accessory.context.inUse = false; - let str = accessory.context.reachableLAN ? - "and locally with IP [" + this.lanDevices.get(device.deviceid).ip + "]" : - "but LAN mode unavailable as unsupported/shared device"; - this.log("[%s] found in eWeLink %s.", accessory.displayName, str); - this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - if (!isX) { - for (let i = 1; i <= accessory.context.channelCount; i++) { - if (!this.devicesInHB.has(device.deviceid + "SW" + i)) { - if (cns.devicesHideable.includes(accessory.context.type)) { - if ((this.config.hideFromHB || "").includes(device.deviceid + "SW" + i)) { - continue; - } else { - this.addAccessory(device, device.deviceid + "SW" + i, "switch"); - } - } - } - let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); - if ((this.config.hideFromHB || "").includes(device.deviceid + "SW" + i) && cns.devicesHideable.includes(accessory.context.type)) { - this.removeAccessory(oAccessory); - continue; - } - if (isRfBridge && oAccessory.context.sensorType !== "button") { - let ct = this.cusS.has(oAccessory.context.hbDeviceId) ? this.cusS.get(oAccessory.context.hbDeviceId).type : "motion"; - if (ct !== oAccessory.context.sensorType) rfBridgeChange = true; - } - oAccessory.getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); - oAccessory.context.reachableWAN = device.online; - oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; - this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); - } - } - if (rfBridgeChange) { - this.log.warn("[%s] bridge configuration changed so devices will be removed and readded.", accessory.displayName); - for (let i = 0; i <= accessory.context.channelCount; i++) { - let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); - this.removeAccessory(oAccessory); - } - this.initialiseDevice(device); - return; - } - if (!this.refreshAccessory(accessory, device.params)) { - this.log.warn("[%s] could not be initialised. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.) [debug:%s:%s].", accessory.displayName, accessory.context.type, accessory.context.channelCount); - } - } else { - this.log.warn("[%s] cannot be initialised as it wasn't found in Homebridge.", device.name); - } - } - addAccessory(device, hbDeviceId, type) { - let switchNumber = hbDeviceId.substr(-1).toString(), - newDeviceName = type === "rf_sub" ? device.tags.zyx_info[switchNumber - 1].name : device.name, - channelCount = type === "rf_pri" ? - Object.keys((device.tags && device.tags.zyx_info) || []).length : - cns.chansFromUiid[device.extra.uiid]; - if (["1", "2", "3", "4"].includes(switchNumber) && type !== "rf_sub") { - newDeviceName += " SW" + switchNumber; - if ((this.config.hideFromHB || "").includes(hbDeviceId) && cns.devicesHideable.includes(type)) { - this.log("[%s] will not be added as per configuration.", newDeviceName); - return; - } - } - if ((this.config.nameOverride || {}).hasOwnProperty(hbDeviceId)) { - newDeviceName = this.config.nameOverride[hbDeviceId]; - } - const accessory = new Accessory(newDeviceName, UUIDGen.generate(hbDeviceId).toString()); - try { - accessory.getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.SerialNumber, hbDeviceId) - .setCharacteristic(Characteristic.Manufacturer, device.brandName) - .setCharacteristic(Characteristic.Model, device.productModel + " (" + device.extra.model + ")") - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) - .setCharacteristic(Characteristic.Identify, false); - accessory.context = { - hbDeviceId, - eweDeviceId: device.deviceid, - eweUIID: device.extra.uiid, - eweModel: device.productModel, - eweApiKey: device.apikey, - switchNumber, - channelCount, - type - }; - switch (type) { - case "valve": - ["A", "B"].forEach(v => { - accessory.addService(Service.Valve, "Valve " + v, "valve" + v.toLowerCase()) - .setCharacteristic(Characteristic.Active, 0) - .setCharacteristic(Characteristic.InUse, 0) - .setCharacteristic(Characteristic.ValveType, 1) - .setCharacteristic(Characteristic.SetDuration, (this.config.valveTimeLength || 120)) - .addCharacteristic(Characteristic.RemainingDuration); - }); - break; - case "blind": - accessory.addService(Service.WindowCovering) - .setCharacteristic(Characteristic.CurrentPosition, 100) - .setCharacteristic(Characteristic.TargetPosition, 100) - .setCharacteristic(Characteristic.PositionState, 2); - break; - case "garage": - accessory.addService(Service.GarageDoorOpener) - .setCharacteristic(Characteristic.CurrentDoorState, 1) - .setCharacteristic(Characteristic.TargetDoorState, 1) - .setCharacteristic(Characteristic.ObstructionDetected, false); - break; - case "lock": - accessory.addService(Service.LockMechanism) - .setCharacteristic(Characteristic.LockCurrentState, 1) - .setCharacteristic(Characteristic.LockTargetState, 1); - break; - case "sensor": - accessory.addService(Service.ContactSensor); - break; - case "fan": - accessory.addService(Service.Fanv2); - accessory.addService(Service.Lightbulb); - break; - case "thermostat": - if (!this.config.hideTHSwitch) accessory.addService(Service.Switch); - accessory.addService(Service.TemperatureSensor); - if (device.params.sensorType !== "DS18B20") accessory.addService(Service.HumiditySensor); - break; - case "outlet": - accessory.addService(Service.Outlet); - accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.Voltage); - accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.CurrentConsumption); - accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.ElectricCurrent); - accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.TotalConsumption); - accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.ResetTotal); - accessory.context = { - ...accessory.context, - ...{ - extraPersistedData: {}, - lastReset: 0, - totalEnergy: 0, - totalEnergyTemp: 0 - } - }; - break; - case "usb": - accessory.addService(Service.Outlet); - break; - case "light": - accessory.addService(Service.Lightbulb); - break; - case "switch": - case "scm": - accessory.addService(Service.Switch); - break; - case "rf_pri": - accessory.context.rfChlMap = {}; - break; - case "zb_pri": - break; - case "rf_sub": - accessory.context.rfChls = {}; - switch (device.tags.zyx_info[parseInt(switchNumber) - 1].remote_type) { - case "1": - case "2": - case "3": - case "4": - accessory.context.sensorType = "button"; - break; - case "6": - accessory.context.sensorType = this.cusS.has(hbDeviceId) ? this.cusS.get(hbDeviceId).type : "motion"; - break; - default: - throw "unsupported rf device type [" + device.tags.zyx_info[parseInt(switchNumber) - 1].remote_type + "]. Please create an issue on GitHub"; - } - let mAccessory = this.devicesInHB.get(device.deviceid + "SW0"); - device.tags.zyx_info[parseInt(switchNumber) - 1].buttonName.forEach(button => { - let rfData; - Object.entries(button).forEach(([k, v]) => rfData = { - rfChan: k, - name: v - }); - accessory.context.rfChls[rfData.rfChan] = rfData.name; - mAccessory.context.rfChlMap[rfData.rfChan] = switchNumber; - switch (accessory.context.sensorType) { - case "button": - accessory.addService(Service.Switch, rfData.name, "switch" + rfData.rfChan); - break; - case "water": - accessory.addService(Service.LeakSensor); - break; - case "fire": - case "smoke": - accessory.addService(Service.SmokeSensor); - break; - case "co": - accessory.addService(Service.CarbonMonoxideSensor); - break; - case "co2": - accessory.addService(Service.CarbonDioxideSensor); - break; - case "contact": - accessory.addService(Service.ContactSensor); - break; - case "occupancy": - accessory.addService(Service.OccupancySensor); - break; - default: - accessory.addService(Service.MotionSensor); - break; - } - this.devicesInHB.set(mAccessory.context.hbDeviceId, mAccessory); - }); - break; - case "zb_sub": //*** credit @tasict ***\\ - accessory.addService(Service.BatteryService); - switch (device.extra.uiid) { - case 1000: - accessory.addService(Service.StatelessProgrammableSwitch); - if (this.config.hideZBLDPress) { - accessory.getService(Service.StatelessProgrammableSwitch) - .getCharacteristic(Characteristic.ProgrammableSwitchEvent) - .setProps({ - validValues: [0] - }); - } - break; - case 1770: - accessory.addService(Service.TemperatureSensor); - accessory.addService(Service.HumiditySensor); - break; - case 2026: - accessory.addService(Service.MotionSensor); - break; - case 3026: - accessory.addService(Service.ContactSensor); - break; - default: - throw "unsupported zigbee device type [" + device.extra.uiid + "]. Please create an issue on GitHub"; - } - break; + oAccessory.context.reachableWAN = device.online; + oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); + } + } + if (rfBridgeChange) { + this.log.warn( + "[%s] bridge configuration changed so devices will be removed and readded.", + accessory.displayName + ); + for (let i = 0; i <= accessory.context.channelCount; i++) { + let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); + this.removeAccessory(oAccessory); + } + this.initialiseDevice(device); + return; + } + if (!this.refreshAccessory(accessory, device.params)) { + this.log.warn( + "[%s] could not be initialised. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.) [debug:%s:%s].", + accessory.displayName, + accessory.context.type, + accessory.context.channelCount + ); + } + } else { + this.log.warn("[%s] cannot be initialised as it wasn't found in Homebridge.", device.name); + } + } + addAccessory(device, hbDeviceId, type) { + let switchNumber = hbDeviceId.substr(-1).toString(), + newDeviceName = type === "rf_sub" ? device.tags.zyx_info[switchNumber - 1].name : device.name, + channelCount = + type === "rf_pri" + ? Object.keys((device.tags && device.tags.zyx_info) || []).length + : cns.chansFromUiid[device.extra.uiid]; + if (["1", "2", "3", "4"].includes(switchNumber) && type !== "rf_sub") { + newDeviceName += " SW" + switchNumber; + if ((this.config.hideFromHB || "").includes(hbDeviceId) && cns.devicesHideable.includes(type)) { + this.log("[%s] will not be added as per configuration.", newDeviceName); + return; + } + } + if ((this.config.nameOverride || {}).hasOwnProperty(hbDeviceId)) { + newDeviceName = this.config.nameOverride[hbDeviceId]; + } + const accessory = new Accessory(newDeviceName, UUIDGen.generate(hbDeviceId).toString()); + try { + accessory + .getService(Service.AccessoryInformation) + .setCharacteristic(Characteristic.SerialNumber, hbDeviceId) + .setCharacteristic(Characteristic.Manufacturer, device.brandName) + .setCharacteristic(Characteristic.Model, device.productModel + " (" + device.extra.model + ")") + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) + .setCharacteristic(Characteristic.Identify, false); + accessory.context = { + hbDeviceId, + eweDeviceId: device.deviceid, + eweUIID: device.extra.uiid, + eweModel: device.productModel, + eweApiKey: device.apikey, + switchNumber, + channelCount, + type, + }; + switch (type) { + case "valve": + ["A", "B"].forEach(v => { + accessory + .addService(Service.Valve, "Valve " + v, "valve" + v.toLowerCase()) + .setCharacteristic(Characteristic.Active, 0) + .setCharacteristic(Characteristic.InUse, 0) + .setCharacteristic(Characteristic.ValveType, 1) + .setCharacteristic(Characteristic.SetDuration, this.config.valveTimeLength || 120) + .addCharacteristic(Characteristic.RemainingDuration); + }); + break; + case "blind": + accessory + .addService(Service.WindowCovering) + .setCharacteristic(Characteristic.CurrentPosition, 100) + .setCharacteristic(Characteristic.TargetPosition, 100) + .setCharacteristic(Characteristic.PositionState, 2); + break; + case "garage": + accessory + .addService(Service.GarageDoorOpener) + .setCharacteristic(Characteristic.CurrentDoorState, 1) + .setCharacteristic(Characteristic.TargetDoorState, 1) + .setCharacteristic(Characteristic.ObstructionDetected, false); + break; + case "lock": + accessory + .addService(Service.LockMechanism) + .setCharacteristic(Characteristic.LockCurrentState, 1) + .setCharacteristic(Characteristic.LockTargetState, 1); + break; + case "sensor": + accessory.addService(Service.ContactSensor); + break; + case "fan": + accessory.addService(Service.Fanv2); + accessory.addService(Service.Lightbulb); + break; + case "thermostat": + if (!this.config.hideTHSwitch) accessory.addService(Service.Switch); + accessory.addService(Service.TemperatureSensor); + if (device.params.sensorType !== "DS18B20") accessory.addService(Service.HumiditySensor); + break; + case "outlet": + accessory.addService(Service.Outlet); + accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.Voltage); + accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.CurrentConsumption); + accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.ElectricCurrent); + accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.TotalConsumption); + accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.ResetTotal); + accessory.context = { + ...accessory.context, + ...{ + extraPersistedData: {}, + lastReset: 0, + totalEnergy: 0, + totalEnergyTemp: 0, + }, + }; + break; + case "usb": + accessory.addService(Service.Outlet); + break; + case "light": + accessory.addService(Service.Lightbulb); + break; + case "switch": + case "scm": + accessory.addService(Service.Switch); + break; + case "rf_pri": + accessory.context.rfChlMap = {}; + break; + case "zb_pri": + break; + case "rf_sub": + accessory.context.rfChls = {}; + switch (device.tags.zyx_info[parseInt(switchNumber) - 1].remote_type) { + case "1": + case "2": + case "3": + case "4": + accessory.context.sensorType = "button"; + break; + case "6": + accessory.context.sensorType = this.cusS.has(hbDeviceId) ? this.cusS.get(hbDeviceId).type : "motion"; + break; default: - throw "device is not supported by this plugin. Please create an issue on GitHub"; - } - this.devicesInHB.set(hbDeviceId, accessory); - this.api.registerPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); - this.configureAccessory(accessory); - this.log("[%s] has been added to Homebridge.", newDeviceName); - } catch (err) { - this.log.warn("[%s] could not be added as %s.", newDeviceName, err); - } - } - configureAccessory(accessory) { - if (!this.log) return; - try { - accessory.context.reachableWAN = true; - accessory.context.reachableLAN = true; - switch (accessory.context.type) { - case "valve": - ["A", "B"].forEach(v => { - accessory.getService("Valve " + v).getCharacteristic(Characteristic.Active) - .on("set", (value, callback) => this.internalValveUpdate(accessory, "Valve " + v, value, callback)); - accessory.getService("Valve " + v).getCharacteristic(Characteristic.SetDuration) - .on("set", (value, callback) => { - if (accessory.getService("Valve " + v).getCharacteristic(Characteristic.InUse).value) { - accessory.getService("Valve " + v).updateCharacteristic(Characteristic.RemainingDuration, value); - clearTimeout(accessory.getService("Valve " + v).timer); - accessory.getService("Valve " + v).timer = setTimeout(() => { - accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); - }, value * 1000); - } - callback(); - }); - }); - break; - case "blind": - accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.TargetPosition) - .on("set", (value, callback) => this.internalBlindUpdate(accessory, value, callback)) - .setProps({ - minStep: 100 - }); - break; - case "garage": - accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.TargetDoorState) - .on("set", (value, callback) => this.internalGarageUpdate(accessory, value, callback)); - break; - case "lock": - accessory.getService(Service.LockMechanism).getCharacteristic(Characteristic.LockTargetState) - .on("set", (value, callback) => this.internalLockUpdate(accessory, value, callback)); - break; - case "fan": - accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active) - .on("set", (value, callback) => this.internalFanUpdate(accessory, "power", value, callback)); - accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.RotationSpeed) - .on("set", (value, callback) => this.internalFanUpdate(accessory, "speed", value, callback)) + throw ( + "unsupported rf device type [" + + device.tags.zyx_info[parseInt(switchNumber) - 1].remote_type + + "]. Please create an issue on GitHub" + ); + } + let mAccessory = this.devicesInHB.get(device.deviceid + "SW0"); + device.tags.zyx_info[parseInt(switchNumber) - 1].buttonName.forEach(button => { + let rfData; + Object.entries(button).forEach( + ([k, v]) => + (rfData = { + rfChan: k, + name: v, + }) + ); + accessory.context.rfChls[rfData.rfChan] = rfData.name; + mAccessory.context.rfChlMap[rfData.rfChan] = switchNumber; + switch (accessory.context.sensorType) { + case "button": + accessory.addService(Service.Switch, rfData.name, "switch" + rfData.rfChan); + break; + case "water": + accessory.addService(Service.LeakSensor); + break; + case "fire": + case "smoke": + accessory.addService(Service.SmokeSensor); + break; + case "co": + accessory.addService(Service.CarbonMonoxideSensor); + break; + case "co2": + accessory.addService(Service.CarbonDioxideSensor); + break; + case "contact": + accessory.addService(Service.ContactSensor); + break; + case "occupancy": + accessory.addService(Service.OccupancySensor); + break; + default: + accessory.addService(Service.MotionSensor); + break; + } + this.devicesInHB.set(mAccessory.context.hbDeviceId, mAccessory); + }); + break; + case "zb_sub": //*** credit @tasict ***\\ + accessory.addService(Service.BatteryService); + switch (device.extra.uiid) { + case 1000: + accessory.addService(Service.StatelessProgrammableSwitch); + if (this.config.hideZBLDPress) { + accessory + .getService(Service.StatelessProgrammableSwitch) + .getCharacteristic(Characteristic.ProgrammableSwitchEvent) .setProps({ - minStep: 33 - }); - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalFanUpdate(accessory, "light", value, callback)); - break; - case "thermostat": - if (!this.config.hideTHSwitch) { - accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalThermostatUpdate(accessory, value, callback)); - } - accessory.log = this.log; - accessory.eveLogger = new EveHistoryService("weather", accessory, { - storage: "fs", - minutes: 5, - path: this.eveLogPath - }); - corrInterval.setCorrectingInterval(() => { - let dataToAdd = { - time: Date.now(), - temp: accessory.getService(Service.TemperatureSensor).getCharacteristic(Characteristic.CurrentTemperature).value - }; - if (accessory.getService(Service.HumiditySensor)) { - dataToAdd.humidity = accessory.getService(Service.HumiditySensor).getCharacteristic(Characteristic.CurrentRelativeHumidity).value; - } - accessory.eveLogger.addEntry(dataToAdd); - }, 300000); - break; - case "outlet": - accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalOutletUpdate(accessory, value, callback)); - accessory.log = this.log; - accessory.eveLogger = new EveHistoryService("energy", accessory, { - storage: "fs", - minutes: 5, - path: this.eveLogPath - }); - if (!accessory.context.hasOwnProperty("lastReset")) { - accessory.context = { - ...accessory.context, - ...{ - extraPersistedData: {}, - lastReset: 0, - totalEnergy: 0, - totalEnergyTemp: 0 - } - }; - } - corrInterval.setCorrectingInterval(() => { - let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value, - currentWatt = isOn ? accessory.getService(Service.Outlet) - .getCharacteristic(EveService.Characteristics.CurrentConsumption).value : 0; - if (accessory.eveLogger.isHistoryLoaded()) { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalEnergy = accessory.context.extraPersistedData.totalenergy + accessory.context.totalEnergyTemp + currentWatt * 10 / 3600 / 1000; - accessory.eveLogger.setExtraPersistedData({ - totalenergy: accessory.context.totalEnergy, - lastReset: accessory.context.extraPersistedData.lastReset - }); - } else { - accessory.context.totalEnergy = accessory.context.totalEnergyTemp + currentWatt * 10 / 3600 / 1000; - accessory.eveLogger.setExtraPersistedData({ - totalenergy: accessory.context.totalEnergy, - lastReset: 0 - }); - } - accessory.context.totalEnergytemp = 0; - } else { - accessory.context.totalEnergyTemp += currentWatt * 10 / 3600 / 1000; - accessory.context.totalEnergy = accessory.context.totalEnergyTemp; - } - accessory.eveLogger.addEntry({ - time: Date.now(), - power: currentWatt - }); - }, 300000); - accessory.getService(Service.Outlet).getCharacteristic(EveService.Characteristics.TotalConsumption) - .on("get", callback => { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower; - } - callback(null, accessory.context.totalEnergy); - }); - accessory.getService(Service.Outlet).getCharacteristic(EveService.Characteristics.ResetTotal) - .on("set", (value, callback) => { - accessory.context.totalEnergy = 0; - accessory.context.lastReset = value; - accessory.eveLogger.setExtraPersistedData({ - totalPower: 0, - lastReset: value - }); - callback(); - }) - .on("get", callback => { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.lastReset = accessory.context.extraPersistedData.lastReset; - } - callback(null, accessory.context.lastReset); + validValues: [0], }); - break; - case "usb": - accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalUSBUpdate(accessory, value, callback)); - break; - case "scm": - accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalSCMUpdate(accessory, value, callback)); - break; - case "light": - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalLightbulbUpdate(accessory, value, callback)); - if (cns.devicesBrightable.includes(accessory.context.eweUIID)) { - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Brightness) - .on("set", (value, callback) => { - if (value > 0) { - if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { - this.internalLightbulbUpdate(accessory, true, function() { - return; - }); - } - this.internalBrightnessUpdate(accessory, value, callback); - } else { - this.internalLightbulbUpdate(accessory, false, callback); - } - }); - } else if (cns.devicesColourable.includes(accessory.context.eweUIID)) { - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Brightness) - .on("set", (value, callback) => { - if (value > 0) { - if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { - this.internalLightbulbUpdate(accessory, true, function() { - return; - }); - } - this.internalHSBUpdate(accessory, "bri", value, callback); - } else { - this.internalLightbulbUpdate(accessory, false, callback); - } - }); - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Hue) - .on("set", (value, callback) => this.internalHSBUpdate(accessory, "hue", value, callback)); - accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Saturation) - .on("set", (value, callback) => callback()); - } - break; - case "switch": - accessory.getService(Service.Switch).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalSwitchUpdate(accessory, value, callback)); - break; - case "rf_sub": - accessory.context.rfChls = accessory.context.rfChls || {}; - if (accessory.context.sensorType === "button") { - Object.entries(accessory.context.rfChls).forEach(([k, v]) => { - accessory.getService(v).updateCharacteristic(Characteristic.On, false); - accessory.getService(v).getCharacteristic(Characteristic.On) - .on("set", (value, callback) => { - value ? this.internalRFDeviceUpdate(accessory, k, callback) : callback(); - }); - }); - } - break; - case "zb_sub": - if (accessory.context.eweUIID === 1770) { - accessory.log = this.log; - accessory.eveLogger = new EveHistoryService("weather", accessory, { - storage: "fs", - minutes: 5, - path: this.eveLogPath - }); - corrInterval.setCorrectingInterval(() => { - let dataToAdd = { - time: Date.now(), - temp: accessory.getService(Service.TemperatureSensor).getCharacteristic(Characteristic.CurrentTemperature).value, - humidity: accessory.getService(Service.HumiditySensor).getCharacteristic(Characteristic.CurrentRelativeHumidity).value - }; - accessory.eveLogger.addEntry(dataToAdd); - }, 300000); - } - break; - } - this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - } catch (err) { - this.log.warn("[%s] could not be refreshed as %s.", accessory.displayName, err); - } - } - refreshAccessory(accessory, newParams) { + } + break; + case 1770: + accessory.addService(Service.TemperatureSensor); + accessory.addService(Service.HumiditySensor); + break; + case 2026: + accessory.addService(Service.MotionSensor); + break; + case 3026: + accessory.addService(Service.ContactSensor); + break; + default: + throw "unsupported zigbee device type [" + device.extra.uiid + "]. Please create an issue on GitHub"; + } + break; + default: + throw "device is not supported by this plugin. Please create an issue on GitHub"; + } + this.devicesInHB.set(hbDeviceId, accessory); + this.api.registerPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); + this.configureAccessory(accessory); + this.log("[%s] has been added to Homebridge.", newDeviceName); + } catch (err) { + this.log.warn("[%s] could not be added as %s.", newDeviceName, err); + } + } + configureAccessory(accessory) { + if (!this.log) return; + try { + accessory.context.reachableWAN = true; + accessory.context.reachableLAN = true; switch (accessory.context.type) { - case "valve": - if (Object.keys(newParams).some(v => cns.devicesValveParams.includes(v)) && Array.isArray(newParams.switches)) { - this.externalValveUpdate(accessory, newParams); - } - return true; - case "blind": - if (Object.keys(newParams).some(v => cns.devicesBlindParams.includes(v)) && Array.isArray(newParams.switches)) { - this.externalBlindUpdate(accessory, newParams); - } - return true; - case "garage": - if (Object.keys(newParams).some(v => cns.devicesGarageParams.includes(v)) && Array.isArray(newParams.switches)) { - this.externalGarageUpdate(accessory, newParams); - } - return true; - case "lock": - if (Object.keys(newParams).some(v => cns.devicesLockParams.includes(v))) { - this.externalLockUpdate(accessory, newParams); - } - return true; - case "sensor": - if (Object.keys(newParams).some(v => cns.devicesSensorParams.includes(v))) { - this.externalSensorUpdate(accessory, newParams); - } - return true; - case "fan": - if (Object.keys(newParams).some(v => cns.devicesFanParams.includes(v))) { - this.externalFanUpdate(accessory, newParams); - } - return true; - case "thermostat": - if (Object.keys(newParams).some(v => cns.devicesThermostatParams.includes(v))) { - this.externalThermostatUpdate(accessory, newParams); - } - return true; - case "outlet": - if (Object.keys(newParams).some(v => cns.devicesOutletParams.includes(v))) { - this.externalOutletUpdate(accessory, newParams); - } - return true; - case "usb": - if (Object.keys(newParams).some(v => cns.devicesUSBParams.includes(v)) && Array.isArray(newParams.switches)) { - this.externalUSBUpdate(accessory, newParams); - } - return true; - case "scm": - if (Object.keys(newParams).some(v => cns.devicesSCMParams.includes(v)) && Array.isArray(newParams.switches)) { - this.externalSCMUpdate(accessory, newParams); - } - return true; - case "light": - if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID) && cns.devicesSingleSwitchLight.includes(accessory.context.eweModel)) { - if (Object.keys(newParams).some(v => cns.devicesSingleSwitchLightParams.includes(v))) { - this.externalSingleLightUpdate(accessory, newParams); - } - } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID) && cns.devicesMultiSwitchLight.includes(accessory.context.eweModel)) { - if (Object.keys(newParams).some(v => cns.devicesMultiSwitchLightParams.includes(v)) && Array.isArray(newParams.switches)) { - this.externalMultiLightUpdate(accessory, newParams); - } - } - return true; - case "switch": - if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID)) { - if (Object.keys(newParams).some(v => cns.devicesSingleSwitchParams.includes(v))) { - this.externalSingleSwitchUpdate(accessory, newParams); - } - } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID)) { - if (Object.keys(newParams).some(v => cns.devicesMultiSwitchParams.includes(v)) && Array.isArray(newParams.switches)) { - this.externalMultiSwitchUpdate(accessory, newParams); - } - } - return true; - case "rf_pri": - if (Object.keys(newParams).some(v => cns.devicesRFBridgeParams.includes(v))) { - this.externalRFDeviceUpdate(accessory, newParams); + case "valve": + ["A", "B"].forEach(v => { + accessory + .getService("Valve " + v) + .getCharacteristic(Characteristic.Active) + .on("set", (value, callback) => this.internalValveUpdate(accessory, "Valve " + v, value, callback)); + accessory + .getService("Valve " + v) + .getCharacteristic(Characteristic.SetDuration) + .on("set", (value, callback) => { + if (accessory.getService("Valve " + v).getCharacteristic(Characteristic.InUse).value) { + accessory.getService("Valve " + v).updateCharacteristic(Characteristic.RemainingDuration, value); + clearTimeout(accessory.getService("Valve " + v).timer); + accessory.getService("Valve " + v).timer = setTimeout(() => { + accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); + }, value * 1000); + } + callback(); + }); + }); + break; + case "blind": + accessory + .getService(Service.WindowCovering) + .getCharacteristic(Characteristic.TargetPosition) + .on("set", (value, callback) => this.internalBlindUpdate(accessory, value, callback)) + .setProps({ + minStep: 100, + }); + break; + case "garage": + accessory + .getService(Service.GarageDoorOpener) + .getCharacteristic(Characteristic.TargetDoorState) + .on("set", (value, callback) => this.internalGarageUpdate(accessory, value, callback)); + break; + case "lock": + accessory + .getService(Service.LockMechanism) + .getCharacteristic(Characteristic.LockTargetState) + .on("set", (value, callback) => this.internalLockUpdate(accessory, value, callback)); + break; + case "fan": + accessory + .getService(Service.Fanv2) + .getCharacteristic(Characteristic.Active) + .on("set", (value, callback) => this.internalFanUpdate(accessory, "power", value, callback)); + accessory + .getService(Service.Fanv2) + .getCharacteristic(Characteristic.RotationSpeed) + .on("set", (value, callback) => this.internalFanUpdate(accessory, "speed", value, callback)) + .setProps({ + minStep: 33, + }); + accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On) + .on("set", (value, callback) => this.internalFanUpdate(accessory, "light", value, callback)); + break; + case "thermostat": + if (!this.config.hideTHSwitch) { + accessory + .getService(Service.Switch) + .getCharacteristic(Characteristic.On) + .on("set", (value, callback) => this.internalThermostatUpdate(accessory, value, callback)); + } + accessory.log = this.log; + accessory.eveLogger = new EveHistoryService("weather", accessory, { + storage: "fs", + minutes: 5, + path: this.eveLogPath, + }); + corrInterval.setCorrectingInterval(() => { + let dataToAdd = { + time: Date.now(), + temp: accessory.getService(Service.TemperatureSensor).getCharacteristic(Characteristic.CurrentTemperature) + .value, + }; + if (accessory.getService(Service.HumiditySensor)) { + dataToAdd.humidity = accessory + .getService(Service.HumiditySensor) + .getCharacteristic(Characteristic.CurrentRelativeHumidity).value; } - return true; - case "rf_sub": - case "zb_pri": - return true; - case "zb_sub": - if (Object.keys(newParams).some(v => cns.devicesZBBridgeParams.includes(v))) { - this.externalZBDeviceUpdate(accessory, newParams); + accessory.eveLogger.addEntry(dataToAdd); + }, 300000); + break; + case "outlet": + accessory + .getService(Service.Outlet) + .getCharacteristic(Characteristic.On) + .on("set", (value, callback) => this.internalOutletUpdate(accessory, value, callback)); + accessory.log = this.log; + accessory.eveLogger = new EveHistoryService("energy", accessory, { + storage: "fs", + minutes: 5, + path: this.eveLogPath, + }); + if (!accessory.context.hasOwnProperty("lastReset")) { + accessory.context = { + ...accessory.context, + ...{ + extraPersistedData: {}, + lastReset: 0, + totalEnergy: 0, + totalEnergyTemp: 0, + }, + }; + } + corrInterval.setCorrectingInterval(() => { + let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value, + currentWatt = isOn + ? accessory.getService(Service.Outlet).getCharacteristic(EveService.Characteristics.CurrentConsumption) + .value + : 0; + if (accessory.eveLogger.isHistoryLoaded()) { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.totalEnergy = + accessory.context.extraPersistedData.totalenergy + + accessory.context.totalEnergyTemp + + (currentWatt * 10) / 3600 / 1000; + accessory.eveLogger.setExtraPersistedData({ + totalenergy: accessory.context.totalEnergy, + lastReset: accessory.context.extraPersistedData.lastReset, + }); + } else { + accessory.context.totalEnergy = accessory.context.totalEnergyTemp + (currentWatt * 10) / 3600 / 1000; + accessory.eveLogger.setExtraPersistedData({ + totalenergy: accessory.context.totalEnergy, + lastReset: 0, + }); + } + accessory.context.totalEnergytemp = 0; + } else { + accessory.context.totalEnergyTemp += (currentWatt * 10) / 3600 / 1000; + accessory.context.totalEnergy = accessory.context.totalEnergyTemp; } - return true; - default: - return false; - } - } - removeAccessory(accessory) { - try { - this.devicesInHB.delete(accessory.context.hbDeviceId); - this.api.unregisterPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); - this.log("[%s] has been removed from Homebridge.", accessory.displayName); - } catch (err) { - this.log.warn("[%s] needed to be removed but couldn't as %s.", accessory.displayName, err); - } - } - sendDeviceUpdate(accessory, params, callback) { - let payload = { - apikey: accessory.context.eweApiKey, - deviceid: accessory.context.eweDeviceId, - params - }; - let sendViaWS = () => { - if (accessory.context.reachableWAN) { - this.wsClient.sendUpdate(payload); - callback(); - } else { - this.log.error("[%s] could not be updated as it appears to be offline.", accessory.displayName); - callback("Device has failed to update"); - } - }; - if (cns.devicesNonLAN.includes(accessory.context.eweUIID) || !accessory.context.reachableLAN) { - sendViaWS(); - } else { - this.lanClient.sendUpdate(payload) - .then(() => callback()) - .catch(err => { - if (this.debug) { - this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); - } - sendViaWS(); + accessory.eveLogger.addEntry({ + time: Date.now(), + power: currentWatt, }); - } - } - receiveDeviceUpdate(device) { - let accessory; - switch (device.action) { - case "sysmsg": - if ((accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0"))) { - let isX = accessory.context.hbDeviceId.substr(-1) === "X"; - if (device.params.updateSource === "WS") { - if (accessory.context.reachableWAN !== device.params.online) { - accessory.context.reachableWAN = device.params.online; - this.log("[%s] has been reported [%s] via [WS].", accessory.displayName, accessory.context.reachableWAN ? "online" : "offline"); - this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - if (accessory.context.reachableWAN) this.wsClient.requestUpdate(accessory); - } else { - if (this.debug) { - this.log("[%s] Nothing to update from above WS message.", accessory.displayName); - } + }, 300000); + accessory + .getService(Service.Outlet) + .getCharacteristic(EveService.Characteristics.TotalConsumption) + .on("get", callback => { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower; + } + callback(null, accessory.context.totalEnergy); + }); + accessory + .getService(Service.Outlet) + .getCharacteristic(EveService.Characteristics.ResetTotal) + .on("set", (value, callback) => { + accessory.context.totalEnergy = 0; + accessory.context.lastReset = value; + accessory.eveLogger.setExtraPersistedData({ + totalPower: 0, + lastReset: value, + }); + callback(); + }) + .on("get", callback => { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.lastReset = accessory.context.extraPersistedData.lastReset; + } + callback(null, accessory.context.lastReset); + }); + break; + case "usb": + accessory + .getService(Service.Outlet) + .getCharacteristic(Characteristic.On) + .on("set", (value, callback) => this.internalUSBUpdate(accessory, value, callback)); + break; + case "scm": + accessory + .getService(Service.Switch) + .getCharacteristic(Characteristic.On) + .on("set", (value, callback) => this.internalSCMUpdate(accessory, value, callback)); + break; + case "light": + accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On) + .on("set", (value, callback) => this.internalLightbulbUpdate(accessory, value, callback)); + if (cns.devicesBrightable.includes(accessory.context.eweUIID)) { + accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.Brightness) + .on("set", (value, callback) => { + if (value > 0) { + if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + this.internalLightbulbUpdate(accessory, true, function () { + return; + }); } - } - if (!isX) { - for (let i = 1; i <= accessory.context.channelCount; i++) { - if (this.devicesInHB.has(device.deviceid + "SW" + i)) { - let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); - oAccessory.context.reachableWAN = device.params.online; - this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); - } + this.internalBrightnessUpdate(accessory, value, callback); + } else { + this.internalLightbulbUpdate(accessory, false, callback); + } + }); + } else if (cns.devicesColourable.includes(accessory.context.eweUIID)) { + accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.Brightness) + .on("set", (value, callback) => { + if (value > 0) { + if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + this.internalLightbulbUpdate(accessory, true, function () { + return; + }); } - } - } - break; - case "update": - if ((accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0"))) { - if (device.params.updateSource === "WS" && !accessory.context.reachableWAN) { - accessory.context.reachableWAN = true; - this.log("[%s] has been reported [online] via [WS].", accessory.displayName); - } - if (device.params.updateSource === "LAN" && !accessory.context.reachableLAN) { - accessory.context.reachableLAN = true; - this.log("[%s] has been reported [online] via [LAN].", accessory.displayName); - } - if (this.debug) { - this.log("[%s] externally updated from above %s message and will be refreshed.", accessory.displayName, device.params.updateSource); - } - if (!this.refreshAccessory(accessory, device.params)) { - this.log.warn("[%s] cannot be refreshed. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.). [debug:%s:%s]", accessory.displayName, accessory.context.type, accessory.context.channelCount); - } + this.internalHSBUpdate(accessory, "bri", value, callback); + } else { + this.internalLightbulbUpdate(accessory, false, callback); + } + }); + accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.Hue) + .on("set", (value, callback) => this.internalHSBUpdate(accessory, "hue", value, callback)); + accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.Saturation) + .on("set", (value, callback) => callback()); + } + break; + case "switch": + accessory + .getService(Service.Switch) + .getCharacteristic(Characteristic.On) + .on("set", (value, callback) => this.internalSwitchUpdate(accessory, value, callback)); + break; + case "rf_sub": + accessory.context.rfChls = accessory.context.rfChls || {}; + if (accessory.context.sensorType === "button") { + Object.entries(accessory.context.rfChls).forEach(([k, v]) => { + accessory.getService(v).updateCharacteristic(Characteristic.On, false); + accessory + .getService(v) + .getCharacteristic(Characteristic.On) + .on("set", (value, callback) => { + value ? this.internalRFDeviceUpdate(accessory, k, callback) : callback(); + }); + }); + } + break; + case "zb_sub": + if (accessory.context.eweUIID === 1770) { + accessory.log = this.log; + accessory.eveLogger = new EveHistoryService("weather", accessory, { + storage: "fs", + minutes: 5, + path: this.eveLogPath, + }); + corrInterval.setCorrectingInterval(() => { + let dataToAdd = { + time: Date.now(), + temp: accessory + .getService(Service.TemperatureSensor) + .getCharacteristic(Characteristic.CurrentTemperature).value, + humidity: accessory + .getService(Service.HumiditySensor) + .getCharacteristic(Characteristic.CurrentRelativeHumidity).value, + }; + accessory.eveLogger.addEntry(dataToAdd); + }, 300000); + } + break; + } + this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + } catch (err) { + this.log.warn("[%s] could not be refreshed as %s.", accessory.displayName, err); + } + } + refreshAccessory(accessory, newParams) { + switch (accessory.context.type) { + case "valve": + if (Object.keys(newParams).some(v => cns.devicesValveParams.includes(v)) && Array.isArray(newParams.switches)) { + this.externalValveUpdate(accessory, newParams); + } + return true; + case "blind": + if (Object.keys(newParams).some(v => cns.devicesBlindParams.includes(v)) && Array.isArray(newParams.switches)) { + this.externalBlindUpdate(accessory, newParams); + } + return true; + case "garage": + if ( + Object.keys(newParams).some(v => cns.devicesGarageParams.includes(v)) && + Array.isArray(newParams.switches) + ) { + this.externalGarageUpdate(accessory, newParams); + } + return true; + case "lock": + if (Object.keys(newParams).some(v => cns.devicesLockParams.includes(v))) { + this.externalLockUpdate(accessory, newParams); + } + return true; + case "sensor": + if (Object.keys(newParams).some(v => cns.devicesSensorParams.includes(v))) { + this.externalSensorUpdate(accessory, newParams); + } + return true; + case "fan": + if (Object.keys(newParams).some(v => cns.devicesFanParams.includes(v))) { + this.externalFanUpdate(accessory, newParams); + } + return true; + case "thermostat": + if (Object.keys(newParams).some(v => cns.devicesThermostatParams.includes(v))) { + this.externalThermostatUpdate(accessory, newParams); + } + return true; + case "outlet": + if (Object.keys(newParams).some(v => cns.devicesOutletParams.includes(v))) { + this.externalOutletUpdate(accessory, newParams); + } + return true; + case "usb": + if (Object.keys(newParams).some(v => cns.devicesUSBParams.includes(v)) && Array.isArray(newParams.switches)) { + this.externalUSBUpdate(accessory, newParams); + } + return true; + case "scm": + if (Object.keys(newParams).some(v => cns.devicesSCMParams.includes(v)) && Array.isArray(newParams.switches)) { + this.externalSCMUpdate(accessory, newParams); + } + return true; + case "light": + if ( + cns.devicesSingleSwitch.includes(accessory.context.eweUIID) && + cns.devicesSingleSwitchLight.includes(accessory.context.eweModel) + ) { + if (Object.keys(newParams).some(v => cns.devicesSingleSwitchLightParams.includes(v))) { + this.externalSingleLightUpdate(accessory, newParams); + } + } else if ( + cns.devicesMultiSwitch.includes(accessory.context.eweUIID) && + cns.devicesMultiSwitchLight.includes(accessory.context.eweModel) + ) { + if ( + Object.keys(newParams).some(v => cns.devicesMultiSwitchLightParams.includes(v)) && + Array.isArray(newParams.switches) + ) { + this.externalMultiLightUpdate(accessory, newParams); + } + } + return true; + case "switch": + if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID)) { + if (Object.keys(newParams).some(v => cns.devicesSingleSwitchParams.includes(v))) { + this.externalSingleSwitchUpdate(accessory, newParams); + } + } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID)) { + if ( + Object.keys(newParams).some(v => cns.devicesMultiSwitchParams.includes(v)) && + Array.isArray(newParams.switches) + ) { + this.externalMultiSwitchUpdate(accessory, newParams); + } + } + return true; + case "rf_pri": + if (Object.keys(newParams).some(v => cns.devicesRFBridgeParams.includes(v))) { + this.externalRFDeviceUpdate(accessory, newParams); + } + return true; + case "rf_sub": + case "zb_pri": + return true; + case "zb_sub": + if (Object.keys(newParams).some(v => cns.devicesZBBridgeParams.includes(v))) { + this.externalZBDeviceUpdate(accessory, newParams); + } + return true; + default: + return false; + } + } + removeAccessory(accessory) { + try { + this.devicesInHB.delete(accessory.context.hbDeviceId); + this.api.unregisterPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); + this.log("[%s] has been removed from Homebridge.", accessory.displayName); + } catch (err) { + this.log.warn("[%s] needed to be removed but couldn't as %s.", accessory.displayName, err); + } + } + sendDeviceUpdate(accessory, params, callback) { + let payload = { + apikey: accessory.context.eweApiKey, + deviceid: accessory.context.eweDeviceId, + params, + }; + let sendViaWS = () => { + if (accessory.context.reachableWAN) { + this.wsClient.sendUpdate(payload); + callback(); + } else { + this.log.error("[%s] could not be updated as it appears to be offline.", accessory.displayName); + callback("Device has failed to update"); + } + }; + if (cns.devicesNonLAN.includes(accessory.context.eweUIID) || !accessory.context.reachableLAN) { + sendViaWS(); + } else { + this.lanClient + .sendUpdate(payload) + .then(() => callback()) + .catch(err => { + if (this.debug) { + this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); + } + sendViaWS(); + }); + } + } + receiveDeviceUpdate(device) { + let accessory; + switch (device.action) { + case "sysmsg": + if ( + (accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0")) + ) { + let isX = accessory.context.hbDeviceId.substr(-1) === "X"; + if (device.params.updateSource === "WS") { + if (accessory.context.reachableWAN !== device.params.online) { + accessory.context.reachableWAN = device.params.online; + this.log( + "[%s] has been reported [%s] via [WS].", + accessory.displayName, + accessory.context.reachableWAN ? "online" : "offline" + ); + this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + if (accessory.context.reachableWAN) this.wsClient.requestUpdate(accessory); } else { - if (!(this.config.hideDevFromHB || "").includes(device.deviceid)) { - this.log.warn("[%s] Accessory received via %s update does not exist in Homebridge. If it's a new accessory please restart Homebridge so it is added.", device.deviceid, device.params.updateSource); - } + if (this.debug) { + this.log("[%s] Nothing to update from above WS message.", accessory.displayName); + } } - break; + } + if (!isX) { + for (let i = 1; i <= accessory.context.channelCount; i++) { + if (this.devicesInHB.has(device.deviceid + "SW" + i)) { + let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); + oAccessory.context.reachableWAN = device.params.online; + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); + } + } + } + } + break; + case "update": + if ( + (accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0")) + ) { + if (device.params.updateSource === "WS" && !accessory.context.reachableWAN) { + accessory.context.reachableWAN = true; + this.log("[%s] has been reported [online] via [WS].", accessory.displayName); + } + if (device.params.updateSource === "LAN" && !accessory.context.reachableLAN) { + accessory.context.reachableLAN = true; + this.log("[%s] has been reported [online] via [LAN].", accessory.displayName); + } + if (this.debug) { + this.log( + "[%s] externally updated from above %s message and will be refreshed.", + accessory.displayName, + device.params.updateSource + ); + } + if (!this.refreshAccessory(accessory, device.params)) { + this.log.warn( + "[%s] cannot be refreshed. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.). [debug:%s:%s]", + accessory.displayName, + accessory.context.type, + accessory.context.channelCount + ); + } + } else { + if (!(this.config.hideDevFromHB || "").includes(device.deviceid)) { + this.log.warn( + "[%s] Accessory received via %s update does not exist in Homebridge. If it's a new accessory please restart Homebridge so it is added.", + device.deviceid, + device.params.updateSource + ); + } + } + break; + } + } + internalValveUpdate(accessory, valve, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; } - } - internalValveUpdate(accessory, valve, value, callback) { - try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } - let params = {}; - accessory.getService(valve) - .updateCharacteristic(Characteristic.Active, value) - .updateCharacteristic(Characteristic.InUse, value); - switch (value) { - case 0: - accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, 0); - clearTimeout(accessory.getService(valve).timer); - break; - case 1: - let timer = accessory.getService(valve).getCharacteristic(Characteristic.SetDuration).value; - accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, timer); - accessory.getService(valve).timer = setTimeout(() => { - accessory.getService(valve).setCharacteristic(Characteristic.Active, 0); - }, (timer * 1000)); - break; - } - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; - switch (valve) { - case "Valve A": - params.switches[0].switch = value ? "on" : "off"; - params.switches[1].switch = accessory.getService("Valve B").getCharacteristic(Characteristic.Active).value ? "on" : "off"; - break; - case "Valve B": - params.switches[0].switch = accessory.getService("Valve A").getCharacteristic(Characteristic.Active).value ? "on" : "off"; - params.switches[1].switch = value ? "on" : "off"; - break; - default: - throw "unknown valve [" + valve + "]"; - } - params.switches[2].switch = "off"; - params.switches[3].switch = "off"; - this.sendDeviceUpdate(accessory, params, callback); - } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); - } - } - internalBlindUpdate(accessory, value, callback) { - try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } - let blindConfig; - if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; - } - if (blindConfig.type !== "blind" || !["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { - throw "improper configuration"; - } - let oldPos, params = {}; - value = value >= 50 ? 100 : 0; - oldPos = accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.PositionState).value; - if (value === oldPos * 100) { - accessory.getService(Service.WindowCovering) - .updateCharacteristic(Characteristic.TargetPosition, value) - .updateCharacteristic(Characteristic.PositionState, oldPos); - callback(); - return; - } - switch (blindConfig.setup) { + let params = {}; + accessory + .getService(valve) + .updateCharacteristic(Characteristic.Active, value) + .updateCharacteristic(Characteristic.InUse, value); + switch (value) { + case 0: + accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, 0); + clearTimeout(accessory.getService(valve).timer); + break; + case 1: + let timer = accessory.getService(valve).getCharacteristic(Characteristic.SetDuration).value; + accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, timer); + accessory.getService(valve).timer = setTimeout(() => { + accessory.getService(valve).setCharacteristic(Characteristic.Active, 0); + }, timer * 1000); + break; + } + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + switch (valve) { + case "Valve A": + params.switches[0].switch = value ? "on" : "off"; + params.switches[1].switch = accessory.getService("Valve B").getCharacteristic(Characteristic.Active).value + ? "on" + : "off"; + break; + case "Valve B": + params.switches[0].switch = accessory.getService("Valve A").getCharacteristic(Characteristic.Active).value + ? "on" + : "off"; + params.switches[1].switch = value ? "on" : "off"; + break; + default: + throw "unknown valve [" + valve + "]"; + } + params.switches[2].switch = "off"; + params.switches[3].switch = "off"; + this.sendDeviceUpdate(accessory, params, callback); + } catch (err) { + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + internalBlindUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let blindConfig; + if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; + } + if (blindConfig.type !== "blind" || !["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { + throw "improper configuration"; + } + let oldPos, + params = {}; + value = value >= 50 ? 100 : 0; + oldPos = accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.PositionState).value; + if (value === oldPos * 100) { + accessory + .getService(Service.WindowCovering) + .updateCharacteristic(Characteristic.TargetPosition, value) + .updateCharacteristic(Characteristic.PositionState, oldPos); + callback(); + return; + } + switch (blindConfig.setup) { + case "oneSwitch": + params.switch = "on"; + break; + case "twoSwitch": + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = value === 100 ? "on" : "off"; + params.switches[1].switch = value === 0 ? "on" : "off"; + break; + } + this.sendDeviceUpdate(accessory, params, function () { + return; + }); + accessory + .getService(Service.WindowCovering) + .updateCharacteristic(Characteristic.TargetPosition, value) + .updateCharacteristic(Characteristic.PositionState, value / 100); + setTimeout(() => { + accessory + .getService(Service.WindowCovering) + .updateCharacteristic(Characteristic.CurrentPosition, value) + .updateCharacteristic(Characteristic.PositionState, 2); + callback(); + }, parseInt(blindConfig.operationTime) * 100); + } catch (err) { + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + internalGarageUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let garageConfig; + if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; + } + if (garageConfig.type !== "garage" || !["oneSwitch", "twoSwitch"].includes(garageConfig.setup)) { + throw "improper configuration"; + } + accessory.context.inUse = true; + accessory.context.state = value; + let sensorDefinition = garageConfig.sensorId || false, + sAccessory = false, + oldPos, + newPos = value, + params = {}, + delay = 0; + if (sensorDefinition && !(sAccessory = this.devicesInHB.get(garageConfig.sensorId + "SWX"))) { + throw "defined DW2 sensor doesn't exist"; + } + if (sAccessory.context.type !== "sensor") { + throw "defined DW2 sensor isn't a sensor"; + } + oldPos = sAccessory + ? sAccessory.getService(Service.ContactSensor).getCharacteristic(Characteristic.ContactSensorState).value === 0 + ? 1 + : 0 + : accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.CurrentDoorState).value; + if (newPos === oldPos % 2) { + accessory.context.inUse = false; + callback(); + return; + } + if (garageConfig.setup === "oneSwitch" && [2, 3].includes(oldPos)) { + accessory + .getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.CurrentDoorState, ((oldPos * 2) % 3) + 2); + delay = 1500; + } + setTimeout(() => { + if (accessory.context.state === newPos) { + accessory + .getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.TargetDoorState, newPos) + .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2); + switch (garageConfig.setup) { case "oneSwitch": - params.switch = "on"; - break; + params.switch = "on"; + break; case "twoSwitch": - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = value === 100 ? "on" : "off"; - params.switches[1].switch = value === 0 ? "on" : "off"; - break; - } - this.sendDeviceUpdate(accessory, params, function() { - return; - }); - accessory.getService(Service.WindowCovering) - .updateCharacteristic(Characteristic.TargetPosition, value) - .updateCharacteristic(Characteristic.PositionState, (value / 100)); - setTimeout(() => { - accessory.getService(Service.WindowCovering) - .updateCharacteristic(Characteristic.CurrentPosition, value) - .updateCharacteristic(Characteristic.PositionState, 2); - callback(); - }, parseInt(blindConfig.operationTime) * 100); - } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); - } - } - internalGarageUpdate(accessory, value, callback) { - try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } - let garageConfig; - if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; - } - if (garageConfig.type !== "garage" || !["oneSwitch", "twoSwitch"].includes(garageConfig.setup)) { - throw "improper configuration"; - } - accessory.context.inUse = true; - accessory.context.state = value; - let sensorDefinition = garageConfig.sensorId || false, - sAccessory = false, - oldPos, - newPos = value, - params = {}, - delay = 0; - if (sensorDefinition && !(sAccessory = this.devicesInHB.get(garageConfig.sensorId + "SWX"))) { - throw "defined DW2 sensor doesn't exist"; - } - if (sAccessory.context.type !== "sensor") { - throw "defined DW2 sensor isn't a sensor"; - } - oldPos = sAccessory ? - sAccessory.getService(Service.ContactSensor).getCharacteristic(Characteristic.ContactSensorState).value === 0 ? 1 : 0 : - accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.CurrentDoorState).value; - if (newPos === (oldPos % 2)) { - accessory.context.inUse = false; - callback(); + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = newPos === 0 ? "on" : "off"; + params.switches[1].switch = newPos === 1 ? "on" : "off"; + break; + } + this.sendDeviceUpdate(accessory, params, function () { return; - } - if (garageConfig.setup === "oneSwitch" && [2, 3].includes(oldPos)) { - accessory.getService(Service.GarageDoorOpener).updateCharacteristic(Characteristic.CurrentDoorState, oldPos * 2 % 3 + 2); - delay = 1500; - } - setTimeout(() => { - if (accessory.context.state === newPos) { - accessory.getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.TargetDoorState, newPos) - .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2); - switch (garageConfig.setup) { - case "oneSwitch": - params.switch = "on"; - break; - case "twoSwitch": - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = newPos === 0 ? "on" : "off"; - params.switches[1].switch = newPos === 1 ? "on" : "off"; - break; - } - this.sendDeviceUpdate(accessory, params, function() { - return; - }); - setTimeout(() => { - if (!sAccessory) { - accessory.getService(Service.GarageDoorOpener).updateCharacteristic(Characteristic.CurrentDoorState, newPos); - } - accessory.context.inUse = false; - }, parseInt(garageConfig.operationTime) * 100); + }); + setTimeout(() => { + if (!sAccessory) { + accessory + .getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.CurrentDoorState, newPos); } - }, delay); - callback(); - } catch (err) { - accessory.context.inUse = false; - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); - } - } - internalLockUpdate(accessory, value, callback) { - try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } - let lockConfig, params = {}; - if (!(lockConfig = this.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; - } - if (lockConfig.type !== "lock") { - throw "improper configuration"; - } - accessory.context.inUse = true; - this.log("[%s] has received request to unlock.", accessory.displayName); - accessory.getService(Service.LockMechanism) - .updateCharacteristic(Characteristic.LockTargetState, 0) - .updateCharacteristic(Characteristic.LockCurrentState, 0); - params.switch = "on"; - this.sendDeviceUpdate(accessory, params, callback); - setTimeout(() => { - accessory.getService(Service.LockMechanism) - .updateCharacteristic(Characteristic.LockTargetState, 1) - .updateCharacteristic(Characteristic.LockCurrentState, 1); accessory.context.inUse = false; - }, parseInt(lockConfig.operationTime) * 100); - } catch (err) { - accessory.context.inUse = false; - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); - } - } - internalFanUpdate(accessory, type, value, callback) { - try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } - let newPower, newSpeed, newLight; - switch (type) { - case "power": - newPower = value; - newSpeed = value ? 33 : 0; - newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; - break; - case "speed": - newPower = value >= 33 ? 1 : 0; - newSpeed = value; - newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; - break; - case "light": - newPower = accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active).value; - newSpeed = accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.RotationSpeed).value; - newLight = value; - break; - } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, newLight); - accessory.getService(Service.Fanv2) - .updateCharacteristic(Characteristic.Active, newPower) - .updateCharacteristic(Characteristic.RotationSpeed, newSpeed); - let params = { - switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches - }; - params.switches[0].switch = newLight ? "on" : "off"; - params.switches[1].switch = (newPower === 1 && newSpeed >= 33) ? "on" : "off"; - params.switches[2].switch = (newPower === 1 && newSpeed >= 66 && newSpeed < 99) ? "on" : "off"; - params.switches[3].switch = (newPower === 1 && newSpeed >= 99) ? "on" : "off"; - if (this.debug) { - this.log.warn("Fan Update - setting " + type + " to " + value); - this.log("[%s] new stats: power [%s], speed [%s%], light [%s].", accessory.displayName, newPower, newSpeed, newLight); - } - this.sendDeviceUpdate(accessory, params, callback); - } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); - } - } - internalThermostatUpdate(accessory, value, callback) { - try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } - let params = { - switch: value ? "on" : "off", - mainSwitch: value ? "on" : "off" - }; - if (this.debug) { + }, parseInt(garageConfig.operationTime) * 100); + } + }, delay); + callback(); + } catch (err) { + accessory.context.inUse = false; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + internalLockUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let lockConfig, + params = {}; + if (!(lockConfig = this.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; + } + if (lockConfig.type !== "lock") { + throw "improper configuration"; + } + accessory.context.inUse = true; + this.log("[%s] has received request to unlock.", accessory.displayName); + accessory + .getService(Service.LockMechanism) + .updateCharacteristic(Characteristic.LockTargetState, 0) + .updateCharacteristic(Characteristic.LockCurrentState, 0); + params.switch = "on"; + this.sendDeviceUpdate(accessory, params, callback); + setTimeout(() => { + accessory + .getService(Service.LockMechanism) + .updateCharacteristic(Characteristic.LockTargetState, 1) + .updateCharacteristic(Characteristic.LockCurrentState, 1); + accessory.context.inUse = false; + }, parseInt(lockConfig.operationTime) * 100); + } catch (err) { + accessory.context.inUse = false; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + internalFanUpdate(accessory, type, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let newPower, newSpeed, newLight; + switch (type) { + case "power": + newPower = value; + newSpeed = value ? 33 : 0; + newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; + break; + case "speed": + newPower = value >= 33 ? 1 : 0; + newSpeed = value; + newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; + break; + case "light": + newPower = accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active).value; + newSpeed = accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.RotationSpeed).value; + newLight = value; + break; + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, newLight); + accessory + .getService(Service.Fanv2) + .updateCharacteristic(Characteristic.Active, newPower) + .updateCharacteristic(Characteristic.RotationSpeed, newSpeed); + let params = { + switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches, + }; + params.switches[0].switch = newLight ? "on" : "off"; + params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? "on" : "off"; + params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? "on" : "off"; + params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? "on" : "off"; + if (this.debug) { + this.log.warn("Fan Update - setting " + type + " to " + value); + this.log( + "[%s] new stats: power [%s], speed [%s%], light [%s].", + accessory.displayName, + newPower, + newSpeed, + newLight + ); + } + this.sendDeviceUpdate(accessory, params, callback); + } catch (err) { + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + internalThermostatUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let params = { + switch: value ? "on" : "off", + mainSwitch: value ? "on" : "off", + }; + if (this.debug) { + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + this.sendDeviceUpdate(accessory, params, callback); + } catch (err) { + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + internalOutletUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let params = { + switch: value ? "on" : "off", + }; + if (this.debug) { + this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); + this.sendDeviceUpdate(accessory, params, callback); + } catch (err) { + callback("[" + accessory.displayName + "] " + err + "."); + } + } + internalUSBUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let params = { + switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches, + }; + params.switches[0].switch = value ? "on" : "off"; + if (this.debug) { + this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); + this.sendDeviceUpdate(accessory, params, callback); + } catch (err) { + callback("[" + accessory.displayName + "] " + err + "."); + } + } + internalSCMUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let params = { + switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches, + }; + params.switches[0].switch = value ? "on" : "off"; + if (this.debug) { + this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + this.sendDeviceUpdate(accessory, params, callback); + } catch (err) { + callback("[" + accessory.displayName + "] " + err + "."); + } + } + internalLightbulbUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let oAccessory, + params = {}; + switch (accessory.context.switchNumber) { + case "X": + if (accessory.context.eweUIID === 22) { + //*** B1 ***\\ + params.state = value ? "on" : "off"; + } else { + params.switch = value ? "on" : "off"; + } + if (this.debug) { this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); - this.sendDeviceUpdate(accessory, params, callback); - } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); - } - } - internalOutletUpdate(accessory, value, callback) { - try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } - let params = { - switch: value ? "on" : "off" - }; - if (this.debug) { - this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); - this.sendDeviceUpdate(accessory, params, callback); - } catch (err) { - callback("[" + accessory.displayName + "] " + err + "."); - } - } - internalUSBUpdate(accessory, value, callback) { - try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } - let params = { - switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches - }; - params.switches[0].switch = value ? "on" : "off"; - if (this.debug) { - this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); - this.sendDeviceUpdate(accessory, params, callback); - } catch (err) { - callback("[" + accessory.displayName + "] " + err + "."); - } - } - internalSCMUpdate(accessory, value, callback) { - try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } - let params = { - switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches - }; - params.switches[0].switch = value ? "on" : "off"; - if (this.debug) { - this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); - this.sendDeviceUpdate(accessory, params, callback); - } catch (err) { - callback("[" + accessory.displayName + "] " + err + "."); - } - } - internalLightbulbUpdate(accessory, value, callback) { - try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } - let oAccessory, params = {}; - switch (accessory.context.switchNumber) { - case "X": - if (accessory.context.eweUIID === 22) { //*** B1 ***\\ - params.state = value ? "on" : "off"; - } else { - params.switch = value ? "on" : "off"; - } - if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); - break; - case "0": - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = value ? "on" : "off"; - params.switches[1].switch = value ? "on" : "off"; - params.switches[2].switch = value ? "on" : "off"; - params.switches[3].switch = value ? "on" : "off"; - if (this.debug) { - this.log("[%s] updating to turn group [%s].", accessory.displayName, value ? "on" : "off"); - } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); - for (let i = 1; i <= 4; i++) { - if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); - oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); - } - } - break; - case "1": - case "2": - case "3": - case "4": - if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); - let tAccessory, - masterState = "off"; - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; - for (let i = 1; i <= 4; i++) { - if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - i === parseInt(accessory.context.switchNumber) ? - params.switches[i - 1].switch = value ? "on" : "off" : - params.switches[i - 1].switch = tAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value ? "on" : "off"; - if (tAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { - masterState = "on"; - } - } else { - params.switches[i - 1].switch = "off"; - } - } - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, masterState === "on"); - break; - default: - throw "unknown switch number [" + accessory.context.switchNumber + "]"; - } - this.sendDeviceUpdate(accessory, params, callback); - } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); - } - } - internalBrightnessUpdate(accessory, value, callback) { - try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } - let params = {}; - if (value === 0) { - params.switch = "off"; - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, false); - } else { - if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { - params.switch = "on"; + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + break; + case "0": + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = value ? "on" : "off"; + params.switches[1].switch = value ? "on" : "off"; + params.switches[2].switch = value ? "on" : "off"; + params.switches[3].switch = value ? "on" : "off"; + if (this.debug) { + this.log("[%s] updating to turn group [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + for (let i = 1; i <= 4; i++) { + if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); + oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); } - switch (accessory.context.eweUIID) { - case 36: //*** KING-M4 ***\\ - params.bright = Math.round(value * 9 / 10 + 10); - break; - case 44: //*** D1 ***\\ - params.brightness = value; - params.mode = 0; - break; - default: - throw "unknown device UIID"; + } + break; + case "1": + case "2": + case "3": + case "4": + if (this.debug) { + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + let tAccessory, + masterState = "off"; + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + for (let i = 1; i <= 4; i++) { + if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + i === parseInt(accessory.context.switchNumber) + ? (params.switches[i - 1].switch = value ? "on" : "off") + : (params.switches[i - 1].switch = tAccessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On).value + ? "on" + : "off"); + if (tAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + masterState = "on"; + } + } else { + params.switches[i - 1].switch = "off"; } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, value); - } - if (this.debug) { - this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); - } - setTimeout(() => this.sendDeviceUpdate(accessory, params, callback), 250); - } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); - } - } - internalHSBUpdate(accessory, type, value, callback) { - try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } - let newRGB, - params = {}, - curHue = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Hue).value, - curSat = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Saturation).value; - switch (type) { - case "hue": - newRGB = convert.hsv.rgb(value, curSat, 100); - switch (accessory.context.eweUIID) { - case 22: //*** B1 ***\\ - params = { - zyx_mode: 2, - type: "middle", - channel0: "0", - channel1: "0", - channel2: newRGB[0].toString(), - channel3: newRGB[1].toString(), - channel4: newRGB[2].toString() - }; - break; - case 59: //*** L1 ***\\ - params = { - mode: 1, - colorR: newRGB[0], - colorG: newRGB[1], - colorB: newRGB[2] - }; - break; - default: - throw "unknown device UIID"; - } - if (this.debug) { - this.log("[%s] updating hue to [%s°].", accessory.displayName, value); - } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Hue, value); - break; - case "bri": - switch (accessory.context.eweUIID) { - case 22: //*** B1 ***\\ - newRGB = convert.hsv.rgb(curHue, curSat, value); - params = { - zyx_mode: 2, - type: "middle", - channel0: "0", - channel1: "0", - channel2: newRGB[0].toString(), - channel3: newRGB[1].toString(), - channel4: newRGB[2].toString() - }; - break; - case 59: //*** L1 ***\\ - params = { - mode: 1, - bright: value - }; - break; - } - if (this.debug) { - this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); - } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, value); - break; - default: - throw "unknown device UIID"; - } - setTimeout(() => this.sendDeviceUpdate(accessory, params, callback), 250); - } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); - } - } - internalSwitchUpdate(accessory, value, callback) { - try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } - let oAccessory, params = {}; - switch (accessory.context.switchNumber) { - case "X": - params.switch = value ? "on" : "off"; - if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); - break; - case "0": - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = value ? "on" : "off"; - params.switches[1].switch = value ? "on" : "off"; - params.switches[2].switch = value ? "on" : "off"; - params.switches[3].switch = value ? "on" : "off"; - if (this.debug) { - this.log("[%s] updating to turn group [%s].", accessory.displayName, value ? "on" : "off"); - } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); - for (let i = 1; i <= 4; i++) { - if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); - oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); - } - } - break; - case "1": - case "2": - case "3": - case "4": - if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); - let tAccessory, - masterState = "off"; - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; - for (let i = 1; i <= 4; i++) { - if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - i === parseInt(accessory.context.switchNumber) ? - params.switches[i - 1].switch = value ? "on" : "off" : - params.switches[i - 1].switch = tAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value ? "on" : "off"; - if (tAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value) { - masterState = "on"; - } - } else { - params.switches[i - 1].switch = "off"; - } - } - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, masterState === "on"); - break; + } + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); + oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, masterState === "on"); + break; + default: + throw "unknown switch number [" + accessory.context.switchNumber + "]"; + } + this.sendDeviceUpdate(accessory, params, callback); + } catch (err) { + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + internalBrightnessUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let params = {}; + if (value === 0) { + params.switch = "off"; + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, false); + } else { + if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + params.switch = "on"; + } + switch (accessory.context.eweUIID) { + case 36: //*** KING-M4 ***\\ + params.bright = Math.round((value * 9) / 10 + 10); + break; + case 44: //*** D1 ***\\ + params.brightness = value; + params.mode = 0; + break; + default: + throw "unknown device UIID"; + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, value); + } + if (this.debug) { + this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); + } + setTimeout(() => this.sendDeviceUpdate(accessory, params, callback), 250); + } catch (err) { + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + internalHSBUpdate(accessory, type, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let newRGB, + params = {}, + curHue = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Hue).value, + curSat = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Saturation).value; + switch (type) { + case "hue": + newRGB = convert.hsv.rgb(value, curSat, 100); + switch (accessory.context.eweUIID) { + case 22: //*** B1 ***\\ + params = { + zyx_mode: 2, + type: "middle", + channel0: "0", + channel1: "0", + channel2: newRGB[0].toString(), + channel3: newRGB[1].toString(), + channel4: newRGB[2].toString(), + }; + break; + case 59: //*** L1 ***\\ + params = { + mode: 1, + colorR: newRGB[0], + colorG: newRGB[1], + colorB: newRGB[2], + }; + break; default: - throw "unknown switch number [" + accessory.context.switchNumber + "]"; - } - this.sendDeviceUpdate(accessory, params, callback); - } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); - } - } - internalRFDeviceUpdate(accessory, rfChl, callback) { - try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } - rfChl = parseInt(rfChl); - let params = { - cmd: "transmit", - rfChl - }; - if (this.debug) { - this.log("[%s %s] mimicking RF button press.", accessory.displayName, accessory.context.rfChls[rfChl]); - } - accessory.getService(accessory.context.rfChls[rfChl]).updateCharacteristic(Characteristic.On, true); - this.sendDeviceUpdate(accessory, params, callback); - setTimeout(() => accessory.getService(accessory.context.rfChls[rfChl]).updateCharacteristic(Characteristic.On, false), 3000); - } catch (err) { - let str = "[" + accessory.displayName + " " + name + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); - } - } - externalValveUpdate(accessory, params) { - try { - ["A", "B"].forEach((v, k) => { - accessory.getService("Valve " + v) - .updateCharacteristic(Characteristic.Active, params.switches[k].switch === "on") - .updateCharacteristic(Characteristic.InUse, params.switches[k].switch === "on"); - if (params.switches[k].switch === "on") { - let timer = accessory.getService("Valve " + v).getCharacteristic(Characteristic.SetDuration).value; - accessory.getService("Valve " + v).updateCharacteristic(Characteristic.RemainingDuration, timer); - accessory.getService("Valve " + v).timer = setTimeout(() => { - accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); - }, (timer * 1000)); + throw "unknown device UIID"; + } + if (this.debug) { + this.log("[%s] updating hue to [%s°].", accessory.displayName, value); + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Hue, value); + break; + case "bri": + switch (accessory.context.eweUIID) { + case 22: //*** B1 ***\\ + newRGB = convert.hsv.rgb(curHue, curSat, value); + params = { + zyx_mode: 2, + type: "middle", + channel0: "0", + channel1: "0", + channel2: newRGB[0].toString(), + channel3: newRGB[1].toString(), + channel4: newRGB[2].toString(), + }; + break; + case 59: //*** L1 ***\\ + params = { + mode: 1, + bright: value, + }; + break; + } + if (this.debug) { + this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, value); + break; + default: + throw "unknown device UIID"; + } + setTimeout(() => this.sendDeviceUpdate(accessory, params, callback), 250); + } catch (err) { + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + internalSwitchUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let oAccessory, + params = {}; + switch (accessory.context.switchNumber) { + case "X": + params.switch = value ? "on" : "off"; + if (this.debug) { + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + break; + case "0": + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = value ? "on" : "off"; + params.switches[1].switch = value ? "on" : "off"; + params.switches[2].switch = value ? "on" : "off"; + params.switches[3].switch = value ? "on" : "off"; + if (this.debug) { + this.log("[%s] updating to turn group [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + for (let i = 1; i <= 4; i++) { + if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); + oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + } + } + break; + case "1": + case "2": + case "3": + case "4": + if (this.debug) { + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + } + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + let tAccessory, + masterState = "off"; + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + for (let i = 1; i <= 4; i++) { + if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + i === parseInt(accessory.context.switchNumber) + ? (params.switches[i - 1].switch = value ? "on" : "off") + : (params.switches[i - 1].switch = tAccessory + .getService(Service.Switch) + .getCharacteristic(Characteristic.On).value + ? "on" + : "off"); + if (tAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value) { + masterState = "on"; + } } else { - accessory.getService("Valve " + v).updateCharacteristic(Characteristic.RemainingDuration, 0); - clearTimeout(accessory.getService("Valve " + v).timer); + params.switches[i - 1].switch = "off"; } - }); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalBlindUpdate(accessory, params) { - try { - let blindConfig, nSte; - if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; - } - if (blindConfig.type !== "blind" || ["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { - throw "improper configuration"; - } - switch (blindConfig.setup) { - case "oneSwitch": - if (params.switch === "off") { - return; - } - nSte = accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.PositionState).value === 0 ? 1 : 0; - break; - case "twoSwitch": - if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { - return; - } - let switchUp = params.switches[0].switch === "on" ? -1 : 0, // matrix of numbers to get - switchDown = params.switches[1].switch === "on" ? 0 : 2; // ... the correct HomeKit value - nSte = switchUp + switchDown; - break; - } - accessory.getService(Service.WindowCovering) - .updateCharacteristic(Characteristic.PositionState, nSte) - .updateCharacteristic(Characteristic.TargetPosition, nSte * 100); - setTimeout(() => { - accessory.getService(Service.WindowCovering) - .updateCharacteristic(Characteristic.PositionState, 2) - .updateCharacteristic(Characteristic.CurrentPosition, nSte * 100); - }, parseInt(blindConfig.operationTime) * 100); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalGarageUpdate(accessory, params) { - try { - let garageConfig, - oldPos = accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.CurrentDoorState).value, - newPos = [0, 2].includes(oldPos) ? 3 : 2; - if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; - } - if (garageConfig.type !== "garage" || !["oneSwitch", "twoSwitch"].includes(garageConfig.setup)) { - throw "improper configuration"; - } - if (accessory.context.inUse || garageConfig.sensorId) { + } + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); + oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, masterState === "on"); + break; + default: + throw "unknown switch number [" + accessory.context.switchNumber + "]"; + } + this.sendDeviceUpdate(accessory, params, callback); + } catch (err) { + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + internalRFDeviceUpdate(accessory, rfChl, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + rfChl = parseInt(rfChl); + let params = { + cmd: "transmit", + rfChl, + }; + if (this.debug) { + this.log("[%s %s] mimicking RF button press.", accessory.displayName, accessory.context.rfChls[rfChl]); + } + accessory.getService(accessory.context.rfChls[rfChl]).updateCharacteristic(Characteristic.On, true); + this.sendDeviceUpdate(accessory, params, callback); + setTimeout( + () => accessory.getService(accessory.context.rfChls[rfChl]).updateCharacteristic(Characteristic.On, false), + 3000 + ); + } catch (err) { + let str = "[" + accessory.displayName + " " + name + "] could not be updated as " + err + "."; + this.log.error(str); + callback(str); + } + } + externalValveUpdate(accessory, params) { + try { + ["A", "B"].forEach((v, k) => { + accessory + .getService("Valve " + v) + .updateCharacteristic(Characteristic.Active, params.switches[k].switch === "on") + .updateCharacteristic(Characteristic.InUse, params.switches[k].switch === "on"); + if (params.switches[k].switch === "on") { + let timer = accessory.getService("Valve " + v).getCharacteristic(Characteristic.SetDuration).value; + accessory.getService("Valve " + v).updateCharacteristic(Characteristic.RemainingDuration, timer); + accessory.getService("Valve " + v).timer = setTimeout(() => { + accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); + }, timer * 1000); + } else { + accessory.getService("Valve " + v).updateCharacteristic(Characteristic.RemainingDuration, 0); + clearTimeout(accessory.getService("Valve " + v).timer); + } + }); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } + externalBlindUpdate(accessory, params) { + try { + let blindConfig, nSte; + if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; + } + if (blindConfig.type !== "blind" || ["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { + throw "improper configuration"; + } + switch (blindConfig.setup) { + case "oneSwitch": + if (params.switch === "off") { return; - } - switch (garageConfig.setup) { - case "oneSwitch": - if (params.switch === "off") { - return; - } - break; - case "twoSwitch": - if (params.switches[0].switch === params.switches[1].switch || params.switches[oldPos % 2].switch === "on") { - return; - } - break; - } - accessory.context.inUse = true; - if (!garageConfig.sensorId) { - accessory.getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.CurrentDoorState, newPos) - .updateCharacteristic(Characteristic.TargetDoorState, newPos - 2); - setTimeout(() => { - accessory.getService(Service.GarageDoorOpener).updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2); - }, parseInt(garageConfig.operationTime) * 100); - } - setTimeout(() => { - accessory.context.inUse = false; - }, parseInt(garageConfig.operationTime) * 100); - } catch (err) { - accessory.context.inUse = false; - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalLockUpdate(accessory, params) { - try { - let lockConfig; - if (!(lockConfig = this.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; - } - if (lockConfig.type !== "lock") { - throw "improper configuration"; - } - if (params.switch === "off" || accessory.context.inUse) { + } + nSte = + accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.PositionState).value === 0 + ? 1 + : 0; + break; + case "twoSwitch": + if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { return; - } - accessory.context.inUse = true; - accessory.getService(Service.LockMechanism) - .updateCharacteristic(Characteristic.LockCurrentState, 0) - .updateCharacteristic(Characteristic.LockTargetState, 0); - setTimeout(() => { - accessory.getService(Service.LockMechanism) - .updateCharacteristic(Characteristic.LockCurrentState, 1) - .updateCharacteristic(Characteristic.LockTargetState, 1); - accessory.context.inUse = false; - }, parseInt(lockConfig.operationTime) * 100); - } catch (err) { - accessory.context.inUse = false; - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalSensorUpdate(accessory, params) { - try { - let newState = params.switch === "on" ? 1 : 0, - oAccessory = false; - accessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, newState); - if (params.hasOwnProperty("battery")) { - let batteryService = accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); - batteryService.updateCharacteristic(Characteristic.BatteryLevel, params.battery); - batteryService.updateCharacteristic(Characteristic.StatusLowBattery, params.battery <= 25); - } - this.cusG.forEach(group => { - if (group.sensorId === accessory.context.eweDeviceId && group.type === "garage") { - if ((oAccessory = this.devicesInHB.get(group.deviceId + "SWX"))) { - switch (newState) { - case 0: - oAccessory.getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.TargetDoorState, 1) - .updateCharacteristic(Characteristic.CurrentDoorState, 1); - break; - case 1: - setTimeout(() => { - oAccessory.getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.TargetDoorState, 0) - .updateCharacteristic(Characteristic.CurrentDoorState, 0); - }, group.operationTime * 100); - break; - default: - throw "unknown sensor status received [" + newState + "]"; - } - } + } + let switchUp = params.switches[0].switch === "on" ? -1 : 0, // matrix of numbers to get + switchDown = params.switches[1].switch === "on" ? 0 : 2; // ... the correct HomeKit value + nSte = switchUp + switchDown; + break; + } + accessory + .getService(Service.WindowCovering) + .updateCharacteristic(Characteristic.PositionState, nSte) + .updateCharacteristic(Characteristic.TargetPosition, nSte * 100); + setTimeout(() => { + accessory + .getService(Service.WindowCovering) + .updateCharacteristic(Characteristic.PositionState, 2) + .updateCharacteristic(Characteristic.CurrentPosition, nSte * 100); + }, parseInt(blindConfig.operationTime) * 100); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } + externalGarageUpdate(accessory, params) { + try { + let garageConfig, + oldPos = accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.CurrentDoorState) + .value, + newPos = [0, 2].includes(oldPos) ? 3 : 2; + if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; + } + if (garageConfig.type !== "garage" || !["oneSwitch", "twoSwitch"].includes(garageConfig.setup)) { + throw "improper configuration"; + } + if (accessory.context.inUse || garageConfig.sensorId) { + return; + } + switch (garageConfig.setup) { + case "oneSwitch": + if (params.switch === "off") { + return; + } + break; + case "twoSwitch": + if (params.switches[0].switch === params.switches[1].switch || params.switches[oldPos % 2].switch === "on") { + return; + } + break; + } + accessory.context.inUse = true; + if (!garageConfig.sensorId) { + accessory + .getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.CurrentDoorState, newPos) + .updateCharacteristic(Characteristic.TargetDoorState, newPos - 2); + setTimeout(() => { + accessory + .getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2); + }, parseInt(garageConfig.operationTime) * 100); + } + setTimeout(() => { + accessory.context.inUse = false; + }, parseInt(garageConfig.operationTime) * 100); + } catch (err) { + accessory.context.inUse = false; + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } + externalLockUpdate(accessory, params) { + try { + let lockConfig; + if (!(lockConfig = this.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; + } + if (lockConfig.type !== "lock") { + throw "improper configuration"; + } + if (params.switch === "off" || accessory.context.inUse) { + return; + } + accessory.context.inUse = true; + accessory + .getService(Service.LockMechanism) + .updateCharacteristic(Characteristic.LockCurrentState, 0) + .updateCharacteristic(Characteristic.LockTargetState, 0); + setTimeout(() => { + accessory + .getService(Service.LockMechanism) + .updateCharacteristic(Characteristic.LockCurrentState, 1) + .updateCharacteristic(Characteristic.LockTargetState, 1); + accessory.context.inUse = false; + }, parseInt(lockConfig.operationTime) * 100); + } catch (err) { + accessory.context.inUse = false; + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } + externalSensorUpdate(accessory, params) { + try { + let newState = params.switch === "on" ? 1 : 0, + oAccessory = false; + accessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, newState); + if (params.hasOwnProperty("battery")) { + let batteryService = + accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); + batteryService.updateCharacteristic(Characteristic.BatteryLevel, params.battery); + batteryService.updateCharacteristic(Characteristic.StatusLowBattery, params.battery <= 25); + } + this.cusG.forEach(group => { + if (group.sensorId === accessory.context.eweDeviceId && group.type === "garage") { + if ((oAccessory = this.devicesInHB.get(group.deviceId + "SWX"))) { + switch (newState) { + case 0: + oAccessory + .getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.TargetDoorState, 1) + .updateCharacteristic(Characteristic.CurrentDoorState, 1); + break; + case 1: + setTimeout(() => { + oAccessory + .getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.TargetDoorState, 0) + .updateCharacteristic(Characteristic.CurrentDoorState, 0); + }, group.operationTime * 100); + break; + default: + throw "unknown sensor status received [" + newState + "]"; } - }); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalFanUpdate(accessory, params) { - try { - let light, status, speed; - if (Array.isArray(params.switches)) { - light = params.switches[0].switch === "on"; - switch (params.switches[1].switch+params.switches[2].switch+params.switches[3].switch) { - default: - status = 0; - speed = 0; - break; - case "onoffoff": - status = 1; - speed = 33; - break; - case "ononoff": - status = 1; - speed = 66; - break; - case "onoffon": - status = 1; - speed = 99; + } + } + }); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } + externalFanUpdate(accessory, params) { + try { + let light, status, speed; + if (Array.isArray(params.switches)) { + light = params.switches[0].switch === "on"; + switch (params.switches[1].switch + params.switches[2].switch + params.switches[3].switch) { + default: + status = 0; + speed = 0; + break; + case "onoffoff": + status = 1; + speed = 33; + break; + case "ononoff": + status = 1; + speed = 66; + break; + case "onoffon": + status = 1; + speed = 99; + } + } else if (params.hasOwnProperty("light") && params.hasOwnProperty("fan") && params.hasOwnProperty("speed")) { + light = params.light === "on"; + status = params.fan === "on" ? 1 : 0; + speed = params.speed * 33 * status; + } else { + throw "unknown parameters received"; + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, light); + accessory + .getService(Service.Fanv2) + .updateCharacteristic(Characteristic.Active, status) + .updateCharacteristic(Characteristic.RotationSpeed, speed); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } + externalThermostatUpdate(accessory, params) { + try { + if (!this.config.hideTHSwitch && (params.hasOwnProperty("switch") || params.hasOwnProperty("mainSwitch"))) { + let newState = params.hasOwnProperty("switch") ? params.switch === "on" : params.mainSwitch === "on"; + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, newState); + } + let eveLog = { + time: Date.now(), + }; + if (params.hasOwnProperty("currentTemperature") && accessory.getService(Service.TemperatureSensor)) { + let currentTemp = params.currentTemperature !== "unavailable" ? params.currentTemperature : 0; + accessory + .getService(Service.TemperatureSensor) + .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); + eveLog.temp = parseFloat(currentTemp); + } + if (params.hasOwnProperty("currentHumidity") && accessory.getService(Service.HumiditySensor)) { + let currentHumi = params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; + accessory + .getService(Service.HumiditySensor) + .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); + eveLog.humidity = parseFloat(currentHumi); + } + if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { + accessory.eveLogger.addEntry(eveLog); + } + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } + externalOutletUpdate(accessory, params) { + try { + if (params.hasOwnProperty("switch")) { + accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switch === "on"); + } + if (params.hasOwnProperty("power")) { + accessory + .getService(Service.Outlet) + .updateCharacteristic(EveService.Characteristics.CurrentConsumption, parseFloat(params.power)); + accessory + .getService(Service.Outlet) + .updateCharacteristic(Characteristic.OutletInUse, parseFloat(params.power) > 0); + let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value; + accessory.eveLogger.addEntry({ + time: Date.now(), + power: isOn ? parseFloat(params.power) : 0, + }); + } + if (params.hasOwnProperty("voltage")) { + accessory + .getService(Service.Outlet) + .updateCharacteristic(EveService.Characteristics.Voltage, parseFloat(params.voltage)); + } + if (params.hasOwnProperty("current")) { + accessory + .getService(Service.Outlet) + .updateCharacteristic(EveService.Characteristics.ElectricCurrent, parseFloat(params.current)); + } + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } + externalUSBUpdate(accessory, params) { + try { + accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } + externalSCMUpdate(accessory, params) { + try { + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } + externalSingleLightUpdate(accessory, params) { + try { + let newColour, + mode, + isOn = false; + if (accessory.context.eweUIID === 22 && params.hasOwnProperty("state")) { + isOn = params.state === "on"; + } else if (accessory.context.eweUIID !== 22 && params.hasOwnProperty("switch")) { + isOn = params.switch === "on"; + } else { + isOn = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; + } + if (isOn) { + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, true); + switch (accessory.context.eweUIID) { + case 36: // KING-M4 + if (params.hasOwnProperty("bright")) { + let nb = Math.round(((params.bright - 10) * 10) / 9); // eWeLink scale is 10-100 and HomeKit scale is 0-100. + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, nb); } - } else if (params.hasOwnProperty("light") && params.hasOwnProperty("fan") && params.hasOwnProperty("speed")) { - light = params.light === "on"; - status = params.fan === "on" ? 1 : 0; - speed = params.speed * 33 * status; - } else { - throw "unknown parameters received"; - } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, light); - accessory.getService(Service.Fanv2) - .updateCharacteristic(Characteristic.Active, status) - .updateCharacteristic(Characteristic.RotationSpeed, speed); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalThermostatUpdate(accessory, params) { - try { - if (!this.config.hideTHSwitch && (params.hasOwnProperty("switch") || params.hasOwnProperty("mainSwitch"))) { - let newState = params.hasOwnProperty("switch") ? params.switch === "on" : params.mainSwitch === "on"; - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, newState); - } - let eveLog = { - time: Date.now() - }; - if (params.hasOwnProperty("currentTemperature") && accessory.getService(Service.TemperatureSensor)) { - let currentTemp = params.currentTemperature !== "unavailable" ? params.currentTemperature : 0; - accessory.getService(Service.TemperatureSensor).updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); - eveLog.temp = parseFloat(currentTemp); - } - if (params.hasOwnProperty("currentHumidity") && accessory.getService(Service.HumiditySensor)) { - let currentHumi = params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; - accessory.getService(Service.HumiditySensor).updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); - eveLog.humidity = parseFloat(currentHumi); - } - if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { - accessory.eveLogger.addEntry(eveLog); - } - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalOutletUpdate(accessory, params) { - try { - if (params.hasOwnProperty("switch")) { - accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switch === "on"); - } - if (params.hasOwnProperty("power")) { - accessory.getService(Service.Outlet).updateCharacteristic(EveService.Characteristics.CurrentConsumption, parseFloat(params.power)); - accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.OutletInUse, parseFloat(params.power) > 0); - let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value; - accessory.eveLogger.addEntry({ - time: Date.now(), - power: isOn ? parseFloat(params.power) : 0 - }); - } - if (params.hasOwnProperty("voltage")) { - accessory.getService(Service.Outlet).updateCharacteristic(EveService.Characteristics.Voltage, parseFloat(params.voltage)); - } - if (params.hasOwnProperty("current")) { - accessory.getService(Service.Outlet).updateCharacteristic(EveService.Characteristics.ElectricCurrent, parseFloat(params.current)); - } - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalUSBUpdate(accessory, params) { - try { - accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalSCMUpdate(accessory, params) { - try { - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalSingleLightUpdate(accessory, params) { - try { - let newColour, mode, isOn = false; - if (accessory.context.eweUIID === 22 && params.hasOwnProperty("state")) { - isOn = params.state === "on"; - } else if (accessory.context.eweUIID !== 22 && params.hasOwnProperty("switch")) { - isOn = params.switch === "on"; - } else { - isOn = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; - } - if (isOn) { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, true); - switch (accessory.context.eweUIID) { - case 36: // KING-M4 - if (params.hasOwnProperty("bright")) { - let nb = Math.round((params.bright - 10) * 10 / 9); // eWeLink scale is 10-100 and HomeKit scale is 0-100. - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, nb); - } - break; - case 44: // D1 - if (params.hasOwnProperty("brightness")) { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, params.brightness); - } - break; - case 22: // B1 - if (params.hasOwnProperty("zyx_mode")) { - mode = parseInt(params.zyx_mode); - } else if (params.hasOwnProperty("channel0") && (parseInt(params.channel0) + parseInt(params.channel1) > 0)) { - mode = 1; - } else { - mode = 2; - } - if (mode === 2) { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, true); - newColour = convert.rgb.hsv(parseInt(params.channel2), parseInt(params.channel3), parseInt(params.channel4)); - accessory.getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.Hue, newColour[0]) - .updateCharacteristic(Characteristic.Saturation, 100) - .updateCharacteristic(Characteristic.Brightness, 100); - } else if (mode === 1) { - throw "has been set to white mode which is not supported"; - } - break; - case 59: // L1 - if (params.hasOwnProperty("bright")) { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, params.bright); - } - if (params.hasOwnProperty("colorR")) { - newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB); - accessory.getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.Hue, newColour[0]) - .updateCharacteristic(Characteristic.Saturation, newColour[1]); - } - break; - default: - return; + break; + case 44: // D1 + if (params.hasOwnProperty("brightness")) { + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.Brightness, params.brightness); } - } else { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, false); - } - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalMultiLightUpdate(accessory, params) { - try { - let idToCheck = accessory.context.hbDeviceId.slice(0, -1), - primaryState = false; - for (let i = 1; i <= accessory.context.channelCount; i++) { - if (this.devicesInHB.has(idToCheck + i)) { - let oAccessory = this.devicesInHB.get(idToCheck + i); - oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); - if (params.switches[i - 1].switch === "on") { - primaryState = true; - } + break; + case 22: // B1 + if (params.hasOwnProperty("zyx_mode")) { + mode = parseInt(params.zyx_mode); + } else if (params.hasOwnProperty("channel0") && parseInt(params.channel0) + parseInt(params.channel1) > 0) { + mode = 1; + } else { + mode = 2; } - } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, primaryState); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalSingleSwitchUpdate(accessory, params) { - try { - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switch === "on"); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalMultiSwitchUpdate(accessory, params) { - try { - let idToCheck = accessory.context.hbDeviceId.slice(0, -1), - primaryState = false; - for (let i = 1; i <= accessory.context.channelCount; i++) { - if (this.devicesInHB.has(idToCheck + i)) { - let oAccessory = this.devicesInHB.get(idToCheck + i); - oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); - if (params.switches[i - 1].switch === "on") { - primaryState = true; - } + if (mode === 2) { + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, true); + newColour = convert.rgb.hsv( + parseInt(params.channel2), + parseInt(params.channel3), + parseInt(params.channel4) + ); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.Hue, newColour[0]) + .updateCharacteristic(Characteristic.Saturation, 100) + .updateCharacteristic(Characteristic.Brightness, 100); + } else if (mode === 1) { + throw "has been set to white mode which is not supported"; } - } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalRFDeviceUpdate(accessory, params) { - try { - if (!params.hasOwnProperty("updateSource")) return; - let idToCheck = accessory.context.hbDeviceId.slice(0, -1), - timeNow = new Date(); - if (params.hasOwnProperty("cmd") && params.cmd === "transmit" && params.hasOwnProperty("rfChl")) { // RF Button - let bAccessory; - if ((bAccessory = this.devicesInHB.get(idToCheck + accessory.context.rfChlMap[params.rfChl]))) { - bAccessory.getService(bAccessory.context.rfChls[params.rfChl]).updateCharacteristic(Characteristic.On, 1); - setTimeout(() => bAccessory.getService(bAccessory.context.rfChls[params.rfChl]).updateCharacteristic(Characteristic.On, 0), 3000); - } else { - throw "rf button not found in Homebridge"; + break; + case 59: // L1 + if (params.hasOwnProperty("bright")) { + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, params.bright); } - } else if (params.hasOwnProperty("cmd") && params.cmd === "trigger") { // RF Sensor - Object.keys(params) - .filter(name => /rfTrig/.test(name)) - .forEach(chan => { - let chanNum = chan.substr(-1).toString(), - accessoryNum = accessory.context.rfChlMap[chanNum], - oAccessory; - if ((oAccessory = this.devicesInHB.get(idToCheck + accessoryNum))) { - let timeOfMotion = new Date(params[chan]), - timeDifference = (timeNow.getTime() - timeOfMotion.getTime()) / 1000; - if (timeDifference < (this.config.sensorTimeDifference || 120)) { - switch (oAccessory.context.sensorType) { - case "button": - break; - case "water": - oAccessory.getService(Service.LeakSensor).updateCharacteristic(Characteristic.LeakDetected, 1); - setTimeout(() => { - oAccessory.getService(Service.LeakSensor).updateCharacteristic(Characteristic.LeakDetected, 0); - }, (this.config.sensorTimeLength || 2) * 1000); - break; - case "fire": - case "smoke": - oAccessory.getService(Service.SmokeSensor).updateCharacteristic(Characteristic.SmokeDetected, 1); - setTimeout(() => { - oAccessory.getService(Service.SmokeSensor).updateCharacteristic(Characteristic.SmokeDetected, 0); - }, (this.config.sensorTimeLength || 2) * 1000); - break; - case "co": - oAccessory.getService(Service.CarbonMonoxideSensor).updateCharacteristic(Characteristic.CarbonMonoxideDetected, 1); - setTimeout(() => { - oAccessory.getService(Service.CarbonMonoxideSensor).updateCharacteristic(Characteristic.CarbonMonoxideDetected, 0); - }, (this.config.sensorTimeLength || 2) * 1000); - break; - case "co2": - oAccessory.getService(Service.CarbonDioxideSensor).updateCharacteristic(Characteristic.CarbonDioxideDetected, 1); - setTimeout(() => { - oAccessory.getService(Service.CarbonDioxideSensor).updateCharacteristic(Characteristic.CarbonDioxideDetected, 0); - }, (this.config.sensorTimeLength || 2) * 1000); - break; - case "contact": - oAccessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, 1); - setTimeout(() => { - oAccessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, 0); - }, (this.config.sensorTimeLength || 2) * 1000); - break; - case "occupancy": - oAccessory.getService(Service.OccupancySensor).updateCharacteristic(Characteristic.OccupancyDetected, 1); - setTimeout(() => { - oAccessory.getService(Service.OccupancySensor).updateCharacteristic(Characteristic.OccupancyDetected, 0); - }, (this.config.sensorTimeLength || 2) * 1000); - break; - default: - oAccessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, true); - setTimeout(() => { - oAccessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, false); - }, (this.config.sensorTimeLength || 2) * 1000); - break; - } - if (this.debug) { - this.log("[%s] has detected [%s].", oAccessory.displayName, oAccessory.context.sensorType); - } - } - } - }); - } - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalZBDeviceUpdate(accessory, params) { - try { //*** credit @tasict ***\\ - if (params.hasOwnProperty("battery")) { - let batteryService = accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); - batteryService.updateCharacteristic(Characteristic.BatteryLevel, params.battery); - batteryService.updateCharacteristic(Characteristic.StatusLowBattery, params.battery <= 25); - } - switch (accessory.context.eweUIID) { - case 1000: - if (params.hasOwnProperty("key") && [0, 1, 2].includes(params.key)) { - accessory.getService(Service.StatelessProgrammableSwitch).updateCharacteristic(Characteristic.ProgrammableSwitchEvent, params.key); - } - break; - case 1770: - let eveLog = { - time: Date.now() - }; - if (params.hasOwnProperty("temperature")) { - let currentTemp = parseInt(params.temperature) / 100; - accessory.getService(Service.TemperatureSensor).updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); - eveLog.temp = parseFloat(currentTemp); - } - if (params.hasOwnProperty("humidity")) { - let currentHumi = parseInt(params.humidity) / 100; - accessory.getService(Service.HumiditySensor).updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); - eveLog.humidity = parseFloat(currentHumi); - } - if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { - accessory.eveLogger.addEntry(eveLog); - } - break; - case 2026: - if (params.hasOwnProperty("motion") && params.motion === 1 && params.hasOwnProperty("trigTime")) { - let timeNow = new Date(), - timeDifference = (timeNow.getTime() - params.trigTime) / 1000; - if (timeDifference < (this.config.sensorTimeDifference || 120)) { - accessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, 1); - setTimeout(() => { - accessory.getService(Service.MotionSensor).updateCharacteristic(Characteristic.MotionDetected, 0); - }, (this.config.sensorTimeLength || 2) * 1000); - } - break; - } - break; - case 3026: - if (params.hasOwnProperty("lock") && [0, 1].includes(params.lock)) { - accessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, params.lock); - } - break; - } - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } + if (params.hasOwnProperty("colorR")) { + newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.Hue, newColour[0]) + .updateCharacteristic(Characteristic.Saturation, newColour[1]); + } + break; + default: + return; + } + } else { + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, false); + } + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } + externalMultiLightUpdate(accessory, params) { + try { + let idToCheck = accessory.context.hbDeviceId.slice(0, -1), + primaryState = false; + for (let i = 1; i <= accessory.context.channelCount; i++) { + if (this.devicesInHB.has(idToCheck + i)) { + let oAccessory = this.devicesInHB.get(idToCheck + i); + oAccessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); + if (params.switches[i - 1].switch === "on") { + primaryState = true; + } + } + } + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, primaryState); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } + externalSingleSwitchUpdate(accessory, params) { + try { + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switch === "on"); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } + externalMultiSwitchUpdate(accessory, params) { + try { + let idToCheck = accessory.context.hbDeviceId.slice(0, -1), + primaryState = false; + for (let i = 1; i <= accessory.context.channelCount; i++) { + if (this.devicesInHB.has(idToCheck + i)) { + let oAccessory = this.devicesInHB.get(idToCheck + i); + oAccessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); + if (params.switches[i - 1].switch === "on") { + primaryState = true; + } + } + } + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } + externalRFDeviceUpdate(accessory, params) { + try { + if (!params.hasOwnProperty("updateSource")) return; + let idToCheck = accessory.context.hbDeviceId.slice(0, -1), + timeNow = new Date(); + if (params.hasOwnProperty("cmd") && params.cmd === "transmit" && params.hasOwnProperty("rfChl")) { + // RF Button + let bAccessory; + if ((bAccessory = this.devicesInHB.get(idToCheck + accessory.context.rfChlMap[params.rfChl]))) { + bAccessory.getService(bAccessory.context.rfChls[params.rfChl]).updateCharacteristic(Characteristic.On, 1); + setTimeout( + () => + bAccessory.getService(bAccessory.context.rfChls[params.rfChl]).updateCharacteristic(Characteristic.On, 0), + 3000 + ); + } else { + throw "rf button not found in Homebridge"; + } + } else if (params.hasOwnProperty("cmd") && params.cmd === "trigger") { + // RF Sensor + Object.keys(params) + .filter(name => /rfTrig/.test(name)) + .forEach(chan => { + let chanNum = chan.substr(-1).toString(), + accessoryNum = accessory.context.rfChlMap[chanNum], + oAccessory; + if ((oAccessory = this.devicesInHB.get(idToCheck + accessoryNum))) { + let timeOfMotion = new Date(params[chan]), + diff = (timeNow.getTime() - timeOfMotion.getTime()) / 1000; + if (diff < (this.config.sensorTimeDifference || 120)) { + switch (oAccessory.context.sensorType) { + case "button": + break; + case "water": + oAccessory.getService(Service.LeakSensor).updateCharacteristic(Characteristic.LeakDetected, 1); + setTimeout(() => { + oAccessory.getService(Service.LeakSensor).updateCharacteristic(Characteristic.LeakDetected, 0); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + case "fire": + case "smoke": + oAccessory.getService(Service.SmokeSensor).updateCharacteristic(Characteristic.SmokeDetected, 1); + setTimeout(() => { + oAccessory.getService(Service.SmokeSensor).updateCharacteristic(Characteristic.SmokeDetected, 0); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + case "co": + oAccessory + .getService(Service.CarbonMonoxideSensor) + .updateCharacteristic(Characteristic.CarbonMonoxideDetected, 1); + setTimeout(() => { + oAccessory + .getService(Service.CarbonMonoxideSensor) + .updateCharacteristic(Characteristic.CarbonMonoxideDetected, 0); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + case "co2": + oAccessory + .getService(Service.CarbonDioxideSensor) + .updateCharacteristic(Characteristic.CarbonDioxideDetected, 1); + setTimeout(() => { + oAccessory + .getService(Service.CarbonDioxideSensor) + .updateCharacteristic(Characteristic.CarbonDioxideDetected, 0); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + case "contact": + oAccessory + .getService(Service.ContactSensor) + .updateCharacteristic(Characteristic.ContactSensorState, 1); + setTimeout(() => { + oAccessory + .getService(Service.ContactSensor) + .updateCharacteristic(Characteristic.ContactSensorState, 0); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + case "occupancy": + oAccessory + .getService(Service.OccupancySensor) + .updateCharacteristic(Characteristic.OccupancyDetected, 1); + setTimeout(() => { + oAccessory + .getService(Service.OccupancySensor) + .updateCharacteristic(Characteristic.OccupancyDetected, 0); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + default: + oAccessory + .getService(Service.MotionSensor) + .updateCharacteristic(Characteristic.MotionDetected, true); + setTimeout(() => { + oAccessory + .getService(Service.MotionSensor) + .updateCharacteristic(Characteristic.MotionDetected, false); + }, (this.config.sensorTimeLength || 2) * 1000); + break; + } + if (this.debug) { + this.log("[%s] has detected [%s].", oAccessory.displayName, oAccessory.context.sensorType); + } + } + } + }); + } + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } + externalZBDeviceUpdate(accessory, params) { + try { + //*** credit @tasict ***\\ + if (params.hasOwnProperty("battery")) { + let batteryService = + accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); + batteryService.updateCharacteristic(Characteristic.BatteryLevel, params.battery); + batteryService.updateCharacteristic(Characteristic.StatusLowBattery, params.battery <= 25); + } + switch (accessory.context.eweUIID) { + case 1000: + if (params.hasOwnProperty("key") && [0, 1, 2].includes(params.key)) { + accessory + .getService(Service.StatelessProgrammableSwitch) + .updateCharacteristic(Characteristic.ProgrammableSwitchEvent, params.key); + } + break; + case 1770: + let eveLog = { + time: Date.now(), + }; + if (params.hasOwnProperty("temperature")) { + let currentTemp = parseInt(params.temperature) / 100; + accessory + .getService(Service.TemperatureSensor) + .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); + eveLog.temp = parseFloat(currentTemp); + } + if (params.hasOwnProperty("humidity")) { + let currentHumi = parseInt(params.humidity) / 100; + accessory + .getService(Service.HumiditySensor) + .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); + eveLog.humidity = parseFloat(currentHumi); + } + if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { + accessory.eveLogger.addEntry(eveLog); + } + break; + case 2026: + if (params.hasOwnProperty("motion") && params.hasOwnProperty("trigTime")) { + let timeNow = new Date(), + diff = (timeNow.getTime() - params.trigTime) / 1000; + accessory + .getService(Service.MotionSensor) + .updateCharacteristic( + Characteristic.MotionDetected, + params.hasOwnProperty("updateSource") && + params.motion === 1 && + diff < (this.config.sensortimeDifference || 120) + ); + break; + } + break; + case 3026: + if (params.hasOwnProperty("lock") && [0, 1].includes(params.lock)) { + accessory + .getService(Service.ContactSensor) + .updateCharacteristic(Characteristic.ContactSensorState, params.lock); + } + break; + } + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } } -module.exports = function(homebridge) { - Accessory = homebridge.platformAccessory; - Characteristic = homebridge.hap.Characteristic; - EveService = new hbLib.EveHomeKitTypes(homebridge); - EveHistoryService = fakegato(homebridge); - Service = homebridge.hap.Service; - UUIDGen = homebridge.hap.uuid; - return eWeLink; -}; \ No newline at end of file +module.exports = function (homebridge) { + Accessory = homebridge.platformAccessory; + Characteristic = homebridge.hap.Characteristic; + EveService = new hbLib.EveHomeKitTypes(homebridge); + EveHistoryService = fakegato(homebridge); + Service = homebridge.hap.Service; + UUIDGen = homebridge.hap.uuid; + return eWeLink; +}; diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 0382542b..57e12c2f 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -1,156 +1,176 @@ /* jshint esversion: 9, -W030, node: true */ "use strict"; const axios = require("axios"), - constants = require("./constants"), - crypto = require("crypto"); + constants = require("./constants"), + crypto = require("crypto"); module.exports = class eWeLinkHTTP { - constructor(config, log) { - this.config = config; - this.log = log; - this.debug = this.config.debug || false; - this.debugReqRes = this.config.debugReqRes || false; - } - login() { - let data = { - countryCode: "+" + this.config.countryCode.toString().replace("+", "").replace(" ", ""), - password: this.config.password - }; - this.config.username.includes("@") ? - data.email = this.config.username : - data.phoneNumber = this.config.username; - if (this.debugReqRes) { - let msg = JSON.stringify(data, null, 2).replace(this.config.password, "**hidden**").replace(this.config.username, "**hidden**"); - this.log.warn("Sending HTTP login request. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("Sending HTTP login request."); - } - let dataToSign = crypto.createHmac("sha256", constants.appSecret).update(JSON.stringify(data)).digest("base64"); - return new Promise((resolve, reject) => { - axios({ - url: "https://" + this.httpHost + "/v2/user/login", - method: "post", - headers: { - Authorization: "Sign " + dataToSign, - "Content-Type": "application/json", - Host: this.httpHost, - "X-CK-Appid": constants.appId, - "X-CK-Nonce": Math.random().toString(36).substr(2, 8) - }, - data - }).then(res => { - let body = res.data; - if (body.hasOwnProperty("error") && body.error === 10004 && body.hasOwnProperty("data") && body.data.hasOwnProperty("region")) { - switch (body.data.region) { - case "eu": - case "us": - case "as": - this.httpHost = body.data.region + "-apia.coolkit.cc"; - break; - case "cn": - this.httpHost = "cn-apia.coolkit.cn"; - break; - default: - throw "No valid region received - [" + body.data.region + "]."; - } - if (this.debug) { - this.log("New HTTP API host received [%s].", this.httpHost); - } - resolve(this.login()); - return; - } - if (!body.data.at) { - throw "Server did not respond with an authentication token. Please double check your eWeLink username and password in the Homebridge configuration.\n" + JSON.stringify(body, null, 2); - } - this.aToken = body.data.at; - this.apiKey = body.data.user.apikey; - resolve({ - aToken: body.data.at, - apiKey: body.data.user.apikey, - httpHost: this.httpHost - }); - }).catch(err => { - reject(err); - }); - }); - } - getHost() { - let data = { - appid: constants.appId, - country_code: this.config.countryCode.toString().replace("+", "").replace(" ", ""), - nonce: Math.random().toString(36).substr(2, 8), - ts: Math.floor(new Date().getTime() / 1000), - version: 8 - }, - dataToSign = []; - Object.keys(data).forEach(function(key) { - dataToSign.push({ - key: key, - value: data[key] - }); - }); - dataToSign.sort(function(a, b) { - return a.key < b.key ? -1 : 1; - }); - dataToSign = dataToSign.map(function(kv) { - return kv.key + "=" + kv.value; - }).join("&"); - dataToSign = crypto.createHmac("sha256", "6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM").update(dataToSign).digest("base64"); - return new Promise((resolve, reject) => { - axios.get("https://api.coolkit.cc:8080/api/user/region", { - headers: { - Authorization: "Sign " + dataToSign, - "Content-Type": "application/json" - }, - params: data - }).then(res => { - let body = res.data; - if (!body.region) { - throw "Server did not respond with a region.\n" + JSON.stringify(body, null, 2); - } - switch (body.region) { - case "eu": - case "us": - case "as": - this.httpHost = body.region + "-apia.coolkit.cc"; - break; - case "cn": - this.httpHost = "cn-apia.coolkit.cn"; - break; - default: - throw "No valid region received - [" + body.region + "]."; + constructor(config, log) { + this.config = config; + this.log = log; + this.debug = this.config.debug || false; + this.debugReqRes = this.config.debugReqRes || false; + } + login() { + let data = { + countryCode: "+" + this.config.countryCode.toString().replace("+", "").replace(" ", ""), + password: this.config.password, + }; + this.config.username.includes("@") + ? (data.email = this.config.username) + : (data.phoneNumber = this.config.username); + if (this.debugReqRes) { + let msg = JSON.stringify(data, null, 2) + .replace(this.config.password, "**hidden**") + .replace(this.config.username, "**hidden**"); + this.log.warn("Sending HTTP login request. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("Sending HTTP login request."); + } + let dataToSign = crypto.createHmac("sha256", constants.appSecret).update(JSON.stringify(data)).digest("base64"); + return new Promise((resolve, reject) => { + axios({ + url: "https://" + this.httpHost + "/v2/user/login", + method: "post", + headers: { + Authorization: "Sign " + dataToSign, + "Content-Type": "application/json", + Host: this.httpHost, + "X-CK-Appid": constants.appId, + "X-CK-Nonce": Math.random().toString(36).substr(2, 8), + }, + data, + }) + .then(res => { + let body = res.data; + if ( + body.hasOwnProperty("error") && + body.error === 10004 && + body.hasOwnProperty("data") && + body.data.hasOwnProperty("region") + ) { + switch (body.data.region) { + case "eu": + case "us": + case "as": + this.httpHost = body.data.region + "-apia.coolkit.cc"; + break; + case "cn": + this.httpHost = "cn-apia.coolkit.cn"; + break; + default: + throw "No valid region received - [" + body.data.region + "]."; } if (this.debug) { - this.log("HTTP API host received [%s].", this.httpHost); - } - resolve(this.httpHost); - }).catch(err => { - reject(err); - }); - }); - } - getDevices() { - return new Promise((resolve, reject) => { - axios.get("https://" + this.httpHost + "/v2/device/thing", { - headers: { - Authorization: "Bearer " + this.aToken, - "Content-Type": "application/json", - Host: this.httpHost, - "X-CK-Appid": constants.appId, - "X-CK-Nonce": Math.random().toString(36).substr(2, 8) - } - }).then(res => { - let body = res.data; - if (!body.hasOwnProperty("error") || (body.hasOwnProperty("error") && body.error !== 0)) { - throw JSON.stringify(body, null, 2); - } - let deviceList = []; - if (body.data.thingList && body.data.thingList.length > 0) { - body.data.thingList.forEach(device => deviceList.push(device.itemData)); + this.log("New HTTP API host received [%s].", this.httpHost); } - resolve(deviceList); - }).catch(err => { - reject(err); - }); + resolve(this.login()); + return; + } + if (!body.data.at) { + throw ( + "Server did not respond with an authentication token. Please double check your eWeLink username and password in the Homebridge configuration.\n" + + JSON.stringify(body, null, 2) + ); + } + this.aToken = body.data.at; + this.apiKey = body.data.user.apikey; + resolve({ + aToken: body.data.at, + apiKey: body.data.user.apikey, + httpHost: this.httpHost, + }); + }) + .catch(err => { + reject(err); + }); + }); + } + getHost() { + let data = { + appid: constants.appId, + country_code: this.config.countryCode.toString().replace("+", "").replace(" ", ""), + nonce: Math.random().toString(36).substr(2, 8), + ts: Math.floor(new Date().getTime() / 1000), + version: 8, + }, + dataToSign = []; + Object.keys(data).forEach(function (key) { + dataToSign.push({ + key: key, + value: data[key], }); - } -}; \ No newline at end of file + }); + dataToSign.sort(function (a, b) { + return a.key < b.key ? -1 : 1; + }); + dataToSign = dataToSign + .map(function (kv) { + return kv.key + "=" + kv.value; + }) + .join("&"); + dataToSign = crypto.createHmac("sha256", "6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM").update(dataToSign).digest("base64"); + return new Promise((resolve, reject) => { + axios + .get("https://api.coolkit.cc:8080/api/user/region", { + headers: { + Authorization: "Sign " + dataToSign, + "Content-Type": "application/json", + }, + params: data, + }) + .then(res => { + let body = res.data; + if (!body.region) { + throw "Server did not respond with a region.\n" + JSON.stringify(body, null, 2); + } + switch (body.region) { + case "eu": + case "us": + case "as": + this.httpHost = body.region + "-apia.coolkit.cc"; + break; + case "cn": + this.httpHost = "cn-apia.coolkit.cn"; + break; + default: + throw "No valid region received - [" + body.region + "]."; + } + if (this.debug) { + this.log("HTTP API host received [%s].", this.httpHost); + } + resolve(this.httpHost); + }) + .catch(err => { + reject(err); + }); + }); + } + getDevices() { + return new Promise((resolve, reject) => { + axios + .get("https://" + this.httpHost + "/v2/device/thing", { + headers: { + Authorization: "Bearer " + this.aToken, + "Content-Type": "application/json", + Host: this.httpHost, + "X-CK-Appid": constants.appId, + "X-CK-Nonce": Math.random().toString(36).substr(2, 8), + }, + }) + .then(res => { + let body = res.data; + if (!body.hasOwnProperty("error") || (body.hasOwnProperty("error") && body.error !== 0)) { + throw JSON.stringify(body, null, 2); + } + let deviceList = []; + if (body.data.thingList && body.data.thingList.length > 0) { + body.data.thingList.forEach(device => deviceList.push(device.itemData)); + } + resolve(deviceList); + }) + .catch(err => { + reject(err); + }); + }); + } +}; diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index f6ff9188..2bbbf005 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -1,181 +1,196 @@ /* jshint esversion: 9, -W030, node: true */ "use strict"; const axios = require("axios"), - constants = require("./constants"), - crypto = require("crypto"), - dns = require("node-dns-sd"), - eventemitter = require("events"); + constants = require("./constants"), + crypto = require("crypto"), + dns = require("node-dns-sd"), + eventemitter = require("events"); module.exports = class eWeLinkLAN { - constructor(config, log, devices) { - this.config = config; - this.log = log; - this.devices = devices; - this.ipOverrides = this.config.ipOverride || {}; - let deviceMap = new Map(); - devices.forEach(device => { - deviceMap.set(device.deviceid, { - apiKey: device.devicekey, - online: this.ipOverrides.hasOwnProperty(device.deviceid) ? true : false, - ip: this.ipOverrides.hasOwnProperty(device.deviceid) ? this.ipOverrides[device.deviceid] : null - }); + constructor(config, log, devices) { + this.config = config; + this.log = log; + this.devices = devices; + this.ipOverrides = this.config.ipOverride || {}; + let deviceMap = new Map(); + devices.forEach(device => { + deviceMap.set(device.deviceid, { + apiKey: device.devicekey, + online: this.ipOverrides.hasOwnProperty(device.deviceid) ? true : false, + ip: this.ipOverrides.hasOwnProperty(device.deviceid) ? this.ipOverrides[device.deviceid] : null, }); - this.deviceMap = deviceMap; - this.debug = this.config.debug || false; - this.debugReqRes = this.config.debugReqRes || false; - this.emitter = new eventemitter(); - } - getHosts() { - return new Promise((resolve, reject) => { - dns.discover({ - name: "_ewelink._tcp.local" - }).then(res => { - let onlineCount = 0; - res.forEach(device => { - let d, deviceId = device.fqdn.replace("._ewelink._tcp.local", "").replace("eWeLink_", ""); - if ((d = this.deviceMap.get(deviceId))) { - if (!this.ipOverrides.hasOwnProperty(deviceId)) { - this.deviceMap.set(deviceId, { - apiKey: d.apiKey, - online: true, - ip: device.address - }); - } - onlineCount++; - } - }); - resolve({ - map: this.deviceMap, - count: onlineCount - }); - }).catch(err => { - reject(err); - }); - }); - } - startMonitor() { - dns.ondata = packet => { - if (packet.answers) { - packet.answers - .filter(value => value.name.includes("_ewelink._tcp.local")) - .filter(value => value.type === "TXT") - .filter(value => this.deviceMap.has(value.rdata.id)) - .forEach(value => { - let rdata = value.rdata, - deviceInfo = this.deviceMap.get(rdata.id), - data = rdata.data1 + - (rdata.hasOwnProperty("data2") ? rdata.data2 : "") + - (rdata.hasOwnProperty("data3") ? rdata.data3 : "") + - (rdata.hasOwnProperty("data4") ? rdata.data4 : ""), - key = crypto.createHash("md5").update(Buffer.from(deviceInfo.apiKey, "utf8")).digest(), - dText = crypto.createDecipheriv("aes-128-cbc", key, Buffer.from(rdata.iv, "base64")), - pText = Buffer.concat([dText.update(Buffer.from(data, "base64")), dText.final()]).toString("utf8"), - params; - if (packet.address !== deviceInfo.ip && !this.ipOverrides.hasOwnProperty(rdata.id)) { - this.deviceMap.set(rdata.id, { - apiKey: deviceInfo.apiKey, - online: true, - ip: packet.address - }); - if (this.debug) { - this.log.warn("[%s] updating IP address to [%s].", rdata.id, packet.address); - } - } - try { - params = JSON.parse(pText); - } catch (e) { - this.log.warn("[%s] An error occured reading the LAN message [%s]", rdata.id, e); - return; - } - for (let param in params) { - if (params.hasOwnProperty(param)) { - if (!constants.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { - delete params[param]; - } - } - } - if (Object.keys(params).length > 0) { - params.updateSource = "LAN"; - let returnTemplate = { - deviceid: rdata.id, - action: "update", - params - }; - if (this.debugReqRes) { - let msg = JSON.stringify(returnTemplate, null, 2).replace(rdata.id, "**hidden**"); - this.log("LAN message received.\n%s", msg); - } else if (this.debug) { - this.log("LAN message received."); - } - this.emitter.emit("update", returnTemplate); - } - }); - } - }; - return new Promise((resolve, reject) => { - dns.startMonitoring().then(() => { - resolve(); - }).catch(err => { - reject(err); - }); - }); - } - sendUpdate(json) { - return new Promise((resolve, reject) => { - if (!this.deviceMap.get(json.deviceid).online) { - throw "device does not support LAN mode"; - } - let apiKey, suffix, params = {}; - if (json.params.hasOwnProperty("switches")) { - params.switches = json.params.switches; - suffix = "switches"; - } else if (json.params.hasOwnProperty("switch")) { - params.switch = json.params.switch; - suffix = "switch"; - } else { - throw "plugin does not support lan mode for this device yet - feel free to create a github issue"; - } - if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { - let key = crypto.createHash('md5').update(Buffer.from(apiKey, 'utf8')).digest(), - iv = crypto.randomBytes(16), - enc = crypto.createCipheriv('aes-128-cbc', key, iv), - data = { - data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString('base64'), - deviceid: json.deviceid, - encrypt: true, - iv: iv.toString('base64'), - selfApikey: "123", - sequence: Date.now().toString() - }; - if (this.debugReqRes) { - let msg = JSON.stringify(json, null, 2).replace(json.apikey, "**hidden**").replace(json.apikey, "**hidden**").replace(json.deviceid, "**hidden**"); - this.log.warn("LAN message sent. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("LAN message sent."); + }); + this.deviceMap = deviceMap; + this.debug = this.config.debug || false; + this.debugReqRes = this.config.debugReqRes || false; + this.emitter = new eventemitter(); + } + getHosts() { + return new Promise((resolve, reject) => { + dns + .discover({ + name: "_ewelink._tcp.local", + }) + .then(res => { + let onlineCount = 0; + res.forEach(device => { + let d, + deviceId = device.fqdn.replace("._ewelink._tcp.local", "").replace("eWeLink_", ""); + if ((d = this.deviceMap.get(deviceId))) { + if (!this.ipOverrides.hasOwnProperty(deviceId)) { + this.deviceMap.set(deviceId, { + apiKey: d.apiKey, + online: true, + ip: device.address, + }); + } + onlineCount++; } - axios({ - method: "post", - url: "http://" + this.deviceMap.get(json.deviceid).ip + ":8081/zeroconf/" + suffix, - headers: { - Accept: "application/json", - "Content-Type": "application/json" - }, - data - }).then(res => { - if (res.data.hasOwnProperty("error") && res.data.error === 0) { - resolve(); - } - throw res.data; - }).catch(err => { - reject(err); - }); - } - }); - } - receiveUpdate(f) { - this.emitter.addListener("update", f); - } - closeConnection() { - dns.stopMonitoring(); - this.log("LAN monitoring gracefully stopped."); - } -}; \ No newline at end of file + }); + resolve({ + map: this.deviceMap, + count: onlineCount, + }); + }) + .catch(err => { + reject(err); + }); + }); + } + startMonitor() { + dns.ondata = packet => { + if (packet.answers) { + packet.answers + .filter(value => value.name.includes("_ewelink._tcp.local")) + .filter(value => value.type === "TXT") + .filter(value => this.deviceMap.has(value.rdata.id)) + .forEach(value => { + let rdata = value.rdata, + deviceInfo = this.deviceMap.get(rdata.id), + data = + rdata.data1 + + (rdata.hasOwnProperty("data2") ? rdata.data2 : "") + + (rdata.hasOwnProperty("data3") ? rdata.data3 : "") + + (rdata.hasOwnProperty("data4") ? rdata.data4 : ""), + key = crypto.createHash("md5").update(Buffer.from(deviceInfo.apiKey, "utf8")).digest(), + dText = crypto.createDecipheriv("aes-128-cbc", key, Buffer.from(rdata.iv, "base64")), + pText = Buffer.concat([dText.update(Buffer.from(data, "base64")), dText.final()]).toString("utf8"), + params; + if (packet.address !== deviceInfo.ip && !this.ipOverrides.hasOwnProperty(rdata.id)) { + this.deviceMap.set(rdata.id, { + apiKey: deviceInfo.apiKey, + online: true, + ip: packet.address, + }); + if (this.debug) { + this.log.warn("[%s] updating IP address to [%s].", rdata.id, packet.address); + } + } + try { + params = JSON.parse(pText); + } catch (e) { + this.log.warn("[%s] An error occured reading the LAN message [%s]", rdata.id, e); + return; + } + for (let param in params) { + if (params.hasOwnProperty(param)) { + if (!constants.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { + delete params[param]; + } + } + } + if (Object.keys(params).length > 0) { + params.updateSource = "LAN"; + let returnTemplate = { + deviceid: rdata.id, + action: "update", + params, + }; + if (this.debugReqRes) { + let msg = JSON.stringify(returnTemplate, null, 2).replace(rdata.id, "**hidden**"); + this.log("LAN message received.\n%s", msg); + } else if (this.debug) { + this.log("LAN message received."); + } + this.emitter.emit("update", returnTemplate); + } + }); + } + }; + return new Promise((resolve, reject) => { + dns + .startMonitoring() + .then(() => { + resolve(); + }) + .catch(err => { + reject(err); + }); + }); + } + sendUpdate(json) { + return new Promise((resolve, reject) => { + if (!this.deviceMap.get(json.deviceid).online) { + throw "device does not support LAN mode"; + } + let apiKey, + suffix, + params = {}; + if (json.params.hasOwnProperty("switches")) { + params.switches = json.params.switches; + suffix = "switches"; + } else if (json.params.hasOwnProperty("switch")) { + params.switch = json.params.switch; + suffix = "switch"; + } else { + throw "plugin does not support lan mode for this device yet - feel free to create a github issue"; + } + if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { + let key = crypto.createHash("md5").update(Buffer.from(apiKey, "utf8")).digest(), + iv = crypto.randomBytes(16), + enc = crypto.createCipheriv("aes-128-cbc", key, iv), + data = { + data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString("base64"), + deviceid: json.deviceid, + encrypt: true, + iv: iv.toString("base64"), + selfApikey: "123", + sequence: Date.now().toString(), + }; + if (this.debugReqRes) { + let msg = JSON.stringify(json, null, 2) + .replace(json.apikey, "**hidden**") + .replace(json.apikey, "**hidden**") + .replace(json.deviceid, "**hidden**"); + this.log.warn("LAN message sent. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("LAN message sent."); + } + axios({ + method: "post", + url: "http://" + this.deviceMap.get(json.deviceid).ip + ":8081/zeroconf/" + suffix, + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + data, + }) + .then(res => { + if (res.data.hasOwnProperty("error") && res.data.error === 0) { + resolve(); + } + throw res.data; + }) + .catch(err => { + reject(err); + }); + } + }); + } + receiveUpdate(f) { + this.emitter.addListener("update", f); + } + closeConnection() { + dns.stopMonitoring(); + this.log("LAN monitoring gracefully stopped."); + } +}; diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 9cb70c1c..86f08e3e 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -1,282 +1,299 @@ /* jshint esversion: 9, -W030, node: true */ "use strict"; const axios = require("axios"), - constants = require("./constants"), - eventemitter = require("events"), - ws = require("ws"); + constants = require("./constants"), + eventemitter = require("events"), + ws = require("ws"); module.exports = class eWeLinkWS { - constructor(config, log, res) { - this.config = config; - this.log = log; - this.debug = this.config.debug || false; - this.debugReqRes = this.config.debugReqRes || false; - this.httpHost = res.httpHost; - this.aToken = res.aToken; - this.apiKey = res.apiKey; - this.wsIsOpen = false; - this.emitter = new eventemitter(); - this.delaySend = 0; - } - getHost() { - return new Promise((resolve, reject) => { - axios({ - method: "post", - url: "https://" + this.httpHost.replace("-api", "-disp") + "/dispatch/app", - headers: { - Authorization: "Bearer " + this.aToken, - "Content-Type": "application/json" - }, - data: { - appid: constants.appId, - nonce: Math.random().toString(36).substr(2, 8), - ts: Math.floor(new Date().getTime() / 1000), - version: 8 - } - }).then(res => { - let body = res.data; - if (!body.domain) { - throw "Server did not respond with a web socket host."; - } - if (this.debug) { - this.log("Web socket host received [%s].", body.domain); - } - this.wsHost = body.domain; - resolve(body.domain); - }).catch(err => { - reject(err); - }); - }); - } - login() { - this.ws = new ws("wss://" + this.wsHost + ":8080/api/ws"); - this.ws.on("open", () => { - this.wsIsOpen = true; - let payload = { - action: "userOnline", - apikey: this.apiKey, - appid: constants.appId, - at: this.aToken, - nonce: Math.random().toString(36).substr(2, 8), - sequence: Math.floor(new Date()), - ts: Math.floor(new Date() / 1000), - userAgent: "app", - version: 8 - }; - this.ws.send(JSON.stringify(payload)); - if (this.debugReqRes) { - let msg = JSON.stringify(payload, null, 2).replace(this.aToken, "**hidden**").replace(this.apiKey, "**hidden**"); - this.log.warn("Sending WS login request. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("Sending WS login request."); - } - }); - this.ws.on("message", m => { - if (m === "pong") { - return; - } - let device; - try { - device = JSON.parse(m); - } catch (e) { - this.log.warn("An error occured reading the web socket message [%s]", e); - return; - } - // for requestUpdate response - if (device.hasOwnProperty("deviceid") && device.hasOwnProperty("params") && device.hasOwnProperty("error") && device.error === 0) { - device.action = "update"; - } else if (device.hasOwnProperty("deviceid") && device.hasOwnProperty("error") && device.error === 504) { - device.action = "sysmsg"; - device.params = { - online: false + constructor(config, log, res) { + this.config = config; + this.log = log; + this.debug = this.config.debug || false; + this.debugReqRes = this.config.debugReqRes || false; + this.httpHost = res.httpHost; + this.aToken = res.aToken; + this.apiKey = res.apiKey; + this.wsIsOpen = false; + this.emitter = new eventemitter(); + this.delaySend = 0; + } + getHost() { + return new Promise((resolve, reject) => { + axios({ + method: "post", + url: "https://" + this.httpHost.replace("-api", "-disp") + "/dispatch/app", + headers: { + Authorization: "Bearer " + this.aToken, + "Content-Type": "application/json", + }, + data: { + appid: constants.appId, + nonce: Math.random().toString(36).substr(2, 8), + ts: Math.floor(new Date().getTime() / 1000), + version: 8, + }, + }) + .then(res => { + let body = res.data; + if (!body.domain) { + throw "Server did not respond with a web socket host."; + } + if (this.debug) { + this.log("Web socket host received [%s].", body.domain); + } + this.wsHost = body.domain; + resolve(body.domain); + }) + .catch(err => { + reject(err); + }); + }); + } + login() { + this.ws = new ws("wss://" + this.wsHost + ":8080/api/ws"); + this.ws.on("open", () => { + this.wsIsOpen = true; + let payload = { + action: "userOnline", + apikey: this.apiKey, + appid: constants.appId, + at: this.aToken, + nonce: Math.random().toString(36).substr(2, 8), + sequence: Math.floor(new Date()), + ts: Math.floor(new Date() / 1000), + userAgent: "app", + version: 8, + }; + this.ws.send(JSON.stringify(payload)); + if (this.debugReqRes) { + let msg = JSON.stringify(payload, null, 2) + .replace(this.aToken, "**hidden**") + .replace(this.apiKey, "**hidden**"); + this.log.warn("Sending WS login request. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("Sending WS login request."); + } + }); + this.ws.on("message", m => { + if (m === "pong") { + return; + } + let device; + try { + device = JSON.parse(m); + } catch (e) { + this.log.warn("An error occured reading the web socket message [%s]", e); + return; + } + // for requestUpdate response + if ( + device.hasOwnProperty("deviceid") && + device.hasOwnProperty("params") && + device.hasOwnProperty("error") && + device.error === 0 + ) { + device.action = "update"; + } else if (device.hasOwnProperty("deviceid") && device.hasOwnProperty("error") && device.error === 504) { + device.action = "sysmsg"; + device.params = { + online: false, + }; + } + // for external updates + if (device.hasOwnProperty("config") && device.config.hb && device.config.hbInterval && !this.hbInterval) { + this.hbInterval = setInterval(() => { + this.ws.send("ping"); + }, (device.config.hbInterval + 7) * 1000); + } else if (device.hasOwnProperty("action")) { + switch (device.action) { + case "sysmsg": + device.params.updateSource = "WS"; + let returnTemplate = { + deviceid: device.deviceid, + action: "sysmsg", + params: device.params, }; - } - // for external updates - if (device.hasOwnProperty("config") && device.config.hb && device.config.hbInterval && !this.hbInterval) { - this.hbInterval = setInterval(() => { - this.ws.send("ping"); - }, (device.config.hbInterval + 7) * 1000); - } else if (device.hasOwnProperty("action")) { - switch (device.action) { - case "sysmsg": - device.params.updateSource = "WS"; - let returnTemplate = { - deviceid: device.deviceid, - action: "sysmsg", - params: device.params - }; - if (this.debugReqRes) { - let msg = JSON.stringify(returnTemplate, null, 2).replace(device.deviceid, "**hidden**"); - this.log("WS message received.\n%s", msg); - } else if (this.debug) { - this.log("WS message received."); - } - this.emitter.emit("update", returnTemplate); - break; - case "update": - for (let param in device.params) { - if (device.params.hasOwnProperty(param)) { - if (!constants.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { - delete device.params[param]; - } - } - } - if (Object.keys(device.params).length > 0) { - device.params.updateSource = "WS"; - let returnTemplate = { - deviceid: device.deviceid, - action: "update", - params: device.params - }; - if (this.debugReqRes) { - let msg = JSON.stringify(returnTemplate, null, 2).replace(device.deviceid, "**hidden**"); - this.log("WS message received.\n%s", msg); - } else if (this.debug) { - this.log("WS message received."); - } - this.emitter.emit("update", returnTemplate); - } - break; - default: - this.log.warn("[%s] WS message has unknown action.\n" + JSON.stringify(device, null, 2), device.deviceid); - return; + if (this.debugReqRes) { + let msg = JSON.stringify(returnTemplate, null, 2).replace(device.deviceid, "**hidden**"); + this.log("WS message received.\n%s", msg); + } else if (this.debug) { + this.log("WS message received."); } - } else if (device.hasOwnProperty("error") && device.error === 0) { - // *** Safe to ignore these messages *** \\ - } else { - if (this.debug) { - this.log.warn("WS unknown command received.\n" + JSON.stringify(device, null, 2)); + this.emitter.emit("update", returnTemplate); + break; + case "update": + for (let param in device.params) { + if (device.params.hasOwnProperty(param)) { + if (!constants.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { + delete device.params[param]; + } + } } - } - }); - this.ws.on("close", (e, m) => { - if (m === "Stopping Homebridge") { - this.log("Web socket gracefully closed."); - } else { - this.log.warn("Web socket closed - [%s - %s].", e, m); - if (e !== 1000) { - this.log("Web socket will try to reconnect in five seconds."); - setTimeout(() => { - this.login(); - }, 5000); - } else { - this.log("Please try restarting Homebridge so that this plugin can work again."); + if (Object.keys(device.params).length > 0) { + device.params.updateSource = "WS"; + let returnTemplate = { + deviceid: device.deviceid, + action: "update", + params: device.params, + }; + if (this.debugReqRes) { + let msg = JSON.stringify(returnTemplate, null, 2).replace(device.deviceid, "**hidden**"); + this.log("WS message received.\n%s", msg); + } else if (this.debug) { + this.log("WS message received."); + } + this.emitter.emit("update", returnTemplate); } - } - this.wsIsOpen = false; - if (this.hbInterval) { - clearInterval(this.hbInterval); - this.hbInterval = null; - } - this.ws.removeAllListeners(); - }); - this.ws.on("error", (e) => { - this.log.error("Web socket error - [%s].", e); - if (e.code === "ECONNREFUSED") { - this.log.warn("Web socket will try to reconnect in five seconds then try the command again."); - this.ws.removeAllListeners(); - setTimeout(() => { - this.login(); - }, 5000); - } else { - this.log.warn("If this was unexpected then please try restarting Homebridge."); - } - }); - } - sendUpdate(json) { - json = { - ...json, - ...{ - action: "update", - sequence: Math.floor(new Date()), - userAgent: "app" - } - }; - let sendOperation = req => { - if (!this.wsIsOpen) { - setTimeout(() => { - sendOperation(req); - }, 280); + break; + case "reportSubDevice": return; - } - if (this.ws) { - this.ws.send(req); - if (this.debugReqRes) { - let msg = JSON.stringify(json, null, 2).replace(json.apikey, "**hidden**").replace(json.apiKey, "**hidden**").replace(json.deviceid, "**hidden**"); - this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("WS message sent."); - } + default: + this.log.warn("[%s] WS message has unknown action.\n" + JSON.stringify(device, null, 2), device.deviceid); return; - } - this.delaySend = this.delaySend <= 0 ? 0 : this.delaySend -= 280; - }; - let string = JSON.stringify(json); - if (this.wsIsOpen) { - setTimeout(sendOperation, this.delaySend, string); - this.delaySend += 280; + } + } else if (device.hasOwnProperty("error") && device.error === 0) { + // *** Safe to ignore these messages *** \\ } else { - this.log.warn("Web socket is currently reconnecting. Command will be resent."); - let interval, - waitToSend = req => { - if (this.wsIsOpen) { - clearInterval(interval); - sendOperation(req); - } - }; - interval = setInterval(waitToSend, 2500, string); + if (this.debug) { + this.log.warn("WS unknown command received.\n" + JSON.stringify(device, null, 2)); + } } - } - requestUpdate(accessory) { - let json = { - action: "query", - apikey: accessory.context.eweApiKey, - deviceid: accessory.context.eweDeviceId, - params: [], - sequence: Math.floor(new Date()), - ts: 0, - userAgent: "app" - }, - sendOperation = req => { - if (!this.wsIsOpen) { - setTimeout(() => { - sendOperation(req); - }, 280); - return; - } - if (this.ws) { - this.ws.send(req); - if (this.debugReqRes) { - let msg = JSON.stringify(json, null, 2).replace(json.apikey, "**hidden**").replace(json.apiKey, "**hidden**").replace(json.deviceid, "**hidden**"); - this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("WS message sent."); - } - return; - } - this.delaySend = this.delaySend <= 0 ? 0 : this.delaySend -= 280; - }, - string = JSON.stringify(json); - if (this.wsIsOpen) { - setTimeout(sendOperation, this.delaySend, string); - this.delaySend += 280; + }); + this.ws.on("close", (e, m) => { + if (m === "Stopping Homebridge") { + this.log("Web socket gracefully closed."); } else { - this.log.warn("Web socket is currently reconnecting. Command will be resent."); - let interval, - waitToSend = req => { - if (this.wsIsOpen) { - clearInterval(interval); - sendOperation(req); - } - }; - interval = setInterval(waitToSend, 2500, string); + this.log.warn("Web socket closed - [%s - %s].", e, m); + if (e !== 1000) { + this.log("Web socket will try to reconnect in five seconds."); + setTimeout(() => { + this.login(); + }, 5000); + } else { + this.log("Please try restarting Homebridge so that this plugin can work again."); + } + } + this.wsIsOpen = false; + if (this.hbInterval) { + clearInterval(this.hbInterval); + this.hbInterval = null; + } + this.ws.removeAllListeners(); + }); + this.ws.on("error", e => { + this.log.error("Web socket error - [%s].", e); + if (e.code === "ECONNREFUSED") { + this.log.warn("Web socket will try to reconnect in five seconds then try the command again."); + this.ws.removeAllListeners(); + setTimeout(() => { + this.login(); + }, 5000); + } else { + this.log.warn("If this was unexpected then please try restarting Homebridge."); + } + }); + } + sendUpdate(json) { + json = { + ...json, + ...{ + action: "update", + sequence: Math.floor(new Date()), + userAgent: "app", + }, + }; + let sendOperation = req => { + if (!this.wsIsOpen) { + setTimeout(() => { + sendOperation(req); + }, 280); + return; } - } - receiveUpdate(f) { - this.emitter.addListener("update", f); - } - closeConnection() { - if (this.ws && this.wsIsOpen) { - this.ws.close(1000, "Stopping Homebridge"); + if (this.ws) { + this.ws.send(req); + if (this.debugReqRes) { + let msg = JSON.stringify(json, null, 2) + .replace(json.apikey, "**hidden**") + .replace(json.apiKey, "**hidden**") + .replace(json.deviceid, "**hidden**"); + this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("WS message sent."); + } + return; } - } -}; \ No newline at end of file + this.delaySend = this.delaySend <= 0 ? 0 : (this.delaySend -= 280); + }; + let string = JSON.stringify(json); + if (this.wsIsOpen) { + setTimeout(sendOperation, this.delaySend, string); + this.delaySend += 280; + } else { + this.log.warn("Web socket is currently reconnecting. Command will be resent."); + let interval, + waitToSend = req => { + if (this.wsIsOpen) { + clearInterval(interval); + sendOperation(req); + } + }; + interval = setInterval(waitToSend, 2500, string); + } + } + requestUpdate(accessory) { + let json = { + action: "query", + apikey: accessory.context.eweApiKey, + deviceid: accessory.context.eweDeviceId, + params: [], + sequence: Math.floor(new Date()), + ts: 0, + userAgent: "app", + }, + sendOperation = req => { + if (!this.wsIsOpen) { + setTimeout(() => { + sendOperation(req); + }, 280); + return; + } + if (this.ws) { + this.ws.send(req); + if (this.debugReqRes) { + let msg = JSON.stringify(json, null, 2) + .replace(json.apikey, "**hidden**") + .replace(json.apiKey, "**hidden**") + .replace(json.deviceid, "**hidden**"); + this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("WS message sent."); + } + return; + } + this.delaySend = this.delaySend <= 0 ? 0 : (this.delaySend -= 280); + }, + string = JSON.stringify(json); + if (this.wsIsOpen) { + setTimeout(sendOperation, this.delaySend, string); + this.delaySend += 280; + } else { + this.log.warn("Web socket is currently reconnecting. Command will be resent."); + let interval, + waitToSend = req => { + if (this.wsIsOpen) { + clearInterval(interval); + sendOperation(req); + } + }; + interval = setInterval(waitToSend, 2500, string); + } + } + receiveUpdate(f) { + this.emitter.addListener("update", f); + } + closeConnection() { + if (this.ws && this.wsIsOpen) { + this.ws.close(1000, "Stopping Homebridge"); + } + } +}; diff --git a/package-lock.json b/package-lock.json index 89e609db..61a31ae5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,624 +1,630 @@ { - "name": "homebridge-ewelink", - "version": "2.26.2", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" - }, - "abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "requires": { - "event-target-shim": "^5.0.0" - } - }, - "agent-base": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.1.tgz", - "integrity": "sha512-01q25QQDwLSsyfhrKbn8yuur+JNw0H+0Y4JiGIKd3z9aYk/w/2kxD/Upc+t2ZBBSUNff50VjPsSW2YxM8QYKVg==", - "requires": { - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" - }, - "arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" - }, - "axios": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz", - "integrity": "sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==", - "requires": { - "follow-redirects": "^1.10.0" - } - }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" - }, - "bignumber.js": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", - "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" - }, - "bonjour": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", - "requires": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" - } - }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, - "buffer-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "correcting-interval": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/correcting-interval/-/correcting-interval-2.0.0.tgz", - "integrity": "sha1-iTdklFcN+C7axTQRHV8n/z6gstM=" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - } - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" - } - }, - "dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" - }, - "dns-packet": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", - "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", - "requires": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", - "requires": { - "buffer-indexof": "^1.0.0" - } - }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "fakegato-history": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/fakegato-history/-/fakegato-history-0.5.6.tgz", - "integrity": "sha512-LlsOkiw9LntVlRlBkssD5ozhEkQzYuEJUlvXk5YAgBQcWzk19PQ5g+NoKfs6SRY1qAeC1onb65hes4mCvY+JmA==", - "requires": { - "debug": "^2.2.0", - "googleapis": ">39.1.0", - "moment": "*" - } - }, - "fast-text-encoding": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", - "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" - }, - "follow-redirects": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", - "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==" - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "gaxios": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.1.0.tgz", - "integrity": "sha512-DDTn3KXVJJigtz+g0J3vhcfbDbKtAroSTxauWsdnP57sM5KZ3d2c/3D9RKFJ86s43hfw6WULg6TXYw/AYiBlpA==", - "requires": { - "abort-controller": "^3.0.0", - "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", - "is-stream": "^2.0.0", - "node-fetch": "^2.3.0" - } - }, - "gcp-metadata": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.4.tgz", - "integrity": "sha512-5J/GIH0yWt/56R3dNaNWPGQ/zXsZOddYECfJaqxFWgrZ9HC2Kvc5vl9upOgUUHKzURjAVf2N+f6tEJiojqXUuA==", - "requires": { - "gaxios": "^3.0.0", - "json-bigint": "^1.0.0" - } - }, - "google-auth-library": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.6.tgz", - "integrity": "sha512-fWYdRdg55HSJoRq9k568jJA1lrhg9i2xgfhVIMJbskUmbDpJGHsbv9l41DGhCDXM21F9Kn4kUwdysgxSYBYJUw==", - "requires": { - "arrify": "^2.0.0", - "base64-js": "^1.3.0", - "ecdsa-sig-formatter": "^1.0.11", - "fast-text-encoding": "^1.0.0", - "gaxios": "^3.0.0", - "gcp-metadata": "^4.1.0", - "gtoken": "^5.0.0", - "jws": "^4.0.0", - "lru-cache": "^6.0.0" - } - }, - "google-p12-pem": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.3.tgz", - "integrity": "sha512-wS0ek4ZtFx/ACKYF3JhyGe5kzH7pgiQ7J5otlumqR9psmWMYc+U9cErKlCYVYHoUaidXHdZ2xbo34kB+S+24hA==", - "requires": { - "node-forge": "^0.10.0" - } - }, - "googleapis": { - "version": "59.0.0", - "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-59.0.0.tgz", - "integrity": "sha512-GV/E4KRN89a4GxSk7D7cwUfRYgcJHR05sOgm/WGdwc/u8dxNXG5lWmz9gF5ZwFGk2yKtVxL4VZNn4zBuZ6rmGg==", - "requires": { - "google-auth-library": "^6.0.0", - "googleapis-common": "^4.4.0" - } - }, - "googleapis-common": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-4.4.0.tgz", - "integrity": "sha512-Bgrs8/1OZQFFIfVuX38L9t48rPAkVUXttZy6NzhhXxFOEMSHgfFIjxou7RIXOkBHxmx2pVwct9WjKkbnqMYImQ==", - "requires": { - "extend": "^3.0.2", - "gaxios": "^3.0.0", - "google-auth-library": "^6.0.0", - "qs": "^6.7.0", - "url-template": "^2.0.8", - "uuid": "^8.0.0" - } - }, - "gtoken": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.3.tgz", - "integrity": "sha512-Nyd1wZCMRc2dj/mAD0LlfQLcAO06uKdpKJXvK85SGrF5+5+Bpfil9u/2aw35ltvEHjvl0h5FMKN5knEU+9JrOg==", - "requires": { - "gaxios": "^3.0.0", - "google-p12-pem": "^3.0.0", - "jws": "^4.0.0", - "mime": "^2.2.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" - }, - "homebridge-lib": { - "version": "4.7.14", - "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-4.7.14.tgz", - "integrity": "sha512-8eUGTVrCRd7WHwEH49CgqYUu2q9WjeTVDnEA5WXL2ZvPevTMCck5GcVIXtvVWxr9we8Ay0ybFp0N5RRlrIzH/g==", - "requires": { - "bonjour": "^3.5.0", - "chalk": "^4.1.0", - "debug": "^4.1.1", - "semver": "^7.3.2" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "requires": { - "agent-base": "6", - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" - }, - "is-arguments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", - "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==" - }, - "is-callable": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.1.tgz", - "integrity": "sha512-wliAfSzx6V+6WfMOmus1xy0XvSgf/dlStkvTfq7F0g4bOIW0PSUbnyse3NhDwdyYS1ozfUtAAySqTws3z9Eqgg==" - }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" - }, - "is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "requires": { - "has-symbols": "^1.0.1" - } - }, - "json-bigint": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "requires": { - "bignumber.js": "^9.0.0" - } - }, - "jwa": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", - "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "requires": { - "jwa": "^2.0.0", - "safe-buffer": "^5.0.1" - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "mime": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", - "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" - }, - "moment": { - "version": "2.27.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz", - "integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "multicast-dns": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", - "requires": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" - } - }, - "multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" - }, - "node-dns-sd": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/node-dns-sd/-/node-dns-sd-0.4.1.tgz", - "integrity": "sha512-x+WSuMgvDBQv24OCq75YHcZj1SOzvP5fU4Tz+PBUiVvVBsfc+9XAHAuIftaCpf2nPLl+ys71uZoGr/v9fVDa6A==" - }, - "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" - }, - "node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" - }, - "object-inspect": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", - "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==" - }, - "object-is": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz", - "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "qs": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", - "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" - }, - "regexp.prototype.flags": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", - "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" - }, - "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - }, - "thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" - }, - "url-template": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", - "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" - }, - "uuid": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.0.tgz", - "integrity": "sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==" - }, - "ws": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz", - "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "name": "homebridge-ewelink", + "version": "2.26.2", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "agent-base": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.1.tgz", + "integrity": "sha512-01q25QQDwLSsyfhrKbn8yuur+JNw0H+0Y4JiGIKd3z9aYk/w/2kxD/Upc+t2ZBBSUNff50VjPsSW2YxM8QYKVg==", + "requires": { + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + }, + "axios": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz", + "integrity": "sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, + "bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "correcting-interval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/correcting-interval/-/correcting-interval-2.0.0.tgz", + "integrity": "sha1-iTdklFcN+C7axTQRHV8n/z6gstM=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" + }, + "dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "fakegato-history": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/fakegato-history/-/fakegato-history-0.5.6.tgz", + "integrity": "sha512-LlsOkiw9LntVlRlBkssD5ozhEkQzYuEJUlvXk5YAgBQcWzk19PQ5g+NoKfs6SRY1qAeC1onb65hes4mCvY+JmA==", + "requires": { + "debug": "^2.2.0", + "googleapis": ">39.1.0", + "moment": "*" + } + }, + "fast-text-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", + "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" + }, + "follow-redirects": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", + "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==" + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "gaxios": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.1.0.tgz", + "integrity": "sha512-DDTn3KXVJJigtz+g0J3vhcfbDbKtAroSTxauWsdnP57sM5KZ3d2c/3D9RKFJ86s43hfw6WULg6TXYw/AYiBlpA==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + } + }, + "gcp-metadata": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.4.tgz", + "integrity": "sha512-5J/GIH0yWt/56R3dNaNWPGQ/zXsZOddYECfJaqxFWgrZ9HC2Kvc5vl9upOgUUHKzURjAVf2N+f6tEJiojqXUuA==", + "requires": { + "gaxios": "^3.0.0", + "json-bigint": "^1.0.0" + } + }, + "google-auth-library": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.6.tgz", + "integrity": "sha512-fWYdRdg55HSJoRq9k568jJA1lrhg9i2xgfhVIMJbskUmbDpJGHsbv9l41DGhCDXM21F9Kn4kUwdysgxSYBYJUw==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^3.0.0", + "gcp-metadata": "^4.1.0", + "gtoken": "^5.0.0", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + } + }, + "google-p12-pem": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.3.tgz", + "integrity": "sha512-wS0ek4ZtFx/ACKYF3JhyGe5kzH7pgiQ7J5otlumqR9psmWMYc+U9cErKlCYVYHoUaidXHdZ2xbo34kB+S+24hA==", + "requires": { + "node-forge": "^0.10.0" + } + }, + "googleapis": { + "version": "59.0.0", + "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-59.0.0.tgz", + "integrity": "sha512-GV/E4KRN89a4GxSk7D7cwUfRYgcJHR05sOgm/WGdwc/u8dxNXG5lWmz9gF5ZwFGk2yKtVxL4VZNn4zBuZ6rmGg==", + "requires": { + "google-auth-library": "^6.0.0", + "googleapis-common": "^4.4.0" + } + }, + "googleapis-common": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-4.4.0.tgz", + "integrity": "sha512-Bgrs8/1OZQFFIfVuX38L9t48rPAkVUXttZy6NzhhXxFOEMSHgfFIjxou7RIXOkBHxmx2pVwct9WjKkbnqMYImQ==", + "requires": { + "extend": "^3.0.2", + "gaxios": "^3.0.0", + "google-auth-library": "^6.0.0", + "qs": "^6.7.0", + "url-template": "^2.0.8", + "uuid": "^8.0.0" + } + }, + "gtoken": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.3.tgz", + "integrity": "sha512-Nyd1wZCMRc2dj/mAD0LlfQLcAO06uKdpKJXvK85SGrF5+5+Bpfil9u/2aw35ltvEHjvl0h5FMKN5knEU+9JrOg==", + "requires": { + "gaxios": "^3.0.0", + "google-p12-pem": "^3.0.0", + "jws": "^4.0.0", + "mime": "^2.2.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "homebridge-lib": { + "version": "4.7.14", + "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-4.7.14.tgz", + "integrity": "sha512-8eUGTVrCRd7WHwEH49CgqYUu2q9WjeTVDnEA5WXL2ZvPevTMCck5GcVIXtvVWxr9we8Ay0ybFp0N5RRlrIzH/g==", + "requires": { + "bonjour": "^3.5.0", + "chalk": "^4.1.0", + "debug": "^4.1.1", + "semver": "^7.3.2" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==" + }, + "is-callable": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.1.tgz", + "integrity": "sha512-wliAfSzx6V+6WfMOmus1xy0XvSgf/dlStkvTfq7F0g4bOIW0PSUbnyse3NhDwdyYS1ozfUtAAySqTws3z9Eqgg==" + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" + }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, + "jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "mime": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" + }, + "moment": { + "version": "2.27.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz", + "integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" + }, + "node-dns-sd": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/node-dns-sd/-/node-dns-sd-0.4.1.tgz", + "integrity": "sha512-x+WSuMgvDBQv24OCq75YHcZj1SOzvP5fU4Tz+PBUiVvVBsfc+9XAHAuIftaCpf2nPLl+ys71uZoGr/v9fVDa6A==" + }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" + }, + "object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==" + }, + "object-is": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz", + "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "prettier": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.1.tgz", + "integrity": "sha512-9bY+5ZWCfqj3ghYBLxApy2zf6m+NJo5GzmLTpr9FsApsfjriNnS2dahWReHMi7qNPhhHl9SYHJs2cHZLgexNIw==", + "dev": true + }, + "qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" + }, + "regexp.prototype.flags": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", + "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" + }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" } - } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" + }, + "uuid": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.0.tgz", + "integrity": "sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==" + }, + "ws": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz", + "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } } diff --git a/package.json b/package.json index 5e90fe89..06d38b28 100644 --- a/package.json +++ b/package.json @@ -1,68 +1,71 @@ { - "name": "homebridge-ewelink", - "version": "2.26.2", - "author": "bwp91", - "contributors": [ - "gbro115", - "MrTomAsh", - "howanghk", - "LeJeko", - "aremishevsky-chegg", - "samkni", - "robsonfj", - "ramsesz", - "metarutaiga", - "janbuecker", - "jacopofranza", - "donavanbecker", - "dhutchison", - "danielk117", - "bassrock", - "VictorKrasnov", - "JuniorGenius", - "BobbySlope" - ], - "description": "Homebridge plugin to control eWeLink devices with original firmware.", - "license": "MIT", - "keywords": [ - "homebridge", - "homebridge-plugin", - "homekit", - "sonoff", - "ewelink" - ], - "engines": { - "node": ">=6.0.0", - "homebridge": ">=0.2.0" - }, - "repository": { - "type": "git", - "url": "https://github.com/bwp91/homebridge-ewelink" - }, - "bugs": { - "url": "https://github.com/bwp91/homebridge-ewelink/issues" - }, - "dependencies": { - "axios": "0.20.0", - "color-convert": "2.0.1", - "correcting-interval": "2.0.0", - "fakegato-history": "0.5.6", - "homebridge-lib": "4.7.14", - "node-dns-sd": "0.4.1", - "ws": "7.3.1" - }, - "funding": [ - { - "type": "kofi", - "url": "https://ko-fi.com/bwp91" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/bwp91" - }, - { - "type": "paypal", - "url": "https://www.paypal.me/BenPotter" - } - ] + "name": "homebridge-ewelink", + "version": "2.26.2", + "author": "bwp91", + "contributors": [ + "gbro115", + "MrTomAsh", + "howanghk", + "LeJeko", + "aremishevsky-chegg", + "samkni", + "robsonfj", + "ramsesz", + "metarutaiga", + "janbuecker", + "jacopofranza", + "donavanbecker", + "dhutchison", + "danielk117", + "bassrock", + "VictorKrasnov", + "JuniorGenius", + "BobbySlope" + ], + "description": "Homebridge plugin to control eWeLink devices with original firmware.", + "license": "MIT", + "keywords": [ + "homebridge", + "homebridge-plugin", + "homekit", + "sonoff", + "ewelink" + ], + "engines": { + "node": ">=6.0.0", + "homebridge": ">=0.2.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/bwp91/homebridge-ewelink" + }, + "bugs": { + "url": "https://github.com/bwp91/homebridge-ewelink/issues" + }, + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/bwp91" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/bwp91" + }, + { + "type": "paypal", + "url": "https://www.paypal.me/BenPotter" + } + ], + "dependencies": { + "axios": "0.20.0", + "color-convert": "2.0.1", + "correcting-interval": "2.0.0", + "fakegato-history": "0.5.6", + "homebridge-lib": "4.7.14", + "node-dns-sd": "0.4.1", + "ws": "7.3.1" + }, + "devDependencies": { + "prettier": "2.1.1" + } } From 42845071fa919551a64540ee964151f4498fa1e8 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 15 Sep 2020 18:09:07 +0100 Subject: [PATCH 0151/3183] prettier formatting --- .prettierrc.json | 3 +- lib/constants.js | 30 +- lib/eWeLink.js | 1489 ++++++++++++++++++++++++++++++++++---------- lib/eWeLinkHTTP.js | 38 +- lib/eWeLinkLAN.js | 71 ++- lib/eWeLinkWS.js | 80 ++- 6 files changed, 1322 insertions(+), 389 deletions(-) diff --git a/.prettierrc.json b/.prettierrc.json index 163a0a7e..d68aa739 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,4 +1,3 @@ { - "arrowParens": "avoid", - "printWidth": 120 + "arrowParens": "avoid" } diff --git a/lib/constants.js b/lib/constants.js index c8a8f17f..34215ac6 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -11,7 +11,18 @@ module.exports = { devicesSingleSwitchParams: ["switch"], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], devicesMultiSwitchParams: ["switches"], - devicesSingleSwitchLight: ["T1 1C", "L1", "B1", "B1_R2", "TX1C", "D1", "D1R1", "KING-M4", "Slampher", "GTTA59"], + devicesSingleSwitchLight: [ + "T1 1C", + "L1", + "B1", + "B1_R2", + "TX1C", + "D1", + "D1R1", + "KING-M4", + "Slampher", + "GTTA59", + ], devicesSingleSwitchLightParams: [ "switch", "state", @@ -29,7 +40,12 @@ module.exports = { devicesSensor: [102], devicesSensorParams: ["switch", "battery", "type"], devicesThermostat: [15], - devicesThermostatParams: ["currentTemperature", "currentHumidity", "switch", "masterSwitch"], + devicesThermostatParams: [ + "currentTemperature", + "currentHumidity", + "switch", + "masterSwitch", + ], devicesFan: [34], devicesFanParams: ["switches", "light", "fan", "speed"], devicesOutlet: [32], @@ -42,7 +58,15 @@ module.exports = { devicesRFBridge: [28], devicesRFBridgeParams: ["cmd"], devicesZBBridge: [66], - devicesZBBridgeParams: ["key", "temperature", "humidity", "motion", "lock", "trigTime", "battery"], + devicesZBBridgeParams: [ + "key", + "temperature", + "humidity", + "motion", + "lock", + "trigTime", + "battery", + ], devicesZB: [1000, 1770, 2026, 3026], devicesValveParams: ["switches"], devicesBlindParams: ["switch", "switches"], diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 5b87acf8..0869e08a 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -13,9 +13,15 @@ class eWeLink { constructor(log, config, api) { if (!log || !api || !config) return; if (!config.username || !config.password || !config.countryCode) { - log.error("**************** Cannot load homebridge-ewelink ****************"); - log.error("Your eWeLink credentials are missing from the Homebridge config."); - log.error("****************************************************************"); + log.error( + "**************** Cannot load homebridge-ewelink ****************" + ); + log.error( + "Your eWeLink credentials are missing from the Homebridge config." + ); + log.error( + "****************************************************************" + ); return; } this.log = log; @@ -29,7 +35,9 @@ class eWeLink { this.eveLogPath = this.api.user.storagePath() + "/homebridge-ewelink/"; this.api .on("didFinishLaunching", () => { - this.log("Plugin has finished initialising. Starting synchronisation with eWeLink account."); + this.log( + "Plugin has finished initialising. Starting synchronisation with eWeLink account." + ); //*** Set up HTTP client and get the user HTTP host ***\\ this.httpClient = new eWeLinkHTTP(this.config, this.log); this.httpClient @@ -48,10 +56,23 @@ class eWeLink { .then(res => { //*** Get device IP addresses for LAN mode ***\\ this.httpDevices = res - .filter(device => device.hasOwnProperty("extra") && device.extra.hasOwnProperty("uiid")) - .filter(device => !(this.config.hideDevFromHB || "").includes(device.deviceid)); - this.lanClient = new eWeLinkLAN(this.config, this.log, this.httpDevices); - this.httpDevices.forEach(device => this.devicesInEwe.set(device.deviceid, device)); + .filter( + device => + device.hasOwnProperty("extra") && + device.extra.hasOwnProperty("uiid") + ) + .filter( + device => + !(this.config.hideDevFromHB || "").includes(device.deviceid) + ); + this.lanClient = new eWeLinkLAN( + this.config, + this.log, + this.httpDevices + ); + this.httpDevices.forEach(device => + this.devicesInEwe.set(device.deviceid, device) + ); return this.lanClient.getHosts(); }) .then(res => { @@ -64,8 +85,13 @@ class eWeLink { //*** Use the device list to refresh Homebridge accessories ***\\ (() => { //*** Remove all Homebridge accessories if none found ***\\ - if (Object.keys(this.httpDevices).length === 0 && Object.keys(this.lanDevices).length === 0) { - Array.from(this.devicesInHB.values()).forEach(a => this.removeAccessory(a)); + if ( + Object.keys(this.httpDevices).length === 0 && + Object.keys(this.lanDevices).length === 0 + ) { + Array.from(this.devicesInHB.values()).forEach(a => + this.removeAccessory(a) + ); this.devicesInHB.clear(); this.log.warn("******* Not loading homebridge-ewelink *******"); this.log.warn("No devices were found in your eWeLink account."); @@ -75,20 +101,41 @@ class eWeLink { //*** Make a map of custom groups from Homebridge config ***\\ if (Object.keys(this.config.groups || []).length > 0) { this.config.groups - .filter(g => g.hasOwnProperty("type") && cns.allowedGroups.includes(g.type)) - .filter(g => g.hasOwnProperty("deviceId") && this.devicesInEwe.has(g.deviceId.toLowerCase())) + .filter( + g => + g.hasOwnProperty("type") && + cns.allowedGroups.includes(g.type) + ) + .filter( + g => + g.hasOwnProperty("deviceId") && + this.devicesInEwe.has(g.deviceId.toLowerCase()) + ) .forEach(g => this.cusG.set(g.deviceId + "SWX", g)); } //*** Make a map of RF Bridge custom sensors from Homebridge config ***\\ if (Object.keys(this.config.bridgeSensors || []).length > 0) { this.config.bridgeSensors - .filter(s => s.hasOwnProperty("deviceId") && this.devicesInEwe.has(s.deviceId.toLowerCase())) + .filter( + s => + s.hasOwnProperty("deviceId") && + this.devicesInEwe.has(s.deviceId.toLowerCase()) + ) .forEach(s => this.cusS.set(s.fullDeviceId, s)); } //*** Logging always helps to see if everything is okay so far ***\\ - this.log("[%s] eWeLink devices were loaded from the Homebridge cache.", this.devicesInHB.size); - this.log("[%s] primary devices were loaded from your eWeLink account.", this.devicesInEwe.size); - this.log("[%s] primary devices were discovered on your local network.", this.lanDevicesOnline); + this.log( + "[%s] eWeLink devices were loaded from the Homebridge cache.", + this.devicesInHB.size + ); + this.log( + "[%s] primary devices were loaded from your eWeLink account.", + this.devicesInEwe.size + ); + this.log( + "[%s] primary devices were discovered on your local network.", + this.lanDevicesOnline + ); //*** Remove Homebridge accessories that don't appear in eWeLink ***\\ this.devicesInHB.forEach(a => { if (!this.devicesInEwe.has(a.context.eweDeviceId)) { @@ -99,7 +146,9 @@ class eWeLink { this.devicesInEwe.forEach(d => this.initialiseDevice(d)); this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); - this.log("eWeLink setup complete. If you're enjoying this package please consider a ⭐ī¸ on GitHub :)."); + this.log( + "eWeLink setup complete. If you're enjoying this package please consider a ⭐ī¸ on GitHub :)." + ); if (this.config.debugReqRes || false) { this.log.warn( "You have 'Request & Response Logging' enabled. This setting is not recommended for long-term use." @@ -108,9 +157,13 @@ class eWeLink { })(); }) .catch(err => { - this.log.error("************** Cannot load homebridge-ewelink **************"); + this.log.error( + "************** Cannot load homebridge-ewelink **************" + ); this.log.error(err); - this.log.error("************************************************************"); + this.log.error( + "************************************************************" + ); if (this.lanClient) this.lanClient.closeConnection(); if (this.wsClient) this.wsClient.closeConnection(); }); @@ -122,16 +175,31 @@ class eWeLink { } initialiseDevice(device) { let accessory; - // if (device.extra.uiid === 102) this.log.warn(device); //*** First add the device if it isn't already in Homebridge. Yeah this code looks a mess :| ***\\ - if (!this.devicesInHB.has(device.deviceid + "SWX") && !this.devicesInHB.has(device.deviceid + "SW0")) { - if (device.extra.uiid === 2 && device.brandName === "coolkit" && device.productModel === "0285") { + if ( + !this.devicesInHB.has(device.deviceid + "SWX") && + !this.devicesInHB.has(device.deviceid + "SW0") + ) { + if ( + device.extra.uiid === 2 && + device.brandName === "coolkit" && + device.productModel === "0285" + ) { this.addAccessory(device, device.deviceid + "SWX", "valve"); - } else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "blind") { + } else if ( + this.cusG.has(device.deviceid + "SWX") && + this.cusG.get(device.deviceid + "SWX").type === "blind" + ) { this.addAccessory(device, device.deviceid + "SWX", "blind"); - } else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "garage") { + } else if ( + this.cusG.has(device.deviceid + "SWX") && + this.cusG.get(device.deviceid + "SWX").type === "garage" + ) { this.addAccessory(device, device.deviceid + "SWX", "garage"); - } else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "lock") { + } else if ( + this.cusG.has(device.deviceid + "SWX") && + this.cusG.get(device.deviceid + "SWX").type === "lock" + ) { this.addAccessory(device, device.deviceid + "SWX", "lock"); } else if (cns.devicesSensor.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SWX", "sensor"); @@ -165,7 +233,9 @@ class eWeLink { } } else if (cns.devicesRFBridge.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SW0", "rf_pri"); - if (Object.keys((device.tags && device.tags.zyx_info) || []).length > 0) { + if ( + Object.keys((device.tags && device.tags.zyx_info) || []).length > 0 + ) { for (let i = 1; i <= Object.keys(device.tags.zyx_info).length; i++) { this.addAccessory(device, device.deviceid + "SW" + i, "rf_sub"); } @@ -189,18 +259,29 @@ class eWeLink { } } //*** Next refresh the device ***\\ - if ((accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0"))) { + if ( + (accessory = + this.devicesInHB.get(device.deviceid + "SWX") || + this.devicesInHB.get(device.deviceid + "SW0")) + ) { let isX = accessory.context.hbDeviceId.substr(-1) === "X", isRfBridge = cns.devicesRFBridge.includes(accessory.context.eweUIID), rfBridgeChange = false; accessory .getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); - accessory.context.reachableWAN = accessory.context.eweUIID !== 102 ? device.online : true; - accessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; + .setCharacteristic( + Characteristic.FirmwareRevision, + device.params.fwVersion + ); + accessory.context.reachableWAN = + accessory.context.eweUIID !== 102 ? device.online : true; + accessory.context.reachableLAN = + this.lanDevices.get(device.deviceid).online || false; accessory.context.inUse = false; let str = accessory.context.reachableLAN - ? "and locally with IP [" + this.lanDevices.get(device.deviceid).ip + "]" + ? "and locally with IP [" + + this.lanDevices.get(device.deviceid).ip + + "]" : "but LAN mode unavailable as unsupported/shared device"; this.log("[%s] found in eWeLink %s.", accessory.displayName, str); this.devicesInHB.set(accessory.context.hbDeviceId, accessory); @@ -208,7 +289,11 @@ class eWeLink { for (let i = 1; i <= accessory.context.channelCount; i++) { if (!this.devicesInHB.has(device.deviceid + "SW" + i)) { if (cns.devicesHideable.includes(accessory.context.type)) { - if ((this.config.hideFromHB || "").includes(device.deviceid + "SW" + i)) { + if ( + (this.config.hideFromHB || "").includes( + device.deviceid + "SW" + i + ) + ) { continue; } else { this.addAccessory(device, device.deviceid + "SW" + i, "switch"); @@ -217,7 +302,9 @@ class eWeLink { } let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); if ( - (this.config.hideFromHB || "").includes(device.deviceid + "SW" + i) && + (this.config.hideFromHB || "").includes( + device.deviceid + "SW" + i + ) && cns.devicesHideable.includes(accessory.context.type) ) { this.removeAccessory(oAccessory); @@ -231,9 +318,13 @@ class eWeLink { } oAccessory .getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); + .setCharacteristic( + Characteristic.FirmwareRevision, + device.params.fwVersion + ); oAccessory.context.reachableWAN = device.online; - oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; + oAccessory.context.reachableLAN = + this.lanDevices.get(device.deviceid).online || false; this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); } } @@ -258,19 +349,28 @@ class eWeLink { ); } } else { - this.log.warn("[%s] cannot be initialised as it wasn't found in Homebridge.", device.name); + this.log.warn( + "[%s] cannot be initialised as it wasn't found in Homebridge.", + device.name + ); } } addAccessory(device, hbDeviceId, type) { let switchNumber = hbDeviceId.substr(-1).toString(), - newDeviceName = type === "rf_sub" ? device.tags.zyx_info[switchNumber - 1].name : device.name, + newDeviceName = + type === "rf_sub" + ? device.tags.zyx_info[switchNumber - 1].name + : device.name, channelCount = type === "rf_pri" ? Object.keys((device.tags && device.tags.zyx_info) || []).length : cns.chansFromUiid[device.extra.uiid]; if (["1", "2", "3", "4"].includes(switchNumber) && type !== "rf_sub") { newDeviceName += " SW" + switchNumber; - if ((this.config.hideFromHB || "").includes(hbDeviceId) && cns.devicesHideable.includes(type)) { + if ( + (this.config.hideFromHB || "").includes(hbDeviceId) && + cns.devicesHideable.includes(type) + ) { this.log("[%s] will not be added as per configuration.", newDeviceName); return; } @@ -278,14 +378,23 @@ class eWeLink { if ((this.config.nameOverride || {}).hasOwnProperty(hbDeviceId)) { newDeviceName = this.config.nameOverride[hbDeviceId]; } - const accessory = new Accessory(newDeviceName, UUIDGen.generate(hbDeviceId).toString()); + const accessory = new Accessory( + newDeviceName, + UUIDGen.generate(hbDeviceId).toString() + ); try { accessory .getService(Service.AccessoryInformation) .setCharacteristic(Characteristic.SerialNumber, hbDeviceId) .setCharacteristic(Characteristic.Manufacturer, device.brandName) - .setCharacteristic(Characteristic.Model, device.productModel + " (" + device.extra.model + ")") - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) + .setCharacteristic( + Characteristic.Model, + device.productModel + " (" + device.extra.model + ")" + ) + .setCharacteristic( + Characteristic.FirmwareRevision, + device.params.fwVersion + ) .setCharacteristic(Characteristic.Identify, false); accessory.context = { hbDeviceId, @@ -301,11 +410,18 @@ class eWeLink { case "valve": ["A", "B"].forEach(v => { accessory - .addService(Service.Valve, "Valve " + v, "valve" + v.toLowerCase()) + .addService( + Service.Valve, + "Valve " + v, + "valve" + v.toLowerCase() + ) .setCharacteristic(Characteristic.Active, 0) .setCharacteristic(Characteristic.InUse, 0) .setCharacteristic(Characteristic.ValveType, 1) - .setCharacteristic(Characteristic.SetDuration, this.config.valveTimeLength || 120) + .setCharacteristic( + Characteristic.SetDuration, + this.config.valveTimeLength || 120 + ) .addCharacteristic(Characteristic.RemainingDuration); }); break; @@ -339,15 +455,26 @@ class eWeLink { case "thermostat": if (!this.config.hideTHSwitch) accessory.addService(Service.Switch); accessory.addService(Service.TemperatureSensor); - if (device.params.sensorType !== "DS18B20") accessory.addService(Service.HumiditySensor); + if (device.params.sensorType !== "DS18B20") + accessory.addService(Service.HumiditySensor); break; case "outlet": accessory.addService(Service.Outlet); - accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.Voltage); - accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.CurrentConsumption); - accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.ElectricCurrent); - accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.TotalConsumption); - accessory.getService(Service.Outlet).addCharacteristic(EveService.Characteristics.ResetTotal); + accessory + .getService(Service.Outlet) + .addCharacteristic(EveService.Characteristics.Voltage); + accessory + .getService(Service.Outlet) + .addCharacteristic(EveService.Characteristics.CurrentConsumption); + accessory + .getService(Service.Outlet) + .addCharacteristic(EveService.Characteristics.ElectricCurrent); + accessory + .getService(Service.Outlet) + .addCharacteristic(EveService.Characteristics.TotalConsumption); + accessory + .getService(Service.Outlet) + .addCharacteristic(EveService.Characteristics.ResetTotal); accessory.context = { ...accessory.context, ...{ @@ -375,7 +502,9 @@ class eWeLink { break; case "rf_sub": accessory.context.rfChls = {}; - switch (device.tags.zyx_info[parseInt(switchNumber) - 1].remote_type) { + switch ( + device.tags.zyx_info[parseInt(switchNumber) - 1].remote_type + ) { case "1": case "2": case "3": @@ -383,7 +512,9 @@ class eWeLink { accessory.context.sensorType = "button"; break; case "6": - accessory.context.sensorType = this.cusS.has(hbDeviceId) ? this.cusS.get(hbDeviceId).type : "motion"; + accessory.context.sensorType = this.cusS.has(hbDeviceId) + ? this.cusS.get(hbDeviceId).type + : "motion"; break; default: throw ( @@ -393,46 +524,52 @@ class eWeLink { ); } let mAccessory = this.devicesInHB.get(device.deviceid + "SW0"); - device.tags.zyx_info[parseInt(switchNumber) - 1].buttonName.forEach(button => { - let rfData; - Object.entries(button).forEach( - ([k, v]) => - (rfData = { - rfChan: k, - name: v, - }) - ); - accessory.context.rfChls[rfData.rfChan] = rfData.name; - mAccessory.context.rfChlMap[rfData.rfChan] = switchNumber; - switch (accessory.context.sensorType) { - case "button": - accessory.addService(Service.Switch, rfData.name, "switch" + rfData.rfChan); - break; - case "water": - accessory.addService(Service.LeakSensor); - break; - case "fire": - case "smoke": - accessory.addService(Service.SmokeSensor); - break; - case "co": - accessory.addService(Service.CarbonMonoxideSensor); - break; - case "co2": - accessory.addService(Service.CarbonDioxideSensor); - break; - case "contact": - accessory.addService(Service.ContactSensor); - break; - case "occupancy": - accessory.addService(Service.OccupancySensor); - break; - default: - accessory.addService(Service.MotionSensor); - break; + device.tags.zyx_info[parseInt(switchNumber) - 1].buttonName.forEach( + button => { + let rfData; + Object.entries(button).forEach( + ([k, v]) => + (rfData = { + rfChan: k, + name: v, + }) + ); + accessory.context.rfChls[rfData.rfChan] = rfData.name; + mAccessory.context.rfChlMap[rfData.rfChan] = switchNumber; + switch (accessory.context.sensorType) { + case "button": + accessory.addService( + Service.Switch, + rfData.name, + "switch" + rfData.rfChan + ); + break; + case "water": + accessory.addService(Service.LeakSensor); + break; + case "fire": + case "smoke": + accessory.addService(Service.SmokeSensor); + break; + case "co": + accessory.addService(Service.CarbonMonoxideSensor); + break; + case "co2": + accessory.addService(Service.CarbonDioxideSensor); + break; + case "contact": + accessory.addService(Service.ContactSensor); + break; + case "occupancy": + accessory.addService(Service.OccupancySensor); + break; + default: + accessory.addService(Service.MotionSensor); + break; + } + this.devicesInHB.set(mAccessory.context.hbDeviceId, mAccessory); } - this.devicesInHB.set(mAccessory.context.hbDeviceId, mAccessory); - }); + ); break; case "zb_sub": //*** credit @tasict ***\\ accessory.addService(Service.BatteryService); @@ -459,14 +596,20 @@ class eWeLink { accessory.addService(Service.ContactSensor); break; default: - throw "unsupported zigbee device type [" + device.extra.uiid + "]. Please create an issue on GitHub"; + throw ( + "unsupported zigbee device type [" + + device.extra.uiid + + "]. Please create an issue on GitHub" + ); } break; default: throw "device is not supported by this plugin. Please create an issue on GitHub"; } this.devicesInHB.set(hbDeviceId, accessory); - this.api.registerPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); + this.api.registerPlatformAccessories("homebridge-ewelink", "eWeLink", [ + accessory, + ]); this.configureAccessory(accessory); this.log("[%s] has been added to Homebridge.", newDeviceName); } catch (err) { @@ -484,16 +627,34 @@ class eWeLink { accessory .getService("Valve " + v) .getCharacteristic(Characteristic.Active) - .on("set", (value, callback) => this.internalValveUpdate(accessory, "Valve " + v, value, callback)); + .on("set", (value, callback) => + this.internalValveUpdate( + accessory, + "Valve " + v, + value, + callback + ) + ); accessory .getService("Valve " + v) .getCharacteristic(Characteristic.SetDuration) .on("set", (value, callback) => { - if (accessory.getService("Valve " + v).getCharacteristic(Characteristic.InUse).value) { - accessory.getService("Valve " + v).updateCharacteristic(Characteristic.RemainingDuration, value); + if ( + accessory + .getService("Valve " + v) + .getCharacteristic(Characteristic.InUse).value + ) { + accessory + .getService("Valve " + v) + .updateCharacteristic( + Characteristic.RemainingDuration, + value + ); clearTimeout(accessory.getService("Valve " + v).timer); accessory.getService("Valve " + v).timer = setTimeout(() => { - accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); + accessory + .getService("Valve " + v) + .setCharacteristic(Characteristic.Active, 0); }, value * 1000); } callback(); @@ -504,7 +665,9 @@ class eWeLink { accessory .getService(Service.WindowCovering) .getCharacteristic(Characteristic.TargetPosition) - .on("set", (value, callback) => this.internalBlindUpdate(accessory, value, callback)) + .on("set", (value, callback) => + this.internalBlindUpdate(accessory, value, callback) + ) .setProps({ minStep: 100, }); @@ -513,37 +676,49 @@ class eWeLink { accessory .getService(Service.GarageDoorOpener) .getCharacteristic(Characteristic.TargetDoorState) - .on("set", (value, callback) => this.internalGarageUpdate(accessory, value, callback)); + .on("set", (value, callback) => + this.internalGarageUpdate(accessory, value, callback) + ); break; case "lock": accessory .getService(Service.LockMechanism) .getCharacteristic(Characteristic.LockTargetState) - .on("set", (value, callback) => this.internalLockUpdate(accessory, value, callback)); + .on("set", (value, callback) => + this.internalLockUpdate(accessory, value, callback) + ); break; case "fan": accessory .getService(Service.Fanv2) .getCharacteristic(Characteristic.Active) - .on("set", (value, callback) => this.internalFanUpdate(accessory, "power", value, callback)); + .on("set", (value, callback) => + this.internalFanUpdate(accessory, "power", value, callback) + ); accessory .getService(Service.Fanv2) .getCharacteristic(Characteristic.RotationSpeed) - .on("set", (value, callback) => this.internalFanUpdate(accessory, "speed", value, callback)) + .on("set", (value, callback) => + this.internalFanUpdate(accessory, "speed", value, callback) + ) .setProps({ minStep: 33, }); accessory .getService(Service.Lightbulb) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalFanUpdate(accessory, "light", value, callback)); + .on("set", (value, callback) => + this.internalFanUpdate(accessory, "light", value, callback) + ); break; case "thermostat": if (!this.config.hideTHSwitch) { accessory .getService(Service.Switch) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalThermostatUpdate(accessory, value, callback)); + .on("set", (value, callback) => + this.internalThermostatUpdate(accessory, value, callback) + ); } accessory.log = this.log; accessory.eveLogger = new EveHistoryService("weather", accessory, { @@ -554,13 +729,16 @@ class eWeLink { corrInterval.setCorrectingInterval(() => { let dataToAdd = { time: Date.now(), - temp: accessory.getService(Service.TemperatureSensor).getCharacteristic(Characteristic.CurrentTemperature) - .value, + temp: accessory + .getService(Service.TemperatureSensor) + .getCharacteristic(Characteristic.CurrentTemperature).value, }; if (accessory.getService(Service.HumiditySensor)) { dataToAdd.humidity = accessory .getService(Service.HumiditySensor) - .getCharacteristic(Characteristic.CurrentRelativeHumidity).value; + .getCharacteristic( + Characteristic.CurrentRelativeHumidity + ).value; } accessory.eveLogger.addEntry(dataToAdd); }, 300000); @@ -569,7 +747,9 @@ class eWeLink { accessory .getService(Service.Outlet) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalOutletUpdate(accessory, value, callback)); + .on("set", (value, callback) => + this.internalOutletUpdate(accessory, value, callback) + ); accessory.log = this.log; accessory.eveLogger = new EveHistoryService("energy", accessory, { storage: "fs", @@ -588,10 +768,15 @@ class eWeLink { }; } corrInterval.setCorrectingInterval(() => { - let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value, + let isOn = accessory + .getService(Service.Outlet) + .getCharacteristic(Characteristic.On).value, currentWatt = isOn - ? accessory.getService(Service.Outlet).getCharacteristic(EveService.Characteristics.CurrentConsumption) - .value + ? accessory + .getService(Service.Outlet) + .getCharacteristic( + EveService.Characteristics.CurrentConsumption + ).value : 0; if (accessory.eveLogger.isHistoryLoaded()) { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); @@ -605,7 +790,9 @@ class eWeLink { lastReset: accessory.context.extraPersistedData.lastReset, }); } else { - accessory.context.totalEnergy = accessory.context.totalEnergyTemp + (currentWatt * 10) / 3600 / 1000; + accessory.context.totalEnergy = + accessory.context.totalEnergyTemp + + (currentWatt * 10) / 3600 / 1000; accessory.eveLogger.setExtraPersistedData({ totalenergy: accessory.context.totalEnergy, lastReset: 0, @@ -613,7 +800,8 @@ class eWeLink { } accessory.context.totalEnergytemp = 0; } else { - accessory.context.totalEnergyTemp += (currentWatt * 10) / 3600 / 1000; + accessory.context.totalEnergyTemp += + (currentWatt * 10) / 3600 / 1000; accessory.context.totalEnergy = accessory.context.totalEnergyTemp; } accessory.eveLogger.addEntry({ @@ -627,7 +815,8 @@ class eWeLink { .on("get", callback => { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower; + accessory.context.totalEnergy = + accessory.context.extraPersistedData.totalPower; } callback(null, accessory.context.totalEnergy); }); @@ -646,7 +835,8 @@ class eWeLink { .on("get", callback => { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); if (accessory.context.extraPersistedData !== undefined) { - accessory.context.lastReset = accessory.context.extraPersistedData.lastReset; + accessory.context.lastReset = + accessory.context.extraPersistedData.lastReset; } callback(null, accessory.context.lastReset); }); @@ -655,26 +845,36 @@ class eWeLink { accessory .getService(Service.Outlet) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalUSBUpdate(accessory, value, callback)); + .on("set", (value, callback) => + this.internalUSBUpdate(accessory, value, callback) + ); break; case "scm": accessory .getService(Service.Switch) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalSCMUpdate(accessory, value, callback)); + .on("set", (value, callback) => + this.internalSCMUpdate(accessory, value, callback) + ); break; case "light": accessory .getService(Service.Lightbulb) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalLightbulbUpdate(accessory, value, callback)); + .on("set", (value, callback) => + this.internalLightbulbUpdate(accessory, value, callback) + ); if (cns.devicesBrightable.includes(accessory.context.eweUIID)) { accessory .getService(Service.Lightbulb) .getCharacteristic(Characteristic.Brightness) .on("set", (value, callback) => { if (value > 0) { - if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + if ( + !accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On).value + ) { this.internalLightbulbUpdate(accessory, true, function () { return; }); @@ -684,13 +884,19 @@ class eWeLink { this.internalLightbulbUpdate(accessory, false, callback); } }); - } else if (cns.devicesColourable.includes(accessory.context.eweUIID)) { + } else if ( + cns.devicesColourable.includes(accessory.context.eweUIID) + ) { accessory .getService(Service.Lightbulb) .getCharacteristic(Characteristic.Brightness) .on("set", (value, callback) => { if (value > 0) { - if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + if ( + !accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On).value + ) { this.internalLightbulbUpdate(accessory, true, function () { return; }); @@ -703,7 +909,9 @@ class eWeLink { accessory .getService(Service.Lightbulb) .getCharacteristic(Characteristic.Hue) - .on("set", (value, callback) => this.internalHSBUpdate(accessory, "hue", value, callback)); + .on("set", (value, callback) => + this.internalHSBUpdate(accessory, "hue", value, callback) + ); accessory .getService(Service.Lightbulb) .getCharacteristic(Characteristic.Saturation) @@ -714,18 +922,24 @@ class eWeLink { accessory .getService(Service.Switch) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalSwitchUpdate(accessory, value, callback)); + .on("set", (value, callback) => + this.internalSwitchUpdate(accessory, value, callback) + ); break; case "rf_sub": accessory.context.rfChls = accessory.context.rfChls || {}; if (accessory.context.sensorType === "button") { Object.entries(accessory.context.rfChls).forEach(([k, v]) => { - accessory.getService(v).updateCharacteristic(Characteristic.On, false); + accessory + .getService(v) + .updateCharacteristic(Characteristic.On, false); accessory .getService(v) .getCharacteristic(Characteristic.On) .on("set", (value, callback) => { - value ? this.internalRFDeviceUpdate(accessory, k, callback) : callback(); + value + ? this.internalRFDeviceUpdate(accessory, k, callback) + : callback(); }); }); } @@ -746,7 +960,8 @@ class eWeLink { .getCharacteristic(Characteristic.CurrentTemperature).value, humidity: accessory .getService(Service.HumiditySensor) - .getCharacteristic(Characteristic.CurrentRelativeHumidity).value, + .getCharacteristic(Characteristic.CurrentRelativeHumidity) + .value, }; accessory.eveLogger.addEntry(dataToAdd); }, 300000); @@ -755,61 +970,95 @@ class eWeLink { } this.devicesInHB.set(accessory.context.hbDeviceId, accessory); } catch (err) { - this.log.warn("[%s] could not be refreshed as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be refreshed as %s.", + accessory.displayName, + err + ); } } refreshAccessory(accessory, newParams) { switch (accessory.context.type) { case "valve": - if (Object.keys(newParams).some(v => cns.devicesValveParams.includes(v)) && Array.isArray(newParams.switches)) { + if ( + Object.keys(newParams).some(v => + cns.devicesValveParams.includes(v) + ) && + Array.isArray(newParams.switches) + ) { this.externalValveUpdate(accessory, newParams); } return true; case "blind": - if (Object.keys(newParams).some(v => cns.devicesBlindParams.includes(v)) && Array.isArray(newParams.switches)) { + if ( + Object.keys(newParams).some(v => + cns.devicesBlindParams.includes(v) + ) && + Array.isArray(newParams.switches) + ) { this.externalBlindUpdate(accessory, newParams); } return true; case "garage": if ( - Object.keys(newParams).some(v => cns.devicesGarageParams.includes(v)) && + Object.keys(newParams).some(v => + cns.devicesGarageParams.includes(v) + ) && Array.isArray(newParams.switches) ) { this.externalGarageUpdate(accessory, newParams); } return true; case "lock": - if (Object.keys(newParams).some(v => cns.devicesLockParams.includes(v))) { + if ( + Object.keys(newParams).some(v => cns.devicesLockParams.includes(v)) + ) { this.externalLockUpdate(accessory, newParams); } return true; case "sensor": - if (Object.keys(newParams).some(v => cns.devicesSensorParams.includes(v))) { + if ( + Object.keys(newParams).some(v => cns.devicesSensorParams.includes(v)) + ) { this.externalSensorUpdate(accessory, newParams); } return true; case "fan": - if (Object.keys(newParams).some(v => cns.devicesFanParams.includes(v))) { + if ( + Object.keys(newParams).some(v => cns.devicesFanParams.includes(v)) + ) { this.externalFanUpdate(accessory, newParams); } return true; case "thermostat": - if (Object.keys(newParams).some(v => cns.devicesThermostatParams.includes(v))) { + if ( + Object.keys(newParams).some(v => + cns.devicesThermostatParams.includes(v) + ) + ) { this.externalThermostatUpdate(accessory, newParams); } return true; case "outlet": - if (Object.keys(newParams).some(v => cns.devicesOutletParams.includes(v))) { + if ( + Object.keys(newParams).some(v => cns.devicesOutletParams.includes(v)) + ) { this.externalOutletUpdate(accessory, newParams); } return true; case "usb": - if (Object.keys(newParams).some(v => cns.devicesUSBParams.includes(v)) && Array.isArray(newParams.switches)) { + if ( + Object.keys(newParams).some(v => cns.devicesUSBParams.includes(v)) && + Array.isArray(newParams.switches) + ) { this.externalUSBUpdate(accessory, newParams); } return true; case "scm": - if (Object.keys(newParams).some(v => cns.devicesSCMParams.includes(v)) && Array.isArray(newParams.switches)) { + if ( + Object.keys(newParams).some(v => cns.devicesSCMParams.includes(v)) && + Array.isArray(newParams.switches) + ) { this.externalSCMUpdate(accessory, newParams); } return true; @@ -818,7 +1067,11 @@ class eWeLink { cns.devicesSingleSwitch.includes(accessory.context.eweUIID) && cns.devicesSingleSwitchLight.includes(accessory.context.eweModel) ) { - if (Object.keys(newParams).some(v => cns.devicesSingleSwitchLightParams.includes(v))) { + if ( + Object.keys(newParams).some(v => + cns.devicesSingleSwitchLightParams.includes(v) + ) + ) { this.externalSingleLightUpdate(accessory, newParams); } } else if ( @@ -826,7 +1079,9 @@ class eWeLink { cns.devicesMultiSwitchLight.includes(accessory.context.eweModel) ) { if ( - Object.keys(newParams).some(v => cns.devicesMultiSwitchLightParams.includes(v)) && + Object.keys(newParams).some(v => + cns.devicesMultiSwitchLightParams.includes(v) + ) && Array.isArray(newParams.switches) ) { this.externalMultiLightUpdate(accessory, newParams); @@ -835,12 +1090,18 @@ class eWeLink { return true; case "switch": if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID)) { - if (Object.keys(newParams).some(v => cns.devicesSingleSwitchParams.includes(v))) { + if ( + Object.keys(newParams).some(v => + cns.devicesSingleSwitchParams.includes(v) + ) + ) { this.externalSingleSwitchUpdate(accessory, newParams); } } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID)) { if ( - Object.keys(newParams).some(v => cns.devicesMultiSwitchParams.includes(v)) && + Object.keys(newParams).some(v => + cns.devicesMultiSwitchParams.includes(v) + ) && Array.isArray(newParams.switches) ) { this.externalMultiSwitchUpdate(accessory, newParams); @@ -848,7 +1109,11 @@ class eWeLink { } return true; case "rf_pri": - if (Object.keys(newParams).some(v => cns.devicesRFBridgeParams.includes(v))) { + if ( + Object.keys(newParams).some(v => + cns.devicesRFBridgeParams.includes(v) + ) + ) { this.externalRFDeviceUpdate(accessory, newParams); } return true; @@ -856,7 +1121,11 @@ class eWeLink { case "zb_pri": return true; case "zb_sub": - if (Object.keys(newParams).some(v => cns.devicesZBBridgeParams.includes(v))) { + if ( + Object.keys(newParams).some(v => + cns.devicesZBBridgeParams.includes(v) + ) + ) { this.externalZBDeviceUpdate(accessory, newParams); } return true; @@ -867,10 +1136,16 @@ class eWeLink { removeAccessory(accessory) { try { this.devicesInHB.delete(accessory.context.hbDeviceId); - this.api.unregisterPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); + this.api.unregisterPlatformAccessories("homebridge-ewelink", "eWeLink", [ + accessory, + ]); this.log("[%s] has been removed from Homebridge.", accessory.displayName); } catch (err) { - this.log.warn("[%s] needed to be removed but couldn't as %s.", accessory.displayName, err); + this.log.warn( + "[%s] needed to be removed but couldn't as %s.", + accessory.displayName, + err + ); } } sendDeviceUpdate(accessory, params, callback) { @@ -884,11 +1159,17 @@ class eWeLink { this.wsClient.sendUpdate(payload); callback(); } else { - this.log.error("[%s] could not be updated as it appears to be offline.", accessory.displayName); + this.log.error( + "[%s] could not be updated as it appears to be offline.", + accessory.displayName + ); callback("Device has failed to update"); } }; - if (cns.devicesNonLAN.includes(accessory.context.eweUIID) || !accessory.context.reachableLAN) { + if ( + cns.devicesNonLAN.includes(accessory.context.eweUIID) || + !accessory.context.reachableLAN + ) { sendViaWS(); } else { this.lanClient @@ -896,7 +1177,11 @@ class eWeLink { .then(() => callback()) .catch(err => { if (this.debug) { - this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); + this.log.warn( + "[%s] Reverting to web socket as %s.", + accessory.displayName, + err + ); } sendViaWS(); }); @@ -907,7 +1192,9 @@ class eWeLink { switch (device.action) { case "sysmsg": if ( - (accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0")) + (accessory = + this.devicesInHB.get(device.deviceid + "SWX") || + this.devicesInHB.get(device.deviceid + "SW0")) ) { let isX = accessory.context.hbDeviceId.substr(-1) === "X"; if (device.params.updateSource === "WS") { @@ -919,17 +1206,23 @@ class eWeLink { accessory.context.reachableWAN ? "online" : "offline" ); this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - if (accessory.context.reachableWAN) this.wsClient.requestUpdate(accessory); + if (accessory.context.reachableWAN) + this.wsClient.requestUpdate(accessory); } else { if (this.debug) { - this.log("[%s] Nothing to update from above WS message.", accessory.displayName); + this.log( + "[%s] Nothing to update from above WS message.", + accessory.displayName + ); } } } if (!isX) { for (let i = 1; i <= accessory.context.channelCount; i++) { if (this.devicesInHB.has(device.deviceid + "SW" + i)) { - let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); + let oAccessory = this.devicesInHB.get( + device.deviceid + "SW" + i + ); oAccessory.context.reachableWAN = device.params.online; this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); } @@ -939,15 +1232,29 @@ class eWeLink { break; case "update": if ( - (accessory = this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0")) + (accessory = + this.devicesInHB.get(device.deviceid + "SWX") || + this.devicesInHB.get(device.deviceid + "SW0")) ) { - if (device.params.updateSource === "WS" && !accessory.context.reachableWAN) { + if ( + device.params.updateSource === "WS" && + !accessory.context.reachableWAN + ) { accessory.context.reachableWAN = true; - this.log("[%s] has been reported [online] via [WS].", accessory.displayName); + this.log( + "[%s] has been reported [online] via [WS].", + accessory.displayName + ); } - if (device.params.updateSource === "LAN" && !accessory.context.reachableLAN) { + if ( + device.params.updateSource === "LAN" && + !accessory.context.reachableLAN + ) { accessory.context.reachableLAN = true; - this.log("[%s] has been reported [online] via [LAN].", accessory.displayName); + this.log( + "[%s] has been reported [online] via [LAN].", + accessory.displayName + ); } if (this.debug) { this.log( @@ -988,27 +1295,41 @@ class eWeLink { .updateCharacteristic(Characteristic.InUse, value); switch (value) { case 0: - accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, 0); + accessory + .getService(valve) + .updateCharacteristic(Characteristic.RemainingDuration, 0); clearTimeout(accessory.getService(valve).timer); break; case 1: - let timer = accessory.getService(valve).getCharacteristic(Characteristic.SetDuration).value; - accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, timer); + let timer = accessory + .getService(valve) + .getCharacteristic(Characteristic.SetDuration).value; + accessory + .getService(valve) + .updateCharacteristic(Characteristic.RemainingDuration, timer); accessory.getService(valve).timer = setTimeout(() => { - accessory.getService(valve).setCharacteristic(Characteristic.Active, 0); + accessory + .getService(valve) + .setCharacteristic(Characteristic.Active, 0); }, timer * 1000); break; } - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEwe.get( + accessory.context.eweDeviceId + ).params.switches; switch (valve) { case "Valve A": params.switches[0].switch = value ? "on" : "off"; - params.switches[1].switch = accessory.getService("Valve B").getCharacteristic(Characteristic.Active).value + params.switches[1].switch = accessory + .getService("Valve B") + .getCharacteristic(Characteristic.Active).value ? "on" : "off"; break; case "Valve B": - params.switches[0].switch = accessory.getService("Valve A").getCharacteristic(Characteristic.Active).value + params.switches[0].switch = accessory + .getService("Valve A") + .getCharacteristic(Characteristic.Active).value ? "on" : "off"; params.switches[1].switch = value ? "on" : "off"; @@ -1020,7 +1341,8 @@ class eWeLink { params.switches[3].switch = "off"; this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1034,13 +1356,18 @@ class eWeLink { if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } - if (blindConfig.type !== "blind" || !["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { + if ( + blindConfig.type !== "blind" || + !["oneSwitch", "twoSwitch"].includes(blindConfig.setup) + ) { throw "improper configuration"; } let oldPos, params = {}; value = value >= 50 ? 100 : 0; - oldPos = accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.PositionState).value; + oldPos = accessory + .getService(Service.WindowCovering) + .getCharacteristic(Characteristic.PositionState).value; if (value === oldPos * 100) { accessory .getService(Service.WindowCovering) @@ -1054,7 +1381,9 @@ class eWeLink { params.switch = "on"; break; case "twoSwitch": - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEwe.get( + accessory.context.eweDeviceId + ).params.switches; params.switches[0].switch = value === 100 ? "on" : "off"; params.switches[1].switch = value === 0 ? "on" : "off"; break; @@ -1074,7 +1403,8 @@ class eWeLink { callback(); }, parseInt(blindConfig.operationTime) * 100); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1088,7 +1418,10 @@ class eWeLink { if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } - if (garageConfig.type !== "garage" || !["oneSwitch", "twoSwitch"].includes(garageConfig.setup)) { + if ( + garageConfig.type !== "garage" || + !["oneSwitch", "twoSwitch"].includes(garageConfig.setup) + ) { throw "improper configuration"; } accessory.context.inUse = true; @@ -1099,17 +1432,24 @@ class eWeLink { newPos = value, params = {}, delay = 0; - if (sensorDefinition && !(sAccessory = this.devicesInHB.get(garageConfig.sensorId + "SWX"))) { + if ( + sensorDefinition && + !(sAccessory = this.devicesInHB.get(garageConfig.sensorId + "SWX")) + ) { throw "defined DW2 sensor doesn't exist"; } if (sAccessory.context.type !== "sensor") { throw "defined DW2 sensor isn't a sensor"; } oldPos = sAccessory - ? sAccessory.getService(Service.ContactSensor).getCharacteristic(Characteristic.ContactSensorState).value === 0 + ? sAccessory + .getService(Service.ContactSensor) + .getCharacteristic(Characteristic.ContactSensorState).value === 0 ? 1 : 0 - : accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.CurrentDoorState).value; + : accessory + .getService(Service.GarageDoorOpener) + .getCharacteristic(Characteristic.CurrentDoorState).value; if (newPos === oldPos % 2) { accessory.context.inUse = false; callback(); @@ -1118,7 +1458,10 @@ class eWeLink { if (garageConfig.setup === "oneSwitch" && [2, 3].includes(oldPos)) { accessory .getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.CurrentDoorState, ((oldPos * 2) % 3) + 2); + .updateCharacteristic( + Characteristic.CurrentDoorState, + ((oldPos * 2) % 3) + 2 + ); delay = 1500; } setTimeout(() => { @@ -1132,7 +1475,9 @@ class eWeLink { params.switch = "on"; break; case "twoSwitch": - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEwe.get( + accessory.context.eweDeviceId + ).params.switches; params.switches[0].switch = newPos === 0 ? "on" : "off"; params.switches[1].switch = newPos === 1 ? "on" : "off"; break; @@ -1153,7 +1498,8 @@ class eWeLink { callback(); } catch (err) { accessory.context.inUse = false; - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1188,7 +1534,8 @@ class eWeLink { }, parseInt(lockConfig.operationTime) * 100); } catch (err) { accessory.context.inUse = false; - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1203,31 +1550,45 @@ class eWeLink { case "power": newPower = value; newSpeed = value ? 33 : 0; - newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; + newLight = accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On).value; break; case "speed": newPower = value >= 33 ? 1 : 0; newSpeed = value; - newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; + newLight = accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On).value; break; case "light": - newPower = accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active).value; - newSpeed = accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.RotationSpeed).value; + newPower = accessory + .getService(Service.Fanv2) + .getCharacteristic(Characteristic.Active).value; + newSpeed = accessory + .getService(Service.Fanv2) + .getCharacteristic(Characteristic.RotationSpeed).value; newLight = value; break; } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, newLight); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, newLight); accessory .getService(Service.Fanv2) .updateCharacteristic(Characteristic.Active, newPower) .updateCharacteristic(Characteristic.RotationSpeed, newSpeed); let params = { - switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches, + switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params + .switches, }; params.switches[0].switch = newLight ? "on" : "off"; - params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? "on" : "off"; - params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? "on" : "off"; - params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? "on" : "off"; + params.switches[1].switch = + newPower === 1 && newSpeed >= 33 ? "on" : "off"; + params.switches[2].switch = + newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? "on" : "off"; + params.switches[3].switch = + newPower === 1 && newSpeed >= 99 ? "on" : "off"; if (this.debug) { this.log.warn("Fan Update - setting " + type + " to " + value); this.log( @@ -1240,7 +1601,8 @@ class eWeLink { } this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1255,12 +1617,19 @@ class eWeLink { mainSwitch: value ? "on" : "off", }; if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + this.log( + "[%s] updating to turn [%s].", + accessory.displayName, + value ? "on" : "off" + ); } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1274,9 +1643,15 @@ class eWeLink { switch: value ? "on" : "off", }; if (this.debug) { - this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); + this.log( + "[%s] requesting to turn [%s].", + accessory.displayName, + value ? "on" : "off" + ); } - accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Outlet) + .updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { callback("[" + accessory.displayName + "] " + err + "."); @@ -1288,13 +1663,20 @@ class eWeLink { throw "it is currently offline"; } let params = { - switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches, + switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params + .switches, }; params.switches[0].switch = value ? "on" : "off"; if (this.debug) { - this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); + this.log( + "[%s] requesting to turn [%s].", + accessory.displayName, + value ? "on" : "off" + ); } - accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Outlet) + .updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { callback("[" + accessory.displayName + "] " + err + "."); @@ -1306,13 +1688,20 @@ class eWeLink { throw "it is currently offline"; } let params = { - switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches, + switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params + .switches, }; params.switches[0].switch = value ? "on" : "off"; if (this.debug) { - this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); + this.log( + "[%s] requesting to turn [%s].", + accessory.displayName, + value ? "on" : "off" + ); } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { callback("[" + accessory.displayName + "] " + err + "."); @@ -1334,24 +1723,44 @@ class eWeLink { params.switch = value ? "on" : "off"; } if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + this.log( + "[%s] updating to turn [%s].", + accessory.displayName, + value ? "on" : "off" + ); } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, value); break; case "0": - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEwe.get( + accessory.context.eweDeviceId + ).params.switches; params.switches[0].switch = value ? "on" : "off"; params.switches[1].switch = value ? "on" : "off"; params.switches[2].switch = value ? "on" : "off"; params.switches[3].switch = value ? "on" : "off"; if (this.debug) { - this.log("[%s] updating to turn group [%s].", accessory.displayName, value ? "on" : "off"); + this.log( + "[%s] updating to turn group [%s].", + accessory.displayName, + value ? "on" : "off" + ); } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, value); for (let i = 1; i <= 4; i++) { - if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); - oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + if ( + this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i) + ) { + oAccessory = this.devicesInHB.get( + accessory.context.eweDeviceId + "SW" + i + ); + oAccessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, value); } } break; @@ -1360,14 +1769,26 @@ class eWeLink { case "3": case "4": if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + this.log( + "[%s] updating to turn [%s].", + accessory.displayName, + value ? "on" : "off" + ); } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, value); let tAccessory, masterState = "off"; - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEwe.get( + accessory.context.eweDeviceId + ).params.switches; for (let i = 1; i <= 4; i++) { - if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + if ( + (tAccessory = this.devicesInHB.get( + accessory.context.eweDeviceId + "SW" + i + )) + ) { i === parseInt(accessory.context.switchNumber) ? (params.switches[i - 1].switch = value ? "on" : "off") : (params.switches[i - 1].switch = tAccessory @@ -1375,22 +1796,33 @@ class eWeLink { .getCharacteristic(Characteristic.On).value ? "on" : "off"); - if (tAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + if ( + tAccessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On).value + ) { masterState = "on"; } } else { params.switches[i - 1].switch = "off"; } } - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, masterState === "on"); + oAccessory = this.devicesInHB.get( + accessory.context.eweDeviceId + "SW0" + ); + oAccessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, masterState === "on"); break; default: - throw "unknown switch number [" + accessory.context.switchNumber + "]"; + throw ( + "unknown switch number [" + accessory.context.switchNumber + "]" + ); } this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1403,9 +1835,15 @@ class eWeLink { let params = {}; if (value === 0) { params.switch = "off"; - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, false); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, false); } else { - if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + if ( + !accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On).value + ) { params.switch = "on"; } switch (accessory.context.eweUIID) { @@ -1419,14 +1857,21 @@ class eWeLink { default: throw "unknown device UIID"; } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, value); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.Brightness, value); } if (this.debug) { - this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); + this.log( + "[%s] updating brightness to [%s%].", + accessory.displayName, + value + ); } setTimeout(() => this.sendDeviceUpdate(accessory, params, callback), 250); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1438,8 +1883,12 @@ class eWeLink { } let newRGB, params = {}, - curHue = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Hue).value, - curSat = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Saturation).value; + curHue = accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.Hue).value, + curSat = accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.Saturation).value; switch (type) { case "hue": newRGB = convert.hsv.rgb(value, curSat, 100); @@ -1467,9 +1916,15 @@ class eWeLink { throw "unknown device UIID"; } if (this.debug) { - this.log("[%s] updating hue to [%s°].", accessory.displayName, value); + this.log( + "[%s] updating hue to [%s°].", + accessory.displayName, + value + ); } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Hue, value); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.Hue, value); break; case "bri": switch (accessory.context.eweUIID) { @@ -1493,16 +1948,23 @@ class eWeLink { break; } if (this.debug) { - this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); + this.log( + "[%s] updating brightness to [%s%].", + accessory.displayName, + value + ); } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, value); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.Brightness, value); break; default: throw "unknown device UIID"; } setTimeout(() => this.sendDeviceUpdate(accessory, params, callback), 250); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1518,24 +1980,44 @@ class eWeLink { case "X": params.switch = value ? "on" : "off"; if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + this.log( + "[%s] updating to turn [%s].", + accessory.displayName, + value ? "on" : "off" + ); } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, value); break; case "0": - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEwe.get( + accessory.context.eweDeviceId + ).params.switches; params.switches[0].switch = value ? "on" : "off"; params.switches[1].switch = value ? "on" : "off"; params.switches[2].switch = value ? "on" : "off"; params.switches[3].switch = value ? "on" : "off"; if (this.debug) { - this.log("[%s] updating to turn group [%s].", accessory.displayName, value ? "on" : "off"); + this.log( + "[%s] updating to turn group [%s].", + accessory.displayName, + value ? "on" : "off" + ); } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, value); for (let i = 1; i <= 4; i++) { - if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); - oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + if ( + this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i) + ) { + oAccessory = this.devicesInHB.get( + accessory.context.eweDeviceId + "SW" + i + ); + oAccessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, value); } } break; @@ -1544,14 +2026,26 @@ class eWeLink { case "3": case "4": if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + this.log( + "[%s] updating to turn [%s].", + accessory.displayName, + value ? "on" : "off" + ); } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, value); let tAccessory, masterState = "off"; - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEwe.get( + accessory.context.eweDeviceId + ).params.switches; for (let i = 1; i <= 4; i++) { - if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + if ( + (tAccessory = this.devicesInHB.get( + accessory.context.eweDeviceId + "SW" + i + )) + ) { i === parseInt(accessory.context.switchNumber) ? (params.switches[i - 1].switch = value ? "on" : "off") : (params.switches[i - 1].switch = tAccessory @@ -1559,22 +2053,33 @@ class eWeLink { .getCharacteristic(Characteristic.On).value ? "on" : "off"); - if (tAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value) { + if ( + tAccessory + .getService(Service.Switch) + .getCharacteristic(Characteristic.On).value + ) { masterState = "on"; } } else { params.switches[i - 1].switch = "off"; } } - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, masterState === "on"); + oAccessory = this.devicesInHB.get( + accessory.context.eweDeviceId + "SW0" + ); + oAccessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, masterState === "on"); break; default: - throw "unknown switch number [" + accessory.context.switchNumber + "]"; + throw ( + "unknown switch number [" + accessory.context.switchNumber + "]" + ); } this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1590,16 +2095,32 @@ class eWeLink { rfChl, }; if (this.debug) { - this.log("[%s %s] mimicking RF button press.", accessory.displayName, accessory.context.rfChls[rfChl]); + this.log( + "[%s %s] mimicking RF button press.", + accessory.displayName, + accessory.context.rfChls[rfChl] + ); } - accessory.getService(accessory.context.rfChls[rfChl]).updateCharacteristic(Characteristic.On, true); + accessory + .getService(accessory.context.rfChls[rfChl]) + .updateCharacteristic(Characteristic.On, true); this.sendDeviceUpdate(accessory, params, callback); setTimeout( - () => accessory.getService(accessory.context.rfChls[rfChl]).updateCharacteristic(Characteristic.On, false), + () => + accessory + .getService(accessory.context.rfChls[rfChl]) + .updateCharacteristic(Characteristic.On, false), 3000 ); } catch (err) { - let str = "[" + accessory.displayName + " " + name + "] could not be updated as " + err + "."; + let str = + "[" + + accessory.displayName + + " " + + name + + "] could not be updated as " + + err + + "."; this.log.error(str); callback(str); } @@ -1609,21 +2130,39 @@ class eWeLink { ["A", "B"].forEach((v, k) => { accessory .getService("Valve " + v) - .updateCharacteristic(Characteristic.Active, params.switches[k].switch === "on") - .updateCharacteristic(Characteristic.InUse, params.switches[k].switch === "on"); + .updateCharacteristic( + Characteristic.Active, + params.switches[k].switch === "on" + ) + .updateCharacteristic( + Characteristic.InUse, + params.switches[k].switch === "on" + ); if (params.switches[k].switch === "on") { - let timer = accessory.getService("Valve " + v).getCharacteristic(Characteristic.SetDuration).value; - accessory.getService("Valve " + v).updateCharacteristic(Characteristic.RemainingDuration, timer); + let timer = accessory + .getService("Valve " + v) + .getCharacteristic(Characteristic.SetDuration).value; + accessory + .getService("Valve " + v) + .updateCharacteristic(Characteristic.RemainingDuration, timer); accessory.getService("Valve " + v).timer = setTimeout(() => { - accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); + accessory + .getService("Valve " + v) + .setCharacteristic(Characteristic.Active, 0); }, timer * 1000); } else { - accessory.getService("Valve " + v).updateCharacteristic(Characteristic.RemainingDuration, 0); + accessory + .getService("Valve " + v) + .updateCharacteristic(Characteristic.RemainingDuration, 0); clearTimeout(accessory.getService("Valve " + v).timer); } }); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalBlindUpdate(accessory, params) { @@ -1632,7 +2171,10 @@ class eWeLink { if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } - if (blindConfig.type !== "blind" || ["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { + if ( + blindConfig.type !== "blind" || + ["oneSwitch", "twoSwitch"].includes(blindConfig.setup) + ) { throw "improper configuration"; } switch (blindConfig.setup) { @@ -1641,12 +2183,17 @@ class eWeLink { return; } nSte = - accessory.getService(Service.WindowCovering).getCharacteristic(Characteristic.PositionState).value === 0 + accessory + .getService(Service.WindowCovering) + .getCharacteristic(Characteristic.PositionState).value === 0 ? 1 : 0; break; case "twoSwitch": - if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { + if ( + params.switches[0].switch === "off" && + params.switches[1].switch === "off" + ) { return; } let switchUp = params.switches[0].switch === "on" ? -1 : 0, // matrix of numbers to get @@ -1665,19 +2212,27 @@ class eWeLink { .updateCharacteristic(Characteristic.CurrentPosition, nSte * 100); }, parseInt(blindConfig.operationTime) * 100); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalGarageUpdate(accessory, params) { try { let garageConfig, - oldPos = accessory.getService(Service.GarageDoorOpener).getCharacteristic(Characteristic.CurrentDoorState) - .value, + oldPos = accessory + .getService(Service.GarageDoorOpener) + .getCharacteristic(Characteristic.CurrentDoorState).value, newPos = [0, 2].includes(oldPos) ? 3 : 2; if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } - if (garageConfig.type !== "garage" || !["oneSwitch", "twoSwitch"].includes(garageConfig.setup)) { + if ( + garageConfig.type !== "garage" || + !["oneSwitch", "twoSwitch"].includes(garageConfig.setup) + ) { throw "improper configuration"; } if (accessory.context.inUse || garageConfig.sensorId) { @@ -1690,7 +2245,10 @@ class eWeLink { } break; case "twoSwitch": - if (params.switches[0].switch === params.switches[1].switch || params.switches[oldPos % 2].switch === "on") { + if ( + params.switches[0].switch === params.switches[1].switch || + params.switches[oldPos % 2].switch === "on" + ) { return; } break; @@ -1712,7 +2270,11 @@ class eWeLink { }, parseInt(garageConfig.operationTime) * 100); } catch (err) { accessory.context.inUse = false; - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalLockUpdate(accessory, params) { @@ -1741,22 +2303,39 @@ class eWeLink { }, parseInt(lockConfig.operationTime) * 100); } catch (err) { accessory.context.inUse = false; - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalSensorUpdate(accessory, params) { try { - let newState = params.switch === "on" ? 1 : 0, - oAccessory = false; - accessory.getService(Service.ContactSensor).updateCharacteristic(Characteristic.ContactSensorState, newState); if (params.hasOwnProperty("battery")) { let batteryService = - accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); - batteryService.updateCharacteristic(Characteristic.BatteryLevel, params.battery); - batteryService.updateCharacteristic(Characteristic.StatusLowBattery, params.battery <= 25); + accessory.getService(Service.BatteryService) || + accessory.addService(Service.BatteryService), + scaledBattery = Math.round(params.battery * 33.3); + batteryService.updateCharacteristic( + Characteristic.BatteryLevel, + scaledBattery + ); + batteryService.updateCharacteristic( + Characteristic.StatusLowBattery, + scaledBattery < 25 + ); } + let newState = params.switch === "on" ? 1 : 0, + oAccessory = false; + accessory + .getService(Service.ContactSensor) + .updateCharacteristic(Characteristic.ContactSensorState, newState); this.cusG.forEach(group => { - if (group.sensorId === accessory.context.eweDeviceId && group.type === "garage") { + if ( + group.sensorId === accessory.context.eweDeviceId && + group.type === "garage" + ) { if ((oAccessory = this.devicesInHB.get(group.deviceId + "SWX"))) { switch (newState) { case 0: @@ -1780,7 +2359,11 @@ class eWeLink { } }); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalFanUpdate(accessory, params) { @@ -1788,7 +2371,11 @@ class eWeLink { let light, status, speed; if (Array.isArray(params.switches)) { light = params.switches[0].switch === "on"; - switch (params.switches[1].switch + params.switches[2].switch + params.switches[3].switch) { + switch ( + params.switches[1].switch + + params.switches[2].switch + + params.switches[3].switch + ) { default: status = 0; speed = 0; @@ -1805,65 +2392,109 @@ class eWeLink { status = 1; speed = 99; } - } else if (params.hasOwnProperty("light") && params.hasOwnProperty("fan") && params.hasOwnProperty("speed")) { + } else if ( + params.hasOwnProperty("light") && + params.hasOwnProperty("fan") && + params.hasOwnProperty("speed") + ) { light = params.light === "on"; status = params.fan === "on" ? 1 : 0; speed = params.speed * 33 * status; } else { throw "unknown parameters received"; } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, light); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, light); accessory .getService(Service.Fanv2) .updateCharacteristic(Characteristic.Active, status) .updateCharacteristic(Characteristic.RotationSpeed, speed); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalThermostatUpdate(accessory, params) { try { - if (!this.config.hideTHSwitch && (params.hasOwnProperty("switch") || params.hasOwnProperty("mainSwitch"))) { - let newState = params.hasOwnProperty("switch") ? params.switch === "on" : params.mainSwitch === "on"; - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, newState); + if ( + !this.config.hideTHSwitch && + (params.hasOwnProperty("switch") || params.hasOwnProperty("mainSwitch")) + ) { + let newState = params.hasOwnProperty("switch") + ? params.switch === "on" + : params.mainSwitch === "on"; + accessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, newState); } let eveLog = { time: Date.now(), }; - if (params.hasOwnProperty("currentTemperature") && accessory.getService(Service.TemperatureSensor)) { - let currentTemp = params.currentTemperature !== "unavailable" ? params.currentTemperature : 0; + if ( + params.hasOwnProperty("currentTemperature") && + accessory.getService(Service.TemperatureSensor) + ) { + let currentTemp = + params.currentTemperature !== "unavailable" + ? params.currentTemperature + : 0; accessory .getService(Service.TemperatureSensor) .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); eveLog.temp = parseFloat(currentTemp); } - if (params.hasOwnProperty("currentHumidity") && accessory.getService(Service.HumiditySensor)) { - let currentHumi = params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; + if ( + params.hasOwnProperty("currentHumidity") && + accessory.getService(Service.HumiditySensor) + ) { + let currentHumi = + params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; accessory .getService(Service.HumiditySensor) - .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); + .updateCharacteristic( + Characteristic.CurrentRelativeHumidity, + currentHumi + ); eveLog.humidity = parseFloat(currentHumi); } if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { accessory.eveLogger.addEntry(eveLog); } } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalOutletUpdate(accessory, params) { try { if (params.hasOwnProperty("switch")) { - accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switch === "on"); + accessory + .getService(Service.Outlet) + .updateCharacteristic(Characteristic.On, params.switch === "on"); } if (params.hasOwnProperty("power")) { accessory .getService(Service.Outlet) - .updateCharacteristic(EveService.Characteristics.CurrentConsumption, parseFloat(params.power)); + .updateCharacteristic( + EveService.Characteristics.CurrentConsumption, + parseFloat(params.power) + ); accessory .getService(Service.Outlet) - .updateCharacteristic(Characteristic.OutletInUse, parseFloat(params.power) > 0); - let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value; + .updateCharacteristic( + Characteristic.OutletInUse, + parseFloat(params.power) > 0 + ); + let isOn = accessory + .getService(Service.Outlet) + .getCharacteristic(Characteristic.On).value; accessory.eveLogger.addEntry({ time: Date.now(), power: isOn ? parseFloat(params.power) : 0, @@ -1872,29 +2503,57 @@ class eWeLink { if (params.hasOwnProperty("voltage")) { accessory .getService(Service.Outlet) - .updateCharacteristic(EveService.Characteristics.Voltage, parseFloat(params.voltage)); + .updateCharacteristic( + EveService.Characteristics.Voltage, + parseFloat(params.voltage) + ); } if (params.hasOwnProperty("current")) { accessory .getService(Service.Outlet) - .updateCharacteristic(EveService.Characteristics.ElectricCurrent, parseFloat(params.current)); + .updateCharacteristic( + EveService.Characteristics.ElectricCurrent, + parseFloat(params.current) + ); } } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalUSBUpdate(accessory, params) { try { - accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); + accessory + .getService(Service.Outlet) + .updateCharacteristic( + Characteristic.On, + params.switches[0].switch === "on" + ); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalSCMUpdate(accessory, params) { try { - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); + accessory + .getService(Service.Switch) + .updateCharacteristic( + Characteristic.On, + params.switches[0].switch === "on" + ); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalSingleLightUpdate(accessory, params) { @@ -1904,37 +2563,54 @@ class eWeLink { isOn = false; if (accessory.context.eweUIID === 22 && params.hasOwnProperty("state")) { isOn = params.state === "on"; - } else if (accessory.context.eweUIID !== 22 && params.hasOwnProperty("switch")) { + } else if ( + accessory.context.eweUIID !== 22 && + params.hasOwnProperty("switch") + ) { isOn = params.switch === "on"; } else { - isOn = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; + isOn = accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On).value; } if (isOn) { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, true); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, true); switch (accessory.context.eweUIID) { case 36: // KING-M4 if (params.hasOwnProperty("bright")) { let nb = Math.round(((params.bright - 10) * 10) / 9); // eWeLink scale is 10-100 and HomeKit scale is 0-100. - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, nb); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.Brightness, nb); } break; case 44: // D1 if (params.hasOwnProperty("brightness")) { accessory .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.Brightness, params.brightness); + .updateCharacteristic( + Characteristic.Brightness, + params.brightness + ); } break; case 22: // B1 if (params.hasOwnProperty("zyx_mode")) { mode = parseInt(params.zyx_mode); - } else if (params.hasOwnProperty("channel0") && parseInt(params.channel0) + parseInt(params.channel1) > 0) { + } else if ( + params.hasOwnProperty("channel0") && + parseInt(params.channel0) + parseInt(params.channel1) > 0 + ) { mode = 1; } else { mode = 2; } if (mode === 2) { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, true); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, true); newColour = convert.rgb.hsv( parseInt(params.channel2), parseInt(params.channel3), @@ -1951,10 +2627,16 @@ class eWeLink { break; case 59: // L1 if (params.hasOwnProperty("bright")) { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Brightness, params.bright); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.Brightness, params.bright); } if (params.hasOwnProperty("colorR")) { - newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB); + newColour = convert.rgb.hsv( + params.colorR, + params.colorG, + params.colorB + ); accessory .getService(Service.Lightbulb) .updateCharacteristic(Characteristic.Hue, newColour[0]) @@ -1965,10 +2647,16 @@ class eWeLink { return; } } else { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, false); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, false); } } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalMultiLightUpdate(accessory, params) { @@ -1980,22 +2668,37 @@ class eWeLink { let oAccessory = this.devicesInHB.get(idToCheck + i); oAccessory .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); + .updateCharacteristic( + Characteristic.On, + params.switches[i - 1].switch === "on" + ); if (params.switches[i - 1].switch === "on") { primaryState = true; } } } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, primaryState); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, primaryState); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalSingleSwitchUpdate(accessory, params) { try { - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switch === "on"); + accessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, params.switch === "on"); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalMultiSwitchUpdate(accessory, params) { @@ -2007,15 +2710,24 @@ class eWeLink { let oAccessory = this.devicesInHB.get(idToCheck + i); oAccessory .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); + .updateCharacteristic( + Characteristic.On, + params.switches[i - 1].switch === "on" + ); if (params.switches[i - 1].switch === "on") { primaryState = true; } } } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState); + accessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, primaryState); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalRFDeviceUpdate(accessory, params) { @@ -2023,14 +2735,26 @@ class eWeLink { if (!params.hasOwnProperty("updateSource")) return; let idToCheck = accessory.context.hbDeviceId.slice(0, -1), timeNow = new Date(); - if (params.hasOwnProperty("cmd") && params.cmd === "transmit" && params.hasOwnProperty("rfChl")) { + if ( + params.hasOwnProperty("cmd") && + params.cmd === "transmit" && + params.hasOwnProperty("rfChl") + ) { // RF Button let bAccessory; - if ((bAccessory = this.devicesInHB.get(idToCheck + accessory.context.rfChlMap[params.rfChl]))) { - bAccessory.getService(bAccessory.context.rfChls[params.rfChl]).updateCharacteristic(Characteristic.On, 1); + if ( + (bAccessory = this.devicesInHB.get( + idToCheck + accessory.context.rfChlMap[params.rfChl] + )) + ) { + bAccessory + .getService(bAccessory.context.rfChls[params.rfChl]) + .updateCharacteristic(Characteristic.On, 1); setTimeout( () => - bAccessory.getService(bAccessory.context.rfChls[params.rfChl]).updateCharacteristic(Characteristic.On, 0), + bAccessory + .getService(bAccessory.context.rfChls[params.rfChl]) + .updateCharacteristic(Characteristic.On, 0), 3000 ); } else { @@ -2052,78 +2776,124 @@ class eWeLink { case "button": break; case "water": - oAccessory.getService(Service.LeakSensor).updateCharacteristic(Characteristic.LeakDetected, 1); + oAccessory + .getService(Service.LeakSensor) + .updateCharacteristic(Characteristic.LeakDetected, 1); setTimeout(() => { - oAccessory.getService(Service.LeakSensor).updateCharacteristic(Characteristic.LeakDetected, 0); + oAccessory + .getService(Service.LeakSensor) + .updateCharacteristic(Characteristic.LeakDetected, 0); }, (this.config.sensorTimeLength || 2) * 1000); break; case "fire": case "smoke": - oAccessory.getService(Service.SmokeSensor).updateCharacteristic(Characteristic.SmokeDetected, 1); + oAccessory + .getService(Service.SmokeSensor) + .updateCharacteristic(Characteristic.SmokeDetected, 1); setTimeout(() => { - oAccessory.getService(Service.SmokeSensor).updateCharacteristic(Characteristic.SmokeDetected, 0); + oAccessory + .getService(Service.SmokeSensor) + .updateCharacteristic(Characteristic.SmokeDetected, 0); }, (this.config.sensorTimeLength || 2) * 1000); break; case "co": oAccessory .getService(Service.CarbonMonoxideSensor) - .updateCharacteristic(Characteristic.CarbonMonoxideDetected, 1); + .updateCharacteristic( + Characteristic.CarbonMonoxideDetected, + 1 + ); setTimeout(() => { oAccessory .getService(Service.CarbonMonoxideSensor) - .updateCharacteristic(Characteristic.CarbonMonoxideDetected, 0); + .updateCharacteristic( + Characteristic.CarbonMonoxideDetected, + 0 + ); }, (this.config.sensorTimeLength || 2) * 1000); break; case "co2": oAccessory .getService(Service.CarbonDioxideSensor) - .updateCharacteristic(Characteristic.CarbonDioxideDetected, 1); + .updateCharacteristic( + Characteristic.CarbonDioxideDetected, + 1 + ); setTimeout(() => { oAccessory .getService(Service.CarbonDioxideSensor) - .updateCharacteristic(Characteristic.CarbonDioxideDetected, 0); + .updateCharacteristic( + Characteristic.CarbonDioxideDetected, + 0 + ); }, (this.config.sensorTimeLength || 2) * 1000); break; case "contact": oAccessory .getService(Service.ContactSensor) - .updateCharacteristic(Characteristic.ContactSensorState, 1); + .updateCharacteristic( + Characteristic.ContactSensorState, + 1 + ); setTimeout(() => { oAccessory .getService(Service.ContactSensor) - .updateCharacteristic(Characteristic.ContactSensorState, 0); + .updateCharacteristic( + Characteristic.ContactSensorState, + 0 + ); }, (this.config.sensorTimeLength || 2) * 1000); break; case "occupancy": oAccessory .getService(Service.OccupancySensor) - .updateCharacteristic(Characteristic.OccupancyDetected, 1); + .updateCharacteristic( + Characteristic.OccupancyDetected, + 1 + ); setTimeout(() => { oAccessory .getService(Service.OccupancySensor) - .updateCharacteristic(Characteristic.OccupancyDetected, 0); + .updateCharacteristic( + Characteristic.OccupancyDetected, + 0 + ); }, (this.config.sensorTimeLength || 2) * 1000); break; default: oAccessory .getService(Service.MotionSensor) - .updateCharacteristic(Characteristic.MotionDetected, true); + .updateCharacteristic( + Characteristic.MotionDetected, + true + ); setTimeout(() => { oAccessory .getService(Service.MotionSensor) - .updateCharacteristic(Characteristic.MotionDetected, false); + .updateCharacteristic( + Characteristic.MotionDetected, + false + ); }, (this.config.sensorTimeLength || 2) * 1000); break; } if (this.debug) { - this.log("[%s] has detected [%s].", oAccessory.displayName, oAccessory.context.sensorType); + this.log( + "[%s] has detected [%s].", + oAccessory.displayName, + oAccessory.context.sensorType + ); } } } }); } } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalZBDeviceUpdate(accessory, params) { @@ -2131,16 +2901,26 @@ class eWeLink { //*** credit @tasict ***\\ if (params.hasOwnProperty("battery")) { let batteryService = - accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); - batteryService.updateCharacteristic(Characteristic.BatteryLevel, params.battery); - batteryService.updateCharacteristic(Characteristic.StatusLowBattery, params.battery <= 25); + accessory.getService(Service.BatteryService) || + accessory.addService(Service.BatteryService); + batteryService.updateCharacteristic( + Characteristic.BatteryLevel, + params.battery + ); + batteryService.updateCharacteristic( + Characteristic.StatusLowBattery, + params.battery < 25 + ); } switch (accessory.context.eweUIID) { case 1000: if (params.hasOwnProperty("key") && [0, 1, 2].includes(params.key)) { accessory .getService(Service.StatelessProgrammableSwitch) - .updateCharacteristic(Characteristic.ProgrammableSwitchEvent, params.key); + .updateCharacteristic( + Characteristic.ProgrammableSwitchEvent, + params.key + ); } break; case 1770: @@ -2151,22 +2931,34 @@ class eWeLink { let currentTemp = parseInt(params.temperature) / 100; accessory .getService(Service.TemperatureSensor) - .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); + .updateCharacteristic( + Characteristic.CurrentTemperature, + currentTemp + ); eveLog.temp = parseFloat(currentTemp); } if (params.hasOwnProperty("humidity")) { let currentHumi = parseInt(params.humidity) / 100; accessory .getService(Service.HumiditySensor) - .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); + .updateCharacteristic( + Characteristic.CurrentRelativeHumidity, + currentHumi + ); eveLog.humidity = parseFloat(currentHumi); } - if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { + if ( + eveLog.hasOwnProperty("temp") || + eveLog.hasOwnProperty("humidity") + ) { accessory.eveLogger.addEntry(eveLog); } break; case 2026: - if (params.hasOwnProperty("motion") && params.hasOwnProperty("trigTime")) { + if ( + params.hasOwnProperty("motion") && + params.hasOwnProperty("trigTime") + ) { let timeNow = new Date(), diff = (timeNow.getTime() - params.trigTime) / 1000; accessory @@ -2184,12 +2976,19 @@ class eWeLink { if (params.hasOwnProperty("lock") && [0, 1].includes(params.lock)) { accessory .getService(Service.ContactSensor) - .updateCharacteristic(Characteristic.ContactSensorState, params.lock); + .updateCharacteristic( + Characteristic.ContactSensorState, + params.lock + ); } break; } } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } } diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 57e12c2f..093bd0f2 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -12,7 +12,9 @@ module.exports = class eWeLinkHTTP { } login() { let data = { - countryCode: "+" + this.config.countryCode.toString().replace("+", "").replace(" ", ""), + countryCode: + "+" + + this.config.countryCode.toString().replace("+", "").replace(" ", ""), password: this.config.password, }; this.config.username.includes("@") @@ -22,11 +24,17 @@ module.exports = class eWeLinkHTTP { let msg = JSON.stringify(data, null, 2) .replace(this.config.password, "**hidden**") .replace(this.config.username, "**hidden**"); - this.log.warn("Sending HTTP login request. This text is yellow for clarity.\n%s", msg); + this.log.warn( + "Sending HTTP login request. This text is yellow for clarity.\n%s", + msg + ); } else if (this.debug) { this.log("Sending HTTP login request."); } - let dataToSign = crypto.createHmac("sha256", constants.appSecret).update(JSON.stringify(data)).digest("base64"); + let dataToSign = crypto + .createHmac("sha256", constants.appSecret) + .update(JSON.stringify(data)) + .digest("base64"); return new Promise((resolve, reject) => { axios({ url: "https://" + this.httpHost + "/v2/user/login", @@ -88,7 +96,10 @@ module.exports = class eWeLinkHTTP { getHost() { let data = { appid: constants.appId, - country_code: this.config.countryCode.toString().replace("+", "").replace(" ", ""), + country_code: this.config.countryCode + .toString() + .replace("+", "") + .replace(" ", ""), nonce: Math.random().toString(36).substr(2, 8), ts: Math.floor(new Date().getTime() / 1000), version: 8, @@ -108,7 +119,10 @@ module.exports = class eWeLinkHTTP { return kv.key + "=" + kv.value; }) .join("&"); - dataToSign = crypto.createHmac("sha256", "6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM").update(dataToSign).digest("base64"); + dataToSign = crypto + .createHmac("sha256", "6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM") + .update(dataToSign) + .digest("base64"); return new Promise((resolve, reject) => { axios .get("https://api.coolkit.cc:8080/api/user/region", { @@ -121,7 +135,10 @@ module.exports = class eWeLinkHTTP { .then(res => { let body = res.data; if (!body.region) { - throw "Server did not respond with a region.\n" + JSON.stringify(body, null, 2); + throw ( + "Server did not respond with a region.\n" + + JSON.stringify(body, null, 2) + ); } switch (body.region) { case "eu": @@ -159,12 +176,17 @@ module.exports = class eWeLinkHTTP { }) .then(res => { let body = res.data; - if (!body.hasOwnProperty("error") || (body.hasOwnProperty("error") && body.error !== 0)) { + if ( + !body.hasOwnProperty("error") || + (body.hasOwnProperty("error") && body.error !== 0) + ) { throw JSON.stringify(body, null, 2); } let deviceList = []; if (body.data.thingList && body.data.thingList.length > 0) { - body.data.thingList.forEach(device => deviceList.push(device.itemData)); + body.data.thingList.forEach(device => + deviceList.push(device.itemData) + ); } resolve(deviceList); }) diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 2bbbf005..25baee53 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -16,7 +16,9 @@ module.exports = class eWeLinkLAN { deviceMap.set(device.deviceid, { apiKey: device.devicekey, online: this.ipOverrides.hasOwnProperty(device.deviceid) ? true : false, - ip: this.ipOverrides.hasOwnProperty(device.deviceid) ? this.ipOverrides[device.deviceid] : null, + ip: this.ipOverrides.hasOwnProperty(device.deviceid) + ? this.ipOverrides[device.deviceid] + : null, }); }); this.deviceMap = deviceMap; @@ -34,7 +36,9 @@ module.exports = class eWeLinkLAN { let onlineCount = 0; res.forEach(device => { let d, - deviceId = device.fqdn.replace("._ewelink._tcp.local", "").replace("eWeLink_", ""); + deviceId = device.fqdn + .replace("._ewelink._tcp.local", "") + .replace("eWeLink_", ""); if ((d = this.deviceMap.get(deviceId))) { if (!this.ipOverrides.hasOwnProperty(deviceId)) { this.deviceMap.set(deviceId, { @@ -71,29 +75,52 @@ module.exports = class eWeLinkLAN { (rdata.hasOwnProperty("data2") ? rdata.data2 : "") + (rdata.hasOwnProperty("data3") ? rdata.data3 : "") + (rdata.hasOwnProperty("data4") ? rdata.data4 : ""), - key = crypto.createHash("md5").update(Buffer.from(deviceInfo.apiKey, "utf8")).digest(), - dText = crypto.createDecipheriv("aes-128-cbc", key, Buffer.from(rdata.iv, "base64")), - pText = Buffer.concat([dText.update(Buffer.from(data, "base64")), dText.final()]).toString("utf8"), + key = crypto + .createHash("md5") + .update(Buffer.from(deviceInfo.apiKey, "utf8")) + .digest(), + dText = crypto.createDecipheriv( + "aes-128-cbc", + key, + Buffer.from(rdata.iv, "base64") + ), + pText = Buffer.concat([ + dText.update(Buffer.from(data, "base64")), + dText.final(), + ]).toString("utf8"), params; - if (packet.address !== deviceInfo.ip && !this.ipOverrides.hasOwnProperty(rdata.id)) { + if ( + packet.address !== deviceInfo.ip && + !this.ipOverrides.hasOwnProperty(rdata.id) + ) { this.deviceMap.set(rdata.id, { apiKey: deviceInfo.apiKey, online: true, ip: packet.address, }); if (this.debug) { - this.log.warn("[%s] updating IP address to [%s].", rdata.id, packet.address); + this.log.warn( + "[%s] updating IP address to [%s].", + rdata.id, + packet.address + ); } } try { params = JSON.parse(pText); } catch (e) { - this.log.warn("[%s] An error occured reading the LAN message [%s]", rdata.id, e); + this.log.warn( + "[%s] An error occured reading the LAN message [%s]", + rdata.id, + e + ); return; } for (let param in params) { if (params.hasOwnProperty(param)) { - if (!constants.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { + if ( + !constants.paramsToKeep.includes(param.replace(/[0-9]/g, "")) + ) { delete params[param]; } } @@ -106,7 +133,10 @@ module.exports = class eWeLinkLAN { params, }; if (this.debugReqRes) { - let msg = JSON.stringify(returnTemplate, null, 2).replace(rdata.id, "**hidden**"); + let msg = JSON.stringify(returnTemplate, null, 2).replace( + rdata.id, + "**hidden**" + ); this.log("LAN message received.\n%s", msg); } else if (this.debug) { this.log("LAN message received."); @@ -145,11 +175,17 @@ module.exports = class eWeLinkLAN { throw "plugin does not support lan mode for this device yet - feel free to create a github issue"; } if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { - let key = crypto.createHash("md5").update(Buffer.from(apiKey, "utf8")).digest(), + let key = crypto + .createHash("md5") + .update(Buffer.from(apiKey, "utf8")) + .digest(), iv = crypto.randomBytes(16), enc = crypto.createCipheriv("aes-128-cbc", key, iv), data = { - data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString("base64"), + data: Buffer.concat([ + enc.update(JSON.stringify(params)), + enc.final(), + ]).toString("base64"), deviceid: json.deviceid, encrypt: true, iv: iv.toString("base64"), @@ -161,13 +197,20 @@ module.exports = class eWeLinkLAN { .replace(json.apikey, "**hidden**") .replace(json.apikey, "**hidden**") .replace(json.deviceid, "**hidden**"); - this.log.warn("LAN message sent. This text is yellow for clarity.\n%s", msg); + this.log.warn( + "LAN message sent. This text is yellow for clarity.\n%s", + msg + ); } else if (this.debug) { this.log("LAN message sent."); } axios({ method: "post", - url: "http://" + this.deviceMap.get(json.deviceid).ip + ":8081/zeroconf/" + suffix, + url: + "http://" + + this.deviceMap.get(json.deviceid).ip + + ":8081/zeroconf/" + + suffix, headers: { Accept: "application/json", "Content-Type": "application/json", diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 86f08e3e..56fbeb64 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -21,7 +21,8 @@ module.exports = class eWeLinkWS { return new Promise((resolve, reject) => { axios({ method: "post", - url: "https://" + this.httpHost.replace("-api", "-disp") + "/dispatch/app", + url: + "https://" + this.httpHost.replace("-api", "-disp") + "/dispatch/app", headers: { Authorization: "Bearer " + this.aToken, "Content-Type": "application/json", @@ -69,7 +70,10 @@ module.exports = class eWeLinkWS { let msg = JSON.stringify(payload, null, 2) .replace(this.aToken, "**hidden**") .replace(this.apiKey, "**hidden**"); - this.log.warn("Sending WS login request. This text is yellow for clarity.\n%s", msg); + this.log.warn( + "Sending WS login request. This text is yellow for clarity.\n%s", + msg + ); } else if (this.debug) { this.log("Sending WS login request."); } @@ -82,7 +86,10 @@ module.exports = class eWeLinkWS { try { device = JSON.parse(m); } catch (e) { - this.log.warn("An error occured reading the web socket message [%s]", e); + this.log.warn( + "An error occured reading the web socket message [%s]", + e + ); return; } // for requestUpdate response @@ -93,14 +100,23 @@ module.exports = class eWeLinkWS { device.error === 0 ) { device.action = "update"; - } else if (device.hasOwnProperty("deviceid") && device.hasOwnProperty("error") && device.error === 504) { + } else if ( + device.hasOwnProperty("deviceid") && + device.hasOwnProperty("error") && + device.error === 504 + ) { device.action = "sysmsg"; device.params = { online: false, }; } // for external updates - if (device.hasOwnProperty("config") && device.config.hb && device.config.hbInterval && !this.hbInterval) { + if ( + device.hasOwnProperty("config") && + device.config.hb && + device.config.hbInterval && + !this.hbInterval + ) { this.hbInterval = setInterval(() => { this.ws.send("ping"); }, (device.config.hbInterval + 7) * 1000); @@ -114,7 +130,10 @@ module.exports = class eWeLinkWS { params: device.params, }; if (this.debugReqRes) { - let msg = JSON.stringify(returnTemplate, null, 2).replace(device.deviceid, "**hidden**"); + let msg = JSON.stringify(returnTemplate, null, 2).replace( + device.deviceid, + "**hidden**" + ); this.log("WS message received.\n%s", msg); } else if (this.debug) { this.log("WS message received."); @@ -124,7 +143,9 @@ module.exports = class eWeLinkWS { case "update": for (let param in device.params) { if (device.params.hasOwnProperty(param)) { - if (!constants.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { + if ( + !constants.paramsToKeep.includes(param.replace(/[0-9]/g, "")) + ) { delete device.params[param]; } } @@ -137,7 +158,10 @@ module.exports = class eWeLinkWS { params: device.params, }; if (this.debugReqRes) { - let msg = JSON.stringify(returnTemplate, null, 2).replace(device.deviceid, "**hidden**"); + let msg = JSON.stringify(returnTemplate, null, 2).replace( + device.deviceid, + "**hidden**" + ); this.log("WS message received.\n%s", msg); } else if (this.debug) { this.log("WS message received."); @@ -148,14 +172,20 @@ module.exports = class eWeLinkWS { case "reportSubDevice": return; default: - this.log.warn("[%s] WS message has unknown action.\n" + JSON.stringify(device, null, 2), device.deviceid); + this.log.warn( + "[%s] WS message has unknown action.\n" + + JSON.stringify(device, null, 2), + device.deviceid + ); return; } } else if (device.hasOwnProperty("error") && device.error === 0) { // *** Safe to ignore these messages *** \\ } else { if (this.debug) { - this.log.warn("WS unknown command received.\n" + JSON.stringify(device, null, 2)); + this.log.warn( + "WS unknown command received.\n" + JSON.stringify(device, null, 2) + ); } } }); @@ -170,7 +200,9 @@ module.exports = class eWeLinkWS { this.login(); }, 5000); } else { - this.log("Please try restarting Homebridge so that this plugin can work again."); + this.log( + "Please try restarting Homebridge so that this plugin can work again." + ); } } this.wsIsOpen = false; @@ -183,13 +215,17 @@ module.exports = class eWeLinkWS { this.ws.on("error", e => { this.log.error("Web socket error - [%s].", e); if (e.code === "ECONNREFUSED") { - this.log.warn("Web socket will try to reconnect in five seconds then try the command again."); + this.log.warn( + "Web socket will try to reconnect in five seconds then try the command again." + ); this.ws.removeAllListeners(); setTimeout(() => { this.login(); }, 5000); } else { - this.log.warn("If this was unexpected then please try restarting Homebridge."); + this.log.warn( + "If this was unexpected then please try restarting Homebridge." + ); } }); } @@ -216,7 +252,10 @@ module.exports = class eWeLinkWS { .replace(json.apikey, "**hidden**") .replace(json.apiKey, "**hidden**") .replace(json.deviceid, "**hidden**"); - this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); + this.log.warn( + "WS message sent. This text is yellow for clarity.\n%s", + msg + ); } else if (this.debug) { this.log("WS message sent."); } @@ -229,7 +268,9 @@ module.exports = class eWeLinkWS { setTimeout(sendOperation, this.delaySend, string); this.delaySend += 280; } else { - this.log.warn("Web socket is currently reconnecting. Command will be resent."); + this.log.warn( + "Web socket is currently reconnecting. Command will be resent." + ); let interval, waitToSend = req => { if (this.wsIsOpen) { @@ -264,7 +305,10 @@ module.exports = class eWeLinkWS { .replace(json.apikey, "**hidden**") .replace(json.apiKey, "**hidden**") .replace(json.deviceid, "**hidden**"); - this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); + this.log.warn( + "WS message sent. This text is yellow for clarity.\n%s", + msg + ); } else if (this.debug) { this.log("WS message sent."); } @@ -277,7 +321,9 @@ module.exports = class eWeLinkWS { setTimeout(sendOperation, this.delaySend, string); this.delaySend += 280; } else { - this.log.warn("Web socket is currently reconnecting. Command will be resent."); + this.log.warn( + "Web socket is currently reconnecting. Command will be resent." + ); let interval, waitToSend = req => { if (this.wsIsOpen) { From f176305ab47bd3824c8f02a94c4abb4329756d85 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 15 Sep 2020 18:20:19 +0100 Subject: [PATCH 0152/3183] Update eWeLinkHTTP.js --- lib/eWeLinkHTTP.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 093bd0f2..1aafd1e4 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -120,7 +120,7 @@ module.exports = class eWeLinkHTTP { }) .join("&"); dataToSign = crypto - .createHmac("sha256", "6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM") + .createHmac("sha256", constants.appSecret) .update(dataToSign) .digest("base64"); return new Promise((resolve, reject) => { From fb71abd9869024b0fb01d4d1a93c763d1e5e6bd5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 15 Sep 2020 18:26:32 +0100 Subject: [PATCH 0153/3183] dw2 add battery --- lib/eWeLink.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 0869e08a..13c6d210 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -447,6 +447,7 @@ class eWeLink { break; case "sensor": accessory.addService(Service.ContactSensor); + accessory.addService(Service.BatteryService); break; case "fan": accessory.addService(Service.Fanv2); From fb75298a74a77458152ccf99a7b9041cc6f32bb6 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 15 Sep 2020 18:26:45 +0100 Subject: [PATCH 0154/3183] remove "type" from sensor params --- lib/constants.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/constants.js b/lib/constants.js index 34215ac6..d8892025 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -38,7 +38,7 @@ module.exports = { devicesBrightable: [36, 44], devicesColourable: [22, 59], devicesSensor: [102], - devicesSensorParams: ["switch", "battery", "type"], + devicesSensorParams: ["switch", "battery"], devicesThermostat: [15], devicesThermostatParams: [ "currentTemperature", From 175a4e119a9526394b18e8db33f575c55da75365 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 15 Sep 2020 19:04:03 +0100 Subject: [PATCH 0155/3183] 2.27.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 61a31ae5..71955065 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.26.2", + "version": "2.27.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 06d38b28..90ba8792 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.26.2", + "version": "2.27.0", "author": "bwp91", "contributors": [ "gbro115", From a8725d0b82686f25fafa5e3c4337bb6b5d8cade3 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Tue, 15 Sep 2020 23:05:51 +0100 Subject: [PATCH 0156/3183] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 60323284..f85ca40c 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,8 @@ [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/latest?label=release)](https://www.npmjs.com/package/homebridge-ewelink) - [![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://www.npmjs.com/package/homebridge-ewelink) + [![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://www.npmjs.com/package/homebridge-ewelink) + [![Contribute](https://img.shields.io/badge/contribute-a%20drink-yellow)](https://ko-fi.com/bwp91) From 7232c7dca41bdcc4699c804844ad79a17d8f05ca Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Tue, 15 Sep 2020 23:07:37 +0100 Subject: [PATCH 0157/3183] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f85ca40c..79d92ff6 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,9 @@ [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) [![Discord](https://img.shields.io/discord/432663330281226270?color=728ED5&logo=discord&label=discord)](https://discord.com/channels/432663330281226270/742733745743855627) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) - [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/latest?label=release)](https://www.npmjs.com/package/homebridge-ewelink) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://www.npmjs.com/package/homebridge-ewelink) + [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) [![Contribute](https://img.shields.io/badge/contribute-a%20drink-yellow)](https://ko-fi.com/bwp91) From 4c24c9f3bbe93bddfd333db580defdc116d150e5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Sep 2020 05:47:00 +0000 Subject: [PATCH 0158/3183] Bump prettier from 2.1.1 to 2.1.2 Bumps [prettier](https://github.com/prettier/prettier) from 2.1.1 to 2.1.2. - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/master/CHANGELOG.md) - [Commits](https://github.com/prettier/prettier/compare/2.1.1...2.1.2) Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 71955065..3e66d828 100644 --- a/package-lock.json +++ b/package-lock.json @@ -546,9 +546,9 @@ } }, "prettier": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.1.tgz", - "integrity": "sha512-9bY+5ZWCfqj3ghYBLxApy2zf6m+NJo5GzmLTpr9FsApsfjriNnS2dahWReHMi7qNPhhHl9SYHJs2cHZLgexNIw==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz", + "integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==", "dev": true }, "qs": { diff --git a/package.json b/package.json index 90ba8792..015ed59c 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,6 @@ "ws": "7.3.1" }, "devDependencies": { - "prettier": "2.1.1" + "prettier": "2.1.2" } } From 556a0e048249a7e8c423f052a6b8283318389b73 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 16 Sep 2020 13:57:48 +0100 Subject: [PATCH 0159/3183] 3.0 initial changes --- .prettierrc.json | 3 +- lib/constants.js | 7 +- lib/eWeLink.js | 1389 +++++++++++++------------------------------- lib/eWeLinkHTTP.js | 241 ++++---- lib/eWeLinkLAN.js | 91 +-- lib/eWeLinkWS.js | 156 ++--- 6 files changed, 624 insertions(+), 1263 deletions(-) diff --git a/.prettierrc.json b/.prettierrc.json index d68aa739..87f5e5e8 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,3 +1,4 @@ { - "arrowParens": "avoid" + "arrowParens": "avoid", + "printWidth": 100 } diff --git a/lib/constants.js b/lib/constants.js index d8892025..fe7fcb40 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -40,12 +40,7 @@ module.exports = { devicesSensor: [102], devicesSensorParams: ["switch", "battery"], devicesThermostat: [15], - devicesThermostatParams: [ - "currentTemperature", - "currentHumidity", - "switch", - "masterSwitch", - ], + devicesThermostatParams: ["currentTemperature", "currentHumidity", "switch", "masterSwitch"], devicesFan: [34], devicesFanParams: ["switches", "light", "fan", "speed"], devicesOutlet: [32], diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 13c6d210..855a0402 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -13,15 +13,9 @@ class eWeLink { constructor(log, config, api) { if (!log || !api || !config) return; if (!config.username || !config.password || !config.countryCode) { - log.error( - "**************** Cannot load homebridge-ewelink ****************" - ); - log.error( - "Your eWeLink credentials are missing from the Homebridge config." - ); - log.error( - "****************************************************************" - ); + log.error("*********** Cannot load homebridge-ewelink ***********"); + log.error("eWeLink credentials missing from the Homebridge config."); + log.error("*******************************************************"); return; } this.log = log; @@ -29,153 +23,103 @@ class eWeLink { this.api = api; this.debug = this.config.debug || false; this.devicesInHB = new Map(); - this.devicesInEwe = new Map(); + this.devicesInEW = new Map(); this.cusG = new Map(); this.cusS = new Map(); this.eveLogPath = this.api.user.storagePath() + "/homebridge-ewelink/"; this.api - .on("didFinishLaunching", () => { - this.log( - "Plugin has finished initialising. Starting synchronisation with eWeLink account." - ); - //*** Set up HTTP client and get the user HTTP host ***\\ - this.httpClient = new eWeLinkHTTP(this.config, this.log); - this.httpClient - .getHost() - .then(() => this.httpClient.login()) - .then(res => { - //*** Set up the web socket client ***\\ - this.wsClient = new eWeLinkWS(this.config, this.log, res); - return this.wsClient.getHost(); - }) - .then(() => { - //*** Open web socket connection and get device list via HTTP ***\\ - this.wsClient.login(); - return this.httpClient.getDevices(); - }) - .then(res => { - //*** Get device IP addresses for LAN mode ***\\ - this.httpDevices = res - .filter( - device => - device.hasOwnProperty("extra") && - device.extra.hasOwnProperty("uiid") - ) - .filter( - device => - !(this.config.hideDevFromHB || "").includes(device.deviceid) - ); - this.lanClient = new eWeLinkLAN( - this.config, - this.log, - this.httpDevices - ); - this.httpDevices.forEach(device => - this.devicesInEwe.set(device.deviceid, device) - ); - return this.lanClient.getHosts(); - }) - .then(res => { - //*** Set up the LAN mode listener ***\\ - this.lanDevices = res.map; - this.lanDevicesOnline = res.count; - return this.lanClient.startMonitor(); - }) - .then(() => { - //*** Use the device list to refresh Homebridge accessories ***\\ - (() => { - //*** Remove all Homebridge accessories if none found ***\\ - if ( - Object.keys(this.httpDevices).length === 0 && - Object.keys(this.lanDevices).length === 0 - ) { - Array.from(this.devicesInHB.values()).forEach(a => - this.removeAccessory(a) - ); - this.devicesInHB.clear(); - this.log.warn("******* Not loading homebridge-ewelink *******"); - this.log.warn("No devices were found in your eWeLink account."); - this.log.warn("**********************************************"); - return; - } - //*** Make a map of custom groups from Homebridge config ***\\ - if (Object.keys(this.config.groups || []).length > 0) { - this.config.groups - .filter( - g => - g.hasOwnProperty("type") && - cns.allowedGroups.includes(g.type) - ) - .filter( - g => - g.hasOwnProperty("deviceId") && - this.devicesInEwe.has(g.deviceId.toLowerCase()) - ) - .forEach(g => this.cusG.set(g.deviceId + "SWX", g)); - } - //*** Make a map of RF Bridge custom sensors from Homebridge config ***\\ - if (Object.keys(this.config.bridgeSensors || []).length > 0) { - this.config.bridgeSensors - .filter( - s => - s.hasOwnProperty("deviceId") && - this.devicesInEwe.has(s.deviceId.toLowerCase()) - ) - .forEach(s => this.cusS.set(s.fullDeviceId, s)); - } - //*** Logging always helps to see if everything is okay so far ***\\ - this.log( - "[%s] eWeLink devices were loaded from the Homebridge cache.", - this.devicesInHB.size - ); - this.log( - "[%s] primary devices were loaded from your eWeLink account.", - this.devicesInEwe.size - ); - this.log( - "[%s] primary devices were discovered on your local network.", - this.lanDevicesOnline - ); - //*** Remove Homebridge accessories that don't appear in eWeLink ***\\ - this.devicesInHB.forEach(a => { - if (!this.devicesInEwe.has(a.context.eweDeviceId)) { - this.removeAccessory(a); - } - }); - //*** Synchronise devices between eWeLink and Homebridge and set up ws/lan listeners ***\\ - this.devicesInEwe.forEach(d => this.initialiseDevice(d)); - this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); - this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); - this.log( - "eWeLink setup complete. If you're enjoying this package please consider a ⭐ī¸ on GitHub :)." - ); - if (this.config.debugReqRes || false) { - this.log.warn( - "You have 'Request & Response Logging' enabled. This setting is not recommended for long-term use." - ); - } - })(); - }) - .catch(err => { - this.log.error( - "************** Cannot load homebridge-ewelink **************" - ); - this.log.error(err); - this.log.error( - "************************************************************" - ); - if (this.lanClient) this.lanClient.closeConnection(); - if (this.wsClient) this.wsClient.closeConnection(); + .on("didFinishLaunching", () => this.eWeLinkSync()) + .on("shutdown", () => { + if (this.lanClient) this.lanClient.closeConnection(); + if (this.wsClient) this.wsClient.closeConnection(); + }); + } + eWeLinkSync() { + this.log("Plugin has finished initialising. Synching with eWeLink."); + this.httpClient = new eWeLinkHTTP(this.config, this.log); + this.httpClient + .getHost() + .then(() => this.httpClient.login()) + .then(res => { + this.authData = res; + return this.httpClient.getDevices(); + }) + .then(res => { + this.httpDevices = res + .filter(d => d.hasOwnProperty("extra") && d.extra.hasOwnProperty("uiid")) + .filter(d => !(this.config.hideDevFromHB || "").includes(d.deviceid)); + this.httpDevices.forEach(device => this.devicesInEW.set(device.deviceid, device)); + this.wsClient = new eWeLinkWS(this.config, this.log, this.authData); + return this.wsClient.getHost(); + }) + .then(() => { + this.wsClient.login(); + this.lanClient = new eWeLinkLAN(this.config, this.log, this.httpDevices); + return this.lanClient.getHosts(); + }) + .then(res => { + this.lanDevices = res.map; + this.lanCount = res.count; + return this.lanClient.startMonitor(); + }) + .then(() => { + (() => { + //*** Remove all Homebridge accessories if none found ***\\ + if ( + Object.keys(this.httpDevices).length === 0 && + Object.keys(this.lanDevices).length === 0 + ) { + Array.from(this.devicesInHB.values()).forEach(a => this.removeAccessory(a)); + this.devicesInHB.clear(); + this.log.warn("******* Not loading homebridge-ewelink *******"); + this.log.warn("No devices were found in your eWeLink account."); + this.log.warn("**********************************************"); + return; + } + //*** Make a map of custom groups from Homebridge config ***\\ + if (Object.keys(this.config.groups || []).length > 0) { + this.config.groups + .filter(g => g.hasOwnProperty("type") && cns.allowedGroups.includes(g.type)) + .filter(g => g.hasOwnProperty("deviceId") && this.devicesInEW.has(g.deviceId)) + .forEach(g => this.cusG.set(g.deviceId + "SWX", g)); + } + //*** Make a map of RF Bridge custom sensors from Homebridge config ***\\ + if (Object.keys(this.config.bridgeSensors || []).length > 0) { + this.config.bridgeSensors + .filter(s => s.hasOwnProperty("deviceId") && this.devicesInEW.has(s.deviceId)) + .forEach(s => this.cusS.set(s.fullDeviceId, s)); + } + //*** Logging always helps to see if everything is okay so far ***\\ + this.log("[%s] eWeLink devices loaded from the Homebridge cache.", this.devicesInHB.size); + this.log("[%s] primary devices loaded from your eWeLink account.", this.devicesInEW.size); + this.log("[%s] primary devices were discovered on your local network.", this.lanCount); + //*** Remove Homebridge accessories that don't appear in eWeLink ***\\ + this.devicesInHB.forEach(a => { + if (!this.devicesInEW.has(a.context.eweDeviceId)) { + this.removeAccessory(a); + } }); + //*** Synchronise devices between eWeLink and Homebridge and set up ws/lan listeners ***\\ + this.devicesInEW.forEach(d => this.initialiseDevice(d)); + this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); + this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); + this.log("eWeLink sync complete. Don't forget to ⭐ī¸ this plugin on GitHub!"); + if (this.config.debugReqRes || false) { + this.log.warn("Note: 'Request & Response Logging' is not advised for long-term use."); + } + })(); }) - .on("shutdown", () => { + .catch(err => { + this.log.error("************** Cannot load homebridge-ewelink **************"); + this.log.error(err); + this.log.error("************************************************************"); if (this.lanClient) this.lanClient.closeConnection(); if (this.wsClient) this.wsClient.closeConnection(); }); } initialiseDevice(device) { let accessory; - //*** First add the device if it isn't already in Homebridge. Yeah this code looks a mess :| ***\\ + //*** First add the device if it isn't already in Homebridge ***\\ if ( !this.devicesInHB.has(device.deviceid + "SWX") && !this.devicesInHB.has(device.deviceid + "SW0") @@ -233,9 +177,7 @@ class eWeLink { } } else if (cns.devicesRFBridge.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SW0", "rf_pri"); - if ( - Object.keys((device.tags && device.tags.zyx_info) || []).length > 0 - ) { + if (Object.keys((device.tags && device.tags.zyx_info) || []).length > 0) { for (let i = 1; i <= Object.keys(device.tags.zyx_info).length; i++) { this.addAccessory(device, device.deviceid + "SW" + i, "rf_sub"); } @@ -269,31 +211,20 @@ class eWeLink { rfBridgeChange = false; accessory .getService(Service.AccessoryInformation) - .setCharacteristic( - Characteristic.FirmwareRevision, - device.params.fwVersion - ); - accessory.context.reachableWAN = - accessory.context.eweUIID !== 102 ? device.online : true; - accessory.context.reachableLAN = - this.lanDevices.get(device.deviceid).online || false; + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); + accessory.context.reachableWAN = accessory.context.eweUIID !== 102 ? device.online : true; + accessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; accessory.context.inUse = false; let str = accessory.context.reachableLAN - ? "and locally with IP [" + - this.lanDevices.get(device.deviceid).ip + - "]" - : "but LAN mode unavailable as unsupported/shared device"; + ? "and locally with IP [" + this.lanDevices.get(device.deviceid).ip + "]" + : "but LAN mode unavailable as offline/unsupported/shared device"; this.log("[%s] found in eWeLink %s.", accessory.displayName, str); this.devicesInHB.set(accessory.context.hbDeviceId, accessory); if (!isX) { for (let i = 1; i <= accessory.context.channelCount; i++) { if (!this.devicesInHB.has(device.deviceid + "SW" + i)) { if (cns.devicesHideable.includes(accessory.context.type)) { - if ( - (this.config.hideFromHB || "").includes( - device.deviceid + "SW" + i - ) - ) { + if ((this.config.hideFromHB || "").includes(device.deviceid + "SW" + i)) { continue; } else { this.addAccessory(device, device.deviceid + "SW" + i, "switch"); @@ -302,9 +233,7 @@ class eWeLink { } let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); if ( - (this.config.hideFromHB || "").includes( - device.deviceid + "SW" + i - ) && + (this.config.hideFromHB || "").includes(device.deviceid + "SW" + i) && cns.devicesHideable.includes(accessory.context.type) ) { this.removeAccessory(oAccessory); @@ -318,13 +247,9 @@ class eWeLink { } oAccessory .getService(Service.AccessoryInformation) - .setCharacteristic( - Characteristic.FirmwareRevision, - device.params.fwVersion - ); + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); oAccessory.context.reachableWAN = device.online; - oAccessory.context.reachableLAN = - this.lanDevices.get(device.deviceid).online || false; + oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); } } @@ -349,18 +274,12 @@ class eWeLink { ); } } else { - this.log.warn( - "[%s] cannot be initialised as it wasn't found in Homebridge.", - device.name - ); + this.log.warn("[%s] cannot be initialised as it wasn't found in Homebridge.", device.name); } } addAccessory(device, hbDeviceId, type) { let switchNumber = hbDeviceId.substr(-1).toString(), - newDeviceName = - type === "rf_sub" - ? device.tags.zyx_info[switchNumber - 1].name - : device.name, + newDeviceName = type === "rf_sub" ? device.tags.zyx_info[switchNumber - 1].name : device.name, channelCount = type === "rf_pri" ? Object.keys((device.tags && device.tags.zyx_info) || []).length @@ -378,10 +297,7 @@ class eWeLink { if ((this.config.nameOverride || {}).hasOwnProperty(hbDeviceId)) { newDeviceName = this.config.nameOverride[hbDeviceId]; } - const accessory = new Accessory( - newDeviceName, - UUIDGen.generate(hbDeviceId).toString() - ); + const accessory = new Accessory(newDeviceName, UUIDGen.generate(hbDeviceId).toString()); try { accessory .getService(Service.AccessoryInformation) @@ -391,10 +307,7 @@ class eWeLink { Characteristic.Model, device.productModel + " (" + device.extra.model + ")" ) - .setCharacteristic( - Characteristic.FirmwareRevision, - device.params.fwVersion - ) + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) .setCharacteristic(Characteristic.Identify, false); accessory.context = { hbDeviceId, @@ -410,18 +323,11 @@ class eWeLink { case "valve": ["A", "B"].forEach(v => { accessory - .addService( - Service.Valve, - "Valve " + v, - "valve" + v.toLowerCase() - ) + .addService(Service.Valve, "Valve " + v, "valve" + v.toLowerCase()) .setCharacteristic(Characteristic.Active, 0) .setCharacteristic(Characteristic.InUse, 0) .setCharacteristic(Characteristic.ValveType, 1) - .setCharacteristic( - Characteristic.SetDuration, - this.config.valveTimeLength || 120 - ) + .setCharacteristic(Characteristic.SetDuration, this.config.valveTimeLength || 120) .addCharacteristic(Characteristic.RemainingDuration); }); break; @@ -456,8 +362,7 @@ class eWeLink { case "thermostat": if (!this.config.hideTHSwitch) accessory.addService(Service.Switch); accessory.addService(Service.TemperatureSensor); - if (device.params.sensorType !== "DS18B20") - accessory.addService(Service.HumiditySensor); + if (device.params.sensorType !== "DS18B20") accessory.addService(Service.HumiditySensor); break; case "outlet": accessory.addService(Service.Outlet); @@ -503,9 +408,7 @@ class eWeLink { break; case "rf_sub": accessory.context.rfChls = {}; - switch ( - device.tags.zyx_info[parseInt(switchNumber) - 1].remote_type - ) { + switch (device.tags.zyx_info[parseInt(switchNumber) - 1].remote_type) { case "1": case "2": case "3": @@ -525,52 +428,46 @@ class eWeLink { ); } let mAccessory = this.devicesInHB.get(device.deviceid + "SW0"); - device.tags.zyx_info[parseInt(switchNumber) - 1].buttonName.forEach( - button => { - let rfData; - Object.entries(button).forEach( - ([k, v]) => - (rfData = { - rfChan: k, - name: v, - }) - ); - accessory.context.rfChls[rfData.rfChan] = rfData.name; - mAccessory.context.rfChlMap[rfData.rfChan] = switchNumber; - switch (accessory.context.sensorType) { - case "button": - accessory.addService( - Service.Switch, - rfData.name, - "switch" + rfData.rfChan - ); - break; - case "water": - accessory.addService(Service.LeakSensor); - break; - case "fire": - case "smoke": - accessory.addService(Service.SmokeSensor); - break; - case "co": - accessory.addService(Service.CarbonMonoxideSensor); - break; - case "co2": - accessory.addService(Service.CarbonDioxideSensor); - break; - case "contact": - accessory.addService(Service.ContactSensor); - break; - case "occupancy": - accessory.addService(Service.OccupancySensor); - break; - default: - accessory.addService(Service.MotionSensor); - break; - } - this.devicesInHB.set(mAccessory.context.hbDeviceId, mAccessory); + device.tags.zyx_info[parseInt(switchNumber) - 1].buttonName.forEach(button => { + let rfData; + Object.entries(button).forEach( + ([k, v]) => + (rfData = { + rfChan: k, + name: v, + }) + ); + accessory.context.rfChls[rfData.rfChan] = rfData.name; + mAccessory.context.rfChlMap[rfData.rfChan] = switchNumber; + switch (accessory.context.sensorType) { + case "button": + accessory.addService(Service.Switch, rfData.name, "switch" + rfData.rfChan); + break; + case "water": + accessory.addService(Service.LeakSensor); + break; + case "fire": + case "smoke": + accessory.addService(Service.SmokeSensor); + break; + case "co": + accessory.addService(Service.CarbonMonoxideSensor); + break; + case "co2": + accessory.addService(Service.CarbonDioxideSensor); + break; + case "contact": + accessory.addService(Service.ContactSensor); + break; + case "occupancy": + accessory.addService(Service.OccupancySensor); + break; + default: + accessory.addService(Service.MotionSensor); + break; } - ); + this.devicesInHB.set(mAccessory.context.hbDeviceId, mAccessory); + }); break; case "zb_sub": //*** credit @tasict ***\\ accessory.addService(Service.BatteryService); @@ -608,9 +505,7 @@ class eWeLink { throw "device is not supported by this plugin. Please create an issue on GitHub"; } this.devicesInHB.set(hbDeviceId, accessory); - this.api.registerPlatformAccessories("homebridge-ewelink", "eWeLink", [ - accessory, - ]); + this.api.registerPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); this.configureAccessory(accessory); this.log("[%s] has been added to Homebridge.", newDeviceName); } catch (err) { @@ -629,33 +524,21 @@ class eWeLink { .getService("Valve " + v) .getCharacteristic(Characteristic.Active) .on("set", (value, callback) => - this.internalValveUpdate( - accessory, - "Valve " + v, - value, - callback - ) + this.internalValveUpdate(accessory, "Valve " + v, value, callback) ); accessory .getService("Valve " + v) .getCharacteristic(Characteristic.SetDuration) .on("set", (value, callback) => { if ( - accessory - .getService("Valve " + v) - .getCharacteristic(Characteristic.InUse).value + accessory.getService("Valve " + v).getCharacteristic(Characteristic.InUse).value ) { accessory .getService("Valve " + v) - .updateCharacteristic( - Characteristic.RemainingDuration, - value - ); + .updateCharacteristic(Characteristic.RemainingDuration, value); clearTimeout(accessory.getService("Valve " + v).timer); accessory.getService("Valve " + v).timer = setTimeout(() => { - accessory - .getService("Valve " + v) - .setCharacteristic(Characteristic.Active, 0); + accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); }, value * 1000); } callback(); @@ -666,9 +549,7 @@ class eWeLink { accessory .getService(Service.WindowCovering) .getCharacteristic(Characteristic.TargetPosition) - .on("set", (value, callback) => - this.internalBlindUpdate(accessory, value, callback) - ) + .on("set", (value, callback) => this.internalBlindUpdate(accessory, value, callback)) .setProps({ minStep: 100, }); @@ -677,17 +558,13 @@ class eWeLink { accessory .getService(Service.GarageDoorOpener) .getCharacteristic(Characteristic.TargetDoorState) - .on("set", (value, callback) => - this.internalGarageUpdate(accessory, value, callback) - ); + .on("set", (value, callback) => this.internalGarageUpdate(accessory, value, callback)); break; case "lock": accessory .getService(Service.LockMechanism) .getCharacteristic(Characteristic.LockTargetState) - .on("set", (value, callback) => - this.internalLockUpdate(accessory, value, callback) - ); + .on("set", (value, callback) => this.internalLockUpdate(accessory, value, callback)); break; case "fan": accessory @@ -737,9 +614,7 @@ class eWeLink { if (accessory.getService(Service.HumiditySensor)) { dataToAdd.humidity = accessory .getService(Service.HumiditySensor) - .getCharacteristic( - Characteristic.CurrentRelativeHumidity - ).value; + .getCharacteristic(Characteristic.CurrentRelativeHumidity).value; } accessory.eveLogger.addEntry(dataToAdd); }, 300000); @@ -748,9 +623,7 @@ class eWeLink { accessory .getService(Service.Outlet) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => - this.internalOutletUpdate(accessory, value, callback) - ); + .on("set", (value, callback) => this.internalOutletUpdate(accessory, value, callback)); accessory.log = this.log; accessory.eveLogger = new EveHistoryService("energy", accessory, { storage: "fs", @@ -769,15 +642,12 @@ class eWeLink { }; } corrInterval.setCorrectingInterval(() => { - let isOn = accessory - .getService(Service.Outlet) - .getCharacteristic(Characteristic.On).value, + let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) + .value, currentWatt = isOn ? accessory .getService(Service.Outlet) - .getCharacteristic( - EveService.Characteristics.CurrentConsumption - ).value + .getCharacteristic(EveService.Characteristics.CurrentConsumption).value : 0; if (accessory.eveLogger.isHistoryLoaded()) { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); @@ -792,8 +662,7 @@ class eWeLink { }); } else { accessory.context.totalEnergy = - accessory.context.totalEnergyTemp + - (currentWatt * 10) / 3600 / 1000; + accessory.context.totalEnergyTemp + (currentWatt * 10) / 3600 / 1000; accessory.eveLogger.setExtraPersistedData({ totalenergy: accessory.context.totalEnergy, lastReset: 0, @@ -801,8 +670,7 @@ class eWeLink { } accessory.context.totalEnergytemp = 0; } else { - accessory.context.totalEnergyTemp += - (currentWatt * 10) / 3600 / 1000; + accessory.context.totalEnergyTemp += (currentWatt * 10) / 3600 / 1000; accessory.context.totalEnergy = accessory.context.totalEnergyTemp; } accessory.eveLogger.addEntry({ @@ -816,8 +684,7 @@ class eWeLink { .on("get", callback => { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalEnergy = - accessory.context.extraPersistedData.totalPower; + accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower; } callback(null, accessory.context.totalEnergy); }); @@ -836,8 +703,7 @@ class eWeLink { .on("get", callback => { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); if (accessory.context.extraPersistedData !== undefined) { - accessory.context.lastReset = - accessory.context.extraPersistedData.lastReset; + accessory.context.lastReset = accessory.context.extraPersistedData.lastReset; } callback(null, accessory.context.lastReset); }); @@ -846,17 +712,13 @@ class eWeLink { accessory .getService(Service.Outlet) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => - this.internalUSBUpdate(accessory, value, callback) - ); + .on("set", (value, callback) => this.internalUSBUpdate(accessory, value, callback)); break; case "scm": accessory .getService(Service.Switch) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => - this.internalSCMUpdate(accessory, value, callback) - ); + .on("set", (value, callback) => this.internalSCMUpdate(accessory, value, callback)); break; case "light": accessory @@ -872,9 +734,8 @@ class eWeLink { .on("set", (value, callback) => { if (value > 0) { if ( - !accessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.On).value + !accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) + .value ) { this.internalLightbulbUpdate(accessory, true, function () { return; @@ -885,18 +746,15 @@ class eWeLink { this.internalLightbulbUpdate(accessory, false, callback); } }); - } else if ( - cns.devicesColourable.includes(accessory.context.eweUIID) - ) { + } else if (cns.devicesColourable.includes(accessory.context.eweUIID)) { accessory .getService(Service.Lightbulb) .getCharacteristic(Characteristic.Brightness) .on("set", (value, callback) => { if (value > 0) { if ( - !accessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.On).value + !accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) + .value ) { this.internalLightbulbUpdate(accessory, true, function () { return; @@ -923,24 +781,18 @@ class eWeLink { accessory .getService(Service.Switch) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => - this.internalSwitchUpdate(accessory, value, callback) - ); + .on("set", (value, callback) => this.internalSwitchUpdate(accessory, value, callback)); break; case "rf_sub": accessory.context.rfChls = accessory.context.rfChls || {}; if (accessory.context.sensorType === "button") { Object.entries(accessory.context.rfChls).forEach(([k, v]) => { - accessory - .getService(v) - .updateCharacteristic(Characteristic.On, false); + accessory.getService(v).updateCharacteristic(Characteristic.On, false); accessory .getService(v) .getCharacteristic(Characteristic.On) .on("set", (value, callback) => { - value - ? this.internalRFDeviceUpdate(accessory, k, callback) - : callback(); + value ? this.internalRFDeviceUpdate(accessory, k, callback) : callback(); }); }); } @@ -961,8 +813,7 @@ class eWeLink { .getCharacteristic(Characteristic.CurrentTemperature).value, humidity: accessory .getService(Service.HumiditySensor) - .getCharacteristic(Characteristic.CurrentRelativeHumidity) - .value, + .getCharacteristic(Characteristic.CurrentRelativeHumidity).value, }; accessory.eveLogger.addEntry(dataToAdd); }, 300000); @@ -971,20 +822,14 @@ class eWeLink { } this.devicesInHB.set(accessory.context.hbDeviceId, accessory); } catch (err) { - this.log.warn( - "[%s] could not be refreshed as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be refreshed as %s.", accessory.displayName, err); } } refreshAccessory(accessory, newParams) { switch (accessory.context.type) { case "valve": if ( - Object.keys(newParams).some(v => - cns.devicesValveParams.includes(v) - ) && + Object.keys(newParams).some(v => cns.devicesValveParams.includes(v)) && Array.isArray(newParams.switches) ) { this.externalValveUpdate(accessory, newParams); @@ -992,9 +837,7 @@ class eWeLink { return true; case "blind": if ( - Object.keys(newParams).some(v => - cns.devicesBlindParams.includes(v) - ) && + Object.keys(newParams).some(v => cns.devicesBlindParams.includes(v)) && Array.isArray(newParams.switches) ) { this.externalBlindUpdate(accessory, newParams); @@ -1002,48 +845,34 @@ class eWeLink { return true; case "garage": if ( - Object.keys(newParams).some(v => - cns.devicesGarageParams.includes(v) - ) && + Object.keys(newParams).some(v => cns.devicesGarageParams.includes(v)) && Array.isArray(newParams.switches) ) { this.externalGarageUpdate(accessory, newParams); } return true; case "lock": - if ( - Object.keys(newParams).some(v => cns.devicesLockParams.includes(v)) - ) { + if (Object.keys(newParams).some(v => cns.devicesLockParams.includes(v))) { this.externalLockUpdate(accessory, newParams); } return true; case "sensor": - if ( - Object.keys(newParams).some(v => cns.devicesSensorParams.includes(v)) - ) { + if (Object.keys(newParams).some(v => cns.devicesSensorParams.includes(v))) { this.externalSensorUpdate(accessory, newParams); } return true; case "fan": - if ( - Object.keys(newParams).some(v => cns.devicesFanParams.includes(v)) - ) { + if (Object.keys(newParams).some(v => cns.devicesFanParams.includes(v))) { this.externalFanUpdate(accessory, newParams); } return true; case "thermostat": - if ( - Object.keys(newParams).some(v => - cns.devicesThermostatParams.includes(v) - ) - ) { + if (Object.keys(newParams).some(v => cns.devicesThermostatParams.includes(v))) { this.externalThermostatUpdate(accessory, newParams); } return true; case "outlet": - if ( - Object.keys(newParams).some(v => cns.devicesOutletParams.includes(v)) - ) { + if (Object.keys(newParams).some(v => cns.devicesOutletParams.includes(v))) { this.externalOutletUpdate(accessory, newParams); } return true; @@ -1068,11 +897,7 @@ class eWeLink { cns.devicesSingleSwitch.includes(accessory.context.eweUIID) && cns.devicesSingleSwitchLight.includes(accessory.context.eweModel) ) { - if ( - Object.keys(newParams).some(v => - cns.devicesSingleSwitchLightParams.includes(v) - ) - ) { + if (Object.keys(newParams).some(v => cns.devicesSingleSwitchLightParams.includes(v))) { this.externalSingleLightUpdate(accessory, newParams); } } else if ( @@ -1080,9 +905,7 @@ class eWeLink { cns.devicesMultiSwitchLight.includes(accessory.context.eweModel) ) { if ( - Object.keys(newParams).some(v => - cns.devicesMultiSwitchLightParams.includes(v) - ) && + Object.keys(newParams).some(v => cns.devicesMultiSwitchLightParams.includes(v)) && Array.isArray(newParams.switches) ) { this.externalMultiLightUpdate(accessory, newParams); @@ -1091,18 +914,12 @@ class eWeLink { return true; case "switch": if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID)) { - if ( - Object.keys(newParams).some(v => - cns.devicesSingleSwitchParams.includes(v) - ) - ) { + if (Object.keys(newParams).some(v => cns.devicesSingleSwitchParams.includes(v))) { this.externalSingleSwitchUpdate(accessory, newParams); } } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID)) { if ( - Object.keys(newParams).some(v => - cns.devicesMultiSwitchParams.includes(v) - ) && + Object.keys(newParams).some(v => cns.devicesMultiSwitchParams.includes(v)) && Array.isArray(newParams.switches) ) { this.externalMultiSwitchUpdate(accessory, newParams); @@ -1110,11 +927,7 @@ class eWeLink { } return true; case "rf_pri": - if ( - Object.keys(newParams).some(v => - cns.devicesRFBridgeParams.includes(v) - ) - ) { + if (Object.keys(newParams).some(v => cns.devicesRFBridgeParams.includes(v))) { this.externalRFDeviceUpdate(accessory, newParams); } return true; @@ -1122,11 +935,7 @@ class eWeLink { case "zb_pri": return true; case "zb_sub": - if ( - Object.keys(newParams).some(v => - cns.devicesZBBridgeParams.includes(v) - ) - ) { + if (Object.keys(newParams).some(v => cns.devicesZBBridgeParams.includes(v))) { this.externalZBDeviceUpdate(accessory, newParams); } return true; @@ -1137,16 +946,10 @@ class eWeLink { removeAccessory(accessory) { try { this.devicesInHB.delete(accessory.context.hbDeviceId); - this.api.unregisterPlatformAccessories("homebridge-ewelink", "eWeLink", [ - accessory, - ]); + this.api.unregisterPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); this.log("[%s] has been removed from Homebridge.", accessory.displayName); } catch (err) { - this.log.warn( - "[%s] needed to be removed but couldn't as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] needed to be removed but couldn't as %s.", accessory.displayName, err); } } sendDeviceUpdate(accessory, params, callback) { @@ -1167,10 +970,7 @@ class eWeLink { callback("Device has failed to update"); } }; - if ( - cns.devicesNonLAN.includes(accessory.context.eweUIID) || - !accessory.context.reachableLAN - ) { + if (cns.devicesNonLAN.includes(accessory.context.eweUIID) || !accessory.context.reachableLAN) { sendViaWS(); } else { this.lanClient @@ -1178,110 +978,81 @@ class eWeLink { .then(() => callback()) .catch(err => { if (this.debug) { - this.log.warn( - "[%s] Reverting to web socket as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); } sendViaWS(); }); } } receiveDeviceUpdate(device) { - let accessory; - switch (device.action) { - case "sysmsg": - if ( - (accessory = - this.devicesInHB.get(device.deviceid + "SWX") || - this.devicesInHB.get(device.deviceid + "SW0")) - ) { - let isX = accessory.context.hbDeviceId.substr(-1) === "X"; - if (device.params.updateSource === "WS") { - if (accessory.context.reachableWAN !== device.params.online) { - accessory.context.reachableWAN = device.params.online; - this.log( - "[%s] has been reported [%s] via [WS].", - accessory.displayName, - accessory.context.reachableWAN ? "online" : "offline" - ); - this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - if (accessory.context.reachableWAN) - this.wsClient.requestUpdate(accessory); - } else { - if (this.debug) { - this.log( - "[%s] Nothing to update from above WS message.", - accessory.displayName - ); - } - } - } - if (!isX) { - for (let i = 1; i <= accessory.context.channelCount; i++) { - if (this.devicesInHB.has(device.deviceid + "SW" + i)) { - let oAccessory = this.devicesInHB.get( - device.deviceid + "SW" + i - ); - oAccessory.context.reachableWAN = device.params.online; - this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); - } - } - } + let accessory, + deviceId = device.deviceid, + statusChange = false; + if ( + (accessory = this.devicesInHB.get(deviceId + "SWX") || this.devicesInHB.get(deviceId + "SW0")) + ) { + let isX = accessory.context.hbDeviceId.substr(-1) === "X"; + + if (device.params.updateSource === "WS") { + if (device.params.online != accessory.context.reachableWAN) { + accessory.context.reachableWAN = device.params.online; + this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + if (accessory.context.reachableWAN) this.wsClient.requestUpdate(accessory); + statusChange = true; + this.log.warn( + "[%s] has been reported [%s] via [WS].", + accessory.displayName, + accessory.context.reachableWAN ? "online" : "offline" + ); } - break; - case "update": - if ( - (accessory = - this.devicesInHB.get(device.deviceid + "SWX") || - this.devicesInHB.get(device.deviceid + "SW0")) - ) { - if ( - device.params.updateSource === "WS" && - !accessory.context.reachableWAN - ) { - accessory.context.reachableWAN = true; - this.log( - "[%s] has been reported [online] via [WS].", - accessory.displayName - ); - } - if ( - device.params.updateSource === "LAN" && - !accessory.context.reachableLAN - ) { - accessory.context.reachableLAN = true; - this.log( - "[%s] has been reported [online] via [LAN].", - accessory.displayName - ); - } - if (this.debug) { - this.log( - "[%s] externally updated from above %s message and will be refreshed.", - accessory.displayName, - device.params.updateSource - ); - } - if (!this.refreshAccessory(accessory, device.params)) { - this.log.warn( - "[%s] cannot be refreshed. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.). [debug:%s:%s]", - accessory.displayName, - accessory.context.type, - accessory.context.channelCount - ); - } - } else { - if (!(this.config.hideDevFromHB || "").includes(device.deviceid)) { - this.log.warn( - "[%s] Accessory received via %s update does not exist in Homebridge. If it's a new accessory please restart Homebridge so it is added.", - device.deviceid, - device.params.updateSource - ); + } + + if (device.params.updateSource === "LAN") { + if (!accessory.context.reachableLAN) { + accessory.context.reachableLAN = true; + this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + this.wsClient.requestUpdate(accessory); + statusChange = true; + this.log.warn("[%s] has been reported [online] via [LAN].", accessory.displayName); + } + if (statusChange && !isX) { + for (let i = 1; i <= accessory.context.channelCount; i++) { + if (this.devicesInHB.has(deviceId + "SW" + i)) { + let oAccessory = this.devicesInHB.get(deviceId + "SW" + i); + oAccessory.context.reachableWAN = device.params.online; + oAccessory.context.reachableLAN = true; + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); + } } } - break; + } + if (this.debug) { + this.log( + "[%s] externally updated from above %s message and will be refreshed.", + accessory.displayName, + device.params.updateSource + ); + } + if (!this.refreshAccessory(accessory, device.params)) { + this.log.warn( + "[%s] cannot be refreshed. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.). [debug:%s:%s]", + accessory.displayName, + accessory.context.type, + accessory.context.channelCount + ); + } + } else { + if (!(this.config.hideDevFromHB || "").includes(deviceId)) { + this.log.warn( + "[%s] update received via %s does not exist in Homebridge so device will be added.", + deviceId, + device.params.updateSource + ); + this.httpClient + .getDevice(deviceId) + .then(res => this.initialiseDevice(res)) + .catch(err => this.log.error("[%s] error getting info [%s]", deviceId, err)); + } } } internalValveUpdate(accessory, valve, value, callback) { @@ -1296,28 +1067,19 @@ class eWeLink { .updateCharacteristic(Characteristic.InUse, value); switch (value) { case 0: - accessory - .getService(valve) - .updateCharacteristic(Characteristic.RemainingDuration, 0); + accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, 0); clearTimeout(accessory.getService(valve).timer); break; case 1: - let timer = accessory - .getService(valve) - .getCharacteristic(Characteristic.SetDuration).value; - accessory - .getService(valve) - .updateCharacteristic(Characteristic.RemainingDuration, timer); + let timer = accessory.getService(valve).getCharacteristic(Characteristic.SetDuration) + .value; + accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, timer); accessory.getService(valve).timer = setTimeout(() => { - accessory - .getService(valve) - .setCharacteristic(Characteristic.Active, 0); + accessory.getService(valve).setCharacteristic(Characteristic.Active, 0); }, timer * 1000); break; } - params.switches = this.devicesInEwe.get( - accessory.context.eweDeviceId - ).params.switches; + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; switch (valve) { case "Valve A": params.switches[0].switch = value ? "on" : "off"; @@ -1342,8 +1104,7 @@ class eWeLink { params.switches[3].switch = "off"; this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1357,10 +1118,7 @@ class eWeLink { if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } - if ( - blindConfig.type !== "blind" || - !["oneSwitch", "twoSwitch"].includes(blindConfig.setup) - ) { + if (blindConfig.type !== "blind" || !["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { throw "improper configuration"; } let oldPos, @@ -1382,9 +1140,7 @@ class eWeLink { params.switch = "on"; break; case "twoSwitch": - params.switches = this.devicesInEwe.get( - accessory.context.eweDeviceId - ).params.switches; + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; params.switches[0].switch = value === 100 ? "on" : "off"; params.switches[1].switch = value === 0 ? "on" : "off"; break; @@ -1404,8 +1160,7 @@ class eWeLink { callback(); }, parseInt(blindConfig.operationTime) * 100); } catch (err) { - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1433,10 +1188,7 @@ class eWeLink { newPos = value, params = {}, delay = 0; - if ( - sensorDefinition && - !(sAccessory = this.devicesInHB.get(garageConfig.sensorId + "SWX")) - ) { + if (sensorDefinition && !(sAccessory = this.devicesInHB.get(garageConfig.sensorId + "SWX"))) { throw "defined DW2 sensor doesn't exist"; } if (sAccessory.context.type !== "sensor") { @@ -1459,10 +1211,7 @@ class eWeLink { if (garageConfig.setup === "oneSwitch" && [2, 3].includes(oldPos)) { accessory .getService(Service.GarageDoorOpener) - .updateCharacteristic( - Characteristic.CurrentDoorState, - ((oldPos * 2) % 3) + 2 - ); + .updateCharacteristic(Characteristic.CurrentDoorState, ((oldPos * 2) % 3) + 2); delay = 1500; } setTimeout(() => { @@ -1476,9 +1225,7 @@ class eWeLink { params.switch = "on"; break; case "twoSwitch": - params.switches = this.devicesInEwe.get( - accessory.context.eweDeviceId - ).params.switches; + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; params.switches[0].switch = newPos === 0 ? "on" : "off"; params.switches[1].switch = newPos === 1 ? "on" : "off"; break; @@ -1499,8 +1246,7 @@ class eWeLink { callback(); } catch (err) { accessory.context.inUse = false; - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1535,8 +1281,7 @@ class eWeLink { }, parseInt(lockConfig.operationTime) * 100); } catch (err) { accessory.context.inUse = false; - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1551,45 +1296,36 @@ class eWeLink { case "power": newPower = value; newSpeed = value ? 33 : 0; - newLight = accessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.On).value; + newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) + .value; break; case "speed": newPower = value >= 33 ? 1 : 0; newSpeed = value; - newLight = accessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.On).value; + newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) + .value; break; case "light": - newPower = accessory - .getService(Service.Fanv2) - .getCharacteristic(Characteristic.Active).value; + newPower = accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active) + .value; newSpeed = accessory .getService(Service.Fanv2) .getCharacteristic(Characteristic.RotationSpeed).value; newLight = value; break; } - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, newLight); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, newLight); accessory .getService(Service.Fanv2) .updateCharacteristic(Characteristic.Active, newPower) .updateCharacteristic(Characteristic.RotationSpeed, newSpeed); let params = { - switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params - .switches, + switches: this.devicesInEW.get(accessory.context.eweDeviceId).params.switches, }; params.switches[0].switch = newLight ? "on" : "off"; - params.switches[1].switch = - newPower === 1 && newSpeed >= 33 ? "on" : "off"; - params.switches[2].switch = - newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? "on" : "off"; - params.switches[3].switch = - newPower === 1 && newSpeed >= 99 ? "on" : "off"; + params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? "on" : "off"; + params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? "on" : "off"; + params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? "on" : "off"; if (this.debug) { this.log.warn("Fan Update - setting " + type + " to " + value); this.log( @@ -1602,8 +1338,7 @@ class eWeLink { } this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1618,19 +1353,12 @@ class eWeLink { mainSwitch: value ? "on" : "off", }; if (this.debug) { - this.log( - "[%s] updating to turn [%s].", - accessory.displayName, - value ? "on" : "off" - ); + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1644,15 +1372,9 @@ class eWeLink { switch: value ? "on" : "off", }; if (this.debug) { - this.log( - "[%s] requesting to turn [%s].", - accessory.displayName, - value ? "on" : "off" - ); + this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory - .getService(Service.Outlet) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { callback("[" + accessory.displayName + "] " + err + "."); @@ -1664,20 +1386,13 @@ class eWeLink { throw "it is currently offline"; } let params = { - switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params - .switches, + switches: this.devicesInEW.get(accessory.context.eweDeviceId).params.switches, }; params.switches[0].switch = value ? "on" : "off"; if (this.debug) { - this.log( - "[%s] requesting to turn [%s].", - accessory.displayName, - value ? "on" : "off" - ); + this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory - .getService(Service.Outlet) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { callback("[" + accessory.displayName + "] " + err + "."); @@ -1689,20 +1404,13 @@ class eWeLink { throw "it is currently offline"; } let params = { - switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params - .switches, + switches: this.devicesInEW.get(accessory.context.eweDeviceId).params.switches, }; params.switches[0].switch = value ? "on" : "off"; if (this.debug) { - this.log( - "[%s] requesting to turn [%s].", - accessory.displayName, - value ? "on" : "off" - ); + this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { callback("[" + accessory.displayName + "] " + err + "."); @@ -1724,20 +1432,12 @@ class eWeLink { params.switch = value ? "on" : "off"; } if (this.debug) { - this.log( - "[%s] updating to turn [%s].", - accessory.displayName, - value ? "on" : "off" - ); + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); break; case "0": - params.switches = this.devicesInEwe.get( - accessory.context.eweDeviceId - ).params.switches; + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; params.switches[0].switch = value ? "on" : "off"; params.switches[1].switch = value ? "on" : "off"; params.switches[2].switch = value ? "on" : "off"; @@ -1749,16 +1449,10 @@ class eWeLink { value ? "on" : "off" ); } - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); for (let i = 1; i <= 4; i++) { - if ( - this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i) - ) { - oAccessory = this.devicesInHB.get( - accessory.context.eweDeviceId + "SW" + i - ); + if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); oAccessory .getService(Service.Lightbulb) .updateCharacteristic(Characteristic.On, value); @@ -1770,26 +1464,14 @@ class eWeLink { case "3": case "4": if (this.debug) { - this.log( - "[%s] updating to turn [%s].", - accessory.displayName, - value ? "on" : "off" - ); + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); let tAccessory, masterState = "off"; - params.switches = this.devicesInEwe.get( - accessory.context.eweDeviceId - ).params.switches; + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; for (let i = 1; i <= 4; i++) { - if ( - (tAccessory = this.devicesInHB.get( - accessory.context.eweDeviceId + "SW" + i - )) - ) { + if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { i === parseInt(accessory.context.switchNumber) ? (params.switches[i - 1].switch = value ? "on" : "off") : (params.switches[i - 1].switch = tAccessory @@ -1798,9 +1480,7 @@ class eWeLink { ? "on" : "off"); if ( - tAccessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.On).value + tAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value ) { masterState = "on"; } @@ -1808,22 +1488,17 @@ class eWeLink { params.switches[i - 1].switch = "off"; } } - oAccessory = this.devicesInHB.get( - accessory.context.eweDeviceId + "SW0" - ); + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); oAccessory .getService(Service.Lightbulb) .updateCharacteristic(Characteristic.On, masterState === "on"); break; default: - throw ( - "unknown switch number [" + accessory.context.switchNumber + "]" - ); + throw "unknown switch number [" + accessory.context.switchNumber + "]"; } this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1836,15 +1511,9 @@ class eWeLink { let params = {}; if (value === 0) { params.switch = "off"; - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, false); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, false); } else { - if ( - !accessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.On).value - ) { + if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { params.switch = "on"; } switch (accessory.context.eweUIID) { @@ -1863,16 +1532,11 @@ class eWeLink { .updateCharacteristic(Characteristic.Brightness, value); } if (this.debug) { - this.log( - "[%s] updating brightness to [%s%].", - accessory.displayName, - value - ); + this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); } setTimeout(() => this.sendDeviceUpdate(accessory, params, callback), 250); } catch (err) { - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1884,9 +1548,8 @@ class eWeLink { } let newRGB, params = {}, - curHue = accessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.Hue).value, + curHue = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Hue) + .value, curSat = accessory .getService(Service.Lightbulb) .getCharacteristic(Characteristic.Saturation).value; @@ -1917,15 +1580,9 @@ class eWeLink { throw "unknown device UIID"; } if (this.debug) { - this.log( - "[%s] updating hue to [%s°].", - accessory.displayName, - value - ); + this.log("[%s] updating hue to [%s°].", accessory.displayName, value); } - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.Hue, value); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Hue, value); break; case "bri": switch (accessory.context.eweUIID) { @@ -1949,11 +1606,7 @@ class eWeLink { break; } if (this.debug) { - this.log( - "[%s] updating brightness to [%s%].", - accessory.displayName, - value - ); + this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); } accessory .getService(Service.Lightbulb) @@ -1964,8 +1617,7 @@ class eWeLink { } setTimeout(() => this.sendDeviceUpdate(accessory, params, callback), 250); } catch (err) { - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1981,20 +1633,12 @@ class eWeLink { case "X": params.switch = value ? "on" : "off"; if (this.debug) { - this.log( - "[%s] updating to turn [%s].", - accessory.displayName, - value ? "on" : "off" - ); + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); break; case "0": - params.switches = this.devicesInEwe.get( - accessory.context.eweDeviceId - ).params.switches; + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; params.switches[0].switch = value ? "on" : "off"; params.switches[1].switch = value ? "on" : "off"; params.switches[2].switch = value ? "on" : "off"; @@ -2006,19 +1650,11 @@ class eWeLink { value ? "on" : "off" ); } - accessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); for (let i = 1; i <= 4; i++) { - if ( - this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i) - ) { - oAccessory = this.devicesInHB.get( - accessory.context.eweDeviceId + "SW" + i - ); - oAccessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, value); + if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); + oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); } } break; @@ -2027,26 +1663,14 @@ class eWeLink { case "3": case "4": if (this.debug) { - this.log( - "[%s] updating to turn [%s].", - accessory.displayName, - value ? "on" : "off" - ); + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); let tAccessory, masterState = "off"; - params.switches = this.devicesInEwe.get( - accessory.context.eweDeviceId - ).params.switches; + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; for (let i = 1; i <= 4; i++) { - if ( - (tAccessory = this.devicesInHB.get( - accessory.context.eweDeviceId + "SW" + i - )) - ) { + if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { i === parseInt(accessory.context.switchNumber) ? (params.switches[i - 1].switch = value ? "on" : "off") : (params.switches[i - 1].switch = tAccessory @@ -2055,9 +1679,7 @@ class eWeLink { ? "on" : "off"); if ( - tAccessory - .getService(Service.Switch) - .getCharacteristic(Characteristic.On).value + tAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value ) { masterState = "on"; } @@ -2065,22 +1687,17 @@ class eWeLink { params.switches[i - 1].switch = "off"; } } - oAccessory = this.devicesInHB.get( - accessory.context.eweDeviceId + "SW0" - ); + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); oAccessory .getService(Service.Switch) .updateCharacteristic(Characteristic.On, masterState === "on"); break; default: - throw ( - "unknown switch number [" + accessory.context.switchNumber + "]" - ); + throw "unknown switch number [" + accessory.context.switchNumber + "]"; } this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -2114,14 +1731,7 @@ class eWeLink { 3000 ); } catch (err) { - let str = - "[" + - accessory.displayName + - " " + - name + - "] could not be updated as " + - err + - "."; + let str = "[" + accessory.displayName + " " + name + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -2131,14 +1741,8 @@ class eWeLink { ["A", "B"].forEach((v, k) => { accessory .getService("Valve " + v) - .updateCharacteristic( - Characteristic.Active, - params.switches[k].switch === "on" - ) - .updateCharacteristic( - Characteristic.InUse, - params.switches[k].switch === "on" - ); + .updateCharacteristic(Characteristic.Active, params.switches[k].switch === "on") + .updateCharacteristic(Characteristic.InUse, params.switches[k].switch === "on"); if (params.switches[k].switch === "on") { let timer = accessory .getService("Valve " + v) @@ -2147,9 +1751,7 @@ class eWeLink { .getService("Valve " + v) .updateCharacteristic(Characteristic.RemainingDuration, timer); accessory.getService("Valve " + v).timer = setTimeout(() => { - accessory - .getService("Valve " + v) - .setCharacteristic(Characteristic.Active, 0); + accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); }, timer * 1000); } else { accessory @@ -2159,11 +1761,7 @@ class eWeLink { } }); } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalBlindUpdate(accessory, params) { @@ -2172,10 +1770,7 @@ class eWeLink { if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } - if ( - blindConfig.type !== "blind" || - ["oneSwitch", "twoSwitch"].includes(blindConfig.setup) - ) { + if (blindConfig.type !== "blind" || ["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { throw "improper configuration"; } switch (blindConfig.setup) { @@ -2191,10 +1786,7 @@ class eWeLink { : 0; break; case "twoSwitch": - if ( - params.switches[0].switch === "off" && - params.switches[1].switch === "off" - ) { + if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { return; } let switchUp = params.switches[0].switch === "on" ? -1 : 0, // matrix of numbers to get @@ -2213,11 +1805,7 @@ class eWeLink { .updateCharacteristic(Characteristic.CurrentPosition, nSte * 100); }, parseInt(blindConfig.operationTime) * 100); } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalGarageUpdate(accessory, params) { @@ -2271,11 +1859,7 @@ class eWeLink { }, parseInt(garageConfig.operationTime) * 100); } catch (err) { accessory.context.inUse = false; - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalLockUpdate(accessory, params) { @@ -2304,11 +1888,7 @@ class eWeLink { }, parseInt(lockConfig.operationTime) * 100); } catch (err) { accessory.context.inUse = false; - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalSensorUpdate(accessory, params) { @@ -2318,14 +1898,8 @@ class eWeLink { accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService), scaledBattery = Math.round(params.battery * 33.3); - batteryService.updateCharacteristic( - Characteristic.BatteryLevel, - scaledBattery - ); - batteryService.updateCharacteristic( - Characteristic.StatusLowBattery, - scaledBattery < 25 - ); + batteryService.updateCharacteristic(Characteristic.BatteryLevel, scaledBattery); + batteryService.updateCharacteristic(Characteristic.StatusLowBattery, scaledBattery < 25); } let newState = params.switch === "on" ? 1 : 0, oAccessory = false; @@ -2333,10 +1907,7 @@ class eWeLink { .getService(Service.ContactSensor) .updateCharacteristic(Characteristic.ContactSensorState, newState); this.cusG.forEach(group => { - if ( - group.sensorId === accessory.context.eweDeviceId && - group.type === "garage" - ) { + if (group.sensorId === accessory.context.eweDeviceId && group.type === "garage") { if ((oAccessory = this.devicesInHB.get(group.deviceId + "SWX"))) { switch (newState) { case 0: @@ -2360,11 +1931,7 @@ class eWeLink { } }); } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalFanUpdate(accessory, params) { @@ -2372,11 +1939,7 @@ class eWeLink { let light, status, speed; if (Array.isArray(params.switches)) { light = params.switches[0].switch === "on"; - switch ( - params.switches[1].switch + - params.switches[2].switch + - params.switches[3].switch - ) { + switch (params.switches[1].switch + params.switches[2].switch + params.switches[3].switch) { default: status = 0; speed = 0; @@ -2404,19 +1967,13 @@ class eWeLink { } else { throw "unknown parameters received"; } - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, light); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, light); accessory .getService(Service.Fanv2) .updateCharacteristic(Characteristic.Active, status) .updateCharacteristic(Characteristic.RotationSpeed, speed); } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalThermostatUpdate(accessory, params) { @@ -2428,9 +1985,7 @@ class eWeLink { let newState = params.hasOwnProperty("switch") ? params.switch === "on" : params.mainSwitch === "on"; - accessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, newState); + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, newState); } let eveLog = { time: Date.now(), @@ -2440,9 +1995,7 @@ class eWeLink { accessory.getService(Service.TemperatureSensor) ) { let currentTemp = - params.currentTemperature !== "unavailable" - ? params.currentTemperature - : 0; + params.currentTemperature !== "unavailable" ? params.currentTemperature : 0; accessory .getService(Service.TemperatureSensor) .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); @@ -2452,25 +2005,17 @@ class eWeLink { params.hasOwnProperty("currentHumidity") && accessory.getService(Service.HumiditySensor) ) { - let currentHumi = - params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; + let currentHumi = params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; accessory .getService(Service.HumiditySensor) - .updateCharacteristic( - Characteristic.CurrentRelativeHumidity, - currentHumi - ); + .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); eveLog.humidity = parseFloat(currentHumi); } if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { accessory.eveLogger.addEntry(eveLog); } } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalOutletUpdate(accessory, params) { @@ -2489,13 +2034,8 @@ class eWeLink { ); accessory .getService(Service.Outlet) - .updateCharacteristic( - Characteristic.OutletInUse, - parseFloat(params.power) > 0 - ); - let isOn = accessory - .getService(Service.Outlet) - .getCharacteristic(Characteristic.On).value; + .updateCharacteristic(Characteristic.OutletInUse, parseFloat(params.power) > 0); + let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value; accessory.eveLogger.addEntry({ time: Date.now(), power: isOn ? parseFloat(params.power) : 0, @@ -2504,10 +2044,7 @@ class eWeLink { if (params.hasOwnProperty("voltage")) { accessory .getService(Service.Outlet) - .updateCharacteristic( - EveService.Characteristics.Voltage, - parseFloat(params.voltage) - ); + .updateCharacteristic(EveService.Characteristics.Voltage, parseFloat(params.voltage)); } if (params.hasOwnProperty("current")) { accessory @@ -2518,43 +2055,25 @@ class eWeLink { ); } } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalUSBUpdate(accessory, params) { try { accessory .getService(Service.Outlet) - .updateCharacteristic( - Characteristic.On, - params.switches[0].switch === "on" - ); + .updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalSCMUpdate(accessory, params) { try { accessory .getService(Service.Switch) - .updateCharacteristic( - Characteristic.On, - params.switches[0].switch === "on" - ); + .updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalSingleLightUpdate(accessory, params) { @@ -2564,20 +2083,13 @@ class eWeLink { isOn = false; if (accessory.context.eweUIID === 22 && params.hasOwnProperty("state")) { isOn = params.state === "on"; - } else if ( - accessory.context.eweUIID !== 22 && - params.hasOwnProperty("switch") - ) { + } else if (accessory.context.eweUIID !== 22 && params.hasOwnProperty("switch")) { isOn = params.switch === "on"; } else { - isOn = accessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.On).value; + isOn = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; } if (isOn) { - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, true); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, true); switch (accessory.context.eweUIID) { case 36: // KING-M4 if (params.hasOwnProperty("bright")) { @@ -2591,10 +2103,7 @@ class eWeLink { if (params.hasOwnProperty("brightness")) { accessory .getService(Service.Lightbulb) - .updateCharacteristic( - Characteristic.Brightness, - params.brightness - ); + .updateCharacteristic(Characteristic.Brightness, params.brightness); } break; case 22: // B1 @@ -2609,9 +2118,7 @@ class eWeLink { mode = 2; } if (mode === 2) { - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, true); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, true); newColour = convert.rgb.hsv( parseInt(params.channel2), parseInt(params.channel3), @@ -2633,11 +2140,7 @@ class eWeLink { .updateCharacteristic(Characteristic.Brightness, params.bright); } if (params.hasOwnProperty("colorR")) { - newColour = convert.rgb.hsv( - params.colorR, - params.colorG, - params.colorB - ); + newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB); accessory .getService(Service.Lightbulb) .updateCharacteristic(Characteristic.Hue, newColour[0]) @@ -2648,16 +2151,10 @@ class eWeLink { return; } } else { - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, false); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, false); } } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalMultiLightUpdate(accessory, params) { @@ -2669,24 +2166,15 @@ class eWeLink { let oAccessory = this.devicesInHB.get(idToCheck + i); oAccessory .getService(Service.Lightbulb) - .updateCharacteristic( - Characteristic.On, - params.switches[i - 1].switch === "on" - ); + .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); if (params.switches[i - 1].switch === "on") { primaryState = true; } } } - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, primaryState); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, primaryState); } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalSingleSwitchUpdate(accessory, params) { @@ -2695,11 +2183,7 @@ class eWeLink { .getService(Service.Switch) .updateCharacteristic(Characteristic.On, params.switch === "on"); } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalMultiSwitchUpdate(accessory, params) { @@ -2711,24 +2195,15 @@ class eWeLink { let oAccessory = this.devicesInHB.get(idToCheck + i); oAccessory .getService(Service.Switch) - .updateCharacteristic( - Characteristic.On, - params.switches[i - 1].switch === "on" - ); + .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); if (params.switches[i - 1].switch === "on") { primaryState = true; } } } - accessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, primaryState); + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState); } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalRFDeviceUpdate(accessory, params) { @@ -2744,9 +2219,7 @@ class eWeLink { // RF Button let bAccessory; if ( - (bAccessory = this.devicesInHB.get( - idToCheck + accessory.context.rfChlMap[params.rfChl] - )) + (bAccessory = this.devicesInHB.get(idToCheck + accessory.context.rfChlMap[params.rfChl])) ) { bAccessory .getService(bAccessory.context.rfChls[params.rfChl]) @@ -2800,81 +2273,51 @@ class eWeLink { case "co": oAccessory .getService(Service.CarbonMonoxideSensor) - .updateCharacteristic( - Characteristic.CarbonMonoxideDetected, - 1 - ); + .updateCharacteristic(Characteristic.CarbonMonoxideDetected, 1); setTimeout(() => { oAccessory .getService(Service.CarbonMonoxideSensor) - .updateCharacteristic( - Characteristic.CarbonMonoxideDetected, - 0 - ); + .updateCharacteristic(Characteristic.CarbonMonoxideDetected, 0); }, (this.config.sensorTimeLength || 2) * 1000); break; case "co2": oAccessory .getService(Service.CarbonDioxideSensor) - .updateCharacteristic( - Characteristic.CarbonDioxideDetected, - 1 - ); + .updateCharacteristic(Characteristic.CarbonDioxideDetected, 1); setTimeout(() => { oAccessory .getService(Service.CarbonDioxideSensor) - .updateCharacteristic( - Characteristic.CarbonDioxideDetected, - 0 - ); + .updateCharacteristic(Characteristic.CarbonDioxideDetected, 0); }, (this.config.sensorTimeLength || 2) * 1000); break; case "contact": oAccessory .getService(Service.ContactSensor) - .updateCharacteristic( - Characteristic.ContactSensorState, - 1 - ); + .updateCharacteristic(Characteristic.ContactSensorState, 1); setTimeout(() => { oAccessory .getService(Service.ContactSensor) - .updateCharacteristic( - Characteristic.ContactSensorState, - 0 - ); + .updateCharacteristic(Characteristic.ContactSensorState, 0); }, (this.config.sensorTimeLength || 2) * 1000); break; case "occupancy": oAccessory .getService(Service.OccupancySensor) - .updateCharacteristic( - Characteristic.OccupancyDetected, - 1 - ); + .updateCharacteristic(Characteristic.OccupancyDetected, 1); setTimeout(() => { oAccessory .getService(Service.OccupancySensor) - .updateCharacteristic( - Characteristic.OccupancyDetected, - 0 - ); + .updateCharacteristic(Characteristic.OccupancyDetected, 0); }, (this.config.sensorTimeLength || 2) * 1000); break; default: oAccessory .getService(Service.MotionSensor) - .updateCharacteristic( - Characteristic.MotionDetected, - true - ); + .updateCharacteristic(Characteristic.MotionDetected, true); setTimeout(() => { oAccessory .getService(Service.MotionSensor) - .updateCharacteristic( - Characteristic.MotionDetected, - false - ); + .updateCharacteristic(Characteristic.MotionDetected, false); }, (this.config.sensorTimeLength || 2) * 1000); break; } @@ -2890,11 +2333,7 @@ class eWeLink { }); } } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalZBDeviceUpdate(accessory, params) { @@ -2904,24 +2343,15 @@ class eWeLink { let batteryService = accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); - batteryService.updateCharacteristic( - Characteristic.BatteryLevel, - params.battery - ); - batteryService.updateCharacteristic( - Characteristic.StatusLowBattery, - params.battery < 25 - ); + batteryService.updateCharacteristic(Characteristic.BatteryLevel, params.battery); + batteryService.updateCharacteristic(Characteristic.StatusLowBattery, params.battery < 25); } switch (accessory.context.eweUIID) { case 1000: if (params.hasOwnProperty("key") && [0, 1, 2].includes(params.key)) { accessory .getService(Service.StatelessProgrammableSwitch) - .updateCharacteristic( - Characteristic.ProgrammableSwitchEvent, - params.key - ); + .updateCharacteristic(Characteristic.ProgrammableSwitchEvent, params.key); } break; case 1770: @@ -2932,34 +2362,22 @@ class eWeLink { let currentTemp = parseInt(params.temperature) / 100; accessory .getService(Service.TemperatureSensor) - .updateCharacteristic( - Characteristic.CurrentTemperature, - currentTemp - ); + .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); eveLog.temp = parseFloat(currentTemp); } if (params.hasOwnProperty("humidity")) { let currentHumi = parseInt(params.humidity) / 100; accessory .getService(Service.HumiditySensor) - .updateCharacteristic( - Characteristic.CurrentRelativeHumidity, - currentHumi - ); + .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); eveLog.humidity = parseFloat(currentHumi); } - if ( - eveLog.hasOwnProperty("temp") || - eveLog.hasOwnProperty("humidity") - ) { + if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { accessory.eveLogger.addEntry(eveLog); } break; case 2026: - if ( - params.hasOwnProperty("motion") && - params.hasOwnProperty("trigTime") - ) { + if (params.hasOwnProperty("motion") && params.hasOwnProperty("trigTime")) { let timeNow = new Date(), diff = (timeNow.getTime() - params.trigTime) / 1000; accessory @@ -2977,19 +2395,12 @@ class eWeLink { if (params.hasOwnProperty("lock") && [0, 1].includes(params.lock)) { accessory .getService(Service.ContactSensor) - .updateCharacteristic( - Characteristic.ContactSensorState, - params.lock - ); + .updateCharacteristic(Characteristic.ContactSensorState, params.lock); } break; } } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } } diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 1aafd1e4..24b1a69d 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -5,29 +5,92 @@ const axios = require("axios"), crypto = require("crypto"); module.exports = class eWeLinkHTTP { constructor(config, log) { - this.config = config; this.log = log; - this.debug = this.config.debug || false; - this.debugReqRes = this.config.debugReqRes || false; + this.debug = config.debug || false; + this.debugReqRes = config.debugReqRes || false; + this.username = config.username.toString(); + this.password = config.password.toString(); + this.cCode = "+" + config.countryCode.toString().replace("+", "").replace(" ", ""); + } + getHost() { + let data = { + appid: constants.appId, + country_code: this.cCode, + nonce: Math.random().toString(36).substr(2, 8), + ts: Math.floor(new Date().getTime() / 1000), + version: 8, + }, + dataToSign = []; + Object.keys(data).forEach(k => { + dataToSign.push({ + key: k, + value: data.k, + }); + }); + dataToSign.sort((a, b) => (a.key < b.key ? -1 : 1)); + dataToSign = dataToSign.map(k => k.key + "=" + k.value).join("&"); + dataToSign = crypto + .createHmac("sha256", constants.appSecret) + .update(dataToSign) + .digest("base64"); + if (this.debugReqRes) { + let msg = JSON.stringify(data, null, 2); + this.log.warn("Sending HTTP getHost request. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("Sending HTTP getHost request."); + } + return new Promise((resolve, reject) => { + axios + .get("https://api.coolkit.cc:8080/api/user/region", { + headers: { + Authorization: "Sign " + dataToSign, + "Content-Type": "application/json", + }, + params: data, + }) + .then(res => { + let body = res.data; + if (!body.region) { + throw "Server did not respond with a region.\n" + JSON.stringify(body, null, 2); + } + switch (body.region) { + case "eu": + case "us": + case "as": + this.httpHost = body.region + "-apia.coolkit.cc"; + break; + case "cn": + this.httpHost = "cn-apia.coolkit.cn"; + break; + default: + throw "No valid region received - [" + body.region + "]."; + } + if (this.debug) { + this.log("HTTP API host received [%s].", this.httpHost); + } + resolve(this.httpHost); + }) + .catch(err => { + if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { + this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); + this.delay().then(() => resolve(this.getHost())); + } else { + reject(err.message || err); + } + }); + }); } login() { let data = { - countryCode: - "+" + - this.config.countryCode.toString().replace("+", "").replace(" ", ""), - password: this.config.password, + countryCode: this.cCode, + password: this.password, }; - this.config.username.includes("@") - ? (data.email = this.config.username) - : (data.phoneNumber = this.config.username); + this.username.includes("@") ? (data.email = this.username) : (data.phoneNumber = this.username); if (this.debugReqRes) { let msg = JSON.stringify(data, null, 2) - .replace(this.config.password, "**hidden**") - .replace(this.config.username, "**hidden**"); - this.log.warn( - "Sending HTTP login request. This text is yellow for clarity.\n%s", - msg - ); + .replace(this.password, "**hidden**") + .replace(this.username, "**hidden**"); + this.log.warn("Sending HTTP login request. This text is yellow for clarity.\n%s", msg); } else if (this.debug) { this.log("Sending HTTP login request."); } @@ -56,17 +119,18 @@ module.exports = class eWeLinkHTTP { body.hasOwnProperty("data") && body.data.hasOwnProperty("region") ) { - switch (body.data.region) { + let givenRegion = body.data.region; + switch (givenRegion) { case "eu": case "us": case "as": - this.httpHost = body.data.region + "-apia.coolkit.cc"; + this.httpHost = givenRegion + "-apia.coolkit.cc"; break; case "cn": this.httpHost = "cn-apia.coolkit.cn"; break; default: - throw "No valid region received - [" + body.data.region + "]."; + throw "No valid region received - [" + givenRegion + "]."; } if (this.debug) { this.log("New HTTP API host received [%s].", this.httpHost); @@ -75,10 +139,7 @@ module.exports = class eWeLinkHTTP { return; } if (!body.data.at) { - throw ( - "Server did not respond with an authentication token. Please double check your eWeLink username and password in the Homebridge configuration.\n" + - JSON.stringify(body, null, 2) - ); + throw "No auth token received.\n" + JSON.stringify(body, null, 2); } this.aToken = body.data.at; this.apiKey = body.data.user.apikey; @@ -88,111 +149,95 @@ module.exports = class eWeLinkHTTP { httpHost: this.httpHost, }); }) - .catch(err => { - reject(err); - }); + .catch(err => reject(err.message || err)); }); } - getHost() { - let data = { - appid: constants.appId, - country_code: this.config.countryCode - .toString() - .replace("+", "") - .replace(" ", ""), - nonce: Math.random().toString(36).substr(2, 8), - ts: Math.floor(new Date().getTime() / 1000), - version: 8, - }, - dataToSign = []; - Object.keys(data).forEach(function (key) { - dataToSign.push({ - key: key, - value: data[key], - }); - }); - dataToSign.sort(function (a, b) { - return a.key < b.key ? -1 : 1; - }); - dataToSign = dataToSign - .map(function (kv) { - return kv.key + "=" + kv.value; - }) - .join("&"); - dataToSign = crypto - .createHmac("sha256", constants.appSecret) - .update(dataToSign) - .digest("base64"); + getDevices() { return new Promise((resolve, reject) => { axios - .get("https://api.coolkit.cc:8080/api/user/region", { + .get("https://" + this.httpHost + "/v2/device/thing", { headers: { - Authorization: "Sign " + dataToSign, + Authorization: "Bearer " + this.aToken, "Content-Type": "application/json", + Host: this.httpHost, + "X-CK-Appid": constants.appId, + "X-CK-Nonce": Math.random().toString(36).substr(2, 8), }, - params: data, }) .then(res => { let body = res.data; - if (!body.region) { - throw ( - "Server did not respond with a region.\n" + - JSON.stringify(body, null, 2) - ); - } - switch (body.region) { - case "eu": - case "us": - case "as": - this.httpHost = body.region + "-apia.coolkit.cc"; - break; - case "cn": - this.httpHost = "cn-apia.coolkit.cn"; - break; - default: - throw "No valid region received - [" + body.region + "]."; + if ( + !body.hasOwnProperty("data") || + !body.hasOwnProperty("error") || + (body.hasOwnProperty("error") && body.error !== 0) + ) { + throw JSON.stringify(body, null, 2); } - if (this.debug) { - this.log("HTTP API host received [%s].", this.httpHost); + let deviceList = []; + if (body.data.thingList && body.data.thingList.length > 0) { + body.data.thingList.forEach(device => deviceList.push(device.itemData)); } - resolve(this.httpHost); + resolve(deviceList); }) .catch(err => { - reject(err); + if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { + this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); + this.delay().then(() => resolve(this.getDevices())); + } else { + reject(err.message || err); + } }); }); } - getDevices() { + + getDevice(deviceId) { return new Promise((resolve, reject) => { - axios - .get("https://" + this.httpHost + "/v2/device/thing", { - headers: { - Authorization: "Bearer " + this.aToken, - "Content-Type": "application/json", - Host: this.httpHost, - "X-CK-Appid": constants.appId, - "X-CK-Nonce": Math.random().toString(36).substr(2, 8), - }, - }) + axios({ + url: "https://" + this.httpHost + "/v2/device/thing", + method: "post", + headers: { + Authorization: "Bearer " + this.aToken, + "Content-Type": "application/json", + Host: this.httpHost, + "X-CK-Appid": constants.appId, + "X-CK-Nonce": Math.random().toString(36).substr(2, 8), + }, + data: { + thingList: [ + { + itemType: 1, + id: deviceId, + }, + ], + }, + }) .then(res => { let body = res.data; if ( + !body.hasOwnProperty("data") || !body.hasOwnProperty("error") || (body.hasOwnProperty("error") && body.error !== 0) ) { throw JSON.stringify(body, null, 2); } - let deviceList = []; - if (body.data.thingList && body.data.thingList.length > 0) { - body.data.thingList.forEach(device => - deviceList.push(device.itemData) - ); + if (body.data.thingList && body.data.thingList.length === 1) { + resolve(body.data.thingList[0].itemData); + } else { + throw "device not found in eWeLink"; } - resolve(deviceList); }) .catch(err => { - reject(err); + if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { + this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); + this.delay().then(() => resolve(this.getDevice(deviceId))); + } else { + reject(err.message || err); + } }); }); } + + delay() { + return new Promise(resolve => setTimeout(resolve, 30000)); + } }; diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 25baee53..567c372d 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -1,19 +1,18 @@ /* jshint esversion: 9, -W030, node: true */ "use strict"; const axios = require("axios"), - constants = require("./constants"), + cns = require("./constants"), crypto = require("crypto"), dns = require("node-dns-sd"), eventemitter = require("events"); module.exports = class eWeLinkLAN { constructor(config, log, devices) { - this.config = config; this.log = log; this.devices = devices; - this.ipOverrides = this.config.ipOverride || {}; - let deviceMap = new Map(); + this.ipOverrides = config.ipOverride || {}; + this.deviceMap = new Map(); devices.forEach(device => { - deviceMap.set(device.deviceid, { + this.deviceMap.set(device.deviceid, { apiKey: device.devicekey, online: this.ipOverrides.hasOwnProperty(device.deviceid) ? true : false, ip: this.ipOverrides.hasOwnProperty(device.deviceid) @@ -21,9 +20,8 @@ module.exports = class eWeLinkLAN { : null, }); }); - this.deviceMap = deviceMap; - this.debug = this.config.debug || false; - this.debugReqRes = this.config.debugReqRes || false; + this.debug = config.debug || false; + this.debugReqRes = config.debugReqRes || false; this.emitter = new eventemitter(); } getHosts() { @@ -36,9 +34,7 @@ module.exports = class eWeLinkLAN { let onlineCount = 0; res.forEach(device => { let d, - deviceId = device.fqdn - .replace("._ewelink._tcp.local", "") - .replace("eWeLink_", ""); + deviceId = device.fqdn.replace("._ewelink._tcp.local", "").replace("eWeLink_", ""); if ((d = this.deviceMap.get(deviceId))) { if (!this.ipOverrides.hasOwnProperty(deviceId)) { this.deviceMap.set(deviceId, { @@ -55,9 +51,7 @@ module.exports = class eWeLinkLAN { count: onlineCount, }); }) - .catch(err => { - reject(err); - }); + .catch(err => reject(err)); }); } startMonitor() { @@ -79,64 +73,44 @@ module.exports = class eWeLinkLAN { .createHash("md5") .update(Buffer.from(deviceInfo.apiKey, "utf8")) .digest(), - dText = crypto.createDecipheriv( - "aes-128-cbc", - key, - Buffer.from(rdata.iv, "base64") - ), + dText = crypto.createDecipheriv("aes-128-cbc", key, Buffer.from(rdata.iv, "base64")), pText = Buffer.concat([ dText.update(Buffer.from(data, "base64")), dText.final(), ]).toString("utf8"), params; - if ( - packet.address !== deviceInfo.ip && - !this.ipOverrides.hasOwnProperty(rdata.id) - ) { + if (packet.address !== deviceInfo.ip && !this.ipOverrides.hasOwnProperty(rdata.id)) { this.deviceMap.set(rdata.id, { apiKey: deviceInfo.apiKey, online: true, ip: packet.address, }); if (this.debug) { - this.log.warn( - "[%s] updating IP address to [%s].", - rdata.id, - packet.address - ); + this.log.warn("[%s] updating IP address to [%s].", rdata.id, packet.address); } } try { params = JSON.parse(pText); } catch (e) { - this.log.warn( - "[%s] An error occured reading the LAN message [%s]", - rdata.id, - e - ); + this.log.warn("[%s] An error occured reading the LAN message [%s]", rdata.id, e); return; } for (let param in params) { if (params.hasOwnProperty(param)) { - if ( - !constants.paramsToKeep.includes(param.replace(/[0-9]/g, "")) - ) { + if (!cns.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { delete params[param]; } } } if (Object.keys(params).length > 0) { params.updateSource = "LAN"; + params.online = true; let returnTemplate = { deviceid: rdata.id, - action: "update", params, }; if (this.debugReqRes) { - let msg = JSON.stringify(returnTemplate, null, 2).replace( - rdata.id, - "**hidden**" - ); + let msg = JSON.stringify(returnTemplate, null, 2).replace(rdata.id, "**hidden**"); this.log("LAN message received.\n%s", msg); } else if (this.debug) { this.log("LAN message received."); @@ -149,12 +123,8 @@ module.exports = class eWeLinkLAN { return new Promise((resolve, reject) => { dns .startMonitoring() - .then(() => { - resolve(); - }) - .catch(err => { - reject(err); - }); + .then(() => resolve()) + .catch(err => reject(err)); }); } sendUpdate(json) { @@ -175,17 +145,13 @@ module.exports = class eWeLinkLAN { throw "plugin does not support lan mode for this device yet - feel free to create a github issue"; } if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { - let key = crypto - .createHash("md5") - .update(Buffer.from(apiKey, "utf8")) - .digest(), + let key = crypto.createHash("md5").update(Buffer.from(apiKey, "utf8")).digest(), iv = crypto.randomBytes(16), enc = crypto.createCipheriv("aes-128-cbc", key, iv), data = { - data: Buffer.concat([ - enc.update(JSON.stringify(params)), - enc.final(), - ]).toString("base64"), + data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString( + "base64" + ), deviceid: json.deviceid, encrypt: true, iv: iv.toString("base64"), @@ -197,20 +163,13 @@ module.exports = class eWeLinkLAN { .replace(json.apikey, "**hidden**") .replace(json.apikey, "**hidden**") .replace(json.deviceid, "**hidden**"); - this.log.warn( - "LAN message sent. This text is yellow for clarity.\n%s", - msg - ); + this.log.warn("LAN message sent. This text is yellow for clarity.\n%s", msg); } else if (this.debug) { this.log("LAN message sent."); } axios({ method: "post", - url: - "http://" + - this.deviceMap.get(json.deviceid).ip + - ":8081/zeroconf/" + - suffix, + url: "http://" + this.deviceMap.get(json.deviceid).ip + ":8081/zeroconf/" + suffix, headers: { Accept: "application/json", "Content-Type": "application/json", @@ -223,9 +182,7 @@ module.exports = class eWeLinkLAN { } throw res.data; }) - .catch(err => { - reject(err); - }); + .catch(err => reject(err)); } }); } diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 56fbeb64..29d265cc 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -1,7 +1,7 @@ /* jshint esversion: 9, -W030, node: true */ "use strict"; const axios = require("axios"), - constants = require("./constants"), + cns = require("./constants"), eventemitter = require("events"), ws = require("ws"); module.exports = class eWeLinkWS { @@ -21,14 +21,13 @@ module.exports = class eWeLinkWS { return new Promise((resolve, reject) => { axios({ method: "post", - url: - "https://" + this.httpHost.replace("-api", "-disp") + "/dispatch/app", + url: "https://" + this.httpHost.replace("-api", "-disp") + "/dispatch/app", headers: { Authorization: "Bearer " + this.aToken, "Content-Type": "application/json", }, data: { - appid: constants.appId, + appid: cns.appId, nonce: Math.random().toString(36).substr(2, 8), ts: Math.floor(new Date().getTime() / 1000), version: 8, @@ -46,7 +45,12 @@ module.exports = class eWeLinkWS { resolve(body.domain); }) .catch(err => { - reject(err); + if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { + this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); + this.delay().then(() => resolve(this.getDevices())); + } else { + reject(err.message || err); + } }); }); } @@ -57,7 +61,7 @@ module.exports = class eWeLinkWS { let payload = { action: "userOnline", apikey: this.apiKey, - appid: constants.appId, + appid: cns.appId, at: this.aToken, nonce: Math.random().toString(36).substr(2, 8), sequence: Math.floor(new Date()), @@ -70,91 +74,60 @@ module.exports = class eWeLinkWS { let msg = JSON.stringify(payload, null, 2) .replace(this.aToken, "**hidden**") .replace(this.apiKey, "**hidden**"); - this.log.warn( - "Sending WS login request. This text is yellow for clarity.\n%s", - msg - ); + this.log.warn("Sending WS login request. This text is yellow for clarity.\n%s", msg); } else if (this.debug) { this.log("Sending WS login request."); } }); this.ws.on("message", m => { - if (m === "pong") { - return; - } - let device; + if (m === "pong") return; + let device, + onlineStatus = true; try { device = JSON.parse(m); - } catch (e) { - this.log.warn( - "An error occured reading the web socket message [%s]", - e - ); + } catch (err) { + this.log.warn("An error occured reading the WS message [%s]", err); return; } - // for requestUpdate response - if ( - device.hasOwnProperty("deviceid") && - device.hasOwnProperty("params") && - device.hasOwnProperty("error") && - device.error === 0 - ) { - device.action = "update"; - } else if ( - device.hasOwnProperty("deviceid") && - device.hasOwnProperty("error") && - device.error === 504 - ) { - device.action = "sysmsg"; - device.params = { - online: false, - }; - } - // for external updates + //*** for heartbeat response ***\\ if ( device.hasOwnProperty("config") && device.config.hb && device.config.hbInterval && !this.hbInterval ) { - this.hbInterval = setInterval(() => { - this.ws.send("ping"); - }, (device.config.hbInterval + 7) * 1000); - } else if (device.hasOwnProperty("action")) { + this.hbInterval = setInterval( + () => this.ws.send("ping"), + (device.config.hbInterval + 7) * 1000 + ); + return; + } + if (!device.hasOwnProperty("params")) device.params = {}; + //*** for requestUpdate response ***\\ + if (device.hasOwnProperty("deviceid") && device.hasOwnProperty("error")) { + device.action = "update"; + onlineStatus = device.error === 0; + } + //*** for all updates including above ***\\ + if (device.hasOwnProperty("action")) { switch (device.action) { + case "update": case "sysmsg": - device.params.updateSource = "WS"; - let returnTemplate = { - deviceid: device.deviceid, - action: "sysmsg", - params: device.params, - }; - if (this.debugReqRes) { - let msg = JSON.stringify(returnTemplate, null, 2).replace( - device.deviceid, - "**hidden**" - ); - this.log("WS message received.\n%s", msg); - } else if (this.debug) { - this.log("WS message received."); + if (device.action === "sysmsg" && device.params.hasOwnProperty("online")) { + onlineStatus = device.params.online; } - this.emitter.emit("update", returnTemplate); - break; - case "update": for (let param in device.params) { if (device.params.hasOwnProperty(param)) { - if ( - !constants.paramsToKeep.includes(param.replace(/[0-9]/g, "")) - ) { + if (!cns.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { delete device.params[param]; } } } + device.params.online = onlineStatus; + device.params.updateSource = "WS"; if (Object.keys(device.params).length > 0) { - device.params.updateSource = "WS"; let returnTemplate = { deviceid: device.deviceid, - action: "update", params: device.params, }; if (this.debugReqRes) { @@ -173,8 +146,7 @@ module.exports = class eWeLinkWS { return; default: this.log.warn( - "[%s] WS message has unknown action.\n" + - JSON.stringify(device, null, 2), + "[%s] WS message has unknown action.\n" + JSON.stringify(device, null, 2), device.deviceid ); return; @@ -183,9 +155,7 @@ module.exports = class eWeLinkWS { // *** Safe to ignore these messages *** \\ } else { if (this.debug) { - this.log.warn( - "WS unknown command received.\n" + JSON.stringify(device, null, 2) - ); + this.log.warn("WS unknown command received.\n" + JSON.stringify(device, null, 2)); } } }); @@ -193,16 +163,13 @@ module.exports = class eWeLinkWS { if (m === "Stopping Homebridge") { this.log("Web socket gracefully closed."); } else { - this.log.warn("Web socket closed - [%s - %s].", e, m); + this.log.warn("Web socket closed - [%s%s].", e, m ? " - " + m : ""); if (e !== 1000) { this.log("Web socket will try to reconnect in five seconds."); - setTimeout(() => { - this.login(); - }, 5000); + this.ws.removeAllListeners(); + setTimeout(() => this.login(), 5000); } else { - this.log( - "Please try restarting Homebridge so that this plugin can work again." - ); + this.log("Please try restarting Homebridge so that this plugin can work again."); } } this.wsIsOpen = false; @@ -219,13 +186,9 @@ module.exports = class eWeLinkWS { "Web socket will try to reconnect in five seconds then try the command again." ); this.ws.removeAllListeners(); - setTimeout(() => { - this.login(); - }, 5000); + setTimeout(() => this.login(), 5000); } else { - this.log.warn( - "If this was unexpected then please try restarting Homebridge." - ); + this.log.warn("If this was unexpected then please try restarting Homebridge."); } }); } @@ -240,9 +203,7 @@ module.exports = class eWeLinkWS { }; let sendOperation = req => { if (!this.wsIsOpen) { - setTimeout(() => { - sendOperation(req); - }, 280); + setTimeout(() => sendOperation(req), 280); return; } if (this.ws) { @@ -252,10 +213,7 @@ module.exports = class eWeLinkWS { .replace(json.apikey, "**hidden**") .replace(json.apiKey, "**hidden**") .replace(json.deviceid, "**hidden**"); - this.log.warn( - "WS message sent. This text is yellow for clarity.\n%s", - msg - ); + this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); } else if (this.debug) { this.log("WS message sent."); } @@ -268,9 +226,7 @@ module.exports = class eWeLinkWS { setTimeout(sendOperation, this.delaySend, string); this.delaySend += 280; } else { - this.log.warn( - "Web socket is currently reconnecting. Command will be resent." - ); + this.log.warn("Web socket is currently reconnecting. Command will be resent."); let interval, waitToSend = req => { if (this.wsIsOpen) { @@ -293,9 +249,7 @@ module.exports = class eWeLinkWS { }, sendOperation = req => { if (!this.wsIsOpen) { - setTimeout(() => { - sendOperation(req); - }, 280); + setTimeout(() => sendOperation(req), 280); return; } if (this.ws) { @@ -305,10 +259,7 @@ module.exports = class eWeLinkWS { .replace(json.apikey, "**hidden**") .replace(json.apiKey, "**hidden**") .replace(json.deviceid, "**hidden**"); - this.log.warn( - "WS message sent. This text is yellow for clarity.\n%s", - msg - ); + this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); } else if (this.debug) { this.log("WS message sent."); } @@ -321,9 +272,7 @@ module.exports = class eWeLinkWS { setTimeout(sendOperation, this.delaySend, string); this.delaySend += 280; } else { - this.log.warn( - "Web socket is currently reconnecting. Command will be resent." - ); + this.log.warn("Web socket is currently reconnecting. Command will be resent."); let interval, waitToSend = req => { if (this.wsIsOpen) { @@ -342,4 +291,7 @@ module.exports = class eWeLinkWS { this.ws.close(1000, "Stopping Homebridge"); } } + delay() { + return new Promise(resolve => setTimeout(resolve, 30000)); + } }; From 37ad909a3b4104b217af6396f08ac39fd4f14b05 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 16 Sep 2020 14:01:01 +0100 Subject: [PATCH 0160/3183] syntax error --- lib/eWeLink.js | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 855a0402..b1735aef 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -992,7 +992,6 @@ class eWeLink { (accessory = this.devicesInHB.get(deviceId + "SWX") || this.devicesInHB.get(deviceId + "SW0")) ) { let isX = accessory.context.hbDeviceId.substr(-1) === "X"; - if (device.params.updateSource === "WS") { if (device.params.online != accessory.context.reachableWAN) { accessory.context.reachableWAN = device.params.online; @@ -1006,23 +1005,20 @@ class eWeLink { ); } } - - if (device.params.updateSource === "LAN") { - if (!accessory.context.reachableLAN) { - accessory.context.reachableLAN = true; - this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - this.wsClient.requestUpdate(accessory); - statusChange = true; - this.log.warn("[%s] has been reported [online] via [LAN].", accessory.displayName); - } - if (statusChange && !isX) { - for (let i = 1; i <= accessory.context.channelCount; i++) { - if (this.devicesInHB.has(deviceId + "SW" + i)) { - let oAccessory = this.devicesInHB.get(deviceId + "SW" + i); - oAccessory.context.reachableWAN = device.params.online; - oAccessory.context.reachableLAN = true; - this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); - } + if (device.params.updateSource === "LAN" && !accessory.context.reachableLAN) { + accessory.context.reachableLAN = true; + this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + this.wsClient.requestUpdate(accessory); + statusChange = true; + this.log.warn("[%s] has been reported [online] via [LAN].", accessory.displayName); + } + if (statusChange && !isX) { + for (let i = 1; i <= accessory.context.channelCount; i++) { + if (this.devicesInHB.has(deviceId + "SW" + i)) { + let oAccessory = this.devicesInHB.get(deviceId + "SW" + i); + oAccessory.context.reachableWAN = device.params.online; + oAccessory.context.reachableLAN = true; + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); } } } From 02f84ed46fb5a002c2df06fc203ebf5c74f1faff Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 16 Sep 2020 14:04:31 +0100 Subject: [PATCH 0161/3183] lan check --- lib/eWeLink.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index b1735aef..23a75865 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1017,7 +1017,9 @@ class eWeLink { if (this.devicesInHB.has(deviceId + "SW" + i)) { let oAccessory = this.devicesInHB.get(deviceId + "SW" + i); oAccessory.context.reachableWAN = device.params.online; - oAccessory.context.reachableLAN = true; + if (device.params.updateSource === "LAN") { + oAccessory.context.reachableLAN = true; + } this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); } } From 3a9962f6f2f7f2893b4d4aa1fa89c0a105018764 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 16 Sep 2020 16:49:39 +0100 Subject: [PATCH 0162/3183] Revert "lan check" This reverts commit 02f84ed46fb5a002c2df06fc203ebf5c74f1faff. --- lib/eWeLink.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 23a75865..b1735aef 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1017,9 +1017,7 @@ class eWeLink { if (this.devicesInHB.has(deviceId + "SW" + i)) { let oAccessory = this.devicesInHB.get(deviceId + "SW" + i); oAccessory.context.reachableWAN = device.params.online; - if (device.params.updateSource === "LAN") { - oAccessory.context.reachableLAN = true; - } + oAccessory.context.reachableLAN = true; this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); } } From e098bd63228b87a003ff8539908260d6fdf4cffa Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 16 Sep 2020 16:49:42 +0100 Subject: [PATCH 0163/3183] Revert "syntax error" This reverts commit 37ad909a3b4104b217af6396f08ac39fd4f14b05. --- lib/eWeLink.js | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index b1735aef..855a0402 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -992,6 +992,7 @@ class eWeLink { (accessory = this.devicesInHB.get(deviceId + "SWX") || this.devicesInHB.get(deviceId + "SW0")) ) { let isX = accessory.context.hbDeviceId.substr(-1) === "X"; + if (device.params.updateSource === "WS") { if (device.params.online != accessory.context.reachableWAN) { accessory.context.reachableWAN = device.params.online; @@ -1005,20 +1006,23 @@ class eWeLink { ); } } - if (device.params.updateSource === "LAN" && !accessory.context.reachableLAN) { - accessory.context.reachableLAN = true; - this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - this.wsClient.requestUpdate(accessory); - statusChange = true; - this.log.warn("[%s] has been reported [online] via [LAN].", accessory.displayName); - } - if (statusChange && !isX) { - for (let i = 1; i <= accessory.context.channelCount; i++) { - if (this.devicesInHB.has(deviceId + "SW" + i)) { - let oAccessory = this.devicesInHB.get(deviceId + "SW" + i); - oAccessory.context.reachableWAN = device.params.online; - oAccessory.context.reachableLAN = true; - this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); + + if (device.params.updateSource === "LAN") { + if (!accessory.context.reachableLAN) { + accessory.context.reachableLAN = true; + this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + this.wsClient.requestUpdate(accessory); + statusChange = true; + this.log.warn("[%s] has been reported [online] via [LAN].", accessory.displayName); + } + if (statusChange && !isX) { + for (let i = 1; i <= accessory.context.channelCount; i++) { + if (this.devicesInHB.has(deviceId + "SW" + i)) { + let oAccessory = this.devicesInHB.get(deviceId + "SW" + i); + oAccessory.context.reachableWAN = device.params.online; + oAccessory.context.reachableLAN = true; + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); + } } } } From 9507b0bed4f99ab07fd69d404fefc6663bbedd84 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 16 Sep 2020 16:49:45 +0100 Subject: [PATCH 0164/3183] Revert "3.0 initial changes" This reverts commit 556a0e048249a7e8c423f052a6b8283318389b73. --- .prettierrc.json | 3 +- lib/constants.js | 7 +- lib/eWeLink.js | 1389 +++++++++++++++++++++++++++++++------------- lib/eWeLinkHTTP.js | 241 ++++---- lib/eWeLinkLAN.js | 91 ++- lib/eWeLinkWS.js | 156 +++-- 6 files changed, 1263 insertions(+), 624 deletions(-) diff --git a/.prettierrc.json b/.prettierrc.json index 87f5e5e8..d68aa739 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,4 +1,3 @@ { - "arrowParens": "avoid", - "printWidth": 100 + "arrowParens": "avoid" } diff --git a/lib/constants.js b/lib/constants.js index fe7fcb40..d8892025 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -40,7 +40,12 @@ module.exports = { devicesSensor: [102], devicesSensorParams: ["switch", "battery"], devicesThermostat: [15], - devicesThermostatParams: ["currentTemperature", "currentHumidity", "switch", "masterSwitch"], + devicesThermostatParams: [ + "currentTemperature", + "currentHumidity", + "switch", + "masterSwitch", + ], devicesFan: [34], devicesFanParams: ["switches", "light", "fan", "speed"], devicesOutlet: [32], diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 855a0402..13c6d210 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -13,9 +13,15 @@ class eWeLink { constructor(log, config, api) { if (!log || !api || !config) return; if (!config.username || !config.password || !config.countryCode) { - log.error("*********** Cannot load homebridge-ewelink ***********"); - log.error("eWeLink credentials missing from the Homebridge config."); - log.error("*******************************************************"); + log.error( + "**************** Cannot load homebridge-ewelink ****************" + ); + log.error( + "Your eWeLink credentials are missing from the Homebridge config." + ); + log.error( + "****************************************************************" + ); return; } this.log = log; @@ -23,103 +29,153 @@ class eWeLink { this.api = api; this.debug = this.config.debug || false; this.devicesInHB = new Map(); - this.devicesInEW = new Map(); + this.devicesInEwe = new Map(); this.cusG = new Map(); this.cusS = new Map(); this.eveLogPath = this.api.user.storagePath() + "/homebridge-ewelink/"; this.api - .on("didFinishLaunching", () => this.eWeLinkSync()) - .on("shutdown", () => { - if (this.lanClient) this.lanClient.closeConnection(); - if (this.wsClient) this.wsClient.closeConnection(); - }); - } - eWeLinkSync() { - this.log("Plugin has finished initialising. Synching with eWeLink."); - this.httpClient = new eWeLinkHTTP(this.config, this.log); - this.httpClient - .getHost() - .then(() => this.httpClient.login()) - .then(res => { - this.authData = res; - return this.httpClient.getDevices(); - }) - .then(res => { - this.httpDevices = res - .filter(d => d.hasOwnProperty("extra") && d.extra.hasOwnProperty("uiid")) - .filter(d => !(this.config.hideDevFromHB || "").includes(d.deviceid)); - this.httpDevices.forEach(device => this.devicesInEW.set(device.deviceid, device)); - this.wsClient = new eWeLinkWS(this.config, this.log, this.authData); - return this.wsClient.getHost(); - }) - .then(() => { - this.wsClient.login(); - this.lanClient = new eWeLinkLAN(this.config, this.log, this.httpDevices); - return this.lanClient.getHosts(); - }) - .then(res => { - this.lanDevices = res.map; - this.lanCount = res.count; - return this.lanClient.startMonitor(); - }) - .then(() => { - (() => { - //*** Remove all Homebridge accessories if none found ***\\ - if ( - Object.keys(this.httpDevices).length === 0 && - Object.keys(this.lanDevices).length === 0 - ) { - Array.from(this.devicesInHB.values()).forEach(a => this.removeAccessory(a)); - this.devicesInHB.clear(); - this.log.warn("******* Not loading homebridge-ewelink *******"); - this.log.warn("No devices were found in your eWeLink account."); - this.log.warn("**********************************************"); - return; - } - //*** Make a map of custom groups from Homebridge config ***\\ - if (Object.keys(this.config.groups || []).length > 0) { - this.config.groups - .filter(g => g.hasOwnProperty("type") && cns.allowedGroups.includes(g.type)) - .filter(g => g.hasOwnProperty("deviceId") && this.devicesInEW.has(g.deviceId)) - .forEach(g => this.cusG.set(g.deviceId + "SWX", g)); - } - //*** Make a map of RF Bridge custom sensors from Homebridge config ***\\ - if (Object.keys(this.config.bridgeSensors || []).length > 0) { - this.config.bridgeSensors - .filter(s => s.hasOwnProperty("deviceId") && this.devicesInEW.has(s.deviceId)) - .forEach(s => this.cusS.set(s.fullDeviceId, s)); - } - //*** Logging always helps to see if everything is okay so far ***\\ - this.log("[%s] eWeLink devices loaded from the Homebridge cache.", this.devicesInHB.size); - this.log("[%s] primary devices loaded from your eWeLink account.", this.devicesInEW.size); - this.log("[%s] primary devices were discovered on your local network.", this.lanCount); - //*** Remove Homebridge accessories that don't appear in eWeLink ***\\ - this.devicesInHB.forEach(a => { - if (!this.devicesInEW.has(a.context.eweDeviceId)) { - this.removeAccessory(a); - } + .on("didFinishLaunching", () => { + this.log( + "Plugin has finished initialising. Starting synchronisation with eWeLink account." + ); + //*** Set up HTTP client and get the user HTTP host ***\\ + this.httpClient = new eWeLinkHTTP(this.config, this.log); + this.httpClient + .getHost() + .then(() => this.httpClient.login()) + .then(res => { + //*** Set up the web socket client ***\\ + this.wsClient = new eWeLinkWS(this.config, this.log, res); + return this.wsClient.getHost(); + }) + .then(() => { + //*** Open web socket connection and get device list via HTTP ***\\ + this.wsClient.login(); + return this.httpClient.getDevices(); + }) + .then(res => { + //*** Get device IP addresses for LAN mode ***\\ + this.httpDevices = res + .filter( + device => + device.hasOwnProperty("extra") && + device.extra.hasOwnProperty("uiid") + ) + .filter( + device => + !(this.config.hideDevFromHB || "").includes(device.deviceid) + ); + this.lanClient = new eWeLinkLAN( + this.config, + this.log, + this.httpDevices + ); + this.httpDevices.forEach(device => + this.devicesInEwe.set(device.deviceid, device) + ); + return this.lanClient.getHosts(); + }) + .then(res => { + //*** Set up the LAN mode listener ***\\ + this.lanDevices = res.map; + this.lanDevicesOnline = res.count; + return this.lanClient.startMonitor(); + }) + .then(() => { + //*** Use the device list to refresh Homebridge accessories ***\\ + (() => { + //*** Remove all Homebridge accessories if none found ***\\ + if ( + Object.keys(this.httpDevices).length === 0 && + Object.keys(this.lanDevices).length === 0 + ) { + Array.from(this.devicesInHB.values()).forEach(a => + this.removeAccessory(a) + ); + this.devicesInHB.clear(); + this.log.warn("******* Not loading homebridge-ewelink *******"); + this.log.warn("No devices were found in your eWeLink account."); + this.log.warn("**********************************************"); + return; + } + //*** Make a map of custom groups from Homebridge config ***\\ + if (Object.keys(this.config.groups || []).length > 0) { + this.config.groups + .filter( + g => + g.hasOwnProperty("type") && + cns.allowedGroups.includes(g.type) + ) + .filter( + g => + g.hasOwnProperty("deviceId") && + this.devicesInEwe.has(g.deviceId.toLowerCase()) + ) + .forEach(g => this.cusG.set(g.deviceId + "SWX", g)); + } + //*** Make a map of RF Bridge custom sensors from Homebridge config ***\\ + if (Object.keys(this.config.bridgeSensors || []).length > 0) { + this.config.bridgeSensors + .filter( + s => + s.hasOwnProperty("deviceId") && + this.devicesInEwe.has(s.deviceId.toLowerCase()) + ) + .forEach(s => this.cusS.set(s.fullDeviceId, s)); + } + //*** Logging always helps to see if everything is okay so far ***\\ + this.log( + "[%s] eWeLink devices were loaded from the Homebridge cache.", + this.devicesInHB.size + ); + this.log( + "[%s] primary devices were loaded from your eWeLink account.", + this.devicesInEwe.size + ); + this.log( + "[%s] primary devices were discovered on your local network.", + this.lanDevicesOnline + ); + //*** Remove Homebridge accessories that don't appear in eWeLink ***\\ + this.devicesInHB.forEach(a => { + if (!this.devicesInEwe.has(a.context.eweDeviceId)) { + this.removeAccessory(a); + } + }); + //*** Synchronise devices between eWeLink and Homebridge and set up ws/lan listeners ***\\ + this.devicesInEwe.forEach(d => this.initialiseDevice(d)); + this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); + this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); + this.log( + "eWeLink setup complete. If you're enjoying this package please consider a ⭐ī¸ on GitHub :)." + ); + if (this.config.debugReqRes || false) { + this.log.warn( + "You have 'Request & Response Logging' enabled. This setting is not recommended for long-term use." + ); + } + })(); + }) + .catch(err => { + this.log.error( + "************** Cannot load homebridge-ewelink **************" + ); + this.log.error(err); + this.log.error( + "************************************************************" + ); + if (this.lanClient) this.lanClient.closeConnection(); + if (this.wsClient) this.wsClient.closeConnection(); }); - //*** Synchronise devices between eWeLink and Homebridge and set up ws/lan listeners ***\\ - this.devicesInEW.forEach(d => this.initialiseDevice(d)); - this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); - this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); - this.log("eWeLink sync complete. Don't forget to ⭐ī¸ this plugin on GitHub!"); - if (this.config.debugReqRes || false) { - this.log.warn("Note: 'Request & Response Logging' is not advised for long-term use."); - } - })(); }) - .catch(err => { - this.log.error("************** Cannot load homebridge-ewelink **************"); - this.log.error(err); - this.log.error("************************************************************"); + .on("shutdown", () => { if (this.lanClient) this.lanClient.closeConnection(); if (this.wsClient) this.wsClient.closeConnection(); }); } initialiseDevice(device) { let accessory; - //*** First add the device if it isn't already in Homebridge ***\\ + //*** First add the device if it isn't already in Homebridge. Yeah this code looks a mess :| ***\\ if ( !this.devicesInHB.has(device.deviceid + "SWX") && !this.devicesInHB.has(device.deviceid + "SW0") @@ -177,7 +233,9 @@ class eWeLink { } } else if (cns.devicesRFBridge.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SW0", "rf_pri"); - if (Object.keys((device.tags && device.tags.zyx_info) || []).length > 0) { + if ( + Object.keys((device.tags && device.tags.zyx_info) || []).length > 0 + ) { for (let i = 1; i <= Object.keys(device.tags.zyx_info).length; i++) { this.addAccessory(device, device.deviceid + "SW" + i, "rf_sub"); } @@ -211,20 +269,31 @@ class eWeLink { rfBridgeChange = false; accessory .getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); - accessory.context.reachableWAN = accessory.context.eweUIID !== 102 ? device.online : true; - accessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; + .setCharacteristic( + Characteristic.FirmwareRevision, + device.params.fwVersion + ); + accessory.context.reachableWAN = + accessory.context.eweUIID !== 102 ? device.online : true; + accessory.context.reachableLAN = + this.lanDevices.get(device.deviceid).online || false; accessory.context.inUse = false; let str = accessory.context.reachableLAN - ? "and locally with IP [" + this.lanDevices.get(device.deviceid).ip + "]" - : "but LAN mode unavailable as offline/unsupported/shared device"; + ? "and locally with IP [" + + this.lanDevices.get(device.deviceid).ip + + "]" + : "but LAN mode unavailable as unsupported/shared device"; this.log("[%s] found in eWeLink %s.", accessory.displayName, str); this.devicesInHB.set(accessory.context.hbDeviceId, accessory); if (!isX) { for (let i = 1; i <= accessory.context.channelCount; i++) { if (!this.devicesInHB.has(device.deviceid + "SW" + i)) { if (cns.devicesHideable.includes(accessory.context.type)) { - if ((this.config.hideFromHB || "").includes(device.deviceid + "SW" + i)) { + if ( + (this.config.hideFromHB || "").includes( + device.deviceid + "SW" + i + ) + ) { continue; } else { this.addAccessory(device, device.deviceid + "SW" + i, "switch"); @@ -233,7 +302,9 @@ class eWeLink { } let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); if ( - (this.config.hideFromHB || "").includes(device.deviceid + "SW" + i) && + (this.config.hideFromHB || "").includes( + device.deviceid + "SW" + i + ) && cns.devicesHideable.includes(accessory.context.type) ) { this.removeAccessory(oAccessory); @@ -247,9 +318,13 @@ class eWeLink { } oAccessory .getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); + .setCharacteristic( + Characteristic.FirmwareRevision, + device.params.fwVersion + ); oAccessory.context.reachableWAN = device.online; - oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; + oAccessory.context.reachableLAN = + this.lanDevices.get(device.deviceid).online || false; this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); } } @@ -274,12 +349,18 @@ class eWeLink { ); } } else { - this.log.warn("[%s] cannot be initialised as it wasn't found in Homebridge.", device.name); + this.log.warn( + "[%s] cannot be initialised as it wasn't found in Homebridge.", + device.name + ); } } addAccessory(device, hbDeviceId, type) { let switchNumber = hbDeviceId.substr(-1).toString(), - newDeviceName = type === "rf_sub" ? device.tags.zyx_info[switchNumber - 1].name : device.name, + newDeviceName = + type === "rf_sub" + ? device.tags.zyx_info[switchNumber - 1].name + : device.name, channelCount = type === "rf_pri" ? Object.keys((device.tags && device.tags.zyx_info) || []).length @@ -297,7 +378,10 @@ class eWeLink { if ((this.config.nameOverride || {}).hasOwnProperty(hbDeviceId)) { newDeviceName = this.config.nameOverride[hbDeviceId]; } - const accessory = new Accessory(newDeviceName, UUIDGen.generate(hbDeviceId).toString()); + const accessory = new Accessory( + newDeviceName, + UUIDGen.generate(hbDeviceId).toString() + ); try { accessory .getService(Service.AccessoryInformation) @@ -307,7 +391,10 @@ class eWeLink { Characteristic.Model, device.productModel + " (" + device.extra.model + ")" ) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) + .setCharacteristic( + Characteristic.FirmwareRevision, + device.params.fwVersion + ) .setCharacteristic(Characteristic.Identify, false); accessory.context = { hbDeviceId, @@ -323,11 +410,18 @@ class eWeLink { case "valve": ["A", "B"].forEach(v => { accessory - .addService(Service.Valve, "Valve " + v, "valve" + v.toLowerCase()) + .addService( + Service.Valve, + "Valve " + v, + "valve" + v.toLowerCase() + ) .setCharacteristic(Characteristic.Active, 0) .setCharacteristic(Characteristic.InUse, 0) .setCharacteristic(Characteristic.ValveType, 1) - .setCharacteristic(Characteristic.SetDuration, this.config.valveTimeLength || 120) + .setCharacteristic( + Characteristic.SetDuration, + this.config.valveTimeLength || 120 + ) .addCharacteristic(Characteristic.RemainingDuration); }); break; @@ -362,7 +456,8 @@ class eWeLink { case "thermostat": if (!this.config.hideTHSwitch) accessory.addService(Service.Switch); accessory.addService(Service.TemperatureSensor); - if (device.params.sensorType !== "DS18B20") accessory.addService(Service.HumiditySensor); + if (device.params.sensorType !== "DS18B20") + accessory.addService(Service.HumiditySensor); break; case "outlet": accessory.addService(Service.Outlet); @@ -408,7 +503,9 @@ class eWeLink { break; case "rf_sub": accessory.context.rfChls = {}; - switch (device.tags.zyx_info[parseInt(switchNumber) - 1].remote_type) { + switch ( + device.tags.zyx_info[parseInt(switchNumber) - 1].remote_type + ) { case "1": case "2": case "3": @@ -428,46 +525,52 @@ class eWeLink { ); } let mAccessory = this.devicesInHB.get(device.deviceid + "SW0"); - device.tags.zyx_info[parseInt(switchNumber) - 1].buttonName.forEach(button => { - let rfData; - Object.entries(button).forEach( - ([k, v]) => - (rfData = { - rfChan: k, - name: v, - }) - ); - accessory.context.rfChls[rfData.rfChan] = rfData.name; - mAccessory.context.rfChlMap[rfData.rfChan] = switchNumber; - switch (accessory.context.sensorType) { - case "button": - accessory.addService(Service.Switch, rfData.name, "switch" + rfData.rfChan); - break; - case "water": - accessory.addService(Service.LeakSensor); - break; - case "fire": - case "smoke": - accessory.addService(Service.SmokeSensor); - break; - case "co": - accessory.addService(Service.CarbonMonoxideSensor); - break; - case "co2": - accessory.addService(Service.CarbonDioxideSensor); - break; - case "contact": - accessory.addService(Service.ContactSensor); - break; - case "occupancy": - accessory.addService(Service.OccupancySensor); - break; - default: - accessory.addService(Service.MotionSensor); - break; + device.tags.zyx_info[parseInt(switchNumber) - 1].buttonName.forEach( + button => { + let rfData; + Object.entries(button).forEach( + ([k, v]) => + (rfData = { + rfChan: k, + name: v, + }) + ); + accessory.context.rfChls[rfData.rfChan] = rfData.name; + mAccessory.context.rfChlMap[rfData.rfChan] = switchNumber; + switch (accessory.context.sensorType) { + case "button": + accessory.addService( + Service.Switch, + rfData.name, + "switch" + rfData.rfChan + ); + break; + case "water": + accessory.addService(Service.LeakSensor); + break; + case "fire": + case "smoke": + accessory.addService(Service.SmokeSensor); + break; + case "co": + accessory.addService(Service.CarbonMonoxideSensor); + break; + case "co2": + accessory.addService(Service.CarbonDioxideSensor); + break; + case "contact": + accessory.addService(Service.ContactSensor); + break; + case "occupancy": + accessory.addService(Service.OccupancySensor); + break; + default: + accessory.addService(Service.MotionSensor); + break; + } + this.devicesInHB.set(mAccessory.context.hbDeviceId, mAccessory); } - this.devicesInHB.set(mAccessory.context.hbDeviceId, mAccessory); - }); + ); break; case "zb_sub": //*** credit @tasict ***\\ accessory.addService(Service.BatteryService); @@ -505,7 +608,9 @@ class eWeLink { throw "device is not supported by this plugin. Please create an issue on GitHub"; } this.devicesInHB.set(hbDeviceId, accessory); - this.api.registerPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); + this.api.registerPlatformAccessories("homebridge-ewelink", "eWeLink", [ + accessory, + ]); this.configureAccessory(accessory); this.log("[%s] has been added to Homebridge.", newDeviceName); } catch (err) { @@ -524,21 +629,33 @@ class eWeLink { .getService("Valve " + v) .getCharacteristic(Characteristic.Active) .on("set", (value, callback) => - this.internalValveUpdate(accessory, "Valve " + v, value, callback) + this.internalValveUpdate( + accessory, + "Valve " + v, + value, + callback + ) ); accessory .getService("Valve " + v) .getCharacteristic(Characteristic.SetDuration) .on("set", (value, callback) => { if ( - accessory.getService("Valve " + v).getCharacteristic(Characteristic.InUse).value + accessory + .getService("Valve " + v) + .getCharacteristic(Characteristic.InUse).value ) { accessory .getService("Valve " + v) - .updateCharacteristic(Characteristic.RemainingDuration, value); + .updateCharacteristic( + Characteristic.RemainingDuration, + value + ); clearTimeout(accessory.getService("Valve " + v).timer); accessory.getService("Valve " + v).timer = setTimeout(() => { - accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); + accessory + .getService("Valve " + v) + .setCharacteristic(Characteristic.Active, 0); }, value * 1000); } callback(); @@ -549,7 +666,9 @@ class eWeLink { accessory .getService(Service.WindowCovering) .getCharacteristic(Characteristic.TargetPosition) - .on("set", (value, callback) => this.internalBlindUpdate(accessory, value, callback)) + .on("set", (value, callback) => + this.internalBlindUpdate(accessory, value, callback) + ) .setProps({ minStep: 100, }); @@ -558,13 +677,17 @@ class eWeLink { accessory .getService(Service.GarageDoorOpener) .getCharacteristic(Characteristic.TargetDoorState) - .on("set", (value, callback) => this.internalGarageUpdate(accessory, value, callback)); + .on("set", (value, callback) => + this.internalGarageUpdate(accessory, value, callback) + ); break; case "lock": accessory .getService(Service.LockMechanism) .getCharacteristic(Characteristic.LockTargetState) - .on("set", (value, callback) => this.internalLockUpdate(accessory, value, callback)); + .on("set", (value, callback) => + this.internalLockUpdate(accessory, value, callback) + ); break; case "fan": accessory @@ -614,7 +737,9 @@ class eWeLink { if (accessory.getService(Service.HumiditySensor)) { dataToAdd.humidity = accessory .getService(Service.HumiditySensor) - .getCharacteristic(Characteristic.CurrentRelativeHumidity).value; + .getCharacteristic( + Characteristic.CurrentRelativeHumidity + ).value; } accessory.eveLogger.addEntry(dataToAdd); }, 300000); @@ -623,7 +748,9 @@ class eWeLink { accessory .getService(Service.Outlet) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalOutletUpdate(accessory, value, callback)); + .on("set", (value, callback) => + this.internalOutletUpdate(accessory, value, callback) + ); accessory.log = this.log; accessory.eveLogger = new EveHistoryService("energy", accessory, { storage: "fs", @@ -642,12 +769,15 @@ class eWeLink { }; } corrInterval.setCorrectingInterval(() => { - let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) - .value, + let isOn = accessory + .getService(Service.Outlet) + .getCharacteristic(Characteristic.On).value, currentWatt = isOn ? accessory .getService(Service.Outlet) - .getCharacteristic(EveService.Characteristics.CurrentConsumption).value + .getCharacteristic( + EveService.Characteristics.CurrentConsumption + ).value : 0; if (accessory.eveLogger.isHistoryLoaded()) { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); @@ -662,7 +792,8 @@ class eWeLink { }); } else { accessory.context.totalEnergy = - accessory.context.totalEnergyTemp + (currentWatt * 10) / 3600 / 1000; + accessory.context.totalEnergyTemp + + (currentWatt * 10) / 3600 / 1000; accessory.eveLogger.setExtraPersistedData({ totalenergy: accessory.context.totalEnergy, lastReset: 0, @@ -670,7 +801,8 @@ class eWeLink { } accessory.context.totalEnergytemp = 0; } else { - accessory.context.totalEnergyTemp += (currentWatt * 10) / 3600 / 1000; + accessory.context.totalEnergyTemp += + (currentWatt * 10) / 3600 / 1000; accessory.context.totalEnergy = accessory.context.totalEnergyTemp; } accessory.eveLogger.addEntry({ @@ -684,7 +816,8 @@ class eWeLink { .on("get", callback => { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower; + accessory.context.totalEnergy = + accessory.context.extraPersistedData.totalPower; } callback(null, accessory.context.totalEnergy); }); @@ -703,7 +836,8 @@ class eWeLink { .on("get", callback => { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); if (accessory.context.extraPersistedData !== undefined) { - accessory.context.lastReset = accessory.context.extraPersistedData.lastReset; + accessory.context.lastReset = + accessory.context.extraPersistedData.lastReset; } callback(null, accessory.context.lastReset); }); @@ -712,13 +846,17 @@ class eWeLink { accessory .getService(Service.Outlet) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalUSBUpdate(accessory, value, callback)); + .on("set", (value, callback) => + this.internalUSBUpdate(accessory, value, callback) + ); break; case "scm": accessory .getService(Service.Switch) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalSCMUpdate(accessory, value, callback)); + .on("set", (value, callback) => + this.internalSCMUpdate(accessory, value, callback) + ); break; case "light": accessory @@ -734,8 +872,9 @@ class eWeLink { .on("set", (value, callback) => { if (value > 0) { if ( - !accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) - .value + !accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On).value ) { this.internalLightbulbUpdate(accessory, true, function () { return; @@ -746,15 +885,18 @@ class eWeLink { this.internalLightbulbUpdate(accessory, false, callback); } }); - } else if (cns.devicesColourable.includes(accessory.context.eweUIID)) { + } else if ( + cns.devicesColourable.includes(accessory.context.eweUIID) + ) { accessory .getService(Service.Lightbulb) .getCharacteristic(Characteristic.Brightness) .on("set", (value, callback) => { if (value > 0) { if ( - !accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) - .value + !accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On).value ) { this.internalLightbulbUpdate(accessory, true, function () { return; @@ -781,18 +923,24 @@ class eWeLink { accessory .getService(Service.Switch) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalSwitchUpdate(accessory, value, callback)); + .on("set", (value, callback) => + this.internalSwitchUpdate(accessory, value, callback) + ); break; case "rf_sub": accessory.context.rfChls = accessory.context.rfChls || {}; if (accessory.context.sensorType === "button") { Object.entries(accessory.context.rfChls).forEach(([k, v]) => { - accessory.getService(v).updateCharacteristic(Characteristic.On, false); + accessory + .getService(v) + .updateCharacteristic(Characteristic.On, false); accessory .getService(v) .getCharacteristic(Characteristic.On) .on("set", (value, callback) => { - value ? this.internalRFDeviceUpdate(accessory, k, callback) : callback(); + value + ? this.internalRFDeviceUpdate(accessory, k, callback) + : callback(); }); }); } @@ -813,7 +961,8 @@ class eWeLink { .getCharacteristic(Characteristic.CurrentTemperature).value, humidity: accessory .getService(Service.HumiditySensor) - .getCharacteristic(Characteristic.CurrentRelativeHumidity).value, + .getCharacteristic(Characteristic.CurrentRelativeHumidity) + .value, }; accessory.eveLogger.addEntry(dataToAdd); }, 300000); @@ -822,14 +971,20 @@ class eWeLink { } this.devicesInHB.set(accessory.context.hbDeviceId, accessory); } catch (err) { - this.log.warn("[%s] could not be refreshed as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be refreshed as %s.", + accessory.displayName, + err + ); } } refreshAccessory(accessory, newParams) { switch (accessory.context.type) { case "valve": if ( - Object.keys(newParams).some(v => cns.devicesValveParams.includes(v)) && + Object.keys(newParams).some(v => + cns.devicesValveParams.includes(v) + ) && Array.isArray(newParams.switches) ) { this.externalValveUpdate(accessory, newParams); @@ -837,7 +992,9 @@ class eWeLink { return true; case "blind": if ( - Object.keys(newParams).some(v => cns.devicesBlindParams.includes(v)) && + Object.keys(newParams).some(v => + cns.devicesBlindParams.includes(v) + ) && Array.isArray(newParams.switches) ) { this.externalBlindUpdate(accessory, newParams); @@ -845,34 +1002,48 @@ class eWeLink { return true; case "garage": if ( - Object.keys(newParams).some(v => cns.devicesGarageParams.includes(v)) && + Object.keys(newParams).some(v => + cns.devicesGarageParams.includes(v) + ) && Array.isArray(newParams.switches) ) { this.externalGarageUpdate(accessory, newParams); } return true; case "lock": - if (Object.keys(newParams).some(v => cns.devicesLockParams.includes(v))) { + if ( + Object.keys(newParams).some(v => cns.devicesLockParams.includes(v)) + ) { this.externalLockUpdate(accessory, newParams); } return true; case "sensor": - if (Object.keys(newParams).some(v => cns.devicesSensorParams.includes(v))) { + if ( + Object.keys(newParams).some(v => cns.devicesSensorParams.includes(v)) + ) { this.externalSensorUpdate(accessory, newParams); } return true; case "fan": - if (Object.keys(newParams).some(v => cns.devicesFanParams.includes(v))) { + if ( + Object.keys(newParams).some(v => cns.devicesFanParams.includes(v)) + ) { this.externalFanUpdate(accessory, newParams); } return true; case "thermostat": - if (Object.keys(newParams).some(v => cns.devicesThermostatParams.includes(v))) { + if ( + Object.keys(newParams).some(v => + cns.devicesThermostatParams.includes(v) + ) + ) { this.externalThermostatUpdate(accessory, newParams); } return true; case "outlet": - if (Object.keys(newParams).some(v => cns.devicesOutletParams.includes(v))) { + if ( + Object.keys(newParams).some(v => cns.devicesOutletParams.includes(v)) + ) { this.externalOutletUpdate(accessory, newParams); } return true; @@ -897,7 +1068,11 @@ class eWeLink { cns.devicesSingleSwitch.includes(accessory.context.eweUIID) && cns.devicesSingleSwitchLight.includes(accessory.context.eweModel) ) { - if (Object.keys(newParams).some(v => cns.devicesSingleSwitchLightParams.includes(v))) { + if ( + Object.keys(newParams).some(v => + cns.devicesSingleSwitchLightParams.includes(v) + ) + ) { this.externalSingleLightUpdate(accessory, newParams); } } else if ( @@ -905,7 +1080,9 @@ class eWeLink { cns.devicesMultiSwitchLight.includes(accessory.context.eweModel) ) { if ( - Object.keys(newParams).some(v => cns.devicesMultiSwitchLightParams.includes(v)) && + Object.keys(newParams).some(v => + cns.devicesMultiSwitchLightParams.includes(v) + ) && Array.isArray(newParams.switches) ) { this.externalMultiLightUpdate(accessory, newParams); @@ -914,12 +1091,18 @@ class eWeLink { return true; case "switch": if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID)) { - if (Object.keys(newParams).some(v => cns.devicesSingleSwitchParams.includes(v))) { + if ( + Object.keys(newParams).some(v => + cns.devicesSingleSwitchParams.includes(v) + ) + ) { this.externalSingleSwitchUpdate(accessory, newParams); } } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID)) { if ( - Object.keys(newParams).some(v => cns.devicesMultiSwitchParams.includes(v)) && + Object.keys(newParams).some(v => + cns.devicesMultiSwitchParams.includes(v) + ) && Array.isArray(newParams.switches) ) { this.externalMultiSwitchUpdate(accessory, newParams); @@ -927,7 +1110,11 @@ class eWeLink { } return true; case "rf_pri": - if (Object.keys(newParams).some(v => cns.devicesRFBridgeParams.includes(v))) { + if ( + Object.keys(newParams).some(v => + cns.devicesRFBridgeParams.includes(v) + ) + ) { this.externalRFDeviceUpdate(accessory, newParams); } return true; @@ -935,7 +1122,11 @@ class eWeLink { case "zb_pri": return true; case "zb_sub": - if (Object.keys(newParams).some(v => cns.devicesZBBridgeParams.includes(v))) { + if ( + Object.keys(newParams).some(v => + cns.devicesZBBridgeParams.includes(v) + ) + ) { this.externalZBDeviceUpdate(accessory, newParams); } return true; @@ -946,10 +1137,16 @@ class eWeLink { removeAccessory(accessory) { try { this.devicesInHB.delete(accessory.context.hbDeviceId); - this.api.unregisterPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); + this.api.unregisterPlatformAccessories("homebridge-ewelink", "eWeLink", [ + accessory, + ]); this.log("[%s] has been removed from Homebridge.", accessory.displayName); } catch (err) { - this.log.warn("[%s] needed to be removed but couldn't as %s.", accessory.displayName, err); + this.log.warn( + "[%s] needed to be removed but couldn't as %s.", + accessory.displayName, + err + ); } } sendDeviceUpdate(accessory, params, callback) { @@ -970,7 +1167,10 @@ class eWeLink { callback("Device has failed to update"); } }; - if (cns.devicesNonLAN.includes(accessory.context.eweUIID) || !accessory.context.reachableLAN) { + if ( + cns.devicesNonLAN.includes(accessory.context.eweUIID) || + !accessory.context.reachableLAN + ) { sendViaWS(); } else { this.lanClient @@ -978,81 +1178,110 @@ class eWeLink { .then(() => callback()) .catch(err => { if (this.debug) { - this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); + this.log.warn( + "[%s] Reverting to web socket as %s.", + accessory.displayName, + err + ); } sendViaWS(); }); } } receiveDeviceUpdate(device) { - let accessory, - deviceId = device.deviceid, - statusChange = false; - if ( - (accessory = this.devicesInHB.get(deviceId + "SWX") || this.devicesInHB.get(deviceId + "SW0")) - ) { - let isX = accessory.context.hbDeviceId.substr(-1) === "X"; - - if (device.params.updateSource === "WS") { - if (device.params.online != accessory.context.reachableWAN) { - accessory.context.reachableWAN = device.params.online; - this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - if (accessory.context.reachableWAN) this.wsClient.requestUpdate(accessory); - statusChange = true; - this.log.warn( - "[%s] has been reported [%s] via [WS].", - accessory.displayName, - accessory.context.reachableWAN ? "online" : "offline" - ); - } - } - - if (device.params.updateSource === "LAN") { - if (!accessory.context.reachableLAN) { - accessory.context.reachableLAN = true; - this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - this.wsClient.requestUpdate(accessory); - statusChange = true; - this.log.warn("[%s] has been reported [online] via [LAN].", accessory.displayName); - } - if (statusChange && !isX) { - for (let i = 1; i <= accessory.context.channelCount; i++) { - if (this.devicesInHB.has(deviceId + "SW" + i)) { - let oAccessory = this.devicesInHB.get(deviceId + "SW" + i); - oAccessory.context.reachableWAN = device.params.online; - oAccessory.context.reachableLAN = true; - this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); + let accessory; + switch (device.action) { + case "sysmsg": + if ( + (accessory = + this.devicesInHB.get(device.deviceid + "SWX") || + this.devicesInHB.get(device.deviceid + "SW0")) + ) { + let isX = accessory.context.hbDeviceId.substr(-1) === "X"; + if (device.params.updateSource === "WS") { + if (accessory.context.reachableWAN !== device.params.online) { + accessory.context.reachableWAN = device.params.online; + this.log( + "[%s] has been reported [%s] via [WS].", + accessory.displayName, + accessory.context.reachableWAN ? "online" : "offline" + ); + this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + if (accessory.context.reachableWAN) + this.wsClient.requestUpdate(accessory); + } else { + if (this.debug) { + this.log( + "[%s] Nothing to update from above WS message.", + accessory.displayName + ); + } + } + } + if (!isX) { + for (let i = 1; i <= accessory.context.channelCount; i++) { + if (this.devicesInHB.has(device.deviceid + "SW" + i)) { + let oAccessory = this.devicesInHB.get( + device.deviceid + "SW" + i + ); + oAccessory.context.reachableWAN = device.params.online; + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); + } } } } - } - if (this.debug) { - this.log( - "[%s] externally updated from above %s message and will be refreshed.", - accessory.displayName, - device.params.updateSource - ); - } - if (!this.refreshAccessory(accessory, device.params)) { - this.log.warn( - "[%s] cannot be refreshed. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.). [debug:%s:%s]", - accessory.displayName, - accessory.context.type, - accessory.context.channelCount - ); - } - } else { - if (!(this.config.hideDevFromHB || "").includes(deviceId)) { - this.log.warn( - "[%s] update received via %s does not exist in Homebridge so device will be added.", - deviceId, - device.params.updateSource - ); - this.httpClient - .getDevice(deviceId) - .then(res => this.initialiseDevice(res)) - .catch(err => this.log.error("[%s] error getting info [%s]", deviceId, err)); - } + break; + case "update": + if ( + (accessory = + this.devicesInHB.get(device.deviceid + "SWX") || + this.devicesInHB.get(device.deviceid + "SW0")) + ) { + if ( + device.params.updateSource === "WS" && + !accessory.context.reachableWAN + ) { + accessory.context.reachableWAN = true; + this.log( + "[%s] has been reported [online] via [WS].", + accessory.displayName + ); + } + if ( + device.params.updateSource === "LAN" && + !accessory.context.reachableLAN + ) { + accessory.context.reachableLAN = true; + this.log( + "[%s] has been reported [online] via [LAN].", + accessory.displayName + ); + } + if (this.debug) { + this.log( + "[%s] externally updated from above %s message and will be refreshed.", + accessory.displayName, + device.params.updateSource + ); + } + if (!this.refreshAccessory(accessory, device.params)) { + this.log.warn( + "[%s] cannot be refreshed. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.). [debug:%s:%s]", + accessory.displayName, + accessory.context.type, + accessory.context.channelCount + ); + } + } else { + if (!(this.config.hideDevFromHB || "").includes(device.deviceid)) { + this.log.warn( + "[%s] Accessory received via %s update does not exist in Homebridge. If it's a new accessory please restart Homebridge so it is added.", + device.deviceid, + device.params.updateSource + ); + } + } + break; } } internalValveUpdate(accessory, valve, value, callback) { @@ -1067,19 +1296,28 @@ class eWeLink { .updateCharacteristic(Characteristic.InUse, value); switch (value) { case 0: - accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, 0); + accessory + .getService(valve) + .updateCharacteristic(Characteristic.RemainingDuration, 0); clearTimeout(accessory.getService(valve).timer); break; case 1: - let timer = accessory.getService(valve).getCharacteristic(Characteristic.SetDuration) - .value; - accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, timer); + let timer = accessory + .getService(valve) + .getCharacteristic(Characteristic.SetDuration).value; + accessory + .getService(valve) + .updateCharacteristic(Characteristic.RemainingDuration, timer); accessory.getService(valve).timer = setTimeout(() => { - accessory.getService(valve).setCharacteristic(Characteristic.Active, 0); + accessory + .getService(valve) + .setCharacteristic(Characteristic.Active, 0); }, timer * 1000); break; } - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEwe.get( + accessory.context.eweDeviceId + ).params.switches; switch (valve) { case "Valve A": params.switches[0].switch = value ? "on" : "off"; @@ -1104,7 +1342,8 @@ class eWeLink { params.switches[3].switch = "off"; this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1118,7 +1357,10 @@ class eWeLink { if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } - if (blindConfig.type !== "blind" || !["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { + if ( + blindConfig.type !== "blind" || + !["oneSwitch", "twoSwitch"].includes(blindConfig.setup) + ) { throw "improper configuration"; } let oldPos, @@ -1140,7 +1382,9 @@ class eWeLink { params.switch = "on"; break; case "twoSwitch": - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEwe.get( + accessory.context.eweDeviceId + ).params.switches; params.switches[0].switch = value === 100 ? "on" : "off"; params.switches[1].switch = value === 0 ? "on" : "off"; break; @@ -1160,7 +1404,8 @@ class eWeLink { callback(); }, parseInt(blindConfig.operationTime) * 100); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1188,7 +1433,10 @@ class eWeLink { newPos = value, params = {}, delay = 0; - if (sensorDefinition && !(sAccessory = this.devicesInHB.get(garageConfig.sensorId + "SWX"))) { + if ( + sensorDefinition && + !(sAccessory = this.devicesInHB.get(garageConfig.sensorId + "SWX")) + ) { throw "defined DW2 sensor doesn't exist"; } if (sAccessory.context.type !== "sensor") { @@ -1211,7 +1459,10 @@ class eWeLink { if (garageConfig.setup === "oneSwitch" && [2, 3].includes(oldPos)) { accessory .getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.CurrentDoorState, ((oldPos * 2) % 3) + 2); + .updateCharacteristic( + Characteristic.CurrentDoorState, + ((oldPos * 2) % 3) + 2 + ); delay = 1500; } setTimeout(() => { @@ -1225,7 +1476,9 @@ class eWeLink { params.switch = "on"; break; case "twoSwitch": - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEwe.get( + accessory.context.eweDeviceId + ).params.switches; params.switches[0].switch = newPos === 0 ? "on" : "off"; params.switches[1].switch = newPos === 1 ? "on" : "off"; break; @@ -1246,7 +1499,8 @@ class eWeLink { callback(); } catch (err) { accessory.context.inUse = false; - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1281,7 +1535,8 @@ class eWeLink { }, parseInt(lockConfig.operationTime) * 100); } catch (err) { accessory.context.inUse = false; - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1296,36 +1551,45 @@ class eWeLink { case "power": newPower = value; newSpeed = value ? 33 : 0; - newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) - .value; + newLight = accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On).value; break; case "speed": newPower = value >= 33 ? 1 : 0; newSpeed = value; - newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) - .value; + newLight = accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On).value; break; case "light": - newPower = accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active) - .value; + newPower = accessory + .getService(Service.Fanv2) + .getCharacteristic(Characteristic.Active).value; newSpeed = accessory .getService(Service.Fanv2) .getCharacteristic(Characteristic.RotationSpeed).value; newLight = value; break; } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, newLight); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, newLight); accessory .getService(Service.Fanv2) .updateCharacteristic(Characteristic.Active, newPower) .updateCharacteristic(Characteristic.RotationSpeed, newSpeed); let params = { - switches: this.devicesInEW.get(accessory.context.eweDeviceId).params.switches, + switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params + .switches, }; params.switches[0].switch = newLight ? "on" : "off"; - params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? "on" : "off"; - params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? "on" : "off"; - params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? "on" : "off"; + params.switches[1].switch = + newPower === 1 && newSpeed >= 33 ? "on" : "off"; + params.switches[2].switch = + newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? "on" : "off"; + params.switches[3].switch = + newPower === 1 && newSpeed >= 99 ? "on" : "off"; if (this.debug) { this.log.warn("Fan Update - setting " + type + " to " + value); this.log( @@ -1338,7 +1602,8 @@ class eWeLink { } this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1353,12 +1618,19 @@ class eWeLink { mainSwitch: value ? "on" : "off", }; if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + this.log( + "[%s] updating to turn [%s].", + accessory.displayName, + value ? "on" : "off" + ); } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1372,9 +1644,15 @@ class eWeLink { switch: value ? "on" : "off", }; if (this.debug) { - this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); + this.log( + "[%s] requesting to turn [%s].", + accessory.displayName, + value ? "on" : "off" + ); } - accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Outlet) + .updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { callback("[" + accessory.displayName + "] " + err + "."); @@ -1386,13 +1664,20 @@ class eWeLink { throw "it is currently offline"; } let params = { - switches: this.devicesInEW.get(accessory.context.eweDeviceId).params.switches, + switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params + .switches, }; params.switches[0].switch = value ? "on" : "off"; if (this.debug) { - this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); + this.log( + "[%s] requesting to turn [%s].", + accessory.displayName, + value ? "on" : "off" + ); } - accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Outlet) + .updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { callback("[" + accessory.displayName + "] " + err + "."); @@ -1404,13 +1689,20 @@ class eWeLink { throw "it is currently offline"; } let params = { - switches: this.devicesInEW.get(accessory.context.eweDeviceId).params.switches, + switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params + .switches, }; params.switches[0].switch = value ? "on" : "off"; if (this.debug) { - this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); + this.log( + "[%s] requesting to turn [%s].", + accessory.displayName, + value ? "on" : "off" + ); } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { callback("[" + accessory.displayName + "] " + err + "."); @@ -1432,12 +1724,20 @@ class eWeLink { params.switch = value ? "on" : "off"; } if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + this.log( + "[%s] updating to turn [%s].", + accessory.displayName, + value ? "on" : "off" + ); } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, value); break; case "0": - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEwe.get( + accessory.context.eweDeviceId + ).params.switches; params.switches[0].switch = value ? "on" : "off"; params.switches[1].switch = value ? "on" : "off"; params.switches[2].switch = value ? "on" : "off"; @@ -1449,10 +1749,16 @@ class eWeLink { value ? "on" : "off" ); } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, value); for (let i = 1; i <= 4; i++) { - if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); + if ( + this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i) + ) { + oAccessory = this.devicesInHB.get( + accessory.context.eweDeviceId + "SW" + i + ); oAccessory .getService(Service.Lightbulb) .updateCharacteristic(Characteristic.On, value); @@ -1464,14 +1770,26 @@ class eWeLink { case "3": case "4": if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + this.log( + "[%s] updating to turn [%s].", + accessory.displayName, + value ? "on" : "off" + ); } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, value); let tAccessory, masterState = "off"; - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEwe.get( + accessory.context.eweDeviceId + ).params.switches; for (let i = 1; i <= 4; i++) { - if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + if ( + (tAccessory = this.devicesInHB.get( + accessory.context.eweDeviceId + "SW" + i + )) + ) { i === parseInt(accessory.context.switchNumber) ? (params.switches[i - 1].switch = value ? "on" : "off") : (params.switches[i - 1].switch = tAccessory @@ -1480,7 +1798,9 @@ class eWeLink { ? "on" : "off"); if ( - tAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value + tAccessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On).value ) { masterState = "on"; } @@ -1488,17 +1808,22 @@ class eWeLink { params.switches[i - 1].switch = "off"; } } - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); + oAccessory = this.devicesInHB.get( + accessory.context.eweDeviceId + "SW0" + ); oAccessory .getService(Service.Lightbulb) .updateCharacteristic(Characteristic.On, masterState === "on"); break; default: - throw "unknown switch number [" + accessory.context.switchNumber + "]"; + throw ( + "unknown switch number [" + accessory.context.switchNumber + "]" + ); } this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1511,9 +1836,15 @@ class eWeLink { let params = {}; if (value === 0) { params.switch = "off"; - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, false); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, false); } else { - if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + if ( + !accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On).value + ) { params.switch = "on"; } switch (accessory.context.eweUIID) { @@ -1532,11 +1863,16 @@ class eWeLink { .updateCharacteristic(Characteristic.Brightness, value); } if (this.debug) { - this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); + this.log( + "[%s] updating brightness to [%s%].", + accessory.displayName, + value + ); } setTimeout(() => this.sendDeviceUpdate(accessory, params, callback), 250); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1548,8 +1884,9 @@ class eWeLink { } let newRGB, params = {}, - curHue = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Hue) - .value, + curHue = accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.Hue).value, curSat = accessory .getService(Service.Lightbulb) .getCharacteristic(Characteristic.Saturation).value; @@ -1580,9 +1917,15 @@ class eWeLink { throw "unknown device UIID"; } if (this.debug) { - this.log("[%s] updating hue to [%s°].", accessory.displayName, value); + this.log( + "[%s] updating hue to [%s°].", + accessory.displayName, + value + ); } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Hue, value); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.Hue, value); break; case "bri": switch (accessory.context.eweUIID) { @@ -1606,7 +1949,11 @@ class eWeLink { break; } if (this.debug) { - this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); + this.log( + "[%s] updating brightness to [%s%].", + accessory.displayName, + value + ); } accessory .getService(Service.Lightbulb) @@ -1617,7 +1964,8 @@ class eWeLink { } setTimeout(() => this.sendDeviceUpdate(accessory, params, callback), 250); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1633,12 +1981,20 @@ class eWeLink { case "X": params.switch = value ? "on" : "off"; if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + this.log( + "[%s] updating to turn [%s].", + accessory.displayName, + value ? "on" : "off" + ); } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, value); break; case "0": - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEwe.get( + accessory.context.eweDeviceId + ).params.switches; params.switches[0].switch = value ? "on" : "off"; params.switches[1].switch = value ? "on" : "off"; params.switches[2].switch = value ? "on" : "off"; @@ -1650,11 +2006,19 @@ class eWeLink { value ? "on" : "off" ); } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, value); for (let i = 1; i <= 4; i++) { - if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); - oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + if ( + this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i) + ) { + oAccessory = this.devicesInHB.get( + accessory.context.eweDeviceId + "SW" + i + ); + oAccessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, value); } } break; @@ -1663,14 +2027,26 @@ class eWeLink { case "3": case "4": if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); + this.log( + "[%s] updating to turn [%s].", + accessory.displayName, + value ? "on" : "off" + ); } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + accessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, value); let tAccessory, masterState = "off"; - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEwe.get( + accessory.context.eweDeviceId + ).params.switches; for (let i = 1; i <= 4; i++) { - if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + if ( + (tAccessory = this.devicesInHB.get( + accessory.context.eweDeviceId + "SW" + i + )) + ) { i === parseInt(accessory.context.switchNumber) ? (params.switches[i - 1].switch = value ? "on" : "off") : (params.switches[i - 1].switch = tAccessory @@ -1679,7 +2055,9 @@ class eWeLink { ? "on" : "off"); if ( - tAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value + tAccessory + .getService(Service.Switch) + .getCharacteristic(Characteristic.On).value ) { masterState = "on"; } @@ -1687,17 +2065,22 @@ class eWeLink { params.switches[i - 1].switch = "off"; } } - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); + oAccessory = this.devicesInHB.get( + accessory.context.eweDeviceId + "SW0" + ); oAccessory .getService(Service.Switch) .updateCharacteristic(Characteristic.On, masterState === "on"); break; default: - throw "unknown switch number [" + accessory.context.switchNumber + "]"; + throw ( + "unknown switch number [" + accessory.context.switchNumber + "]" + ); } this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = + "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1731,7 +2114,14 @@ class eWeLink { 3000 ); } catch (err) { - let str = "[" + accessory.displayName + " " + name + "] could not be updated as " + err + "."; + let str = + "[" + + accessory.displayName + + " " + + name + + "] could not be updated as " + + err + + "."; this.log.error(str); callback(str); } @@ -1741,8 +2131,14 @@ class eWeLink { ["A", "B"].forEach((v, k) => { accessory .getService("Valve " + v) - .updateCharacteristic(Characteristic.Active, params.switches[k].switch === "on") - .updateCharacteristic(Characteristic.InUse, params.switches[k].switch === "on"); + .updateCharacteristic( + Characteristic.Active, + params.switches[k].switch === "on" + ) + .updateCharacteristic( + Characteristic.InUse, + params.switches[k].switch === "on" + ); if (params.switches[k].switch === "on") { let timer = accessory .getService("Valve " + v) @@ -1751,7 +2147,9 @@ class eWeLink { .getService("Valve " + v) .updateCharacteristic(Characteristic.RemainingDuration, timer); accessory.getService("Valve " + v).timer = setTimeout(() => { - accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); + accessory + .getService("Valve " + v) + .setCharacteristic(Characteristic.Active, 0); }, timer * 1000); } else { accessory @@ -1761,7 +2159,11 @@ class eWeLink { } }); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalBlindUpdate(accessory, params) { @@ -1770,7 +2172,10 @@ class eWeLink { if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } - if (blindConfig.type !== "blind" || ["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { + if ( + blindConfig.type !== "blind" || + ["oneSwitch", "twoSwitch"].includes(blindConfig.setup) + ) { throw "improper configuration"; } switch (blindConfig.setup) { @@ -1786,7 +2191,10 @@ class eWeLink { : 0; break; case "twoSwitch": - if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { + if ( + params.switches[0].switch === "off" && + params.switches[1].switch === "off" + ) { return; } let switchUp = params.switches[0].switch === "on" ? -1 : 0, // matrix of numbers to get @@ -1805,7 +2213,11 @@ class eWeLink { .updateCharacteristic(Characteristic.CurrentPosition, nSte * 100); }, parseInt(blindConfig.operationTime) * 100); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalGarageUpdate(accessory, params) { @@ -1859,7 +2271,11 @@ class eWeLink { }, parseInt(garageConfig.operationTime) * 100); } catch (err) { accessory.context.inUse = false; - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalLockUpdate(accessory, params) { @@ -1888,7 +2304,11 @@ class eWeLink { }, parseInt(lockConfig.operationTime) * 100); } catch (err) { accessory.context.inUse = false; - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalSensorUpdate(accessory, params) { @@ -1898,8 +2318,14 @@ class eWeLink { accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService), scaledBattery = Math.round(params.battery * 33.3); - batteryService.updateCharacteristic(Characteristic.BatteryLevel, scaledBattery); - batteryService.updateCharacteristic(Characteristic.StatusLowBattery, scaledBattery < 25); + batteryService.updateCharacteristic( + Characteristic.BatteryLevel, + scaledBattery + ); + batteryService.updateCharacteristic( + Characteristic.StatusLowBattery, + scaledBattery < 25 + ); } let newState = params.switch === "on" ? 1 : 0, oAccessory = false; @@ -1907,7 +2333,10 @@ class eWeLink { .getService(Service.ContactSensor) .updateCharacteristic(Characteristic.ContactSensorState, newState); this.cusG.forEach(group => { - if (group.sensorId === accessory.context.eweDeviceId && group.type === "garage") { + if ( + group.sensorId === accessory.context.eweDeviceId && + group.type === "garage" + ) { if ((oAccessory = this.devicesInHB.get(group.deviceId + "SWX"))) { switch (newState) { case 0: @@ -1931,7 +2360,11 @@ class eWeLink { } }); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalFanUpdate(accessory, params) { @@ -1939,7 +2372,11 @@ class eWeLink { let light, status, speed; if (Array.isArray(params.switches)) { light = params.switches[0].switch === "on"; - switch (params.switches[1].switch + params.switches[2].switch + params.switches[3].switch) { + switch ( + params.switches[1].switch + + params.switches[2].switch + + params.switches[3].switch + ) { default: status = 0; speed = 0; @@ -1967,13 +2404,19 @@ class eWeLink { } else { throw "unknown parameters received"; } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, light); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, light); accessory .getService(Service.Fanv2) .updateCharacteristic(Characteristic.Active, status) .updateCharacteristic(Characteristic.RotationSpeed, speed); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalThermostatUpdate(accessory, params) { @@ -1985,7 +2428,9 @@ class eWeLink { let newState = params.hasOwnProperty("switch") ? params.switch === "on" : params.mainSwitch === "on"; - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, newState); + accessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, newState); } let eveLog = { time: Date.now(), @@ -1995,7 +2440,9 @@ class eWeLink { accessory.getService(Service.TemperatureSensor) ) { let currentTemp = - params.currentTemperature !== "unavailable" ? params.currentTemperature : 0; + params.currentTemperature !== "unavailable" + ? params.currentTemperature + : 0; accessory .getService(Service.TemperatureSensor) .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); @@ -2005,17 +2452,25 @@ class eWeLink { params.hasOwnProperty("currentHumidity") && accessory.getService(Service.HumiditySensor) ) { - let currentHumi = params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; + let currentHumi = + params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; accessory .getService(Service.HumiditySensor) - .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); + .updateCharacteristic( + Characteristic.CurrentRelativeHumidity, + currentHumi + ); eveLog.humidity = parseFloat(currentHumi); } if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { accessory.eveLogger.addEntry(eveLog); } } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalOutletUpdate(accessory, params) { @@ -2034,8 +2489,13 @@ class eWeLink { ); accessory .getService(Service.Outlet) - .updateCharacteristic(Characteristic.OutletInUse, parseFloat(params.power) > 0); - let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value; + .updateCharacteristic( + Characteristic.OutletInUse, + parseFloat(params.power) > 0 + ); + let isOn = accessory + .getService(Service.Outlet) + .getCharacteristic(Characteristic.On).value; accessory.eveLogger.addEntry({ time: Date.now(), power: isOn ? parseFloat(params.power) : 0, @@ -2044,7 +2504,10 @@ class eWeLink { if (params.hasOwnProperty("voltage")) { accessory .getService(Service.Outlet) - .updateCharacteristic(EveService.Characteristics.Voltage, parseFloat(params.voltage)); + .updateCharacteristic( + EveService.Characteristics.Voltage, + parseFloat(params.voltage) + ); } if (params.hasOwnProperty("current")) { accessory @@ -2055,25 +2518,43 @@ class eWeLink { ); } } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalUSBUpdate(accessory, params) { try { accessory .getService(Service.Outlet) - .updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); + .updateCharacteristic( + Characteristic.On, + params.switches[0].switch === "on" + ); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalSCMUpdate(accessory, params) { try { accessory .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); + .updateCharacteristic( + Characteristic.On, + params.switches[0].switch === "on" + ); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalSingleLightUpdate(accessory, params) { @@ -2083,13 +2564,20 @@ class eWeLink { isOn = false; if (accessory.context.eweUIID === 22 && params.hasOwnProperty("state")) { isOn = params.state === "on"; - } else if (accessory.context.eweUIID !== 22 && params.hasOwnProperty("switch")) { + } else if ( + accessory.context.eweUIID !== 22 && + params.hasOwnProperty("switch") + ) { isOn = params.switch === "on"; } else { - isOn = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; + isOn = accessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On).value; } if (isOn) { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, true); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, true); switch (accessory.context.eweUIID) { case 36: // KING-M4 if (params.hasOwnProperty("bright")) { @@ -2103,7 +2591,10 @@ class eWeLink { if (params.hasOwnProperty("brightness")) { accessory .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.Brightness, params.brightness); + .updateCharacteristic( + Characteristic.Brightness, + params.brightness + ); } break; case 22: // B1 @@ -2118,7 +2609,9 @@ class eWeLink { mode = 2; } if (mode === 2) { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, true); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, true); newColour = convert.rgb.hsv( parseInt(params.channel2), parseInt(params.channel3), @@ -2140,7 +2633,11 @@ class eWeLink { .updateCharacteristic(Characteristic.Brightness, params.bright); } if (params.hasOwnProperty("colorR")) { - newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB); + newColour = convert.rgb.hsv( + params.colorR, + params.colorG, + params.colorB + ); accessory .getService(Service.Lightbulb) .updateCharacteristic(Characteristic.Hue, newColour[0]) @@ -2151,10 +2648,16 @@ class eWeLink { return; } } else { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, false); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, false); } } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalMultiLightUpdate(accessory, params) { @@ -2166,15 +2669,24 @@ class eWeLink { let oAccessory = this.devicesInHB.get(idToCheck + i); oAccessory .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); + .updateCharacteristic( + Characteristic.On, + params.switches[i - 1].switch === "on" + ); if (params.switches[i - 1].switch === "on") { primaryState = true; } } } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, primaryState); + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, primaryState); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalSingleSwitchUpdate(accessory, params) { @@ -2183,7 +2695,11 @@ class eWeLink { .getService(Service.Switch) .updateCharacteristic(Characteristic.On, params.switch === "on"); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalMultiSwitchUpdate(accessory, params) { @@ -2195,15 +2711,24 @@ class eWeLink { let oAccessory = this.devicesInHB.get(idToCheck + i); oAccessory .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); + .updateCharacteristic( + Characteristic.On, + params.switches[i - 1].switch === "on" + ); if (params.switches[i - 1].switch === "on") { primaryState = true; } } } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState); + accessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, primaryState); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalRFDeviceUpdate(accessory, params) { @@ -2219,7 +2744,9 @@ class eWeLink { // RF Button let bAccessory; if ( - (bAccessory = this.devicesInHB.get(idToCheck + accessory.context.rfChlMap[params.rfChl])) + (bAccessory = this.devicesInHB.get( + idToCheck + accessory.context.rfChlMap[params.rfChl] + )) ) { bAccessory .getService(bAccessory.context.rfChls[params.rfChl]) @@ -2273,51 +2800,81 @@ class eWeLink { case "co": oAccessory .getService(Service.CarbonMonoxideSensor) - .updateCharacteristic(Characteristic.CarbonMonoxideDetected, 1); + .updateCharacteristic( + Characteristic.CarbonMonoxideDetected, + 1 + ); setTimeout(() => { oAccessory .getService(Service.CarbonMonoxideSensor) - .updateCharacteristic(Characteristic.CarbonMonoxideDetected, 0); + .updateCharacteristic( + Characteristic.CarbonMonoxideDetected, + 0 + ); }, (this.config.sensorTimeLength || 2) * 1000); break; case "co2": oAccessory .getService(Service.CarbonDioxideSensor) - .updateCharacteristic(Characteristic.CarbonDioxideDetected, 1); + .updateCharacteristic( + Characteristic.CarbonDioxideDetected, + 1 + ); setTimeout(() => { oAccessory .getService(Service.CarbonDioxideSensor) - .updateCharacteristic(Characteristic.CarbonDioxideDetected, 0); + .updateCharacteristic( + Characteristic.CarbonDioxideDetected, + 0 + ); }, (this.config.sensorTimeLength || 2) * 1000); break; case "contact": oAccessory .getService(Service.ContactSensor) - .updateCharacteristic(Characteristic.ContactSensorState, 1); + .updateCharacteristic( + Characteristic.ContactSensorState, + 1 + ); setTimeout(() => { oAccessory .getService(Service.ContactSensor) - .updateCharacteristic(Characteristic.ContactSensorState, 0); + .updateCharacteristic( + Characteristic.ContactSensorState, + 0 + ); }, (this.config.sensorTimeLength || 2) * 1000); break; case "occupancy": oAccessory .getService(Service.OccupancySensor) - .updateCharacteristic(Characteristic.OccupancyDetected, 1); + .updateCharacteristic( + Characteristic.OccupancyDetected, + 1 + ); setTimeout(() => { oAccessory .getService(Service.OccupancySensor) - .updateCharacteristic(Characteristic.OccupancyDetected, 0); + .updateCharacteristic( + Characteristic.OccupancyDetected, + 0 + ); }, (this.config.sensorTimeLength || 2) * 1000); break; default: oAccessory .getService(Service.MotionSensor) - .updateCharacteristic(Characteristic.MotionDetected, true); + .updateCharacteristic( + Characteristic.MotionDetected, + true + ); setTimeout(() => { oAccessory .getService(Service.MotionSensor) - .updateCharacteristic(Characteristic.MotionDetected, false); + .updateCharacteristic( + Characteristic.MotionDetected, + false + ); }, (this.config.sensorTimeLength || 2) * 1000); break; } @@ -2333,7 +2890,11 @@ class eWeLink { }); } } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } externalZBDeviceUpdate(accessory, params) { @@ -2343,15 +2904,24 @@ class eWeLink { let batteryService = accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); - batteryService.updateCharacteristic(Characteristic.BatteryLevel, params.battery); - batteryService.updateCharacteristic(Characteristic.StatusLowBattery, params.battery < 25); + batteryService.updateCharacteristic( + Characteristic.BatteryLevel, + params.battery + ); + batteryService.updateCharacteristic( + Characteristic.StatusLowBattery, + params.battery < 25 + ); } switch (accessory.context.eweUIID) { case 1000: if (params.hasOwnProperty("key") && [0, 1, 2].includes(params.key)) { accessory .getService(Service.StatelessProgrammableSwitch) - .updateCharacteristic(Characteristic.ProgrammableSwitchEvent, params.key); + .updateCharacteristic( + Characteristic.ProgrammableSwitchEvent, + params.key + ); } break; case 1770: @@ -2362,22 +2932,34 @@ class eWeLink { let currentTemp = parseInt(params.temperature) / 100; accessory .getService(Service.TemperatureSensor) - .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); + .updateCharacteristic( + Characteristic.CurrentTemperature, + currentTemp + ); eveLog.temp = parseFloat(currentTemp); } if (params.hasOwnProperty("humidity")) { let currentHumi = parseInt(params.humidity) / 100; accessory .getService(Service.HumiditySensor) - .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); + .updateCharacteristic( + Characteristic.CurrentRelativeHumidity, + currentHumi + ); eveLog.humidity = parseFloat(currentHumi); } - if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { + if ( + eveLog.hasOwnProperty("temp") || + eveLog.hasOwnProperty("humidity") + ) { accessory.eveLogger.addEntry(eveLog); } break; case 2026: - if (params.hasOwnProperty("motion") && params.hasOwnProperty("trigTime")) { + if ( + params.hasOwnProperty("motion") && + params.hasOwnProperty("trigTime") + ) { let timeNow = new Date(), diff = (timeNow.getTime() - params.trigTime) / 1000; accessory @@ -2395,12 +2977,19 @@ class eWeLink { if (params.hasOwnProperty("lock") && [0, 1].includes(params.lock)) { accessory .getService(Service.ContactSensor) - .updateCharacteristic(Characteristic.ContactSensorState, params.lock); + .updateCharacteristic( + Characteristic.ContactSensorState, + params.lock + ); } break; } } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.log.warn( + "[%s] could not be updated as %s.", + accessory.displayName, + err + ); } } } diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 24b1a69d..1aafd1e4 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -5,92 +5,29 @@ const axios = require("axios"), crypto = require("crypto"); module.exports = class eWeLinkHTTP { constructor(config, log) { + this.config = config; this.log = log; - this.debug = config.debug || false; - this.debugReqRes = config.debugReqRes || false; - this.username = config.username.toString(); - this.password = config.password.toString(); - this.cCode = "+" + config.countryCode.toString().replace("+", "").replace(" ", ""); - } - getHost() { - let data = { - appid: constants.appId, - country_code: this.cCode, - nonce: Math.random().toString(36).substr(2, 8), - ts: Math.floor(new Date().getTime() / 1000), - version: 8, - }, - dataToSign = []; - Object.keys(data).forEach(k => { - dataToSign.push({ - key: k, - value: data.k, - }); - }); - dataToSign.sort((a, b) => (a.key < b.key ? -1 : 1)); - dataToSign = dataToSign.map(k => k.key + "=" + k.value).join("&"); - dataToSign = crypto - .createHmac("sha256", constants.appSecret) - .update(dataToSign) - .digest("base64"); - if (this.debugReqRes) { - let msg = JSON.stringify(data, null, 2); - this.log.warn("Sending HTTP getHost request. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("Sending HTTP getHost request."); - } - return new Promise((resolve, reject) => { - axios - .get("https://api.coolkit.cc:8080/api/user/region", { - headers: { - Authorization: "Sign " + dataToSign, - "Content-Type": "application/json", - }, - params: data, - }) - .then(res => { - let body = res.data; - if (!body.region) { - throw "Server did not respond with a region.\n" + JSON.stringify(body, null, 2); - } - switch (body.region) { - case "eu": - case "us": - case "as": - this.httpHost = body.region + "-apia.coolkit.cc"; - break; - case "cn": - this.httpHost = "cn-apia.coolkit.cn"; - break; - default: - throw "No valid region received - [" + body.region + "]."; - } - if (this.debug) { - this.log("HTTP API host received [%s].", this.httpHost); - } - resolve(this.httpHost); - }) - .catch(err => { - if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { - this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); - this.delay().then(() => resolve(this.getHost())); - } else { - reject(err.message || err); - } - }); - }); + this.debug = this.config.debug || false; + this.debugReqRes = this.config.debugReqRes || false; } login() { let data = { - countryCode: this.cCode, - password: this.password, + countryCode: + "+" + + this.config.countryCode.toString().replace("+", "").replace(" ", ""), + password: this.config.password, }; - this.username.includes("@") ? (data.email = this.username) : (data.phoneNumber = this.username); + this.config.username.includes("@") + ? (data.email = this.config.username) + : (data.phoneNumber = this.config.username); if (this.debugReqRes) { let msg = JSON.stringify(data, null, 2) - .replace(this.password, "**hidden**") - .replace(this.username, "**hidden**"); - this.log.warn("Sending HTTP login request. This text is yellow for clarity.\n%s", msg); + .replace(this.config.password, "**hidden**") + .replace(this.config.username, "**hidden**"); + this.log.warn( + "Sending HTTP login request. This text is yellow for clarity.\n%s", + msg + ); } else if (this.debug) { this.log("Sending HTTP login request."); } @@ -119,18 +56,17 @@ module.exports = class eWeLinkHTTP { body.hasOwnProperty("data") && body.data.hasOwnProperty("region") ) { - let givenRegion = body.data.region; - switch (givenRegion) { + switch (body.data.region) { case "eu": case "us": case "as": - this.httpHost = givenRegion + "-apia.coolkit.cc"; + this.httpHost = body.data.region + "-apia.coolkit.cc"; break; case "cn": this.httpHost = "cn-apia.coolkit.cn"; break; default: - throw "No valid region received - [" + givenRegion + "]."; + throw "No valid region received - [" + body.data.region + "]."; } if (this.debug) { this.log("New HTTP API host received [%s].", this.httpHost); @@ -139,7 +75,10 @@ module.exports = class eWeLinkHTTP { return; } if (!body.data.at) { - throw "No auth token received.\n" + JSON.stringify(body, null, 2); + throw ( + "Server did not respond with an authentication token. Please double check your eWeLink username and password in the Homebridge configuration.\n" + + JSON.stringify(body, null, 2) + ); } this.aToken = body.data.at; this.apiKey = body.data.user.apikey; @@ -149,95 +88,111 @@ module.exports = class eWeLinkHTTP { httpHost: this.httpHost, }); }) - .catch(err => reject(err.message || err)); + .catch(err => { + reject(err); + }); }); } - getDevices() { + getHost() { + let data = { + appid: constants.appId, + country_code: this.config.countryCode + .toString() + .replace("+", "") + .replace(" ", ""), + nonce: Math.random().toString(36).substr(2, 8), + ts: Math.floor(new Date().getTime() / 1000), + version: 8, + }, + dataToSign = []; + Object.keys(data).forEach(function (key) { + dataToSign.push({ + key: key, + value: data[key], + }); + }); + dataToSign.sort(function (a, b) { + return a.key < b.key ? -1 : 1; + }); + dataToSign = dataToSign + .map(function (kv) { + return kv.key + "=" + kv.value; + }) + .join("&"); + dataToSign = crypto + .createHmac("sha256", constants.appSecret) + .update(dataToSign) + .digest("base64"); return new Promise((resolve, reject) => { axios - .get("https://" + this.httpHost + "/v2/device/thing", { + .get("https://api.coolkit.cc:8080/api/user/region", { headers: { - Authorization: "Bearer " + this.aToken, + Authorization: "Sign " + dataToSign, "Content-Type": "application/json", - Host: this.httpHost, - "X-CK-Appid": constants.appId, - "X-CK-Nonce": Math.random().toString(36).substr(2, 8), }, + params: data, }) .then(res => { let body = res.data; - if ( - !body.hasOwnProperty("data") || - !body.hasOwnProperty("error") || - (body.hasOwnProperty("error") && body.error !== 0) - ) { - throw JSON.stringify(body, null, 2); + if (!body.region) { + throw ( + "Server did not respond with a region.\n" + + JSON.stringify(body, null, 2) + ); } - let deviceList = []; - if (body.data.thingList && body.data.thingList.length > 0) { - body.data.thingList.forEach(device => deviceList.push(device.itemData)); + switch (body.region) { + case "eu": + case "us": + case "as": + this.httpHost = body.region + "-apia.coolkit.cc"; + break; + case "cn": + this.httpHost = "cn-apia.coolkit.cn"; + break; + default: + throw "No valid region received - [" + body.region + "]."; } - resolve(deviceList); + if (this.debug) { + this.log("HTTP API host received [%s].", this.httpHost); + } + resolve(this.httpHost); }) .catch(err => { - if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { - this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); - this.delay().then(() => resolve(this.getDevices())); - } else { - reject(err.message || err); - } + reject(err); }); }); } - - getDevice(deviceId) { + getDevices() { return new Promise((resolve, reject) => { - axios({ - url: "https://" + this.httpHost + "/v2/device/thing", - method: "post", - headers: { - Authorization: "Bearer " + this.aToken, - "Content-Type": "application/json", - Host: this.httpHost, - "X-CK-Appid": constants.appId, - "X-CK-Nonce": Math.random().toString(36).substr(2, 8), - }, - data: { - thingList: [ - { - itemType: 1, - id: deviceId, - }, - ], - }, - }) + axios + .get("https://" + this.httpHost + "/v2/device/thing", { + headers: { + Authorization: "Bearer " + this.aToken, + "Content-Type": "application/json", + Host: this.httpHost, + "X-CK-Appid": constants.appId, + "X-CK-Nonce": Math.random().toString(36).substr(2, 8), + }, + }) .then(res => { let body = res.data; if ( - !body.hasOwnProperty("data") || !body.hasOwnProperty("error") || (body.hasOwnProperty("error") && body.error !== 0) ) { throw JSON.stringify(body, null, 2); } - if (body.data.thingList && body.data.thingList.length === 1) { - resolve(body.data.thingList[0].itemData); - } else { - throw "device not found in eWeLink"; + let deviceList = []; + if (body.data.thingList && body.data.thingList.length > 0) { + body.data.thingList.forEach(device => + deviceList.push(device.itemData) + ); } + resolve(deviceList); }) .catch(err => { - if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { - this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); - this.delay().then(() => resolve(this.getDevice(deviceId))); - } else { - reject(err.message || err); - } + reject(err); }); }); } - - delay() { - return new Promise(resolve => setTimeout(resolve, 30000)); - } }; diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 567c372d..25baee53 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -1,18 +1,19 @@ /* jshint esversion: 9, -W030, node: true */ "use strict"; const axios = require("axios"), - cns = require("./constants"), + constants = require("./constants"), crypto = require("crypto"), dns = require("node-dns-sd"), eventemitter = require("events"); module.exports = class eWeLinkLAN { constructor(config, log, devices) { + this.config = config; this.log = log; this.devices = devices; - this.ipOverrides = config.ipOverride || {}; - this.deviceMap = new Map(); + this.ipOverrides = this.config.ipOverride || {}; + let deviceMap = new Map(); devices.forEach(device => { - this.deviceMap.set(device.deviceid, { + deviceMap.set(device.deviceid, { apiKey: device.devicekey, online: this.ipOverrides.hasOwnProperty(device.deviceid) ? true : false, ip: this.ipOverrides.hasOwnProperty(device.deviceid) @@ -20,8 +21,9 @@ module.exports = class eWeLinkLAN { : null, }); }); - this.debug = config.debug || false; - this.debugReqRes = config.debugReqRes || false; + this.deviceMap = deviceMap; + this.debug = this.config.debug || false; + this.debugReqRes = this.config.debugReqRes || false; this.emitter = new eventemitter(); } getHosts() { @@ -34,7 +36,9 @@ module.exports = class eWeLinkLAN { let onlineCount = 0; res.forEach(device => { let d, - deviceId = device.fqdn.replace("._ewelink._tcp.local", "").replace("eWeLink_", ""); + deviceId = device.fqdn + .replace("._ewelink._tcp.local", "") + .replace("eWeLink_", ""); if ((d = this.deviceMap.get(deviceId))) { if (!this.ipOverrides.hasOwnProperty(deviceId)) { this.deviceMap.set(deviceId, { @@ -51,7 +55,9 @@ module.exports = class eWeLinkLAN { count: onlineCount, }); }) - .catch(err => reject(err)); + .catch(err => { + reject(err); + }); }); } startMonitor() { @@ -73,44 +79,64 @@ module.exports = class eWeLinkLAN { .createHash("md5") .update(Buffer.from(deviceInfo.apiKey, "utf8")) .digest(), - dText = crypto.createDecipheriv("aes-128-cbc", key, Buffer.from(rdata.iv, "base64")), + dText = crypto.createDecipheriv( + "aes-128-cbc", + key, + Buffer.from(rdata.iv, "base64") + ), pText = Buffer.concat([ dText.update(Buffer.from(data, "base64")), dText.final(), ]).toString("utf8"), params; - if (packet.address !== deviceInfo.ip && !this.ipOverrides.hasOwnProperty(rdata.id)) { + if ( + packet.address !== deviceInfo.ip && + !this.ipOverrides.hasOwnProperty(rdata.id) + ) { this.deviceMap.set(rdata.id, { apiKey: deviceInfo.apiKey, online: true, ip: packet.address, }); if (this.debug) { - this.log.warn("[%s] updating IP address to [%s].", rdata.id, packet.address); + this.log.warn( + "[%s] updating IP address to [%s].", + rdata.id, + packet.address + ); } } try { params = JSON.parse(pText); } catch (e) { - this.log.warn("[%s] An error occured reading the LAN message [%s]", rdata.id, e); + this.log.warn( + "[%s] An error occured reading the LAN message [%s]", + rdata.id, + e + ); return; } for (let param in params) { if (params.hasOwnProperty(param)) { - if (!cns.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { + if ( + !constants.paramsToKeep.includes(param.replace(/[0-9]/g, "")) + ) { delete params[param]; } } } if (Object.keys(params).length > 0) { params.updateSource = "LAN"; - params.online = true; let returnTemplate = { deviceid: rdata.id, + action: "update", params, }; if (this.debugReqRes) { - let msg = JSON.stringify(returnTemplate, null, 2).replace(rdata.id, "**hidden**"); + let msg = JSON.stringify(returnTemplate, null, 2).replace( + rdata.id, + "**hidden**" + ); this.log("LAN message received.\n%s", msg); } else if (this.debug) { this.log("LAN message received."); @@ -123,8 +149,12 @@ module.exports = class eWeLinkLAN { return new Promise((resolve, reject) => { dns .startMonitoring() - .then(() => resolve()) - .catch(err => reject(err)); + .then(() => { + resolve(); + }) + .catch(err => { + reject(err); + }); }); } sendUpdate(json) { @@ -145,13 +175,17 @@ module.exports = class eWeLinkLAN { throw "plugin does not support lan mode for this device yet - feel free to create a github issue"; } if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { - let key = crypto.createHash("md5").update(Buffer.from(apiKey, "utf8")).digest(), + let key = crypto + .createHash("md5") + .update(Buffer.from(apiKey, "utf8")) + .digest(), iv = crypto.randomBytes(16), enc = crypto.createCipheriv("aes-128-cbc", key, iv), data = { - data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString( - "base64" - ), + data: Buffer.concat([ + enc.update(JSON.stringify(params)), + enc.final(), + ]).toString("base64"), deviceid: json.deviceid, encrypt: true, iv: iv.toString("base64"), @@ -163,13 +197,20 @@ module.exports = class eWeLinkLAN { .replace(json.apikey, "**hidden**") .replace(json.apikey, "**hidden**") .replace(json.deviceid, "**hidden**"); - this.log.warn("LAN message sent. This text is yellow for clarity.\n%s", msg); + this.log.warn( + "LAN message sent. This text is yellow for clarity.\n%s", + msg + ); } else if (this.debug) { this.log("LAN message sent."); } axios({ method: "post", - url: "http://" + this.deviceMap.get(json.deviceid).ip + ":8081/zeroconf/" + suffix, + url: + "http://" + + this.deviceMap.get(json.deviceid).ip + + ":8081/zeroconf/" + + suffix, headers: { Accept: "application/json", "Content-Type": "application/json", @@ -182,7 +223,9 @@ module.exports = class eWeLinkLAN { } throw res.data; }) - .catch(err => reject(err)); + .catch(err => { + reject(err); + }); } }); } diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 29d265cc..56fbeb64 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -1,7 +1,7 @@ /* jshint esversion: 9, -W030, node: true */ "use strict"; const axios = require("axios"), - cns = require("./constants"), + constants = require("./constants"), eventemitter = require("events"), ws = require("ws"); module.exports = class eWeLinkWS { @@ -21,13 +21,14 @@ module.exports = class eWeLinkWS { return new Promise((resolve, reject) => { axios({ method: "post", - url: "https://" + this.httpHost.replace("-api", "-disp") + "/dispatch/app", + url: + "https://" + this.httpHost.replace("-api", "-disp") + "/dispatch/app", headers: { Authorization: "Bearer " + this.aToken, "Content-Type": "application/json", }, data: { - appid: cns.appId, + appid: constants.appId, nonce: Math.random().toString(36).substr(2, 8), ts: Math.floor(new Date().getTime() / 1000), version: 8, @@ -45,12 +46,7 @@ module.exports = class eWeLinkWS { resolve(body.domain); }) .catch(err => { - if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { - this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); - this.delay().then(() => resolve(this.getDevices())); - } else { - reject(err.message || err); - } + reject(err); }); }); } @@ -61,7 +57,7 @@ module.exports = class eWeLinkWS { let payload = { action: "userOnline", apikey: this.apiKey, - appid: cns.appId, + appid: constants.appId, at: this.aToken, nonce: Math.random().toString(36).substr(2, 8), sequence: Math.floor(new Date()), @@ -74,60 +70,91 @@ module.exports = class eWeLinkWS { let msg = JSON.stringify(payload, null, 2) .replace(this.aToken, "**hidden**") .replace(this.apiKey, "**hidden**"); - this.log.warn("Sending WS login request. This text is yellow for clarity.\n%s", msg); + this.log.warn( + "Sending WS login request. This text is yellow for clarity.\n%s", + msg + ); } else if (this.debug) { this.log("Sending WS login request."); } }); this.ws.on("message", m => { - if (m === "pong") return; - let device, - onlineStatus = true; + if (m === "pong") { + return; + } + let device; try { device = JSON.parse(m); - } catch (err) { - this.log.warn("An error occured reading the WS message [%s]", err); + } catch (e) { + this.log.warn( + "An error occured reading the web socket message [%s]", + e + ); return; } - //*** for heartbeat response ***\\ + // for requestUpdate response + if ( + device.hasOwnProperty("deviceid") && + device.hasOwnProperty("params") && + device.hasOwnProperty("error") && + device.error === 0 + ) { + device.action = "update"; + } else if ( + device.hasOwnProperty("deviceid") && + device.hasOwnProperty("error") && + device.error === 504 + ) { + device.action = "sysmsg"; + device.params = { + online: false, + }; + } + // for external updates if ( device.hasOwnProperty("config") && device.config.hb && device.config.hbInterval && !this.hbInterval ) { - this.hbInterval = setInterval( - () => this.ws.send("ping"), - (device.config.hbInterval + 7) * 1000 - ); - return; - } - if (!device.hasOwnProperty("params")) device.params = {}; - //*** for requestUpdate response ***\\ - if (device.hasOwnProperty("deviceid") && device.hasOwnProperty("error")) { - device.action = "update"; - onlineStatus = device.error === 0; - } - //*** for all updates including above ***\\ - if (device.hasOwnProperty("action")) { + this.hbInterval = setInterval(() => { + this.ws.send("ping"); + }, (device.config.hbInterval + 7) * 1000); + } else if (device.hasOwnProperty("action")) { switch (device.action) { - case "update": case "sysmsg": - if (device.action === "sysmsg" && device.params.hasOwnProperty("online")) { - onlineStatus = device.params.online; + device.params.updateSource = "WS"; + let returnTemplate = { + deviceid: device.deviceid, + action: "sysmsg", + params: device.params, + }; + if (this.debugReqRes) { + let msg = JSON.stringify(returnTemplate, null, 2).replace( + device.deviceid, + "**hidden**" + ); + this.log("WS message received.\n%s", msg); + } else if (this.debug) { + this.log("WS message received."); } + this.emitter.emit("update", returnTemplate); + break; + case "update": for (let param in device.params) { if (device.params.hasOwnProperty(param)) { - if (!cns.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { + if ( + !constants.paramsToKeep.includes(param.replace(/[0-9]/g, "")) + ) { delete device.params[param]; } } } - device.params.online = onlineStatus; - device.params.updateSource = "WS"; if (Object.keys(device.params).length > 0) { + device.params.updateSource = "WS"; let returnTemplate = { deviceid: device.deviceid, + action: "update", params: device.params, }; if (this.debugReqRes) { @@ -146,7 +173,8 @@ module.exports = class eWeLinkWS { return; default: this.log.warn( - "[%s] WS message has unknown action.\n" + JSON.stringify(device, null, 2), + "[%s] WS message has unknown action.\n" + + JSON.stringify(device, null, 2), device.deviceid ); return; @@ -155,7 +183,9 @@ module.exports = class eWeLinkWS { // *** Safe to ignore these messages *** \\ } else { if (this.debug) { - this.log.warn("WS unknown command received.\n" + JSON.stringify(device, null, 2)); + this.log.warn( + "WS unknown command received.\n" + JSON.stringify(device, null, 2) + ); } } }); @@ -163,13 +193,16 @@ module.exports = class eWeLinkWS { if (m === "Stopping Homebridge") { this.log("Web socket gracefully closed."); } else { - this.log.warn("Web socket closed - [%s%s].", e, m ? " - " + m : ""); + this.log.warn("Web socket closed - [%s - %s].", e, m); if (e !== 1000) { this.log("Web socket will try to reconnect in five seconds."); - this.ws.removeAllListeners(); - setTimeout(() => this.login(), 5000); + setTimeout(() => { + this.login(); + }, 5000); } else { - this.log("Please try restarting Homebridge so that this plugin can work again."); + this.log( + "Please try restarting Homebridge so that this plugin can work again." + ); } } this.wsIsOpen = false; @@ -186,9 +219,13 @@ module.exports = class eWeLinkWS { "Web socket will try to reconnect in five seconds then try the command again." ); this.ws.removeAllListeners(); - setTimeout(() => this.login(), 5000); + setTimeout(() => { + this.login(); + }, 5000); } else { - this.log.warn("If this was unexpected then please try restarting Homebridge."); + this.log.warn( + "If this was unexpected then please try restarting Homebridge." + ); } }); } @@ -203,7 +240,9 @@ module.exports = class eWeLinkWS { }; let sendOperation = req => { if (!this.wsIsOpen) { - setTimeout(() => sendOperation(req), 280); + setTimeout(() => { + sendOperation(req); + }, 280); return; } if (this.ws) { @@ -213,7 +252,10 @@ module.exports = class eWeLinkWS { .replace(json.apikey, "**hidden**") .replace(json.apiKey, "**hidden**") .replace(json.deviceid, "**hidden**"); - this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); + this.log.warn( + "WS message sent. This text is yellow for clarity.\n%s", + msg + ); } else if (this.debug) { this.log("WS message sent."); } @@ -226,7 +268,9 @@ module.exports = class eWeLinkWS { setTimeout(sendOperation, this.delaySend, string); this.delaySend += 280; } else { - this.log.warn("Web socket is currently reconnecting. Command will be resent."); + this.log.warn( + "Web socket is currently reconnecting. Command will be resent." + ); let interval, waitToSend = req => { if (this.wsIsOpen) { @@ -249,7 +293,9 @@ module.exports = class eWeLinkWS { }, sendOperation = req => { if (!this.wsIsOpen) { - setTimeout(() => sendOperation(req), 280); + setTimeout(() => { + sendOperation(req); + }, 280); return; } if (this.ws) { @@ -259,7 +305,10 @@ module.exports = class eWeLinkWS { .replace(json.apikey, "**hidden**") .replace(json.apiKey, "**hidden**") .replace(json.deviceid, "**hidden**"); - this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); + this.log.warn( + "WS message sent. This text is yellow for clarity.\n%s", + msg + ); } else if (this.debug) { this.log("WS message sent."); } @@ -272,7 +321,9 @@ module.exports = class eWeLinkWS { setTimeout(sendOperation, this.delaySend, string); this.delaySend += 280; } else { - this.log.warn("Web socket is currently reconnecting. Command will be resent."); + this.log.warn( + "Web socket is currently reconnecting. Command will be resent." + ); let interval, waitToSend = req => { if (this.wsIsOpen) { @@ -291,7 +342,4 @@ module.exports = class eWeLinkWS { this.ws.close(1000, "Stopping Homebridge"); } } - delay() { - return new Promise(resolve => setTimeout(resolve, 30000)); - } }; From d6bb05899b2bd2851730bbabb987d08a6f11653f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 16 Sep 2020 16:58:55 +0100 Subject: [PATCH 0165/3183] zb door sensor battery --- lib/eWeLink.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 13c6d210..38a71cdf 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -2901,6 +2901,12 @@ class eWeLink { try { //*** credit @tasict ***\\ if (params.hasOwnProperty("battery")) { + if ( + accessory.context.eweUIID === 3026 && + (this.config.ZBDWBatt || false) + ) { + params.battery *= 10; + } let batteryService = accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); From cf6c8ff3514ded399f341668ea6a7ea42203b849 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 16 Sep 2020 17:01:23 +0100 Subject: [PATCH 0166/3183] prettier line length --- .prettierrc.json | 3 +- lib/constants.js | 7 +- lib/eWeLink.js | 1082 +++++++++++--------------------------------- lib/eWeLinkHTTP.js | 28 +- lib/eWeLinkLAN.js | 59 +-- lib/eWeLinkWS.js | 50 +- 6 files changed, 298 insertions(+), 931 deletions(-) diff --git a/.prettierrc.json b/.prettierrc.json index d68aa739..87f5e5e8 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,3 +1,4 @@ { - "arrowParens": "avoid" + "arrowParens": "avoid", + "printWidth": 100 } diff --git a/lib/constants.js b/lib/constants.js index d8892025..fe7fcb40 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -40,12 +40,7 @@ module.exports = { devicesSensor: [102], devicesSensorParams: ["switch", "battery"], devicesThermostat: [15], - devicesThermostatParams: [ - "currentTemperature", - "currentHumidity", - "switch", - "masterSwitch", - ], + devicesThermostatParams: ["currentTemperature", "currentHumidity", "switch", "masterSwitch"], devicesFan: [34], devicesFanParams: ["switches", "light", "fan", "speed"], devicesOutlet: [32], diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 38a71cdf..10049c96 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -13,15 +13,9 @@ class eWeLink { constructor(log, config, api) { if (!log || !api || !config) return; if (!config.username || !config.password || !config.countryCode) { - log.error( - "**************** Cannot load homebridge-ewelink ****************" - ); - log.error( - "Your eWeLink credentials are missing from the Homebridge config." - ); - log.error( - "****************************************************************" - ); + log.error("**************** Cannot load homebridge-ewelink ****************"); + log.error("Your eWeLink credentials are missing from the Homebridge config."); + log.error("****************************************************************"); return; } this.log = log; @@ -57,22 +51,11 @@ class eWeLink { //*** Get device IP addresses for LAN mode ***\\ this.httpDevices = res .filter( - device => - device.hasOwnProperty("extra") && - device.extra.hasOwnProperty("uiid") + device => device.hasOwnProperty("extra") && device.extra.hasOwnProperty("uiid") ) - .filter( - device => - !(this.config.hideDevFromHB || "").includes(device.deviceid) - ); - this.lanClient = new eWeLinkLAN( - this.config, - this.log, - this.httpDevices - ); - this.httpDevices.forEach(device => - this.devicesInEwe.set(device.deviceid, device) - ); + .filter(device => !(this.config.hideDevFromHB || "").includes(device.deviceid)); + this.lanClient = new eWeLinkLAN(this.config, this.log, this.httpDevices); + this.httpDevices.forEach(device => this.devicesInEwe.set(device.deviceid, device)); return this.lanClient.getHosts(); }) .then(res => { @@ -89,9 +72,7 @@ class eWeLink { Object.keys(this.httpDevices).length === 0 && Object.keys(this.lanDevices).length === 0 ) { - Array.from(this.devicesInHB.values()).forEach(a => - this.removeAccessory(a) - ); + Array.from(this.devicesInHB.values()).forEach(a => this.removeAccessory(a)); this.devicesInHB.clear(); this.log.warn("******* Not loading homebridge-ewelink *******"); this.log.warn("No devices were found in your eWeLink account."); @@ -101,11 +82,7 @@ class eWeLink { //*** Make a map of custom groups from Homebridge config ***\\ if (Object.keys(this.config.groups || []).length > 0) { this.config.groups - .filter( - g => - g.hasOwnProperty("type") && - cns.allowedGroups.includes(g.type) - ) + .filter(g => g.hasOwnProperty("type") && cns.allowedGroups.includes(g.type)) .filter( g => g.hasOwnProperty("deviceId") && @@ -157,13 +134,9 @@ class eWeLink { })(); }) .catch(err => { - this.log.error( - "************** Cannot load homebridge-ewelink **************" - ); + this.log.error("************** Cannot load homebridge-ewelink **************"); this.log.error(err); - this.log.error( - "************************************************************" - ); + this.log.error("************************************************************"); if (this.lanClient) this.lanClient.closeConnection(); if (this.wsClient) this.wsClient.closeConnection(); }); @@ -233,9 +206,7 @@ class eWeLink { } } else if (cns.devicesRFBridge.includes(device.extra.uiid)) { this.addAccessory(device, device.deviceid + "SW0", "rf_pri"); - if ( - Object.keys((device.tags && device.tags.zyx_info) || []).length > 0 - ) { + if (Object.keys((device.tags && device.tags.zyx_info) || []).length > 0) { for (let i = 1; i <= Object.keys(device.tags.zyx_info).length; i++) { this.addAccessory(device, device.deviceid + "SW" + i, "rf_sub"); } @@ -269,19 +240,12 @@ class eWeLink { rfBridgeChange = false; accessory .getService(Service.AccessoryInformation) - .setCharacteristic( - Characteristic.FirmwareRevision, - device.params.fwVersion - ); - accessory.context.reachableWAN = - accessory.context.eweUIID !== 102 ? device.online : true; - accessory.context.reachableLAN = - this.lanDevices.get(device.deviceid).online || false; + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); + accessory.context.reachableWAN = accessory.context.eweUIID !== 102 ? device.online : true; + accessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; accessory.context.inUse = false; let str = accessory.context.reachableLAN - ? "and locally with IP [" + - this.lanDevices.get(device.deviceid).ip + - "]" + ? "and locally with IP [" + this.lanDevices.get(device.deviceid).ip + "]" : "but LAN mode unavailable as unsupported/shared device"; this.log("[%s] found in eWeLink %s.", accessory.displayName, str); this.devicesInHB.set(accessory.context.hbDeviceId, accessory); @@ -289,11 +253,7 @@ class eWeLink { for (let i = 1; i <= accessory.context.channelCount; i++) { if (!this.devicesInHB.has(device.deviceid + "SW" + i)) { if (cns.devicesHideable.includes(accessory.context.type)) { - if ( - (this.config.hideFromHB || "").includes( - device.deviceid + "SW" + i - ) - ) { + if ((this.config.hideFromHB || "").includes(device.deviceid + "SW" + i)) { continue; } else { this.addAccessory(device, device.deviceid + "SW" + i, "switch"); @@ -302,9 +262,7 @@ class eWeLink { } let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); if ( - (this.config.hideFromHB || "").includes( - device.deviceid + "SW" + i - ) && + (this.config.hideFromHB || "").includes(device.deviceid + "SW" + i) && cns.devicesHideable.includes(accessory.context.type) ) { this.removeAccessory(oAccessory); @@ -318,13 +276,9 @@ class eWeLink { } oAccessory .getService(Service.AccessoryInformation) - .setCharacteristic( - Characteristic.FirmwareRevision, - device.params.fwVersion - ); + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); oAccessory.context.reachableWAN = device.online; - oAccessory.context.reachableLAN = - this.lanDevices.get(device.deviceid).online || false; + oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); } } @@ -349,18 +303,12 @@ class eWeLink { ); } } else { - this.log.warn( - "[%s] cannot be initialised as it wasn't found in Homebridge.", - device.name - ); + this.log.warn("[%s] cannot be initialised as it wasn't found in Homebridge.", device.name); } } addAccessory(device, hbDeviceId, type) { let switchNumber = hbDeviceId.substr(-1).toString(), - newDeviceName = - type === "rf_sub" - ? device.tags.zyx_info[switchNumber - 1].name - : device.name, + newDeviceName = type === "rf_sub" ? device.tags.zyx_info[switchNumber - 1].name : device.name, channelCount = type === "rf_pri" ? Object.keys((device.tags && device.tags.zyx_info) || []).length @@ -378,10 +326,7 @@ class eWeLink { if ((this.config.nameOverride || {}).hasOwnProperty(hbDeviceId)) { newDeviceName = this.config.nameOverride[hbDeviceId]; } - const accessory = new Accessory( - newDeviceName, - UUIDGen.generate(hbDeviceId).toString() - ); + const accessory = new Accessory(newDeviceName, UUIDGen.generate(hbDeviceId).toString()); try { accessory .getService(Service.AccessoryInformation) @@ -391,10 +336,7 @@ class eWeLink { Characteristic.Model, device.productModel + " (" + device.extra.model + ")" ) - .setCharacteristic( - Characteristic.FirmwareRevision, - device.params.fwVersion - ) + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) .setCharacteristic(Characteristic.Identify, false); accessory.context = { hbDeviceId, @@ -410,18 +352,11 @@ class eWeLink { case "valve": ["A", "B"].forEach(v => { accessory - .addService( - Service.Valve, - "Valve " + v, - "valve" + v.toLowerCase() - ) + .addService(Service.Valve, "Valve " + v, "valve" + v.toLowerCase()) .setCharacteristic(Characteristic.Active, 0) .setCharacteristic(Characteristic.InUse, 0) .setCharacteristic(Characteristic.ValveType, 1) - .setCharacteristic( - Characteristic.SetDuration, - this.config.valveTimeLength || 120 - ) + .setCharacteristic(Characteristic.SetDuration, this.config.valveTimeLength || 120) .addCharacteristic(Characteristic.RemainingDuration); }); break; @@ -456,8 +391,7 @@ class eWeLink { case "thermostat": if (!this.config.hideTHSwitch) accessory.addService(Service.Switch); accessory.addService(Service.TemperatureSensor); - if (device.params.sensorType !== "DS18B20") - accessory.addService(Service.HumiditySensor); + if (device.params.sensorType !== "DS18B20") accessory.addService(Service.HumiditySensor); break; case "outlet": accessory.addService(Service.Outlet); @@ -503,9 +437,7 @@ class eWeLink { break; case "rf_sub": accessory.context.rfChls = {}; - switch ( - device.tags.zyx_info[parseInt(switchNumber) - 1].remote_type - ) { + switch (device.tags.zyx_info[parseInt(switchNumber) - 1].remote_type) { case "1": case "2": case "3": @@ -525,52 +457,46 @@ class eWeLink { ); } let mAccessory = this.devicesInHB.get(device.deviceid + "SW0"); - device.tags.zyx_info[parseInt(switchNumber) - 1].buttonName.forEach( - button => { - let rfData; - Object.entries(button).forEach( - ([k, v]) => - (rfData = { - rfChan: k, - name: v, - }) - ); - accessory.context.rfChls[rfData.rfChan] = rfData.name; - mAccessory.context.rfChlMap[rfData.rfChan] = switchNumber; - switch (accessory.context.sensorType) { - case "button": - accessory.addService( - Service.Switch, - rfData.name, - "switch" + rfData.rfChan - ); - break; - case "water": - accessory.addService(Service.LeakSensor); - break; - case "fire": - case "smoke": - accessory.addService(Service.SmokeSensor); - break; - case "co": - accessory.addService(Service.CarbonMonoxideSensor); - break; - case "co2": - accessory.addService(Service.CarbonDioxideSensor); - break; - case "contact": - accessory.addService(Service.ContactSensor); - break; - case "occupancy": - accessory.addService(Service.OccupancySensor); - break; - default: - accessory.addService(Service.MotionSensor); - break; - } - this.devicesInHB.set(mAccessory.context.hbDeviceId, mAccessory); + device.tags.zyx_info[parseInt(switchNumber) - 1].buttonName.forEach(button => { + let rfData; + Object.entries(button).forEach( + ([k, v]) => + (rfData = { + rfChan: k, + name: v, + }) + ); + accessory.context.rfChls[rfData.rfChan] = rfData.name; + mAccessory.context.rfChlMap[rfData.rfChan] = switchNumber; + switch (accessory.context.sensorType) { + case "button": + accessory.addService(Service.Switch, rfData.name, "switch" + rfData.rfChan); + break; + case "water": + accessory.addService(Service.LeakSensor); + break; + case "fire": + case "smoke": + accessory.addService(Service.SmokeSensor); + break; + case "co": + accessory.addService(Service.CarbonMonoxideSensor); + break; + case "co2": + accessory.addService(Service.CarbonDioxideSensor); + break; + case "contact": + accessory.addService(Service.ContactSensor); + break; + case "occupancy": + accessory.addService(Service.OccupancySensor); + break; + default: + accessory.addService(Service.MotionSensor); + break; } - ); + this.devicesInHB.set(mAccessory.context.hbDeviceId, mAccessory); + }); break; case "zb_sub": //*** credit @tasict ***\\ accessory.addService(Service.BatteryService); @@ -608,9 +534,7 @@ class eWeLink { throw "device is not supported by this plugin. Please create an issue on GitHub"; } this.devicesInHB.set(hbDeviceId, accessory); - this.api.registerPlatformAccessories("homebridge-ewelink", "eWeLink", [ - accessory, - ]); + this.api.registerPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); this.configureAccessory(accessory); this.log("[%s] has been added to Homebridge.", newDeviceName); } catch (err) { @@ -629,33 +553,21 @@ class eWeLink { .getService("Valve " + v) .getCharacteristic(Characteristic.Active) .on("set", (value, callback) => - this.internalValveUpdate( - accessory, - "Valve " + v, - value, - callback - ) + this.internalValveUpdate(accessory, "Valve " + v, value, callback) ); accessory .getService("Valve " + v) .getCharacteristic(Characteristic.SetDuration) .on("set", (value, callback) => { if ( - accessory - .getService("Valve " + v) - .getCharacteristic(Characteristic.InUse).value + accessory.getService("Valve " + v).getCharacteristic(Characteristic.InUse).value ) { accessory .getService("Valve " + v) - .updateCharacteristic( - Characteristic.RemainingDuration, - value - ); + .updateCharacteristic(Characteristic.RemainingDuration, value); clearTimeout(accessory.getService("Valve " + v).timer); accessory.getService("Valve " + v).timer = setTimeout(() => { - accessory - .getService("Valve " + v) - .setCharacteristic(Characteristic.Active, 0); + accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); }, value * 1000); } callback(); @@ -666,9 +578,7 @@ class eWeLink { accessory .getService(Service.WindowCovering) .getCharacteristic(Characteristic.TargetPosition) - .on("set", (value, callback) => - this.internalBlindUpdate(accessory, value, callback) - ) + .on("set", (value, callback) => this.internalBlindUpdate(accessory, value, callback)) .setProps({ minStep: 100, }); @@ -677,17 +587,13 @@ class eWeLink { accessory .getService(Service.GarageDoorOpener) .getCharacteristic(Characteristic.TargetDoorState) - .on("set", (value, callback) => - this.internalGarageUpdate(accessory, value, callback) - ); + .on("set", (value, callback) => this.internalGarageUpdate(accessory, value, callback)); break; case "lock": accessory .getService(Service.LockMechanism) .getCharacteristic(Characteristic.LockTargetState) - .on("set", (value, callback) => - this.internalLockUpdate(accessory, value, callback) - ); + .on("set", (value, callback) => this.internalLockUpdate(accessory, value, callback)); break; case "fan": accessory @@ -737,9 +643,7 @@ class eWeLink { if (accessory.getService(Service.HumiditySensor)) { dataToAdd.humidity = accessory .getService(Service.HumiditySensor) - .getCharacteristic( - Characteristic.CurrentRelativeHumidity - ).value; + .getCharacteristic(Characteristic.CurrentRelativeHumidity).value; } accessory.eveLogger.addEntry(dataToAdd); }, 300000); @@ -748,9 +652,7 @@ class eWeLink { accessory .getService(Service.Outlet) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => - this.internalOutletUpdate(accessory, value, callback) - ); + .on("set", (value, callback) => this.internalOutletUpdate(accessory, value, callback)); accessory.log = this.log; accessory.eveLogger = new EveHistoryService("energy", accessory, { storage: "fs", @@ -769,15 +671,12 @@ class eWeLink { }; } corrInterval.setCorrectingInterval(() => { - let isOn = accessory - .getService(Service.Outlet) - .getCharacteristic(Characteristic.On).value, + let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) + .value, currentWatt = isOn ? accessory .getService(Service.Outlet) - .getCharacteristic( - EveService.Characteristics.CurrentConsumption - ).value + .getCharacteristic(EveService.Characteristics.CurrentConsumption).value : 0; if (accessory.eveLogger.isHistoryLoaded()) { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); @@ -792,8 +691,7 @@ class eWeLink { }); } else { accessory.context.totalEnergy = - accessory.context.totalEnergyTemp + - (currentWatt * 10) / 3600 / 1000; + accessory.context.totalEnergyTemp + (currentWatt * 10) / 3600 / 1000; accessory.eveLogger.setExtraPersistedData({ totalenergy: accessory.context.totalEnergy, lastReset: 0, @@ -801,8 +699,7 @@ class eWeLink { } accessory.context.totalEnergytemp = 0; } else { - accessory.context.totalEnergyTemp += - (currentWatt * 10) / 3600 / 1000; + accessory.context.totalEnergyTemp += (currentWatt * 10) / 3600 / 1000; accessory.context.totalEnergy = accessory.context.totalEnergyTemp; } accessory.eveLogger.addEntry({ @@ -816,8 +713,7 @@ class eWeLink { .on("get", callback => { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalEnergy = - accessory.context.extraPersistedData.totalPower; + accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower; } callback(null, accessory.context.totalEnergy); }); @@ -836,8 +732,7 @@ class eWeLink { .on("get", callback => { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); if (accessory.context.extraPersistedData !== undefined) { - accessory.context.lastReset = - accessory.context.extraPersistedData.lastReset; + accessory.context.lastReset = accessory.context.extraPersistedData.lastReset; } callback(null, accessory.context.lastReset); }); @@ -846,17 +741,13 @@ class eWeLink { accessory .getService(Service.Outlet) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => - this.internalUSBUpdate(accessory, value, callback) - ); + .on("set", (value, callback) => this.internalUSBUpdate(accessory, value, callback)); break; case "scm": accessory .getService(Service.Switch) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => - this.internalSCMUpdate(accessory, value, callback) - ); + .on("set", (value, callback) => this.internalSCMUpdate(accessory, value, callback)); break; case "light": accessory @@ -872,9 +763,8 @@ class eWeLink { .on("set", (value, callback) => { if (value > 0) { if ( - !accessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.On).value + !accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) + .value ) { this.internalLightbulbUpdate(accessory, true, function () { return; @@ -885,18 +775,15 @@ class eWeLink { this.internalLightbulbUpdate(accessory, false, callback); } }); - } else if ( - cns.devicesColourable.includes(accessory.context.eweUIID) - ) { + } else if (cns.devicesColourable.includes(accessory.context.eweUIID)) { accessory .getService(Service.Lightbulb) .getCharacteristic(Characteristic.Brightness) .on("set", (value, callback) => { if (value > 0) { if ( - !accessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.On).value + !accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) + .value ) { this.internalLightbulbUpdate(accessory, true, function () { return; @@ -923,24 +810,18 @@ class eWeLink { accessory .getService(Service.Switch) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => - this.internalSwitchUpdate(accessory, value, callback) - ); + .on("set", (value, callback) => this.internalSwitchUpdate(accessory, value, callback)); break; case "rf_sub": accessory.context.rfChls = accessory.context.rfChls || {}; if (accessory.context.sensorType === "button") { Object.entries(accessory.context.rfChls).forEach(([k, v]) => { - accessory - .getService(v) - .updateCharacteristic(Characteristic.On, false); + accessory.getService(v).updateCharacteristic(Characteristic.On, false); accessory .getService(v) .getCharacteristic(Characteristic.On) .on("set", (value, callback) => { - value - ? this.internalRFDeviceUpdate(accessory, k, callback) - : callback(); + value ? this.internalRFDeviceUpdate(accessory, k, callback) : callback(); }); }); } @@ -961,8 +842,7 @@ class eWeLink { .getCharacteristic(Characteristic.CurrentTemperature).value, humidity: accessory .getService(Service.HumiditySensor) - .getCharacteristic(Characteristic.CurrentRelativeHumidity) - .value, + .getCharacteristic(Characteristic.CurrentRelativeHumidity).value, }; accessory.eveLogger.addEntry(dataToAdd); }, 300000); @@ -971,20 +851,14 @@ class eWeLink { } this.devicesInHB.set(accessory.context.hbDeviceId, accessory); } catch (err) { - this.log.warn( - "[%s] could not be refreshed as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be refreshed as %s.", accessory.displayName, err); } } refreshAccessory(accessory, newParams) { switch (accessory.context.type) { case "valve": if ( - Object.keys(newParams).some(v => - cns.devicesValveParams.includes(v) - ) && + Object.keys(newParams).some(v => cns.devicesValveParams.includes(v)) && Array.isArray(newParams.switches) ) { this.externalValveUpdate(accessory, newParams); @@ -992,9 +866,7 @@ class eWeLink { return true; case "blind": if ( - Object.keys(newParams).some(v => - cns.devicesBlindParams.includes(v) - ) && + Object.keys(newParams).some(v => cns.devicesBlindParams.includes(v)) && Array.isArray(newParams.switches) ) { this.externalBlindUpdate(accessory, newParams); @@ -1002,48 +874,34 @@ class eWeLink { return true; case "garage": if ( - Object.keys(newParams).some(v => - cns.devicesGarageParams.includes(v) - ) && + Object.keys(newParams).some(v => cns.devicesGarageParams.includes(v)) && Array.isArray(newParams.switches) ) { this.externalGarageUpdate(accessory, newParams); } return true; case "lock": - if ( - Object.keys(newParams).some(v => cns.devicesLockParams.includes(v)) - ) { + if (Object.keys(newParams).some(v => cns.devicesLockParams.includes(v))) { this.externalLockUpdate(accessory, newParams); } return true; case "sensor": - if ( - Object.keys(newParams).some(v => cns.devicesSensorParams.includes(v)) - ) { + if (Object.keys(newParams).some(v => cns.devicesSensorParams.includes(v))) { this.externalSensorUpdate(accessory, newParams); } return true; case "fan": - if ( - Object.keys(newParams).some(v => cns.devicesFanParams.includes(v)) - ) { + if (Object.keys(newParams).some(v => cns.devicesFanParams.includes(v))) { this.externalFanUpdate(accessory, newParams); } return true; case "thermostat": - if ( - Object.keys(newParams).some(v => - cns.devicesThermostatParams.includes(v) - ) - ) { + if (Object.keys(newParams).some(v => cns.devicesThermostatParams.includes(v))) { this.externalThermostatUpdate(accessory, newParams); } return true; case "outlet": - if ( - Object.keys(newParams).some(v => cns.devicesOutletParams.includes(v)) - ) { + if (Object.keys(newParams).some(v => cns.devicesOutletParams.includes(v))) { this.externalOutletUpdate(accessory, newParams); } return true; @@ -1068,11 +926,7 @@ class eWeLink { cns.devicesSingleSwitch.includes(accessory.context.eweUIID) && cns.devicesSingleSwitchLight.includes(accessory.context.eweModel) ) { - if ( - Object.keys(newParams).some(v => - cns.devicesSingleSwitchLightParams.includes(v) - ) - ) { + if (Object.keys(newParams).some(v => cns.devicesSingleSwitchLightParams.includes(v))) { this.externalSingleLightUpdate(accessory, newParams); } } else if ( @@ -1080,9 +934,7 @@ class eWeLink { cns.devicesMultiSwitchLight.includes(accessory.context.eweModel) ) { if ( - Object.keys(newParams).some(v => - cns.devicesMultiSwitchLightParams.includes(v) - ) && + Object.keys(newParams).some(v => cns.devicesMultiSwitchLightParams.includes(v)) && Array.isArray(newParams.switches) ) { this.externalMultiLightUpdate(accessory, newParams); @@ -1091,18 +943,12 @@ class eWeLink { return true; case "switch": if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID)) { - if ( - Object.keys(newParams).some(v => - cns.devicesSingleSwitchParams.includes(v) - ) - ) { + if (Object.keys(newParams).some(v => cns.devicesSingleSwitchParams.includes(v))) { this.externalSingleSwitchUpdate(accessory, newParams); } } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID)) { if ( - Object.keys(newParams).some(v => - cns.devicesMultiSwitchParams.includes(v) - ) && + Object.keys(newParams).some(v => cns.devicesMultiSwitchParams.includes(v)) && Array.isArray(newParams.switches) ) { this.externalMultiSwitchUpdate(accessory, newParams); @@ -1110,11 +956,7 @@ class eWeLink { } return true; case "rf_pri": - if ( - Object.keys(newParams).some(v => - cns.devicesRFBridgeParams.includes(v) - ) - ) { + if (Object.keys(newParams).some(v => cns.devicesRFBridgeParams.includes(v))) { this.externalRFDeviceUpdate(accessory, newParams); } return true; @@ -1122,11 +964,7 @@ class eWeLink { case "zb_pri": return true; case "zb_sub": - if ( - Object.keys(newParams).some(v => - cns.devicesZBBridgeParams.includes(v) - ) - ) { + if (Object.keys(newParams).some(v => cns.devicesZBBridgeParams.includes(v))) { this.externalZBDeviceUpdate(accessory, newParams); } return true; @@ -1137,16 +975,10 @@ class eWeLink { removeAccessory(accessory) { try { this.devicesInHB.delete(accessory.context.hbDeviceId); - this.api.unregisterPlatformAccessories("homebridge-ewelink", "eWeLink", [ - accessory, - ]); + this.api.unregisterPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); this.log("[%s] has been removed from Homebridge.", accessory.displayName); } catch (err) { - this.log.warn( - "[%s] needed to be removed but couldn't as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] needed to be removed but couldn't as %s.", accessory.displayName, err); } } sendDeviceUpdate(accessory, params, callback) { @@ -1167,10 +999,7 @@ class eWeLink { callback("Device has failed to update"); } }; - if ( - cns.devicesNonLAN.includes(accessory.context.eweUIID) || - !accessory.context.reachableLAN - ) { + if (cns.devicesNonLAN.includes(accessory.context.eweUIID) || !accessory.context.reachableLAN) { sendViaWS(); } else { this.lanClient @@ -1178,11 +1007,7 @@ class eWeLink { .then(() => callback()) .catch(err => { if (this.debug) { - this.log.warn( - "[%s] Reverting to web socket as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); } sendViaWS(); }); @@ -1207,23 +1032,17 @@ class eWeLink { accessory.context.reachableWAN ? "online" : "offline" ); this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - if (accessory.context.reachableWAN) - this.wsClient.requestUpdate(accessory); + if (accessory.context.reachableWAN) this.wsClient.requestUpdate(accessory); } else { if (this.debug) { - this.log( - "[%s] Nothing to update from above WS message.", - accessory.displayName - ); + this.log("[%s] Nothing to update from above WS message.", accessory.displayName); } } } if (!isX) { for (let i = 1; i <= accessory.context.channelCount; i++) { if (this.devicesInHB.has(device.deviceid + "SW" + i)) { - let oAccessory = this.devicesInHB.get( - device.deviceid + "SW" + i - ); + let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); oAccessory.context.reachableWAN = device.params.online; this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); } @@ -1237,25 +1056,13 @@ class eWeLink { this.devicesInHB.get(device.deviceid + "SWX") || this.devicesInHB.get(device.deviceid + "SW0")) ) { - if ( - device.params.updateSource === "WS" && - !accessory.context.reachableWAN - ) { + if (device.params.updateSource === "WS" && !accessory.context.reachableWAN) { accessory.context.reachableWAN = true; - this.log( - "[%s] has been reported [online] via [WS].", - accessory.displayName - ); + this.log("[%s] has been reported [online] via [WS].", accessory.displayName); } - if ( - device.params.updateSource === "LAN" && - !accessory.context.reachableLAN - ) { + if (device.params.updateSource === "LAN" && !accessory.context.reachableLAN) { accessory.context.reachableLAN = true; - this.log( - "[%s] has been reported [online] via [LAN].", - accessory.displayName - ); + this.log("[%s] has been reported [online] via [LAN].", accessory.displayName); } if (this.debug) { this.log( @@ -1296,28 +1103,19 @@ class eWeLink { .updateCharacteristic(Characteristic.InUse, value); switch (value) { case 0: - accessory - .getService(valve) - .updateCharacteristic(Characteristic.RemainingDuration, 0); + accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, 0); clearTimeout(accessory.getService(valve).timer); break; case 1: - let timer = accessory - .getService(valve) - .getCharacteristic(Characteristic.SetDuration).value; - accessory - .getService(valve) - .updateCharacteristic(Characteristic.RemainingDuration, timer); + let timer = accessory.getService(valve).getCharacteristic(Characteristic.SetDuration) + .value; + accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, timer); accessory.getService(valve).timer = setTimeout(() => { - accessory - .getService(valve) - .setCharacteristic(Characteristic.Active, 0); + accessory.getService(valve).setCharacteristic(Characteristic.Active, 0); }, timer * 1000); break; } - params.switches = this.devicesInEwe.get( - accessory.context.eweDeviceId - ).params.switches; + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; switch (valve) { case "Valve A": params.switches[0].switch = value ? "on" : "off"; @@ -1342,8 +1140,7 @@ class eWeLink { params.switches[3].switch = "off"; this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1357,10 +1154,7 @@ class eWeLink { if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } - if ( - blindConfig.type !== "blind" || - !["oneSwitch", "twoSwitch"].includes(blindConfig.setup) - ) { + if (blindConfig.type !== "blind" || !["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { throw "improper configuration"; } let oldPos, @@ -1382,9 +1176,7 @@ class eWeLink { params.switch = "on"; break; case "twoSwitch": - params.switches = this.devicesInEwe.get( - accessory.context.eweDeviceId - ).params.switches; + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; params.switches[0].switch = value === 100 ? "on" : "off"; params.switches[1].switch = value === 0 ? "on" : "off"; break; @@ -1404,8 +1196,7 @@ class eWeLink { callback(); }, parseInt(blindConfig.operationTime) * 100); } catch (err) { - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1433,10 +1224,7 @@ class eWeLink { newPos = value, params = {}, delay = 0; - if ( - sensorDefinition && - !(sAccessory = this.devicesInHB.get(garageConfig.sensorId + "SWX")) - ) { + if (sensorDefinition && !(sAccessory = this.devicesInHB.get(garageConfig.sensorId + "SWX"))) { throw "defined DW2 sensor doesn't exist"; } if (sAccessory.context.type !== "sensor") { @@ -1459,10 +1247,7 @@ class eWeLink { if (garageConfig.setup === "oneSwitch" && [2, 3].includes(oldPos)) { accessory .getService(Service.GarageDoorOpener) - .updateCharacteristic( - Characteristic.CurrentDoorState, - ((oldPos * 2) % 3) + 2 - ); + .updateCharacteristic(Characteristic.CurrentDoorState, ((oldPos * 2) % 3) + 2); delay = 1500; } setTimeout(() => { @@ -1499,8 +1284,7 @@ class eWeLink { callback(); } catch (err) { accessory.context.inUse = false; - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1535,8 +1319,7 @@ class eWeLink { }, parseInt(lockConfig.operationTime) * 100); } catch (err) { accessory.context.inUse = false; - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1551,45 +1334,36 @@ class eWeLink { case "power": newPower = value; newSpeed = value ? 33 : 0; - newLight = accessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.On).value; + newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) + .value; break; case "speed": newPower = value >= 33 ? 1 : 0; newSpeed = value; - newLight = accessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.On).value; + newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) + .value; break; case "light": - newPower = accessory - .getService(Service.Fanv2) - .getCharacteristic(Characteristic.Active).value; + newPower = accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active) + .value; newSpeed = accessory .getService(Service.Fanv2) .getCharacteristic(Characteristic.RotationSpeed).value; newLight = value; break; } - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, newLight); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, newLight); accessory .getService(Service.Fanv2) .updateCharacteristic(Characteristic.Active, newPower) .updateCharacteristic(Characteristic.RotationSpeed, newSpeed); let params = { - switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params - .switches, + switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches, }; params.switches[0].switch = newLight ? "on" : "off"; - params.switches[1].switch = - newPower === 1 && newSpeed >= 33 ? "on" : "off"; - params.switches[2].switch = - newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? "on" : "off"; - params.switches[3].switch = - newPower === 1 && newSpeed >= 99 ? "on" : "off"; + params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? "on" : "off"; + params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? "on" : "off"; + params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? "on" : "off"; if (this.debug) { this.log.warn("Fan Update - setting " + type + " to " + value); this.log( @@ -1602,8 +1376,7 @@ class eWeLink { } this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1618,19 +1391,12 @@ class eWeLink { mainSwitch: value ? "on" : "off", }; if (this.debug) { - this.log( - "[%s] updating to turn [%s].", - accessory.displayName, - value ? "on" : "off" - ); + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1644,15 +1410,9 @@ class eWeLink { switch: value ? "on" : "off", }; if (this.debug) { - this.log( - "[%s] requesting to turn [%s].", - accessory.displayName, - value ? "on" : "off" - ); + this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory - .getService(Service.Outlet) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { callback("[" + accessory.displayName + "] " + err + "."); @@ -1664,20 +1424,13 @@ class eWeLink { throw "it is currently offline"; } let params = { - switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params - .switches, + switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches, }; params.switches[0].switch = value ? "on" : "off"; if (this.debug) { - this.log( - "[%s] requesting to turn [%s].", - accessory.displayName, - value ? "on" : "off" - ); + this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory - .getService(Service.Outlet) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { callback("[" + accessory.displayName + "] " + err + "."); @@ -1689,20 +1442,13 @@ class eWeLink { throw "it is currently offline"; } let params = { - switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params - .switches, + switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches, }; params.switches[0].switch = value ? "on" : "off"; if (this.debug) { - this.log( - "[%s] requesting to turn [%s].", - accessory.displayName, - value ? "on" : "off" - ); + this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { callback("[" + accessory.displayName + "] " + err + "."); @@ -1724,20 +1470,12 @@ class eWeLink { params.switch = value ? "on" : "off"; } if (this.debug) { - this.log( - "[%s] updating to turn [%s].", - accessory.displayName, - value ? "on" : "off" - ); + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); break; case "0": - params.switches = this.devicesInEwe.get( - accessory.context.eweDeviceId - ).params.switches; + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; params.switches[0].switch = value ? "on" : "off"; params.switches[1].switch = value ? "on" : "off"; params.switches[2].switch = value ? "on" : "off"; @@ -1749,16 +1487,10 @@ class eWeLink { value ? "on" : "off" ); } - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); for (let i = 1; i <= 4; i++) { - if ( - this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i) - ) { - oAccessory = this.devicesInHB.get( - accessory.context.eweDeviceId + "SW" + i - ); + if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); oAccessory .getService(Service.Lightbulb) .updateCharacteristic(Characteristic.On, value); @@ -1770,26 +1502,14 @@ class eWeLink { case "3": case "4": if (this.debug) { - this.log( - "[%s] updating to turn [%s].", - accessory.displayName, - value ? "on" : "off" - ); + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); let tAccessory, masterState = "off"; - params.switches = this.devicesInEwe.get( - accessory.context.eweDeviceId - ).params.switches; + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; for (let i = 1; i <= 4; i++) { - if ( - (tAccessory = this.devicesInHB.get( - accessory.context.eweDeviceId + "SW" + i - )) - ) { + if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { i === parseInt(accessory.context.switchNumber) ? (params.switches[i - 1].switch = value ? "on" : "off") : (params.switches[i - 1].switch = tAccessory @@ -1798,9 +1518,7 @@ class eWeLink { ? "on" : "off"); if ( - tAccessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.On).value + tAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value ) { masterState = "on"; } @@ -1808,22 +1526,17 @@ class eWeLink { params.switches[i - 1].switch = "off"; } } - oAccessory = this.devicesInHB.get( - accessory.context.eweDeviceId + "SW0" - ); + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); oAccessory .getService(Service.Lightbulb) .updateCharacteristic(Characteristic.On, masterState === "on"); break; default: - throw ( - "unknown switch number [" + accessory.context.switchNumber + "]" - ); + throw "unknown switch number [" + accessory.context.switchNumber + "]"; } this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1836,15 +1549,9 @@ class eWeLink { let params = {}; if (value === 0) { params.switch = "off"; - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, false); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, false); } else { - if ( - !accessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.On).value - ) { + if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { params.switch = "on"; } switch (accessory.context.eweUIID) { @@ -1863,16 +1570,11 @@ class eWeLink { .updateCharacteristic(Characteristic.Brightness, value); } if (this.debug) { - this.log( - "[%s] updating brightness to [%s%].", - accessory.displayName, - value - ); + this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); } setTimeout(() => this.sendDeviceUpdate(accessory, params, callback), 250); } catch (err) { - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1884,9 +1586,8 @@ class eWeLink { } let newRGB, params = {}, - curHue = accessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.Hue).value, + curHue = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Hue) + .value, curSat = accessory .getService(Service.Lightbulb) .getCharacteristic(Characteristic.Saturation).value; @@ -1917,15 +1618,9 @@ class eWeLink { throw "unknown device UIID"; } if (this.debug) { - this.log( - "[%s] updating hue to [%s°].", - accessory.displayName, - value - ); + this.log("[%s] updating hue to [%s°].", accessory.displayName, value); } - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.Hue, value); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Hue, value); break; case "bri": switch (accessory.context.eweUIID) { @@ -1949,11 +1644,7 @@ class eWeLink { break; } if (this.debug) { - this.log( - "[%s] updating brightness to [%s%].", - accessory.displayName, - value - ); + this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); } accessory .getService(Service.Lightbulb) @@ -1964,8 +1655,7 @@ class eWeLink { } setTimeout(() => this.sendDeviceUpdate(accessory, params, callback), 250); } catch (err) { - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -1981,20 +1671,12 @@ class eWeLink { case "X": params.switch = value ? "on" : "off"; if (this.debug) { - this.log( - "[%s] updating to turn [%s].", - accessory.displayName, - value ? "on" : "off" - ); + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); break; case "0": - params.switches = this.devicesInEwe.get( - accessory.context.eweDeviceId - ).params.switches; + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; params.switches[0].switch = value ? "on" : "off"; params.switches[1].switch = value ? "on" : "off"; params.switches[2].switch = value ? "on" : "off"; @@ -2006,19 +1688,11 @@ class eWeLink { value ? "on" : "off" ); } - accessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); for (let i = 1; i <= 4; i++) { - if ( - this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i) - ) { - oAccessory = this.devicesInHB.get( - accessory.context.eweDeviceId + "SW" + i - ); - oAccessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, value); + if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); + oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); } } break; @@ -2027,26 +1701,14 @@ class eWeLink { case "3": case "4": if (this.debug) { - this.log( - "[%s] updating to turn [%s].", - accessory.displayName, - value ? "on" : "off" - ); + this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, value); + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); let tAccessory, masterState = "off"; - params.switches = this.devicesInEwe.get( - accessory.context.eweDeviceId - ).params.switches; + params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; for (let i = 1; i <= 4; i++) { - if ( - (tAccessory = this.devicesInHB.get( - accessory.context.eweDeviceId + "SW" + i - )) - ) { + if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { i === parseInt(accessory.context.switchNumber) ? (params.switches[i - 1].switch = value ? "on" : "off") : (params.switches[i - 1].switch = tAccessory @@ -2055,9 +1717,7 @@ class eWeLink { ? "on" : "off"); if ( - tAccessory - .getService(Service.Switch) - .getCharacteristic(Characteristic.On).value + tAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value ) { masterState = "on"; } @@ -2065,22 +1725,17 @@ class eWeLink { params.switches[i - 1].switch = "off"; } } - oAccessory = this.devicesInHB.get( - accessory.context.eweDeviceId + "SW0" - ); + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); oAccessory .getService(Service.Switch) .updateCharacteristic(Characteristic.On, masterState === "on"); break; default: - throw ( - "unknown switch number [" + accessory.context.switchNumber + "]" - ); + throw "unknown switch number [" + accessory.context.switchNumber + "]"; } this.sendDeviceUpdate(accessory, params, callback); } catch (err) { - let str = - "[" + accessory.displayName + "] could not be updated as " + err + "."; + let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -2114,14 +1769,7 @@ class eWeLink { 3000 ); } catch (err) { - let str = - "[" + - accessory.displayName + - " " + - name + - "] could not be updated as " + - err + - "."; + let str = "[" + accessory.displayName + " " + name + "] could not be updated as " + err + "."; this.log.error(str); callback(str); } @@ -2131,14 +1779,8 @@ class eWeLink { ["A", "B"].forEach((v, k) => { accessory .getService("Valve " + v) - .updateCharacteristic( - Characteristic.Active, - params.switches[k].switch === "on" - ) - .updateCharacteristic( - Characteristic.InUse, - params.switches[k].switch === "on" - ); + .updateCharacteristic(Characteristic.Active, params.switches[k].switch === "on") + .updateCharacteristic(Characteristic.InUse, params.switches[k].switch === "on"); if (params.switches[k].switch === "on") { let timer = accessory .getService("Valve " + v) @@ -2147,9 +1789,7 @@ class eWeLink { .getService("Valve " + v) .updateCharacteristic(Characteristic.RemainingDuration, timer); accessory.getService("Valve " + v).timer = setTimeout(() => { - accessory - .getService("Valve " + v) - .setCharacteristic(Characteristic.Active, 0); + accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); }, timer * 1000); } else { accessory @@ -2159,11 +1799,7 @@ class eWeLink { } }); } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalBlindUpdate(accessory, params) { @@ -2172,10 +1808,7 @@ class eWeLink { if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } - if ( - blindConfig.type !== "blind" || - ["oneSwitch", "twoSwitch"].includes(blindConfig.setup) - ) { + if (blindConfig.type !== "blind" || ["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { throw "improper configuration"; } switch (blindConfig.setup) { @@ -2191,10 +1824,7 @@ class eWeLink { : 0; break; case "twoSwitch": - if ( - params.switches[0].switch === "off" && - params.switches[1].switch === "off" - ) { + if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { return; } let switchUp = params.switches[0].switch === "on" ? -1 : 0, // matrix of numbers to get @@ -2213,11 +1843,7 @@ class eWeLink { .updateCharacteristic(Characteristic.CurrentPosition, nSte * 100); }, parseInt(blindConfig.operationTime) * 100); } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalGarageUpdate(accessory, params) { @@ -2271,11 +1897,7 @@ class eWeLink { }, parseInt(garageConfig.operationTime) * 100); } catch (err) { accessory.context.inUse = false; - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalLockUpdate(accessory, params) { @@ -2304,11 +1926,7 @@ class eWeLink { }, parseInt(lockConfig.operationTime) * 100); } catch (err) { accessory.context.inUse = false; - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalSensorUpdate(accessory, params) { @@ -2318,14 +1936,8 @@ class eWeLink { accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService), scaledBattery = Math.round(params.battery * 33.3); - batteryService.updateCharacteristic( - Characteristic.BatteryLevel, - scaledBattery - ); - batteryService.updateCharacteristic( - Characteristic.StatusLowBattery, - scaledBattery < 25 - ); + batteryService.updateCharacteristic(Characteristic.BatteryLevel, scaledBattery); + batteryService.updateCharacteristic(Characteristic.StatusLowBattery, scaledBattery < 25); } let newState = params.switch === "on" ? 1 : 0, oAccessory = false; @@ -2333,10 +1945,7 @@ class eWeLink { .getService(Service.ContactSensor) .updateCharacteristic(Characteristic.ContactSensorState, newState); this.cusG.forEach(group => { - if ( - group.sensorId === accessory.context.eweDeviceId && - group.type === "garage" - ) { + if (group.sensorId === accessory.context.eweDeviceId && group.type === "garage") { if ((oAccessory = this.devicesInHB.get(group.deviceId + "SWX"))) { switch (newState) { case 0: @@ -2360,11 +1969,7 @@ class eWeLink { } }); } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalFanUpdate(accessory, params) { @@ -2372,11 +1977,7 @@ class eWeLink { let light, status, speed; if (Array.isArray(params.switches)) { light = params.switches[0].switch === "on"; - switch ( - params.switches[1].switch + - params.switches[2].switch + - params.switches[3].switch - ) { + switch (params.switches[1].switch + params.switches[2].switch + params.switches[3].switch) { default: status = 0; speed = 0; @@ -2404,19 +2005,13 @@ class eWeLink { } else { throw "unknown parameters received"; } - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, light); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, light); accessory .getService(Service.Fanv2) .updateCharacteristic(Characteristic.Active, status) .updateCharacteristic(Characteristic.RotationSpeed, speed); } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalThermostatUpdate(accessory, params) { @@ -2428,9 +2023,7 @@ class eWeLink { let newState = params.hasOwnProperty("switch") ? params.switch === "on" : params.mainSwitch === "on"; - accessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, newState); + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, newState); } let eveLog = { time: Date.now(), @@ -2440,9 +2033,7 @@ class eWeLink { accessory.getService(Service.TemperatureSensor) ) { let currentTemp = - params.currentTemperature !== "unavailable" - ? params.currentTemperature - : 0; + params.currentTemperature !== "unavailable" ? params.currentTemperature : 0; accessory .getService(Service.TemperatureSensor) .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); @@ -2452,25 +2043,17 @@ class eWeLink { params.hasOwnProperty("currentHumidity") && accessory.getService(Service.HumiditySensor) ) { - let currentHumi = - params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; + let currentHumi = params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; accessory .getService(Service.HumiditySensor) - .updateCharacteristic( - Characteristic.CurrentRelativeHumidity, - currentHumi - ); + .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); eveLog.humidity = parseFloat(currentHumi); } if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { accessory.eveLogger.addEntry(eveLog); } } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalOutletUpdate(accessory, params) { @@ -2489,13 +2072,8 @@ class eWeLink { ); accessory .getService(Service.Outlet) - .updateCharacteristic( - Characteristic.OutletInUse, - parseFloat(params.power) > 0 - ); - let isOn = accessory - .getService(Service.Outlet) - .getCharacteristic(Characteristic.On).value; + .updateCharacteristic(Characteristic.OutletInUse, parseFloat(params.power) > 0); + let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value; accessory.eveLogger.addEntry({ time: Date.now(), power: isOn ? parseFloat(params.power) : 0, @@ -2504,10 +2082,7 @@ class eWeLink { if (params.hasOwnProperty("voltage")) { accessory .getService(Service.Outlet) - .updateCharacteristic( - EveService.Characteristics.Voltage, - parseFloat(params.voltage) - ); + .updateCharacteristic(EveService.Characteristics.Voltage, parseFloat(params.voltage)); } if (params.hasOwnProperty("current")) { accessory @@ -2518,43 +2093,25 @@ class eWeLink { ); } } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalUSBUpdate(accessory, params) { try { accessory .getService(Service.Outlet) - .updateCharacteristic( - Characteristic.On, - params.switches[0].switch === "on" - ); + .updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalSCMUpdate(accessory, params) { try { accessory .getService(Service.Switch) - .updateCharacteristic( - Characteristic.On, - params.switches[0].switch === "on" - ); + .updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalSingleLightUpdate(accessory, params) { @@ -2564,20 +2121,13 @@ class eWeLink { isOn = false; if (accessory.context.eweUIID === 22 && params.hasOwnProperty("state")) { isOn = params.state === "on"; - } else if ( - accessory.context.eweUIID !== 22 && - params.hasOwnProperty("switch") - ) { + } else if (accessory.context.eweUIID !== 22 && params.hasOwnProperty("switch")) { isOn = params.switch === "on"; } else { - isOn = accessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.On).value; + isOn = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; } if (isOn) { - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, true); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, true); switch (accessory.context.eweUIID) { case 36: // KING-M4 if (params.hasOwnProperty("bright")) { @@ -2591,10 +2141,7 @@ class eWeLink { if (params.hasOwnProperty("brightness")) { accessory .getService(Service.Lightbulb) - .updateCharacteristic( - Characteristic.Brightness, - params.brightness - ); + .updateCharacteristic(Characteristic.Brightness, params.brightness); } break; case 22: // B1 @@ -2609,9 +2156,7 @@ class eWeLink { mode = 2; } if (mode === 2) { - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, true); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, true); newColour = convert.rgb.hsv( parseInt(params.channel2), parseInt(params.channel3), @@ -2633,11 +2178,7 @@ class eWeLink { .updateCharacteristic(Characteristic.Brightness, params.bright); } if (params.hasOwnProperty("colorR")) { - newColour = convert.rgb.hsv( - params.colorR, - params.colorG, - params.colorB - ); + newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB); accessory .getService(Service.Lightbulb) .updateCharacteristic(Characteristic.Hue, newColour[0]) @@ -2648,16 +2189,10 @@ class eWeLink { return; } } else { - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, false); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, false); } } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalMultiLightUpdate(accessory, params) { @@ -2669,24 +2204,15 @@ class eWeLink { let oAccessory = this.devicesInHB.get(idToCheck + i); oAccessory .getService(Service.Lightbulb) - .updateCharacteristic( - Characteristic.On, - params.switches[i - 1].switch === "on" - ); + .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); if (params.switches[i - 1].switch === "on") { primaryState = true; } } } - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, primaryState); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, primaryState); } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalSingleSwitchUpdate(accessory, params) { @@ -2695,11 +2221,7 @@ class eWeLink { .getService(Service.Switch) .updateCharacteristic(Characteristic.On, params.switch === "on"); } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalMultiSwitchUpdate(accessory, params) { @@ -2711,24 +2233,15 @@ class eWeLink { let oAccessory = this.devicesInHB.get(idToCheck + i); oAccessory .getService(Service.Switch) - .updateCharacteristic( - Characteristic.On, - params.switches[i - 1].switch === "on" - ); + .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); if (params.switches[i - 1].switch === "on") { primaryState = true; } } } - accessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, primaryState); + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState); } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalRFDeviceUpdate(accessory, params) { @@ -2744,9 +2257,7 @@ class eWeLink { // RF Button let bAccessory; if ( - (bAccessory = this.devicesInHB.get( - idToCheck + accessory.context.rfChlMap[params.rfChl] - )) + (bAccessory = this.devicesInHB.get(idToCheck + accessory.context.rfChlMap[params.rfChl])) ) { bAccessory .getService(bAccessory.context.rfChls[params.rfChl]) @@ -2800,81 +2311,51 @@ class eWeLink { case "co": oAccessory .getService(Service.CarbonMonoxideSensor) - .updateCharacteristic( - Characteristic.CarbonMonoxideDetected, - 1 - ); + .updateCharacteristic(Characteristic.CarbonMonoxideDetected, 1); setTimeout(() => { oAccessory .getService(Service.CarbonMonoxideSensor) - .updateCharacteristic( - Characteristic.CarbonMonoxideDetected, - 0 - ); + .updateCharacteristic(Characteristic.CarbonMonoxideDetected, 0); }, (this.config.sensorTimeLength || 2) * 1000); break; case "co2": oAccessory .getService(Service.CarbonDioxideSensor) - .updateCharacteristic( - Characteristic.CarbonDioxideDetected, - 1 - ); + .updateCharacteristic(Characteristic.CarbonDioxideDetected, 1); setTimeout(() => { oAccessory .getService(Service.CarbonDioxideSensor) - .updateCharacteristic( - Characteristic.CarbonDioxideDetected, - 0 - ); + .updateCharacteristic(Characteristic.CarbonDioxideDetected, 0); }, (this.config.sensorTimeLength || 2) * 1000); break; case "contact": oAccessory .getService(Service.ContactSensor) - .updateCharacteristic( - Characteristic.ContactSensorState, - 1 - ); + .updateCharacteristic(Characteristic.ContactSensorState, 1); setTimeout(() => { oAccessory .getService(Service.ContactSensor) - .updateCharacteristic( - Characteristic.ContactSensorState, - 0 - ); + .updateCharacteristic(Characteristic.ContactSensorState, 0); }, (this.config.sensorTimeLength || 2) * 1000); break; case "occupancy": oAccessory .getService(Service.OccupancySensor) - .updateCharacteristic( - Characteristic.OccupancyDetected, - 1 - ); + .updateCharacteristic(Characteristic.OccupancyDetected, 1); setTimeout(() => { oAccessory .getService(Service.OccupancySensor) - .updateCharacteristic( - Characteristic.OccupancyDetected, - 0 - ); + .updateCharacteristic(Characteristic.OccupancyDetected, 0); }, (this.config.sensorTimeLength || 2) * 1000); break; default: oAccessory .getService(Service.MotionSensor) - .updateCharacteristic( - Characteristic.MotionDetected, - true - ); + .updateCharacteristic(Characteristic.MotionDetected, true); setTimeout(() => { oAccessory .getService(Service.MotionSensor) - .updateCharacteristic( - Characteristic.MotionDetected, - false - ); + .updateCharacteristic(Characteristic.MotionDetected, false); }, (this.config.sensorTimeLength || 2) * 1000); break; } @@ -2890,44 +2371,28 @@ class eWeLink { }); } } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } externalZBDeviceUpdate(accessory, params) { try { //*** credit @tasict ***\\ if (params.hasOwnProperty("battery")) { - if ( - accessory.context.eweUIID === 3026 && - (this.config.ZBDWBatt || false) - ) { + if (accessory.context.eweUIID === 3026 && (this.config.ZBDWBatt || false)) { params.battery *= 10; } let batteryService = accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); - batteryService.updateCharacteristic( - Characteristic.BatteryLevel, - params.battery - ); - batteryService.updateCharacteristic( - Characteristic.StatusLowBattery, - params.battery < 25 - ); + batteryService.updateCharacteristic(Characteristic.BatteryLevel, params.battery); + batteryService.updateCharacteristic(Characteristic.StatusLowBattery, params.battery < 25); } switch (accessory.context.eweUIID) { case 1000: if (params.hasOwnProperty("key") && [0, 1, 2].includes(params.key)) { accessory .getService(Service.StatelessProgrammableSwitch) - .updateCharacteristic( - Characteristic.ProgrammableSwitchEvent, - params.key - ); + .updateCharacteristic(Characteristic.ProgrammableSwitchEvent, params.key); } break; case 1770: @@ -2938,34 +2403,22 @@ class eWeLink { let currentTemp = parseInt(params.temperature) / 100; accessory .getService(Service.TemperatureSensor) - .updateCharacteristic( - Characteristic.CurrentTemperature, - currentTemp - ); + .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); eveLog.temp = parseFloat(currentTemp); } if (params.hasOwnProperty("humidity")) { let currentHumi = parseInt(params.humidity) / 100; accessory .getService(Service.HumiditySensor) - .updateCharacteristic( - Characteristic.CurrentRelativeHumidity, - currentHumi - ); + .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); eveLog.humidity = parseFloat(currentHumi); } - if ( - eveLog.hasOwnProperty("temp") || - eveLog.hasOwnProperty("humidity") - ) { + if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { accessory.eveLogger.addEntry(eveLog); } break; case 2026: - if ( - params.hasOwnProperty("motion") && - params.hasOwnProperty("trigTime") - ) { + if (params.hasOwnProperty("motion") && params.hasOwnProperty("trigTime")) { let timeNow = new Date(), diff = (timeNow.getTime() - params.trigTime) / 1000; accessory @@ -2983,19 +2436,12 @@ class eWeLink { if (params.hasOwnProperty("lock") && [0, 1].includes(params.lock)) { accessory .getService(Service.ContactSensor) - .updateCharacteristic( - Characteristic.ContactSensorState, - params.lock - ); + .updateCharacteristic(Characteristic.ContactSensorState, params.lock); } break; } } catch (err) { - this.log.warn( - "[%s] could not be updated as %s.", - accessory.displayName, - err - ); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } } diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 1aafd1e4..dc8370a4 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -12,9 +12,7 @@ module.exports = class eWeLinkHTTP { } login() { let data = { - countryCode: - "+" + - this.config.countryCode.toString().replace("+", "").replace(" ", ""), + countryCode: "+" + this.config.countryCode.toString().replace("+", "").replace(" ", ""), password: this.config.password, }; this.config.username.includes("@") @@ -24,10 +22,7 @@ module.exports = class eWeLinkHTTP { let msg = JSON.stringify(data, null, 2) .replace(this.config.password, "**hidden**") .replace(this.config.username, "**hidden**"); - this.log.warn( - "Sending HTTP login request. This text is yellow for clarity.\n%s", - msg - ); + this.log.warn("Sending HTTP login request. This text is yellow for clarity.\n%s", msg); } else if (this.debug) { this.log("Sending HTTP login request."); } @@ -96,10 +91,7 @@ module.exports = class eWeLinkHTTP { getHost() { let data = { appid: constants.appId, - country_code: this.config.countryCode - .toString() - .replace("+", "") - .replace(" ", ""), + country_code: this.config.countryCode.toString().replace("+", "").replace(" ", ""), nonce: Math.random().toString(36).substr(2, 8), ts: Math.floor(new Date().getTime() / 1000), version: 8, @@ -135,10 +127,7 @@ module.exports = class eWeLinkHTTP { .then(res => { let body = res.data; if (!body.region) { - throw ( - "Server did not respond with a region.\n" + - JSON.stringify(body, null, 2) - ); + throw "Server did not respond with a region.\n" + JSON.stringify(body, null, 2); } switch (body.region) { case "eu": @@ -176,17 +165,12 @@ module.exports = class eWeLinkHTTP { }) .then(res => { let body = res.data; - if ( - !body.hasOwnProperty("error") || - (body.hasOwnProperty("error") && body.error !== 0) - ) { + if (!body.hasOwnProperty("error") || (body.hasOwnProperty("error") && body.error !== 0)) { throw JSON.stringify(body, null, 2); } let deviceList = []; if (body.data.thingList && body.data.thingList.length > 0) { - body.data.thingList.forEach(device => - deviceList.push(device.itemData) - ); + body.data.thingList.forEach(device => deviceList.push(device.itemData)); } resolve(deviceList); }) diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 25baee53..9701fa06 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -36,9 +36,7 @@ module.exports = class eWeLinkLAN { let onlineCount = 0; res.forEach(device => { let d, - deviceId = device.fqdn - .replace("._ewelink._tcp.local", "") - .replace("eWeLink_", ""); + deviceId = device.fqdn.replace("._ewelink._tcp.local", "").replace("eWeLink_", ""); if ((d = this.deviceMap.get(deviceId))) { if (!this.ipOverrides.hasOwnProperty(deviceId)) { this.deviceMap.set(deviceId, { @@ -79,48 +77,31 @@ module.exports = class eWeLinkLAN { .createHash("md5") .update(Buffer.from(deviceInfo.apiKey, "utf8")) .digest(), - dText = crypto.createDecipheriv( - "aes-128-cbc", - key, - Buffer.from(rdata.iv, "base64") - ), + dText = crypto.createDecipheriv("aes-128-cbc", key, Buffer.from(rdata.iv, "base64")), pText = Buffer.concat([ dText.update(Buffer.from(data, "base64")), dText.final(), ]).toString("utf8"), params; - if ( - packet.address !== deviceInfo.ip && - !this.ipOverrides.hasOwnProperty(rdata.id) - ) { + if (packet.address !== deviceInfo.ip && !this.ipOverrides.hasOwnProperty(rdata.id)) { this.deviceMap.set(rdata.id, { apiKey: deviceInfo.apiKey, online: true, ip: packet.address, }); if (this.debug) { - this.log.warn( - "[%s] updating IP address to [%s].", - rdata.id, - packet.address - ); + this.log.warn("[%s] updating IP address to [%s].", rdata.id, packet.address); } } try { params = JSON.parse(pText); } catch (e) { - this.log.warn( - "[%s] An error occured reading the LAN message [%s]", - rdata.id, - e - ); + this.log.warn("[%s] An error occured reading the LAN message [%s]", rdata.id, e); return; } for (let param in params) { if (params.hasOwnProperty(param)) { - if ( - !constants.paramsToKeep.includes(param.replace(/[0-9]/g, "")) - ) { + if (!constants.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { delete params[param]; } } @@ -133,10 +114,7 @@ module.exports = class eWeLinkLAN { params, }; if (this.debugReqRes) { - let msg = JSON.stringify(returnTemplate, null, 2).replace( - rdata.id, - "**hidden**" - ); + let msg = JSON.stringify(returnTemplate, null, 2).replace(rdata.id, "**hidden**"); this.log("LAN message received.\n%s", msg); } else if (this.debug) { this.log("LAN message received."); @@ -175,17 +153,13 @@ module.exports = class eWeLinkLAN { throw "plugin does not support lan mode for this device yet - feel free to create a github issue"; } if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { - let key = crypto - .createHash("md5") - .update(Buffer.from(apiKey, "utf8")) - .digest(), + let key = crypto.createHash("md5").update(Buffer.from(apiKey, "utf8")).digest(), iv = crypto.randomBytes(16), enc = crypto.createCipheriv("aes-128-cbc", key, iv), data = { - data: Buffer.concat([ - enc.update(JSON.stringify(params)), - enc.final(), - ]).toString("base64"), + data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString( + "base64" + ), deviceid: json.deviceid, encrypt: true, iv: iv.toString("base64"), @@ -197,20 +171,13 @@ module.exports = class eWeLinkLAN { .replace(json.apikey, "**hidden**") .replace(json.apikey, "**hidden**") .replace(json.deviceid, "**hidden**"); - this.log.warn( - "LAN message sent. This text is yellow for clarity.\n%s", - msg - ); + this.log.warn("LAN message sent. This text is yellow for clarity.\n%s", msg); } else if (this.debug) { this.log("LAN message sent."); } axios({ method: "post", - url: - "http://" + - this.deviceMap.get(json.deviceid).ip + - ":8081/zeroconf/" + - suffix, + url: "http://" + this.deviceMap.get(json.deviceid).ip + ":8081/zeroconf/" + suffix, headers: { Accept: "application/json", "Content-Type": "application/json", diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 56fbeb64..70e0a209 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -21,8 +21,7 @@ module.exports = class eWeLinkWS { return new Promise((resolve, reject) => { axios({ method: "post", - url: - "https://" + this.httpHost.replace("-api", "-disp") + "/dispatch/app", + url: "https://" + this.httpHost.replace("-api", "-disp") + "/dispatch/app", headers: { Authorization: "Bearer " + this.aToken, "Content-Type": "application/json", @@ -70,10 +69,7 @@ module.exports = class eWeLinkWS { let msg = JSON.stringify(payload, null, 2) .replace(this.aToken, "**hidden**") .replace(this.apiKey, "**hidden**"); - this.log.warn( - "Sending WS login request. This text is yellow for clarity.\n%s", - msg - ); + this.log.warn("Sending WS login request. This text is yellow for clarity.\n%s", msg); } else if (this.debug) { this.log("Sending WS login request."); } @@ -86,10 +82,7 @@ module.exports = class eWeLinkWS { try { device = JSON.parse(m); } catch (e) { - this.log.warn( - "An error occured reading the web socket message [%s]", - e - ); + this.log.warn("An error occured reading the web socket message [%s]", e); return; } // for requestUpdate response @@ -143,9 +136,7 @@ module.exports = class eWeLinkWS { case "update": for (let param in device.params) { if (device.params.hasOwnProperty(param)) { - if ( - !constants.paramsToKeep.includes(param.replace(/[0-9]/g, "")) - ) { + if (!constants.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { delete device.params[param]; } } @@ -173,8 +164,7 @@ module.exports = class eWeLinkWS { return; default: this.log.warn( - "[%s] WS message has unknown action.\n" + - JSON.stringify(device, null, 2), + "[%s] WS message has unknown action.\n" + JSON.stringify(device, null, 2), device.deviceid ); return; @@ -183,9 +173,7 @@ module.exports = class eWeLinkWS { // *** Safe to ignore these messages *** \\ } else { if (this.debug) { - this.log.warn( - "WS unknown command received.\n" + JSON.stringify(device, null, 2) - ); + this.log.warn("WS unknown command received.\n" + JSON.stringify(device, null, 2)); } } }); @@ -200,9 +188,7 @@ module.exports = class eWeLinkWS { this.login(); }, 5000); } else { - this.log( - "Please try restarting Homebridge so that this plugin can work again." - ); + this.log("Please try restarting Homebridge so that this plugin can work again."); } } this.wsIsOpen = false; @@ -223,9 +209,7 @@ module.exports = class eWeLinkWS { this.login(); }, 5000); } else { - this.log.warn( - "If this was unexpected then please try restarting Homebridge." - ); + this.log.warn("If this was unexpected then please try restarting Homebridge."); } }); } @@ -252,10 +236,7 @@ module.exports = class eWeLinkWS { .replace(json.apikey, "**hidden**") .replace(json.apiKey, "**hidden**") .replace(json.deviceid, "**hidden**"); - this.log.warn( - "WS message sent. This text is yellow for clarity.\n%s", - msg - ); + this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); } else if (this.debug) { this.log("WS message sent."); } @@ -268,9 +249,7 @@ module.exports = class eWeLinkWS { setTimeout(sendOperation, this.delaySend, string); this.delaySend += 280; } else { - this.log.warn( - "Web socket is currently reconnecting. Command will be resent." - ); + this.log.warn("Web socket is currently reconnecting. Command will be resent."); let interval, waitToSend = req => { if (this.wsIsOpen) { @@ -305,10 +284,7 @@ module.exports = class eWeLinkWS { .replace(json.apikey, "**hidden**") .replace(json.apiKey, "**hidden**") .replace(json.deviceid, "**hidden**"); - this.log.warn( - "WS message sent. This text is yellow for clarity.\n%s", - msg - ); + this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); } else if (this.debug) { this.log("WS message sent."); } @@ -321,9 +297,7 @@ module.exports = class eWeLinkWS { setTimeout(sendOperation, this.delaySend, string); this.delaySend += 280; } else { - this.log.warn( - "Web socket is currently reconnecting. Command will be resent." - ); + this.log.warn("Web socket is currently reconnecting. Command will be resent."); let interval, waitToSend = req => { if (this.wsIsOpen) { From 8e782a76f3bdff90e7babdcb5d733919653617d4 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 16 Sep 2020 17:05:55 +0100 Subject: [PATCH 0167/3183] 2.27.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3e66d828..bc44c562 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.27.0", + "version": "2.27.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 015ed59c..88b3db2a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.27.0", + "version": "2.27.1", "author": "bwp91", "contributors": [ "gbro115", From 169ae4df8b4ac8fe44be1cd2352d128f1ffb314c Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Thu, 17 Sep 2020 14:44:38 +0100 Subject: [PATCH 0168/3183] Update eWeLink.js --- lib/eWeLink.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 10049c96..8eafef3e 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1227,7 +1227,7 @@ class eWeLink { if (sensorDefinition && !(sAccessory = this.devicesInHB.get(garageConfig.sensorId + "SWX"))) { throw "defined DW2 sensor doesn't exist"; } - if (sAccessory.context.type !== "sensor") { + if (sensorDefinition && sAccessory.context.type !== "sensor") { throw "defined DW2 sensor isn't a sensor"; } oldPos = sAccessory From a6b79031173339879adbae64012ba7fd52e5b8ec Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 17 Sep 2020 14:45:24 +0100 Subject: [PATCH 0169/3183] 2.27.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index bc44c562..93c75ca5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.27.1", + "version": "2.27.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 88b3db2a..7750d662 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.27.1", + "version": "2.27.2", "author": "bwp91", "contributors": [ "gbro115", From 14bc1f792134b57da5938b2708880bbc39a08b16 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sat, 19 Sep 2020 22:40:36 +0100 Subject: [PATCH 0170/3183] Update config.yml --- .github/ISSUE_TEMPLATE/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 2194a932..af5ef704 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: false contact_links: - name: Homebridge Discord - url: https://discord.gg/Z8jmyvb + url: https://discord.gg/7X36mdw about: Chat to me on Discord - my username is bwp91. From 404148f91f5dc90e2825a040e25a1e1134fbb0d2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 20 Sep 2020 13:02:42 +0100 Subject: [PATCH 0171/3183] initial 3.0 beta --- config.schema.json | 13 +- lib/constants.js | 2 +- lib/eWeLink.js | 1673 ++++++++++++++++++++++---------------------- lib/eWeLinkHTTP.js | 286 +++++--- lib/eWeLinkLAN.js | 36 +- lib/eWeLinkWS.js | 330 +++++---- package-lock.json | 5 + package.json | 1 + 8 files changed, 1201 insertions(+), 1145 deletions(-) diff --git a/config.schema.json b/config.schema.json index ee24e05b..e9a2b321 100644 --- a/config.schema.json +++ b/config.schema.json @@ -46,6 +46,12 @@ "description": "A list of eWeLink devices to hide from Homebridge. For example '10009553c8' or multiple devices separated with a comma '10009553c8,10009553c9'.", "default": "" }, + "hideMasters": { + "type": "boolean", + "title": "Hide Master Switches", + "description": "If enabled, the 'SW0' accessory of multi-channel light and switch devices will be hidden from Homebridge.", + "default": false + }, "hideFromHB": { "type": "string", "title": "Hide Device Channels", @@ -225,6 +231,7 @@ "debug", "debugReqRes", "hideDevFromHB", + "hideMasters", "hideFromHB", "sensorTimeLength", "sensorTimeDifference", @@ -261,7 +268,11 @@ "items": [ { "type": "fieldset", - "items": ["bridgeSensors[].deviceId", "bridgeSensors[].fullDeviceId", "bridgeSensors[].type"] + "items": [ + "bridgeSensors[].deviceId", + "bridgeSensors[].fullDeviceId", + "bridgeSensors[].type" + ] } ] } diff --git a/lib/constants.js b/lib/constants.js index fe7fcb40..a89a48c0 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -5,7 +5,7 @@ module.exports = { appId: "oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq", // appSecret: "mXLOjea0woSMvK9gw7Fjsy7YlFO4iSu6", appSecret: "6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM", - devicesHideable: ["switch", "light", "valve"], + devicesHideable: ["switch", "light"], devicesNonLAN: [22, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], devicesSingleSwitchParams: ["switch"], diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 8eafef3e..d8b093a1 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -13,9 +13,9 @@ class eWeLink { constructor(log, config, api) { if (!log || !api || !config) return; if (!config.username || !config.password || !config.countryCode) { - log.error("**************** Cannot load homebridge-ewelink ****************"); - log.error("Your eWeLink credentials are missing from the Homebridge config."); - log.error("****************************************************************"); + log.error("*********** Cannot load homebridge-ewelink ***********"); + log.error("eWeLink credentials missing from the Homebridge config."); + log.error("*******************************************************"); return; } this.log = log; @@ -23,257 +23,247 @@ class eWeLink { this.api = api; this.debug = this.config.debug || false; this.devicesInHB = new Map(); - this.devicesInEwe = new Map(); + this.devicesInEW = new Map(); this.cusG = new Map(); this.cusS = new Map(); + this.hiddenMasters = []; this.eveLogPath = this.api.user.storagePath() + "/homebridge-ewelink/"; this.api - .on("didFinishLaunching", () => { - this.log( - "Plugin has finished initialising. Starting synchronisation with eWeLink account." - ); - //*** Set up HTTP client and get the user HTTP host ***\\ - this.httpClient = new eWeLinkHTTP(this.config, this.log); - this.httpClient - .getHost() - .then(() => this.httpClient.login()) - .then(res => { - //*** Set up the web socket client ***\\ - this.wsClient = new eWeLinkWS(this.config, this.log, res); - return this.wsClient.getHost(); - }) - .then(() => { - //*** Open web socket connection and get device list via HTTP ***\\ - this.wsClient.login(); - return this.httpClient.getDevices(); - }) - .then(res => { - //*** Get device IP addresses for LAN mode ***\\ - this.httpDevices = res - .filter( - device => device.hasOwnProperty("extra") && device.extra.hasOwnProperty("uiid") - ) - .filter(device => !(this.config.hideDevFromHB || "").includes(device.deviceid)); - this.lanClient = new eWeLinkLAN(this.config, this.log, this.httpDevices); - this.httpDevices.forEach(device => this.devicesInEwe.set(device.deviceid, device)); - return this.lanClient.getHosts(); - }) - .then(res => { - //*** Set up the LAN mode listener ***\\ - this.lanDevices = res.map; - this.lanDevicesOnline = res.count; - return this.lanClient.startMonitor(); - }) - .then(() => { - //*** Use the device list to refresh Homebridge accessories ***\\ - (() => { - //*** Remove all Homebridge accessories if none found ***\\ - if ( - Object.keys(this.httpDevices).length === 0 && - Object.keys(this.lanDevices).length === 0 - ) { - Array.from(this.devicesInHB.values()).forEach(a => this.removeAccessory(a)); - this.devicesInHB.clear(); - this.log.warn("******* Not loading homebridge-ewelink *******"); - this.log.warn("No devices were found in your eWeLink account."); - this.log.warn("**********************************************"); - return; - } - //*** Make a map of custom groups from Homebridge config ***\\ - if (Object.keys(this.config.groups || []).length > 0) { - this.config.groups - .filter(g => g.hasOwnProperty("type") && cns.allowedGroups.includes(g.type)) - .filter( - g => - g.hasOwnProperty("deviceId") && - this.devicesInEwe.has(g.deviceId.toLowerCase()) - ) - .forEach(g => this.cusG.set(g.deviceId + "SWX", g)); - } - //*** Make a map of RF Bridge custom sensors from Homebridge config ***\\ - if (Object.keys(this.config.bridgeSensors || []).length > 0) { - this.config.bridgeSensors - .filter( - s => - s.hasOwnProperty("deviceId") && - this.devicesInEwe.has(s.deviceId.toLowerCase()) - ) - .forEach(s => this.cusS.set(s.fullDeviceId, s)); - } - //*** Logging always helps to see if everything is okay so far ***\\ - this.log( - "[%s] eWeLink devices were loaded from the Homebridge cache.", - this.devicesInHB.size - ); - this.log( - "[%s] primary devices were loaded from your eWeLink account.", - this.devicesInEwe.size - ); - this.log( - "[%s] primary devices were discovered on your local network.", - this.lanDevicesOnline - ); - //*** Remove Homebridge accessories that don't appear in eWeLink ***\\ - this.devicesInHB.forEach(a => { - if (!this.devicesInEwe.has(a.context.eweDeviceId)) { - this.removeAccessory(a); - } - }); - //*** Synchronise devices between eWeLink and Homebridge and set up ws/lan listeners ***\\ - this.devicesInEwe.forEach(d => this.initialiseDevice(d)); - this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); - this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); - this.log( - "eWeLink setup complete. If you're enjoying this package please consider a ⭐ī¸ on GitHub :)." - ); - if (this.config.debugReqRes || false) { - this.log.warn( - "You have 'Request & Response Logging' enabled. This setting is not recommended for long-term use." - ); - } - })(); - }) - .catch(err => { - this.log.error("************** Cannot load homebridge-ewelink **************"); - this.log.error(err); - this.log.error("************************************************************"); - if (this.lanClient) this.lanClient.closeConnection(); - if (this.wsClient) this.wsClient.closeConnection(); + .on("didFinishLaunching", () => this.eWeLinkSync()) + .on("shutdown", () => { + if (this.lanClient) this.lanClient.closeConnection(); + if (this.wsClient) this.wsClient.closeConnection(); + }); + } + eWeLinkSync() { + this.log("Plugin has finished initialising. Synching with eWeLink."); + this.httpClient = new eWeLinkHTTP(this.config, this.log); + this.httpClient + .getHost() + .then(() => this.httpClient.login()) + .then(res => { + this.authData = res; + return this.httpClient.getDevices(); + }) + .then(res => { + res.forEach(device => this.devicesInEW.set(device.deviceid, device)); + this.wsClient = new eWeLinkWS(this.config, this.log, this.authData); + this.lanClient = new eWeLinkLAN(this.config, this.log, res); + return this.wsClient.getHost(); + }) + .then(() => { + this.wsClient.login(); + return this.lanClient.getHosts(); + }) + .then(res => { + this.lanDevices = res.map; + this.lanCount = res.count; + return this.lanClient.startMonitor(); + }) + .then(() => { + (() => { + //*** Make a map of custom groups from Homebridge config ***\\ + if (Object.keys(this.config.groups || []).length > 0) { + this.config.groups + .filter(g => g.hasOwnProperty("type") && cns.allowedGroups.includes(g.type)) + .filter(g => g.hasOwnProperty("deviceId") && this.devicesInEW.has(g.deviceId)) + .forEach(g => this.cusG.set(g.deviceId + "SWX", g)); + } + //*** Make a map of RF Bridge custom sensors from Homebridge config ***\\ + if (Object.keys(this.config.bridgeSensors || []).length > 0) { + this.config.bridgeSensors + .filter(s => s.hasOwnProperty("deviceId") && this.devicesInEW.has(s.deviceId)) + .forEach(s => this.cusS.set(s.fullDeviceId, s)); + } + //*** Logging always helps to see if everything is okay so far ***\\ + this.log("[%s] eWeLink devices loaded from the Homebridge cache.", this.devicesInHB.size); + this.log("[%s] primary devices loaded from your eWeLink account.", this.devicesInEW.size); + this.log("[%s] primary devices were discovered on your local network.", this.lanCount); + //*** Remove Homebridge accessories that don't appear in eWeLink ***\\ + this.devicesInHB.forEach(a => { + if (!this.devicesInEW.has(a.context.eweDeviceId)) { + this.removeAccessory(a); + } }); + //*** Synchronise devices between eWeLink and Homebridge and set up ws/lan listeners ***\\ + this.devicesInEW.forEach(d => this.initialiseDevice(d)); + this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); + this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); + this.log("eWeLink sync complete. Don't forget to ⭐ī¸ this plugin on GitHub!"); + if (this.config.debugReqRes || false) { + this.log.warn("Note: 'Request & Response Logging' is not advised for long-term use."); + } + })(); }) - .on("shutdown", () => { + .catch(err => { + this.log.error("************** Cannot load homebridge-ewelink **************"); + this.log.error(err); + this.log.error("************************************************************"); if (this.lanClient) this.lanClient.closeConnection(); if (this.wsClient) this.wsClient.closeConnection(); }); } initialiseDevice(device) { let accessory; - //*** First add the device if it isn't already in Homebridge. Yeah this code looks a mess :| ***\\ + //*** First add the device if it isn't already in Homebridge ***\\ + + //*** IRRIGATION VALVES ***\\ if ( - !this.devicesInHB.has(device.deviceid + "SWX") && - !this.devicesInHB.has(device.deviceid + "SW0") + device.extra.uiid === 2 && + device.brandName === "coolkit" && + device.productModel === "0285" ) { - if ( - device.extra.uiid === 2 && - device.brandName === "coolkit" && - device.productModel === "0285" - ) { - this.addAccessory(device, device.deviceid + "SWX", "valve"); - } else if ( - this.cusG.has(device.deviceid + "SWX") && - this.cusG.get(device.deviceid + "SWX").type === "blind" - ) { - this.addAccessory(device, device.deviceid + "SWX", "blind"); - } else if ( - this.cusG.has(device.deviceid + "SWX") && - this.cusG.get(device.deviceid + "SWX").type === "garage" - ) { - this.addAccessory(device, device.deviceid + "SWX", "garage"); - } else if ( - this.cusG.has(device.deviceid + "SWX") && - this.cusG.get(device.deviceid + "SWX").type === "lock" - ) { - this.addAccessory(device, device.deviceid + "SWX", "lock"); - } else if (cns.devicesSensor.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SWX", "sensor"); - } else if (cns.devicesFan.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SWX", "fan"); - } else if (cns.devicesThermostat.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SWX", "thermostat"); - } else if (cns.devicesOutlet.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SWX", "outlet"); - } else if (cns.devicesUSB.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SWX", "usb"); - } else if (cns.devicesSCM.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SWX", "scm"); - } else if ( - cns.devicesSingleSwitch.includes(device.extra.uiid) && - cns.devicesSingleSwitchLight.includes(device.productModel) - ) { - this.addAccessory(device, device.deviceid + "SWX", "light"); - } else if ( - cns.devicesMultiSwitch.includes(device.extra.uiid) && - cns.devicesMultiSwitchLight.includes(device.productModel) - ) { - for (let i = 0; i <= cns.chansFromUiid[device.extra.uiid]; i++) { - this.addAccessory(device, device.deviceid + "SW" + i, "light"); - } - } else if (cns.devicesSingleSwitch.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SWX", "switch"); - } else if (cns.devicesMultiSwitch.includes(device.extra.uiid)) { - for (let i = 0; i <= cns.chansFromUiid[device.extra.uiid]; i++) { - this.addAccessory(device, device.deviceid + "SW" + i, "switch"); + accessory = this.devicesInHB.has(device.deviceid + "SWX") + ? this.devicesInHB.get(device.deviceid + "SWX") + : this.addAccessory(device, device.deviceid + "SWX", "valve"); + } + + //*** WINDOW BLINDS ***\\ + else if ( + this.cusG.has(device.deviceid + "SWX") && + this.cusG.get(device.deviceid + "SWX").type === "blind" + ) { + accessory = this.devicesInHB.has(device.deviceid + "SWX") + ? this.devicesInHB.get(device.deviceid + "SWX") + : this.addAccessory(device, device.deviceid + "SWX", "blind"); + } + + //*** GARAGES ***\\ + else if ( + this.cusG.has(device.deviceid + "SWX") && + this.cusG.get(device.deviceid + "SWX").type === "garage" + ) { + accessory = this.devicesInHB.has(device.deviceid + "SWX") + ? this.devicesInHB.get(device.deviceid + "SWX") + : this.addAccessory(device, device.deviceid + "SWX", "garage"); + } + + //*** LOCKS ***\\ + else if ( + this.cusG.has(device.deviceid + "SWX") && + this.cusG.get(device.deviceid + "SWX").type === "lock" + ) { + accessory = this.devicesInHB.has(device.deviceid + "SWX") + ? this.devicesInHB.get(device.deviceid + "SWX") + : this.addAccessory(device, device.deviceid + "SWX", "lock"); + } + + //*** DW2 SENSORS ***\\ + else if (cns.devicesSensor.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + "SWX") + ? this.devicesInHB.get(device.deviceid + "SWX") + : this.addAccessory(device, device.deviceid + "SWX", "sensor"); + } + + //*** FANS ***\\ + else if (cns.devicesFan.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + "SWX") + ? this.devicesInHB.get(device.deviceid + "SWX") + : this.addAccessory(device, device.deviceid + "SWX", "fan"); + } + + //*** THERMOSTATS ***\\ + else if (cns.devicesThermostat.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + "SWX") + ? this.devicesInHB.get(device.deviceid + "SWX") + : this.addAccessory(device, device.deviceid + "SWX", "thermostat"); + } + + //*** OUTLETS ***\\ + else if (cns.devicesOutlet.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + "SWX") + ? this.devicesInHB.get(device.deviceid + "SWX") + : this.addAccessory(device, device.deviceid + "SWX", "outlet"); + } + + //*** USB OUTLETS ***\\ + else if (cns.devicesUSB.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + "SWX") + ? this.devicesInHB.get(device.deviceid + "SWX") + : this.addAccessory(device, device.deviceid + "SWX", "usb"); + } + + //*** SINGLE CHANNEL [MULTI CHANNEL HARDWARE] ***\\ + else if (cns.devicesSCM.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + "SWX") + ? this.devicesInHB.get(device.deviceid + "SWX") + : this.addAccessory(device, device.deviceid + "SWX", "scm"); + } + + //*** SINGLE CHANNEL LIGHTS ***\\ + else if ( + cns.devicesSingleSwitch.includes(device.extra.uiid) && + cns.devicesSingleSwitchLight.includes(device.productModel) + ) { + accessory = this.devicesInHB.has(device.deviceid + "SWX") + ? this.devicesInHB.get(device.deviceid + "SWX") + : this.addAccessory(device, device.deviceid + "SWX", "light"); + } + + //*** MULTI CHANNEL LIGHTS ***\\ + else if ( + cns.devicesMultiSwitch.includes(device.extra.uiid) && + cns.devicesMultiSwitchLight.includes(device.productModel) + ) { + if (this.config.hideMasters) { + if (this.devicesInHB.has(device.deviceid + "SW0")) { + this.removeAccessory(this.devicesInHB.get(device.deviceid + "SW0")); } - } else if (cns.devicesRFBridge.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SW0", "rf_pri"); - if (Object.keys((device.tags && device.tags.zyx_info) || []).length > 0) { - for (let i = 1; i <= Object.keys(device.tags.zyx_info).length; i++) { - this.addAccessory(device, device.deviceid + "SW" + i, "rf_sub"); + this.hiddenMasters.push(device.deviceid); + accessory = this.addAccessory(device, device.deviceid + "SW0", "light", true); + } else { + accessory = this.devicesInHB.has(device.deviceid + "SW0") + ? this.devicesInHB.get(device.deviceid + "SW0") + : this.addAccessory(device, device.deviceid + "SW0", "light"); + } + for (let i = 1; i <= cns.chansFromUiid[device.extra.uiid]; i++) { + if ((this.config.hideFromHB || "").includes(device.deviceid + "SW" + i)) { + if (this.devicesInHB.has(device.deviceid + "SW" + i)) { + this.removeAccessory(this.devicesInHB.get(device.deviceid + "SW" + i)); } + } else { + let oAccessory = this.devicesInHB.has(device.deviceid + "SW" + i) + ? this.devicesInHB.get(device.deviceid + "SW" + i) + : this.addAccessory(device, device.deviceid + "SW" + i, "light"); + oAccessory + .getService(Service.AccessoryInformation) + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); + oAccessory.context.reachableWAN = device.online; + oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); } - } else if (cns.devicesZBBridge.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SWX", "zb_pri"); - } else if (cns.devicesZB.includes(device.extra.uiid)) { - this.addAccessory(device, device.deviceid + "SWX", "zb_sub"); - } else if (cns.devicesCamera.includes(device.extra.uiid)) { - this.log.warn( - '[%s] please see "https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-Sonoff-Camera".', - device.name - ); - return; - } else { - this.log.warn( - "[%s] cannot be added as it is not supported by this plugin. Please make a GitHub issue request.", - device.name - ); - return; } } - //*** Next refresh the device ***\\ - if ( - (accessory = - this.devicesInHB.get(device.deviceid + "SWX") || - this.devicesInHB.get(device.deviceid + "SW0")) - ) { - let isX = accessory.context.hbDeviceId.substr(-1) === "X", - isRfBridge = cns.devicesRFBridge.includes(accessory.context.eweUIID), - rfBridgeChange = false; - accessory - .getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); - accessory.context.reachableWAN = accessory.context.eweUIID !== 102 ? device.online : true; - accessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; - accessory.context.inUse = false; - let str = accessory.context.reachableLAN - ? "and locally with IP [" + this.lanDevices.get(device.deviceid).ip + "]" - : "but LAN mode unavailable as unsupported/shared device"; - this.log("[%s] found in eWeLink %s.", accessory.displayName, str); - this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - if (!isX) { - for (let i = 1; i <= accessory.context.channelCount; i++) { - if (!this.devicesInHB.has(device.deviceid + "SW" + i)) { - if (cns.devicesHideable.includes(accessory.context.type)) { - if ((this.config.hideFromHB || "").includes(device.deviceid + "SW" + i)) { - continue; - } else { - this.addAccessory(device, device.deviceid + "SW" + i, "switch"); - } - } - } - let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); - if ( - (this.config.hideFromHB || "").includes(device.deviceid + "SW" + i) && - cns.devicesHideable.includes(accessory.context.type) - ) { - this.removeAccessory(oAccessory); - continue; - } - if (isRfBridge && oAccessory.context.sensorType !== "button") { - let ct = this.cusS.has(oAccessory.context.hbDeviceId) - ? this.cusS.get(oAccessory.context.hbDeviceId).type - : "motion"; - if (ct !== oAccessory.context.sensorType) rfBridgeChange = true; + + //*** SINGLE CHANNEL SWITCHES ***\\ + else if (cns.devicesSingleSwitch.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + "SWX") + ? this.devicesInHB.get(device.deviceid + "SWX") + : this.addAccessory(device, device.deviceid + "SWX", "switch"); + } + + //*** MULTI CHANNEL SWITCHES ***\\ + else if (cns.devicesMultiSwitch.includes(device.extra.uiid)) { + if (this.config.hideMasters) { + if (this.devicesInHB.has(device.deviceid + "SW0")) { + this.removeAccessory(this.devicesInHB.get(device.deviceid + "SW0")); + } + this.hiddenMasters.push(device.deviceid); + accessory = this.addAccessory(device, device.deviceid + "SW0", "switch", true); + } else { + accessory = this.devicesInHB.has(device.deviceid + "SW0") + ? this.devicesInHB.get(device.deviceid + "SW0") + : this.addAccessory(device, device.deviceid + "SW0", "switch"); + } + for (let i = 1; i <= cns.chansFromUiid[device.extra.uiid]; i++) { + if ((this.config.hideFromHB || "").includes(device.deviceid + "SW" + i)) { + if (this.devicesInHB.has(device.deviceid + "SW" + i)) { + this.removeAccessory(this.devicesInHB.get(device.deviceid + "SW" + i)); } + } else { + let oAccessory = this.devicesInHB.has(device.deviceid + "SW" + i) + ? this.devicesInHB.get(device.deviceid + "SW" + i) + : this.addAccessory(device, device.deviceid + "SW" + i, "switch"); oAccessory .getService(Service.AccessoryInformation) .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); @@ -282,31 +272,118 @@ class eWeLink { this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); } } - if (rfBridgeChange) { - this.log.warn( - "[%s] bridge configuration changed so devices will be removed and readded.", - accessory.displayName - ); - for (let i = 0; i <= accessory.context.channelCount; i++) { - let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); - this.removeAccessory(oAccessory); + } + + //*** RF BRIDGES ***\\ + else if (cns.devicesRFBridge.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + "SW0") + ? this.devicesInHB.get(device.deviceid + "SW0") + : this.addAccessory(device, device.deviceid + "SW0", "rf_pri"); + if (Object.keys((device.tags && device.tags.zyx_info) || []).length > 0) { + let rfBridgeChange = false; + for (let i = 1; i <= Object.keys(device.tags.zyx_info).length; i++) { + let oAccessory = this.devicesInHB.has(device.deviceid + "SW" + i) + ? this.devicesInHB.get(device.deviceid + "SW" + i) + : this.addAccessory(device, device.deviceid + "SW" + i, "rf_sub"); + oAccessory + .getService(Service.AccessoryInformation) + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); + oAccessory.context.reachableWAN = device.online; + oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); + if (oAccessory.context.sensorType !== "button" && !rfBridgeChange) { + let ct = this.cusS.has(oAccessory.context.hbDeviceId) + ? this.cusS.get(oAccessory.context.hbDeviceId).type + : "motion"; + if (ct !== oAccessory.context.sensorType) rfBridgeChange = true; + } + } + if (rfBridgeChange) { + this.log.warn( + "[%s] bridge configuration changed so devices will be removed and readded.", + accessory.displayName + ); + for (let i = 0; i <= accessory.context.channelCount; i++) { + let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); + this.removeAccessory(oAccessory); + } + this.initialiseDevice(device); + return; } - this.initialiseDevice(device); - return; } - if (!this.refreshAccessory(accessory, device.params)) { - this.log.warn( - "[%s] could not be initialised. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.) [debug:%s:%s].", - accessory.displayName, - accessory.context.type, - accessory.context.channelCount - ); + } + + //*** ZIGBEE BRIDGES ***\\ + else if (cns.devicesZBBridge.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + "SWX") + ? this.devicesInHB.get(device.deviceid + "SWX") + : this.addAccessory(device, device.deviceid + "SWX", "zb_pri"); + } + + //*** ZIGBEE DEVICES ***\\ + else if (cns.devicesZB.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + "SWX") + ? this.devicesInHB.get(device.deviceid + "SWX") + : this.addAccessory(device, device.deviceid + "SWX", "zb_sub"); + } + + //*** SONOFF CAMERAS ***\\ + else if (cns.devicesCamera.includes(device.extra.uiid)) { + this.log.warn( + ' → [%s] please see "https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-Sonoff-Camera".', + device.name + ); + return; + } + + //*** ALL OTHER = UNSUPPORTED ***\\ + else { + this.log.warn( + " → [%s] cannot be added as it is not supported by this plugin. Please make a GitHub issue request.", + device.name + ); + return; + } + + if (!accessory) { + return; + } + //*** Next refresh the device ***\\ + if (!this.hiddenMasters.includes(device.deviceid)) { + accessory + .getService(Service.AccessoryInformation) + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); + } + accessory.context.reachableWAN = device.online; + accessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; + accessory.context.inUse = false; + + let str = accessory.context.reachableLAN + ? "and found locally with IP [" + this.lanDevices.get(device.deviceid).ip + "]" + : "but LAN mode unavailable as device "; + if (!accessory.context.reachableLAN) { + if (cns.devicesNonLAN.includes(device.extra.uiid)) { + str += "doesn't support it"; + } else if (device.hasOwnProperty("sharedBy") && device.sharedBy.hasOwnProperty("email")) { + str += "is shared (" + device.sharedBy.email + ")"; + } else { + str += "is unreachable"; } - } else { - this.log.warn("[%s] cannot be initialised as it wasn't found in Homebridge.", device.name); + } + + this.log(" → [%s] initialised %s.", device.name, str); + this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + + if (!this.refreshAccessory(accessory, device.params)) { + this.log.warn( + "[%s] could not be initialised. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.) [debug:%s:%s].", + accessory.displayName, + accessory.context.type, + accessory.context.channelCount + ); } } - addAccessory(device, hbDeviceId, type) { + addAccessory(device, hbDeviceId, type, hidden = false) { let switchNumber = hbDeviceId.substr(-1).toString(), newDeviceName = type === "rf_sub" ? device.tags.zyx_info[switchNumber - 1].name : device.name, channelCount = @@ -315,29 +392,24 @@ class eWeLink { : cns.chansFromUiid[device.extra.uiid]; if (["1", "2", "3", "4"].includes(switchNumber) && type !== "rf_sub") { newDeviceName += " SW" + switchNumber; - if ( - (this.config.hideFromHB || "").includes(hbDeviceId) && - cns.devicesHideable.includes(type) - ) { - this.log("[%s] will not be added as per configuration.", newDeviceName); - return; - } } if ((this.config.nameOverride || {}).hasOwnProperty(hbDeviceId)) { newDeviceName = this.config.nameOverride[hbDeviceId]; } - const accessory = new Accessory(newDeviceName, UUIDGen.generate(hbDeviceId).toString()); try { - accessory - .getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.SerialNumber, hbDeviceId) - .setCharacteristic(Characteristic.Manufacturer, device.brandName) - .setCharacteristic( - Characteristic.Model, - device.productModel + " (" + device.extra.model + ")" - ) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) - .setCharacteristic(Characteristic.Identify, false); + const accessory = new Accessory(newDeviceName, UUIDGen.generate(hbDeviceId).toString()); + if (!hidden) { + accessory + .getService(Service.AccessoryInformation) + .setCharacteristic(Characteristic.SerialNumber, hbDeviceId) + .setCharacteristic(Characteristic.Manufacturer, device.brandName) + .setCharacteristic( + Characteristic.Model, + device.productModel + " (" + device.extra.model + ")" + ) + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) + .setCharacteristic(Characteristic.Identify, false); + } accessory.context = { hbDeviceId, eweDeviceId: device.deviceid, @@ -348,197 +420,15 @@ class eWeLink { channelCount, type, }; - switch (type) { - case "valve": - ["A", "B"].forEach(v => { - accessory - .addService(Service.Valve, "Valve " + v, "valve" + v.toLowerCase()) - .setCharacteristic(Characteristic.Active, 0) - .setCharacteristic(Characteristic.InUse, 0) - .setCharacteristic(Characteristic.ValveType, 1) - .setCharacteristic(Characteristic.SetDuration, this.config.valveTimeLength || 120) - .addCharacteristic(Characteristic.RemainingDuration); - }); - break; - case "blind": - accessory - .addService(Service.WindowCovering) - .setCharacteristic(Characteristic.CurrentPosition, 100) - .setCharacteristic(Characteristic.TargetPosition, 100) - .setCharacteristic(Characteristic.PositionState, 2); - break; - case "garage": - accessory - .addService(Service.GarageDoorOpener) - .setCharacteristic(Characteristic.CurrentDoorState, 1) - .setCharacteristic(Characteristic.TargetDoorState, 1) - .setCharacteristic(Characteristic.ObstructionDetected, false); - break; - case "lock": - accessory - .addService(Service.LockMechanism) - .setCharacteristic(Characteristic.LockCurrentState, 1) - .setCharacteristic(Characteristic.LockTargetState, 1); - break; - case "sensor": - accessory.addService(Service.ContactSensor); - accessory.addService(Service.BatteryService); - break; - case "fan": - accessory.addService(Service.Fanv2); - accessory.addService(Service.Lightbulb); - break; - case "thermostat": - if (!this.config.hideTHSwitch) accessory.addService(Service.Switch); - accessory.addService(Service.TemperatureSensor); - if (device.params.sensorType !== "DS18B20") accessory.addService(Service.HumiditySensor); - break; - case "outlet": - accessory.addService(Service.Outlet); - accessory - .getService(Service.Outlet) - .addCharacteristic(EveService.Characteristics.Voltage); - accessory - .getService(Service.Outlet) - .addCharacteristic(EveService.Characteristics.CurrentConsumption); - accessory - .getService(Service.Outlet) - .addCharacteristic(EveService.Characteristics.ElectricCurrent); - accessory - .getService(Service.Outlet) - .addCharacteristic(EveService.Characteristics.TotalConsumption); - accessory - .getService(Service.Outlet) - .addCharacteristic(EveService.Characteristics.ResetTotal); - accessory.context = { - ...accessory.context, - ...{ - extraPersistedData: {}, - lastReset: 0, - totalEnergy: 0, - totalEnergyTemp: 0, - }, - }; - break; - case "usb": - accessory.addService(Service.Outlet); - break; - case "light": - accessory.addService(Service.Lightbulb); - break; - case "switch": - case "scm": - accessory.addService(Service.Switch); - break; - case "rf_pri": - accessory.context.rfChlMap = {}; - break; - case "zb_pri": - break; - case "rf_sub": - accessory.context.rfChls = {}; - switch (device.tags.zyx_info[parseInt(switchNumber) - 1].remote_type) { - case "1": - case "2": - case "3": - case "4": - accessory.context.sensorType = "button"; - break; - case "6": - accessory.context.sensorType = this.cusS.has(hbDeviceId) - ? this.cusS.get(hbDeviceId).type - : "motion"; - break; - default: - throw ( - "unsupported rf device type [" + - device.tags.zyx_info[parseInt(switchNumber) - 1].remote_type + - "]. Please create an issue on GitHub" - ); - } - let mAccessory = this.devicesInHB.get(device.deviceid + "SW0"); - device.tags.zyx_info[parseInt(switchNumber) - 1].buttonName.forEach(button => { - let rfData; - Object.entries(button).forEach( - ([k, v]) => - (rfData = { - rfChan: k, - name: v, - }) - ); - accessory.context.rfChls[rfData.rfChan] = rfData.name; - mAccessory.context.rfChlMap[rfData.rfChan] = switchNumber; - switch (accessory.context.sensorType) { - case "button": - accessory.addService(Service.Switch, rfData.name, "switch" + rfData.rfChan); - break; - case "water": - accessory.addService(Service.LeakSensor); - break; - case "fire": - case "smoke": - accessory.addService(Service.SmokeSensor); - break; - case "co": - accessory.addService(Service.CarbonMonoxideSensor); - break; - case "co2": - accessory.addService(Service.CarbonDioxideSensor); - break; - case "contact": - accessory.addService(Service.ContactSensor); - break; - case "occupancy": - accessory.addService(Service.OccupancySensor); - break; - default: - accessory.addService(Service.MotionSensor); - break; - } - this.devicesInHB.set(mAccessory.context.hbDeviceId, mAccessory); - }); - break; - case "zb_sub": //*** credit @tasict ***\\ - accessory.addService(Service.BatteryService); - switch (device.extra.uiid) { - case 1000: - accessory.addService(Service.StatelessProgrammableSwitch); - if (this.config.hideZBLDPress) { - accessory - .getService(Service.StatelessProgrammableSwitch) - .getCharacteristic(Characteristic.ProgrammableSwitchEvent) - .setProps({ - validValues: [0], - }); - } - break; - case 1770: - accessory.addService(Service.TemperatureSensor); - accessory.addService(Service.HumiditySensor); - break; - case 2026: - accessory.addService(Service.MotionSensor); - break; - case 3026: - accessory.addService(Service.ContactSensor); - break; - default: - throw ( - "unsupported zigbee device type [" + - device.extra.uiid + - "]. Please create an issue on GitHub" - ); - } - break; - default: - throw "device is not supported by this plugin. Please create an issue on GitHub"; + if (!hidden) { + this.api.registerPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); + this.configureAccessory(accessory); + this.log(" → [%s] has been added to Homebridge.", newDeviceName); } - this.devicesInHB.set(hbDeviceId, accessory); - this.api.registerPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); - this.configureAccessory(accessory); - this.log("[%s] has been added to Homebridge.", newDeviceName); + return accessory; } catch (err) { - this.log.warn("[%s] could not be added as %s.", newDeviceName, err); + this.log.warn(" → [%s] could not be added as %s.", newDeviceName, err); + return false; } } configureAccessory(accessory) { @@ -549,25 +439,30 @@ class eWeLink { switch (accessory.context.type) { case "valve": ["A", "B"].forEach(v => { - accessory - .getService("Valve " + v) + let valveService; + if (!(valveService = accessory.getService("Valve " + v))) { + accessory + .addService(Service.Valve, "Valve " + v, "valve" + v.toLowerCase()) + .setCharacteristic(Characteristic.Active, 0) + .setCharacteristic(Characteristic.InUse, 0) + .setCharacteristic(Characteristic.ValveType, 1) + .setCharacteristic(Characteristic.SetDuration, this.config.valveTimeLength || 120) + .addCharacteristic(Characteristic.RemainingDuration); + valveService = accessory.getService("Valve " + v); + } + valveService .getCharacteristic(Characteristic.Active) .on("set", (value, callback) => this.internalValveUpdate(accessory, "Valve " + v, value, callback) ); - accessory - .getService("Valve " + v) + valveService .getCharacteristic(Characteristic.SetDuration) .on("set", (value, callback) => { - if ( - accessory.getService("Valve " + v).getCharacteristic(Characteristic.InUse).value - ) { - accessory - .getService("Valve " + v) - .updateCharacteristic(Characteristic.RemainingDuration, value); - clearTimeout(accessory.getService("Valve " + v).timer); - accessory.getService("Valve " + v).timer = setTimeout(() => { - accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); + if (valveService.getCharacteristic(Characteristic.InUse).value) { + valveService.updateCharacteristic(Characteristic.RemainingDuration, value); + clearTimeout(valveService.timer); + valveService.timer = setTimeout(() => { + valveService.setCharacteristic(Characteristic.Active, 0); }, value * 1000); } callback(); @@ -575,8 +470,16 @@ class eWeLink { }); break; case "blind": - accessory - .getService(Service.WindowCovering) + let wcService; + if (!(wcService = accessory.getService(Service.WindowCovering))) { + accessory + .addService(Service.WindowCovering) + .setCharacteristic(Characteristic.CurrentPosition, 100) + .setCharacteristic(Characteristic.TargetPosition, 100) + .setCharacteristic(Characteristic.PositionState, 2); + wcService = accessory.getService(Service.WindowCovering); + } + wcService .getCharacteristic(Characteristic.TargetPosition) .on("set", (value, callback) => this.internalBlindUpdate(accessory, value, callback)) .setProps({ @@ -584,26 +487,44 @@ class eWeLink { }); break; case "garage": - accessory - .getService(Service.GarageDoorOpener) + let gdService; + if (!(gdService = accessory.getService(Service.GarageDoorOpener))) { + accessory + .addService(Service.GarageDoorOpener) + .setCharacteristic(Characteristic.CurrentDoorState, 1) + .setCharacteristic(Characteristic.TargetDoorState, 1) + .setCharacteristic(Characteristic.ObstructionDetected, false); + gdService = accessory.getService(Service.GarageDoorOpener); + } + gdService .getCharacteristic(Characteristic.TargetDoorState) .on("set", (value, callback) => this.internalGarageUpdate(accessory, value, callback)); break; case "lock": - accessory - .getService(Service.LockMechanism) + let lmService = + accessory.getService(Service.LockMechanism) || + accessory.addService(Service.LockMechanism); + lmService .getCharacteristic(Characteristic.LockTargetState) .on("set", (value, callback) => this.internalLockUpdate(accessory, value, callback)); break; + case "sensor": + accessory.getService(Service.ContactSensor) || + accessory.addService(Service.ContactSensor); + accessory.getService(Service.BatteryService) || + accessory.addService(Service.BatteryService); + break; case "fan": - accessory - .getService(Service.Fanv2) + let fanService = + accessory.getService(Service.Fanv2) || accessory.addService(Service.Fanv2), + fanLightService = + accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb); + fanService .getCharacteristic(Characteristic.Active) .on("set", (value, callback) => this.internalFanUpdate(accessory, "power", value, callback) ); - accessory - .getService(Service.Fanv2) + fanService .getCharacteristic(Characteristic.RotationSpeed) .on("set", (value, callback) => this.internalFanUpdate(accessory, "speed", value, callback) @@ -611,17 +532,26 @@ class eWeLink { .setProps({ minStep: 33, }); - accessory - .getService(Service.Lightbulb) + fanLightService .getCharacteristic(Characteristic.On) .on("set", (value, callback) => this.internalFanUpdate(accessory, "light", value, callback) ); break; case "thermostat": + let tempService = + accessory.getService(Service.TemperatureSensor) || + accessory.addService(Service.TemperatureSensor), + humiService = false; + if (this.devicesInEW.get(accessory.context.eweDeviceId).params.sensorType !== "DS18B20") { + humiService = + accessory.getService(Service.HumiditySensor) || + accessory.addService(Service.HumiditySensor); + } if (!this.config.hideTHSwitch) { - accessory - .getService(Service.Switch) + let switchService = + accessory.getService(Service.Switch) || accessory.addService(Service.Switch); + switchService .getCharacteristic(Characteristic.On) .on("set", (value, callback) => this.internalThermostatUpdate(accessory, value, callback) @@ -636,30 +566,24 @@ class eWeLink { corrInterval.setCorrectingInterval(() => { let dataToAdd = { time: Date.now(), - temp: accessory - .getService(Service.TemperatureSensor) - .getCharacteristic(Characteristic.CurrentTemperature).value, + temp: tempService.getCharacteristic(Characteristic.CurrentTemperature).value, }; - if (accessory.getService(Service.HumiditySensor)) { - dataToAdd.humidity = accessory - .getService(Service.HumiditySensor) - .getCharacteristic(Characteristic.CurrentRelativeHumidity).value; + if (humiService) { + humiService.getCharacteristic(Characteristic.CurrentRelativeHumidity).value; } accessory.eveLogger.addEntry(dataToAdd); }, 300000); break; case "outlet": - accessory - .getService(Service.Outlet) - .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalOutletUpdate(accessory, value, callback)); - accessory.log = this.log; - accessory.eveLogger = new EveHistoryService("energy", accessory, { - storage: "fs", - minutes: 5, - path: this.eveLogPath, - }); - if (!accessory.context.hasOwnProperty("lastReset")) { + let outletService; + if (!(outletService = accessory.getService(Service.Outlet))) { + accessory.addService(Service.Outlet); + outletService = accessory.getService(Service.Outlet); + outletService.addCharacteristic(EveService.Characteristics.Voltage); + outletService.addCharacteristic(EveService.Characteristics.CurrentConsumption); + outletService.addCharacteristic(EveService.Characteristics.ElectricCurrent); + outletService.addCharacteristic(EveService.Characteristics.TotalConsumption); + outletService.addCharacteristic(EveService.Characteristics.ResetTotal); accessory.context = { ...accessory.context, ...{ @@ -670,13 +594,20 @@ class eWeLink { }, }; } + outletService + .getCharacteristic(Characteristic.On) + .on("set", (value, callback) => this.internalOutletUpdate(accessory, value, callback)); + accessory.log = this.log; + accessory.eveLogger = new EveHistoryService("energy", accessory, { + storage: "fs", + minutes: 5, + path: this.eveLogPath, + }); corrInterval.setCorrectingInterval(() => { - let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On) - .value, + let isOn = outletService.getCharacteristic(Characteristic.On).value, currentWatt = isOn - ? accessory - .getService(Service.Outlet) - .getCharacteristic(EveService.Characteristics.CurrentConsumption).value + ? outletService.getCharacteristic(EveService.Characteristics.CurrentConsumption) + .value : 0; if (accessory.eveLogger.isHistoryLoaded()) { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); @@ -707,8 +638,7 @@ class eWeLink { power: currentWatt, }); }, 300000); - accessory - .getService(Service.Outlet) + outletService .getCharacteristic(EveService.Characteristics.TotalConsumption) .on("get", callback => { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); @@ -717,8 +647,7 @@ class eWeLink { } callback(null, accessory.context.totalEnergy); }); - accessory - .getService(Service.Outlet) + outletService .getCharacteristic(EveService.Characteristics.ResetTotal) .on("set", (value, callback) => { accessory.context.totalEnergy = 0; @@ -738,34 +667,33 @@ class eWeLink { }); break; case "usb": - accessory - .getService(Service.Outlet) + let usbService = + accessory.getService(Service.Outlet) || accessory.addService(Service.Outlet); + usbService .getCharacteristic(Characteristic.On) .on("set", (value, callback) => this.internalUSBUpdate(accessory, value, callback)); break; case "scm": - accessory - .getService(Service.Switch) + let scmService = + accessory.getService(Service.Switch) || accessory.addService(Service.Switch); + scmService .getCharacteristic(Characteristic.On) .on("set", (value, callback) => this.internalSCMUpdate(accessory, value, callback)); break; case "light": - accessory - .getService(Service.Lightbulb) + let lightService = + accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb); + lightService .getCharacteristic(Characteristic.On) .on("set", (value, callback) => this.internalLightbulbUpdate(accessory, value, callback) ); if (cns.devicesBrightable.includes(accessory.context.eweUIID)) { - accessory - .getService(Service.Lightbulb) + lightService .getCharacteristic(Characteristic.Brightness) .on("set", (value, callback) => { if (value > 0) { - if ( - !accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) - .value - ) { + if (!lightService.getCharacteristic(Characteristic.On).value) { this.internalLightbulbUpdate(accessory, true, function () { return; }); @@ -776,15 +704,11 @@ class eWeLink { } }); } else if (cns.devicesColourable.includes(accessory.context.eweUIID)) { - accessory - .getService(Service.Lightbulb) + lightService .getCharacteristic(Characteristic.Brightness) .on("set", (value, callback) => { if (value > 0) { - if ( - !accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) - .value - ) { + if (!lightService.getCharacteristic(Characteristic.On).value) { this.internalLightbulbUpdate(accessory, true, function () { return; }); @@ -794,25 +718,102 @@ class eWeLink { this.internalLightbulbUpdate(accessory, false, callback); } }); - accessory - .getService(Service.Lightbulb) + lightService .getCharacteristic(Characteristic.Hue) .on("set", (value, callback) => this.internalHSBUpdate(accessory, "hue", value, callback) ); - accessory - .getService(Service.Lightbulb) + lightService .getCharacteristic(Characteristic.Saturation) .on("set", (value, callback) => callback()); } break; case "switch": - accessory - .getService(Service.Switch) + let switchService = + accessory.getService(Service.Switch) || accessory.addService(Service.Switch); + switchService .getCharacteristic(Characteristic.On) .on("set", (value, callback) => this.internalSwitchUpdate(accessory, value, callback)); break; + case "rf_pri": + if (!accessory.context.hasOwnProperty("rfChlMap")) { + accessory.context.rfChlMap = {}; + } + break; case "rf_sub": + if (!accessory.context.hasOwnProperty("rfChls")) { + accessory.context.rfChls = {}; + } + switch ( + this.devicesInEW.get(accessory.context.eweDeviceId).tags.zyx_info[ + parseInt(accessory.context.switchNumber) - 1 + ].remote_type + ) { + case "1": + case "2": + case "3": + case "4": + accessory.context.sensorType = "button"; + break; + case "6": + accessory.context.sensorType = this.cusS.has(accessory.context.hbDeviceId) + ? this.cusS.get(accessory.context.hbDeviceId).type + : "motion"; + break; + } + let mAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); + this.devicesInEW + .get(mAccessory.context.eweDeviceId) + .tags.zyx_info[parseInt(accessory.context.switchNumber) - 1].buttonName.forEach( + button => { + let rfData; + Object.entries(button).forEach( + ([k, v]) => + (rfData = { + rfChan: k, + name: v, + }) + ); + accessory.context.rfChls[rfData.rfChan] = rfData.name; + mAccessory.context.rfChlMap[rfData.rfChan] = accessory.context.switchNumber; + this.devicesInHB.set(mAccessory.context.hbDeviceId, mAccessory); + switch (accessory.context.sensorType) { + case "button": + accessory.getService(rfData.name) || + accessory.addService(Service.Switch, rfData.name, "switch" + rfData.rfChan); + break; + case "water": + accessory.getService(Service.LeakSensor) || + accessory.addService(Service.LeakSensor); + break; + case "fire": + case "smoke": + accessory.getService(Service.SmokeSensor) || + accessory.addService(Service.SmokeSensor); + break; + case "co": + accessory.getService(Service.CarbonMonoxideSensor) || + accessory.addService(Service.CarbonMonoxideSensor); + break; + case "co2": + accessory.getService(Service.CarbonDioxideSensor) || + accessory.addService(Service.CarbonDioxideSensor); + break; + case "contact": + accessory.getService(Service.ContactSensor) || + accessory.addService(Service.ContactSensor); + break; + case "occupancy": + accessory.getService(Service.OccupancySensor) || + accessory.addService(Service.OccupancySensor); + break; + default: + accessory.getService(Service.MotionSensor) || + accessory.addService(Service.MotionSensor); + break; + } + } + ); accessory.context.rfChls = accessory.context.rfChls || {}; if (accessory.context.sensorType === "button") { Object.entries(accessory.context.rfChls).forEach(([k, v]) => { @@ -825,27 +826,53 @@ class eWeLink { }); }); } + break; - case "zb_sub": - if (accessory.context.eweUIID === 1770) { - accessory.log = this.log; - accessory.eveLogger = new EveHistoryService("weather", accessory, { - storage: "fs", - minutes: 5, - path: this.eveLogPath, - }); - corrInterval.setCorrectingInterval(() => { - let dataToAdd = { - time: Date.now(), - temp: accessory - .getService(Service.TemperatureSensor) - .getCharacteristic(Characteristic.CurrentTemperature).value, - humidity: accessory - .getService(Service.HumiditySensor) - .getCharacteristic(Characteristic.CurrentRelativeHumidity).value, - }; - accessory.eveLogger.addEntry(dataToAdd); - }, 300000); + case "zb_sub": //*** credit @tasict ***\\ + accessory.getService(Service.BatteryService) || + accessory.addService(Service.BatteryService); + switch (accessory.context.eweUIID) { + case 1000: + let zbspsService = + accessory.getService(Service.StatelessProgrammableSwitch) || + accessory.addService(Service.StatelessProgrammableSwitch); + if (this.config.hideZBLDPress) { + zbspsService.getCharacteristic(Characteristic.ProgrammableSwitchEvent).setProps({ + validValues: [0], + }); + } + break; + case 1770: + let zbTempService = + accessory.getService(Service.TemperatureSensor) || + accessory.addService(Service.TemperatureSensor); + let zbHumiService = + accessory.getService(Service.HumiditySensor) || + accessory.addService(Service.HumiditySensor); + accessory.log = this.log; + accessory.eveLogger = new EveHistoryService("weather", accessory, { + storage: "fs", + minutes: 5, + path: this.eveLogPath, + }); + corrInterval.setCorrectingInterval(() => { + let dataToAdd = { + time: Date.now(), + temp: zbTempService.getCharacteristic(Characteristic.CurrentTemperature).value, + humidity: zbHumiService.getCharacteristic(Characteristic.CurrentRelativeHumidity) + .value, + }; + accessory.eveLogger.addEntry(dataToAdd); + }, 300000); + break; + case 2026: + accessory.getService(Service.MotionSensor) || + accessory.addService(Service.MotionSensor); + break; + case 3026: + accessory.getService(Service.ContactSensor) || + accessory.addService(Service.ContactSensor); + break; } break; } @@ -974,11 +1001,11 @@ class eWeLink { } removeAccessory(accessory) { try { - this.devicesInHB.delete(accessory.context.hbDeviceId); this.api.unregisterPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); - this.log("[%s] has been removed from Homebridge.", accessory.displayName); + this.devicesInHB.delete(accessory.context.hbDeviceId); + this.log(" → [%s] was removed from Homebridge.", accessory.displayName); } catch (err) { - this.log.warn("[%s] needed to be removed but couldn't as %s.", accessory.displayName, err); + this.log.warn(" → [%s] wasn't removed as %s.", accessory.displayName, err); } } sendDeviceUpdate(accessory, params, callback) { @@ -989,8 +1016,10 @@ class eWeLink { }; let sendViaWS = () => { if (accessory.context.reachableWAN) { - this.wsClient.sendUpdate(payload); - callback(); + this.wsClient + .sendUpdate(payload) + .then(() => callback()) + .catch(err => callback(err)); } else { this.log.error( "[%s] could not be updated as it appears to be offline.", @@ -1014,81 +1043,73 @@ class eWeLink { } } receiveDeviceUpdate(device) { - let accessory; - switch (device.action) { - case "sysmsg": - if ( - (accessory = - this.devicesInHB.get(device.deviceid + "SWX") || - this.devicesInHB.get(device.deviceid + "SW0")) - ) { - let isX = accessory.context.hbDeviceId.substr(-1) === "X"; - if (device.params.updateSource === "WS") { - if (accessory.context.reachableWAN !== device.params.online) { - accessory.context.reachableWAN = device.params.online; - this.log( - "[%s] has been reported [%s] via [WS].", - accessory.displayName, - accessory.context.reachableWAN ? "online" : "offline" - ); - this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - if (accessory.context.reachableWAN) this.wsClient.requestUpdate(accessory); - } else { - if (this.debug) { - this.log("[%s] Nothing to update from above WS message.", accessory.displayName); - } - } - } - if (!isX) { - for (let i = 1; i <= accessory.context.channelCount; i++) { - if (this.devicesInHB.has(device.deviceid + "SW" + i)) { - let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); - oAccessory.context.reachableWAN = device.params.online; - this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); - } - } - } + let accessory, + deviceId = device.deviceid, + reachableChange = false; + if ( + (accessory = this.devicesInHB.get(deviceId + "SWX") || this.devicesInHB.get(deviceId + "SW0")) + ) { + let isX = accessory.context.hbDeviceId.substr(-1) === "X"; + if (device.params.updateSource === "WS") { + if (device.params.online != accessory.context.reachableWAN) { + accessory.context.reachableWAN = device.params.online; + this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + if (accessory.context.reachableWAN) + this.wsClient.requestUpdate(accessory).catch(() => {}); + reachableChange = true; + this.log.warn( + "[%s] has been reported [%s] via [WS].", + accessory.displayName, + accessory.context.reachableWAN ? "online" : "offline" + ); } - break; - case "update": - if ( - (accessory = - this.devicesInHB.get(device.deviceid + "SWX") || - this.devicesInHB.get(device.deviceid + "SW0")) - ) { - if (device.params.updateSource === "WS" && !accessory.context.reachableWAN) { - accessory.context.reachableWAN = true; - this.log("[%s] has been reported [online] via [WS].", accessory.displayName); - } - if (device.params.updateSource === "LAN" && !accessory.context.reachableLAN) { - accessory.context.reachableLAN = true; - this.log("[%s] has been reported [online] via [LAN].", accessory.displayName); - } - if (this.debug) { - this.log( - "[%s] externally updated from above %s message and will be refreshed.", - accessory.displayName, - device.params.updateSource - ); - } - if (!this.refreshAccessory(accessory, device.params)) { - this.log.warn( - "[%s] cannot be refreshed. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.). [debug:%s:%s]", - accessory.displayName, - accessory.context.type, - accessory.context.channelCount - ); - } - } else { - if (!(this.config.hideDevFromHB || "").includes(device.deviceid)) { - this.log.warn( - "[%s] Accessory received via %s update does not exist in Homebridge. If it's a new accessory please restart Homebridge so it is added.", - device.deviceid, - device.params.updateSource - ); + } + if (device.params.updateSource === "LAN" && !accessory.context.reachableLAN) { + accessory.context.reachableLAN = true; + this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + this.wsClient.requestUpdate(accessory).catch(() => {}); + reachableChange = true; + this.log.warn("[%s] has been reported [online] via [LAN].", accessory.displayName); + } + if (reachableChange && !isX) { + for (let i = 1; i <= accessory.context.channelCount; i++) { + if (this.devicesInHB.has(deviceId + "SW" + i)) { + let oAccessory = this.devicesInHB.get(deviceId + "SW" + i); + oAccessory.context.reachableWAN = device.params.online; + if (device.params.updateSource === "LAN") { + oAccessory.context.reachableLAN = true; + } + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); } } - break; + } + if (this.debug) { + this.log( + "[%s] externally updated from above %s message and will be refreshed.", + accessory.displayName, + device.params.updateSource + ); + } + if (!this.refreshAccessory(accessory, device.params)) { + this.log.warn( + "[%s] cannot be refreshed. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.). [debug:%s:%s]", + accessory.displayName, + accessory.context.type, + accessory.context.channelCount + ); + } + } else { + if (!(this.config.hideDevFromHB || "").includes(deviceId)) { + this.log.warn( + "[%s] update received via %s does not exist in Homebridge so device will be added.", + deviceId, + device.params.updateSource + ); + this.httpClient + .getDevice(deviceId) + .then(res => this.initialiseDevice(res)) + .catch(err => this.log.error("[%s] error getting info [%s]", deviceId, err)); + } } } internalValveUpdate(accessory, valve, value, callback) { @@ -1096,26 +1117,26 @@ class eWeLink { if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { throw "it is currently offline"; } - let params = {}; - accessory - .getService(valve) + let params = {}, + serviceValve = accessory.getService(valve); + serviceValve .updateCharacteristic(Characteristic.Active, value) .updateCharacteristic(Characteristic.InUse, value); switch (value) { case 0: - accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, 0); + serviceValve.updateCharacteristic(Characteristic.RemainingDuration, 0); clearTimeout(accessory.getService(valve).timer); break; case 1: - let timer = accessory.getService(valve).getCharacteristic(Characteristic.SetDuration) - .value; - accessory.getService(valve).updateCharacteristic(Characteristic.RemainingDuration, timer); - accessory.getService(valve).timer = setTimeout(() => { - accessory.getService(valve).setCharacteristic(Characteristic.Active, 0); - }, timer * 1000); + let timer = serviceValve.getCharacteristic(Characteristic.SetDuration).value; + serviceValve.updateCharacteristic(Characteristic.RemainingDuration, timer); + serviceValve.timer = setTimeout( + () => serviceValve.setCharacteristic(Characteristic.Active, 0), + timer * 1000 + ); break; } - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; switch (valve) { case "Valve A": params.switches[0].switch = value ? "on" : "off"; @@ -1158,14 +1179,12 @@ class eWeLink { throw "improper configuration"; } let oldPos, - params = {}; + params = {}, + wcService = accessory.getService(Service.WindowCovering); value = value >= 50 ? 100 : 0; - oldPos = accessory - .getService(Service.WindowCovering) - .getCharacteristic(Characteristic.PositionState).value; + oldPos = wcService.getCharacteristic(Characteristic.PositionState).value; if (value === oldPos * 100) { - accessory - .getService(Service.WindowCovering) + wcService .updateCharacteristic(Characteristic.TargetPosition, value) .updateCharacteristic(Characteristic.PositionState, oldPos); callback(); @@ -1176,7 +1195,7 @@ class eWeLink { params.switch = "on"; break; case "twoSwitch": - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; params.switches[0].switch = value === 100 ? "on" : "off"; params.switches[1].switch = value === 0 ? "on" : "off"; break; @@ -1184,13 +1203,11 @@ class eWeLink { this.sendDeviceUpdate(accessory, params, function () { return; }); - accessory - .getService(Service.WindowCovering) + wcService .updateCharacteristic(Characteristic.TargetPosition, value) .updateCharacteristic(Characteristic.PositionState, value / 100); setTimeout(() => { - accessory - .getService(Service.WindowCovering) + wcService .updateCharacteristic(Characteristic.CurrentPosition, value) .updateCharacteristic(Characteristic.PositionState, 2); callback(); @@ -1223,7 +1240,8 @@ class eWeLink { oldPos, newPos = value, params = {}, - delay = 0; + delay = 0, + gdService = accessory.getService(Service.GarageDoorOpener); if (sensorDefinition && !(sAccessory = this.devicesInHB.get(garageConfig.sensorId + "SWX"))) { throw "defined DW2 sensor doesn't exist"; } @@ -1236,24 +1254,19 @@ class eWeLink { .getCharacteristic(Characteristic.ContactSensorState).value === 0 ? 1 : 0 - : accessory - .getService(Service.GarageDoorOpener) - .getCharacteristic(Characteristic.CurrentDoorState).value; + : gdService.getCharacteristic(Characteristic.CurrentDoorState).value; if (newPos === oldPos % 2) { accessory.context.inUse = false; callback(); return; } if (garageConfig.setup === "oneSwitch" && [2, 3].includes(oldPos)) { - accessory - .getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.CurrentDoorState, ((oldPos * 2) % 3) + 2); + gdService.updateCharacteristic(Characteristic.CurrentDoorState, ((oldPos * 2) % 3) + 2); delay = 1500; } setTimeout(() => { if (accessory.context.state === newPos) { - accessory - .getService(Service.GarageDoorOpener) + gdService .updateCharacteristic(Characteristic.TargetDoorState, newPos) .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2); switch (garageConfig.setup) { @@ -1261,9 +1274,7 @@ class eWeLink { params.switch = "on"; break; case "twoSwitch": - params.switches = this.devicesInEwe.get( - accessory.context.eweDeviceId - ).params.switches; + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; params.switches[0].switch = newPos === 0 ? "on" : "off"; params.switches[1].switch = newPos === 1 ? "on" : "off"; break; @@ -1273,9 +1284,7 @@ class eWeLink { }); setTimeout(() => { if (!sAccessory) { - accessory - .getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.CurrentDoorState, newPos); + gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos); } accessory.context.inUse = false; }, parseInt(garageConfig.operationTime) * 100); @@ -1295,7 +1304,8 @@ class eWeLink { throw "it is currently offline"; } let lockConfig, - params = {}; + params = {}, + lmService = accessory.getService(Service.LockMechanism); if (!(lockConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } @@ -1304,15 +1314,13 @@ class eWeLink { } accessory.context.inUse = true; this.log("[%s] has received request to unlock.", accessory.displayName); - accessory - .getService(Service.LockMechanism) + lmService .updateCharacteristic(Characteristic.LockTargetState, 0) .updateCharacteristic(Characteristic.LockCurrentState, 0); params.switch = "on"; this.sendDeviceUpdate(accessory, params, callback); setTimeout(() => { - accessory - .getService(Service.LockMechanism) + lmService .updateCharacteristic(Characteristic.LockTargetState, 1) .updateCharacteristic(Characteristic.LockCurrentState, 1); accessory.context.inUse = false; @@ -1329,36 +1337,34 @@ class eWeLink { if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { throw "it is currently offline"; } - let newPower, newSpeed, newLight; + let newPower, + newSpeed, + newLight, + lightService = accessory.getService(Service.Lightbulb), + fanService = accessory.getService(Service.Fanv2); switch (type) { case "power": newPower = value; newSpeed = value ? 33 : 0; - newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) - .value; + newLight = lightService.getCharacteristic(Characteristic.On).value; break; case "speed": newPower = value >= 33 ? 1 : 0; newSpeed = value; - newLight = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) - .value; + newLight = lightService.getCharacteristic(Characteristic.On).value; break; case "light": - newPower = accessory.getService(Service.Fanv2).getCharacteristic(Characteristic.Active) - .value; - newSpeed = accessory - .getService(Service.Fanv2) - .getCharacteristic(Characteristic.RotationSpeed).value; + newPower = fanService.getCharacteristic(Characteristic.Active).value; + newSpeed = fanService.getCharacteristic(Characteristic.RotationSpeed).value; newLight = value; break; } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, newLight); - accessory - .getService(Service.Fanv2) + lightService.updateCharacteristic(Characteristic.On, newLight); + fanService .updateCharacteristic(Characteristic.Active, newPower) .updateCharacteristic(Characteristic.RotationSpeed, newSpeed); let params = { - switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches, + switches: this.devicesInEW.get(accessory.context.eweDeviceId).params.switches, }; params.switches[0].switch = newLight ? "on" : "off"; params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? "on" : "off"; @@ -1387,13 +1393,14 @@ class eWeLink { throw "it is currently offline"; } let params = { - switch: value ? "on" : "off", - mainSwitch: value ? "on" : "off", - }; + switch: value ? "on" : "off", + mainSwitch: value ? "on" : "off", + }, + switchService = accessory.getService(Service.Switch); if (this.debug) { this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + switchService.updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; @@ -1407,12 +1414,13 @@ class eWeLink { throw "it is currently offline"; } let params = { - switch: value ? "on" : "off", - }; + switch: value ? "on" : "off", + }, + outletService = accessory.getService(Service.Outlet); if (this.debug) { this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); + outletService.updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { callback("[" + accessory.displayName + "] " + err + "."); @@ -1424,13 +1432,14 @@ class eWeLink { throw "it is currently offline"; } let params = { - switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches, - }; + switches: this.devicesInEW.get(accessory.context.eweDeviceId).params.switches, + }, + outletService = accessory.getService(Service.Outlet); params.switches[0].switch = value ? "on" : "off"; if (this.debug) { this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, value); + outletService.updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { callback("[" + accessory.displayName + "] " + err + "."); @@ -1442,13 +1451,14 @@ class eWeLink { throw "it is currently offline"; } let params = { - switches: this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches, - }; + switches: this.devicesInEW.get(accessory.context.eweDeviceId).params.switches, + }, + switchService = accessory.getService(Service.Switch); params.switches[0].switch = value ? "on" : "off"; if (this.debug) { this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + switchService.updateCharacteristic(Characteristic.On, value); this.sendDeviceUpdate(accessory, params, callback); } catch (err) { callback("[" + accessory.displayName + "] " + err + "."); @@ -1460,7 +1470,8 @@ class eWeLink { throw "it is currently offline"; } let oAccessory, - params = {}; + params = {}, + lightService = accessory.getService(Service.Lightbulb); switch (accessory.context.switchNumber) { case "X": if (accessory.context.eweUIID === 22) { @@ -1472,10 +1483,10 @@ class eWeLink { if (this.debug) { this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + lightService.updateCharacteristic(Characteristic.On, value); break; case "0": - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; params.switches[0].switch = value ? "on" : "off"; params.switches[1].switch = value ? "on" : "off"; params.switches[2].switch = value ? "on" : "off"; @@ -1487,7 +1498,7 @@ class eWeLink { value ? "on" : "off" ); } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + lightService.updateCharacteristic(Characteristic.On, value); for (let i = 1; i <= 4; i++) { if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); @@ -1504,10 +1515,10 @@ class eWeLink { if (this.debug) { this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + lightService.updateCharacteristic(Characteristic.On, value); let tAccessory, masterState = "off"; - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; for (let i = 1; i <= 4; i++) { if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { i === parseInt(accessory.context.switchNumber) @@ -1526,10 +1537,12 @@ class eWeLink { params.switches[i - 1].switch = "off"; } } - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - oAccessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, masterState === "on"); + if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); + oAccessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, masterState === "on"); + } break; default: throw "unknown switch number [" + accessory.context.switchNumber + "]"; @@ -1546,12 +1559,13 @@ class eWeLink { if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { throw "it is currently offline"; } - let params = {}; + let params = {}, + lightService = accessory.getService(Service.Lightbulb); if (value === 0) { params.switch = "off"; - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, false); + lightService.updateCharacteristic(Characteristic.On, false); } else { - if (!accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + if (!lightService.getCharacteristic(Characteristic.On).value) { params.switch = "on"; } switch (accessory.context.eweUIID) { @@ -1565,9 +1579,7 @@ class eWeLink { default: throw "unknown device UIID"; } - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.Brightness, value); + lightService.updateCharacteristic(Characteristic.Brightness, value); } if (this.debug) { this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); @@ -1586,11 +1598,9 @@ class eWeLink { } let newRGB, params = {}, - curHue = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.Hue) - .value, - curSat = accessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.Saturation).value; + lightService = accessory.getService(Service.Lightbulb), + curHue = lightService.getCharacteristic(Characteristic.Hue).value, + curSat = lightService.getCharacteristic(Characteristic.Saturation).value; switch (type) { case "hue": newRGB = convert.hsv.rgb(value, curSat, 100); @@ -1620,7 +1630,7 @@ class eWeLink { if (this.debug) { this.log("[%s] updating hue to [%s°].", accessory.displayName, value); } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.Hue, value); + lightService.updateCharacteristic(Characteristic.Hue, value); break; case "bri": switch (accessory.context.eweUIID) { @@ -1646,9 +1656,7 @@ class eWeLink { if (this.debug) { this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); } - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.Brightness, value); + lightService.updateCharacteristic(Characteristic.Brightness, value); break; default: throw "unknown device UIID"; @@ -1666,17 +1674,18 @@ class eWeLink { throw "it is currently offline"; } let oAccessory, - params = {}; + params = {}, + switchService = accessory.getService(Service.Switch); switch (accessory.context.switchNumber) { case "X": params.switch = value ? "on" : "off"; if (this.debug) { this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + switchService.updateCharacteristic(Characteristic.On, value); break; case "0": - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; params.switches[0].switch = value ? "on" : "off"; params.switches[1].switch = value ? "on" : "off"; params.switches[2].switch = value ? "on" : "off"; @@ -1688,7 +1697,7 @@ class eWeLink { value ? "on" : "off" ); } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + switchService.updateCharacteristic(Characteristic.On, value); for (let i = 1; i <= 4; i++) { if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); @@ -1703,10 +1712,10 @@ class eWeLink { if (this.debug) { this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + switchService.updateCharacteristic(Characteristic.On, value); let tAccessory, masterState = "off"; - params.switches = this.devicesInEwe.get(accessory.context.eweDeviceId).params.switches; + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; for (let i = 1; i <= 4; i++) { if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { i === parseInt(accessory.context.switchNumber) @@ -1725,10 +1734,12 @@ class eWeLink { params.switches[i - 1].switch = "off"; } } - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - oAccessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, masterState === "on"); + if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); + oAccessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, masterState === "on"); + } break; default: throw "unknown switch number [" + accessory.context.switchNumber + "]"; @@ -1747,9 +1758,10 @@ class eWeLink { } rfChl = parseInt(rfChl); let params = { - cmd: "transmit", - rfChl, - }; + cmd: "transmit", + rfChl, + }, + rfService = accessory.getService(accessory.context.rfChls[rfChl]); if (this.debug) { this.log( "[%s %s] mimicking RF button press.", @@ -1757,17 +1769,9 @@ class eWeLink { accessory.context.rfChls[rfChl] ); } - accessory - .getService(accessory.context.rfChls[rfChl]) - .updateCharacteristic(Characteristic.On, true); + rfService.updateCharacteristic(Characteristic.On, true); this.sendDeviceUpdate(accessory, params, callback); - setTimeout( - () => - accessory - .getService(accessory.context.rfChls[rfChl]) - .updateCharacteristic(Characteristic.On, false), - 3000 - ); + setTimeout(() => rfService.updateCharacteristic(Characteristic.On, false), 3000); } catch (err) { let str = "[" + accessory.displayName + " " + name + "] could not be updated as " + err + "."; this.log.error(str); @@ -1777,25 +1781,19 @@ class eWeLink { externalValveUpdate(accessory, params) { try { ["A", "B"].forEach((v, k) => { - accessory - .getService("Valve " + v) + let valveService = accessory.getService("Valve " + v); + valveService .updateCharacteristic(Characteristic.Active, params.switches[k].switch === "on") .updateCharacteristic(Characteristic.InUse, params.switches[k].switch === "on"); if (params.switches[k].switch === "on") { - let timer = accessory - .getService("Valve " + v) - .getCharacteristic(Characteristic.SetDuration).value; - accessory - .getService("Valve " + v) - .updateCharacteristic(Characteristic.RemainingDuration, timer); - accessory.getService("Valve " + v).timer = setTimeout(() => { - accessory.getService("Valve " + v).setCharacteristic(Characteristic.Active, 0); + let timer = valveService.getCharacteristic(Characteristic.SetDuration).value; + valveService.updateCharacteristic(Characteristic.RemainingDuration, timer); + valveService.timer = setTimeout(() => { + valveService.setCharacteristic(Characteristic.Active, 0); }, timer * 1000); } else { - accessory - .getService("Valve " + v) - .updateCharacteristic(Characteristic.RemainingDuration, 0); - clearTimeout(accessory.getService("Valve " + v).timer); + valveService.updateCharacteristic(Characteristic.RemainingDuration, 0); + clearTimeout(valveService.timer); } }); } catch (err) { @@ -1804,7 +1802,9 @@ class eWeLink { } externalBlindUpdate(accessory, params) { try { - let blindConfig, nSte; + let blindConfig, + nSte, + wcService = accessory.getService(Service.WindowCovering); if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } @@ -1816,12 +1816,7 @@ class eWeLink { if (params.switch === "off") { return; } - nSte = - accessory - .getService(Service.WindowCovering) - .getCharacteristic(Characteristic.PositionState).value === 0 - ? 1 - : 0; + nSte = wcService.getCharacteristic(Characteristic.PositionState).value === 0 ? 1 : 0; break; case "twoSwitch": if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { @@ -1832,13 +1827,11 @@ class eWeLink { nSte = switchUp + switchDown; break; } - accessory - .getService(Service.WindowCovering) + wcService .updateCharacteristic(Characteristic.PositionState, nSte) .updateCharacteristic(Characteristic.TargetPosition, nSte * 100); setTimeout(() => { - accessory - .getService(Service.WindowCovering) + wcService .updateCharacteristic(Characteristic.PositionState, 2) .updateCharacteristic(Characteristic.CurrentPosition, nSte * 100); }, parseInt(blindConfig.operationTime) * 100); @@ -1849,9 +1842,8 @@ class eWeLink { externalGarageUpdate(accessory, params) { try { let garageConfig, - oldPos = accessory - .getService(Service.GarageDoorOpener) - .getCharacteristic(Characteristic.CurrentDoorState).value, + gcService = accessory.getService(Service.GarageDoorOpener), + oldPos = gcService.getCharacteristic(Characteristic.CurrentDoorState).value, newPos = [0, 2].includes(oldPos) ? 3 : 2; if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; @@ -1882,14 +1874,11 @@ class eWeLink { } accessory.context.inUse = true; if (!garageConfig.sensorId) { - accessory - .getService(Service.GarageDoorOpener) + gcService .updateCharacteristic(Characteristic.CurrentDoorState, newPos) .updateCharacteristic(Characteristic.TargetDoorState, newPos - 2); setTimeout(() => { - accessory - .getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2); + gcService.updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2); }, parseInt(garageConfig.operationTime) * 100); } setTimeout(() => { @@ -1902,7 +1891,8 @@ class eWeLink { } externalLockUpdate(accessory, params) { try { - let lockConfig; + let lockConfig, + lmService = accessory.getService(Service.LockMechanism); if (!(lockConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } @@ -1913,13 +1903,11 @@ class eWeLink { return; } accessory.context.inUse = true; - accessory - .getService(Service.LockMechanism) + lmService .updateCharacteristic(Characteristic.LockCurrentState, 0) .updateCharacteristic(Characteristic.LockTargetState, 0); setTimeout(() => { - accessory - .getService(Service.LockMechanism) + lmService .updateCharacteristic(Characteristic.LockCurrentState, 1) .updateCharacteristic(Characteristic.LockTargetState, 1); accessory.context.inUse = false; @@ -1940,10 +1928,9 @@ class eWeLink { batteryService.updateCharacteristic(Characteristic.StatusLowBattery, scaledBattery < 25); } let newState = params.switch === "on" ? 1 : 0, - oAccessory = false; - accessory - .getService(Service.ContactSensor) - .updateCharacteristic(Characteristic.ContactSensorState, newState); + oAccessory = false, + contactService = accessory.getService(Service.ContactSensor); + contactService.updateCharacteristic(Characteristic.ContactSensorState, newState); this.cusG.forEach(group => { if (group.sensorId === accessory.context.eweDeviceId && group.type === "garage") { if ((oAccessory = this.devicesInHB.get(group.deviceId + "SWX"))) { @@ -1974,7 +1961,11 @@ class eWeLink { } externalFanUpdate(accessory, params) { try { - let light, status, speed; + let light, + status, + speed, + lightService = accessory.getService(Service.Lightbulb), + fanService = accessory.getService(Service.Fanv2); if (Array.isArray(params.switches)) { light = params.switches[0].switch === "on"; switch (params.switches[1].switch + params.switches[2].switch + params.switches[3].switch) { @@ -2005,9 +1996,8 @@ class eWeLink { } else { throw "unknown parameters received"; } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, light); - accessory - .getService(Service.Fanv2) + lightService.updateCharacteristic(Characteristic.On, light); + fanService .updateCharacteristic(Characteristic.Active, status) .updateCharacteristic(Characteristic.RotationSpeed, speed); } catch (err) { @@ -2021,9 +2011,10 @@ class eWeLink { (params.hasOwnProperty("switch") || params.hasOwnProperty("mainSwitch")) ) { let newState = params.hasOwnProperty("switch") - ? params.switch === "on" - : params.mainSwitch === "on"; - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, newState); + ? params.switch === "on" + : params.mainSwitch === "on", + switchService = accessory.getService(Service.Switch); + switchService.updateCharacteristic(Characteristic.On, newState); } let eveLog = { time: Date.now(), @@ -2058,21 +2049,19 @@ class eWeLink { } externalOutletUpdate(accessory, params) { try { + let outletService = accessory.getService(Service.Outlet); if (params.hasOwnProperty("switch")) { - accessory - .getService(Service.Outlet) - .updateCharacteristic(Characteristic.On, params.switch === "on"); + outletService.updateCharacteristic(Characteristic.On, params.switch === "on"); } if (params.hasOwnProperty("power")) { - accessory - .getService(Service.Outlet) - .updateCharacteristic( - EveService.Characteristics.CurrentConsumption, - parseFloat(params.power) - ); - accessory - .getService(Service.Outlet) - .updateCharacteristic(Characteristic.OutletInUse, parseFloat(params.power) > 0); + outletService.updateCharacteristic( + EveService.Characteristics.CurrentConsumption, + parseFloat(params.power) + ); + outletService.updateCharacteristic( + Characteristic.OutletInUse, + parseFloat(params.power) > 0 + ); let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value; accessory.eveLogger.addEntry({ time: Date.now(), @@ -2080,17 +2069,16 @@ class eWeLink { }); } if (params.hasOwnProperty("voltage")) { - accessory - .getService(Service.Outlet) - .updateCharacteristic(EveService.Characteristics.Voltage, parseFloat(params.voltage)); + outletService.updateCharacteristic( + EveService.Characteristics.Voltage, + parseFloat(params.voltage) + ); } if (params.hasOwnProperty("current")) { - accessory - .getService(Service.Outlet) - .updateCharacteristic( - EveService.Characteristics.ElectricCurrent, - parseFloat(params.current) - ); + outletService.updateCharacteristic( + EveService.Characteristics.ElectricCurrent, + parseFloat(params.current) + ); } } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); @@ -2118,30 +2106,27 @@ class eWeLink { try { let newColour, mode, - isOn = false; + isOn = false, + lightService = accessory.getService(Service.Lightbulb); if (accessory.context.eweUIID === 22 && params.hasOwnProperty("state")) { isOn = params.state === "on"; } else if (accessory.context.eweUIID !== 22 && params.hasOwnProperty("switch")) { isOn = params.switch === "on"; } else { - isOn = accessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value; + isOn = lightService.getCharacteristic(Characteristic.On).value; } if (isOn) { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, true); + lightService.updateCharacteristic(Characteristic.On, true); switch (accessory.context.eweUIID) { case 36: // KING-M4 if (params.hasOwnProperty("bright")) { let nb = Math.round(((params.bright - 10) * 10) / 9); // eWeLink scale is 10-100 and HomeKit scale is 0-100. - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.Brightness, nb); + lightService.updateCharacteristic(Characteristic.Brightness, nb); } break; case 44: // D1 if (params.hasOwnProperty("brightness")) { - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.Brightness, params.brightness); + lightService.updateCharacteristic(Characteristic.Brightness, params.brightness); } break; case 22: // B1 @@ -2156,14 +2141,13 @@ class eWeLink { mode = 2; } if (mode === 2) { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, true); + lightService.updateCharacteristic(Characteristic.On, true); newColour = convert.rgb.hsv( parseInt(params.channel2), parseInt(params.channel3), parseInt(params.channel4) ); - accessory - .getService(Service.Lightbulb) + lightService .updateCharacteristic(Characteristic.Hue, newColour[0]) .updateCharacteristic(Characteristic.Saturation, 100) .updateCharacteristic(Characteristic.Brightness, 100); @@ -2173,14 +2157,11 @@ class eWeLink { break; case 59: // L1 if (params.hasOwnProperty("bright")) { - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.Brightness, params.bright); + lightService.updateCharacteristic(Characteristic.Brightness, params.bright); } if (params.hasOwnProperty("colorR")) { newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB); - accessory - .getService(Service.Lightbulb) + lightService .updateCharacteristic(Characteristic.Hue, newColour[0]) .updateCharacteristic(Characteristic.Saturation, newColour[1]); } @@ -2189,7 +2170,7 @@ class eWeLink { return; } } else { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, false); + lightService.updateCharacteristic(Characteristic.On, false); } } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); @@ -2210,7 +2191,11 @@ class eWeLink { } } } - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, primaryState); + if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { + accessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, primaryState); + } } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } @@ -2239,7 +2224,9 @@ class eWeLink { } } } - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState); + if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState); + } } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index dc8370a4..48ffefb8 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -5,124 +5,51 @@ const axios = require("axios"), crypto = require("crypto"); module.exports = class eWeLinkHTTP { constructor(config, log) { - this.config = config; this.log = log; - this.debug = this.config.debug || false; - this.debugReqRes = this.config.debugReqRes || false; + this.debug = config.debug || false; + this.debugReqRes = config.debugReqRes || false; + this.username = config.username.toString(); + this.password = config.password.toString(); + this.hideDevFromHB = (config.hideDevFromHB || "").toString(); + this.cCode = "+" + config.countryCode.toString().replace("+", "").replace(" ", ""); } - login() { - let data = { - countryCode: "+" + this.config.countryCode.toString().replace("+", "").replace(" ", ""), - password: this.config.password, - }; - this.config.username.includes("@") - ? (data.email = this.config.username) - : (data.phoneNumber = this.config.username); - if (this.debugReqRes) { - let msg = JSON.stringify(data, null, 2) - .replace(this.config.password, "**hidden**") - .replace(this.config.username, "**hidden**"); - this.log.warn("Sending HTTP login request. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("Sending HTTP login request."); - } - let dataToSign = crypto - .createHmac("sha256", constants.appSecret) - .update(JSON.stringify(data)) - .digest("base64"); + getHost() { return new Promise((resolve, reject) => { - axios({ - url: "https://" + this.httpHost + "/v2/user/login", - method: "post", - headers: { - Authorization: "Sign " + dataToSign, - "Content-Type": "application/json", - Host: this.httpHost, - "X-CK-Appid": constants.appId, - "X-CK-Nonce": Math.random().toString(36).substr(2, 8), + let params = { + appid: constants.appId, + country_code: this.cCode, + nonce: Math.random().toString(36).substr(2, 8), + ts: Math.floor(new Date().getTime() / 1000), + version: 8, }, - data, - }) - .then(res => { - let body = res.data; - if ( - body.hasOwnProperty("error") && - body.error === 10004 && - body.hasOwnProperty("data") && - body.data.hasOwnProperty("region") - ) { - switch (body.data.region) { - case "eu": - case "us": - case "as": - this.httpHost = body.data.region + "-apia.coolkit.cc"; - break; - case "cn": - this.httpHost = "cn-apia.coolkit.cn"; - break; - default: - throw "No valid region received - [" + body.data.region + "]."; - } - if (this.debug) { - this.log("New HTTP API host received [%s].", this.httpHost); - } - resolve(this.login()); - return; - } - if (!body.data.at) { - throw ( - "Server did not respond with an authentication token. Please double check your eWeLink username and password in the Homebridge configuration.\n" + - JSON.stringify(body, null, 2) - ); - } - this.aToken = body.data.at; - this.apiKey = body.data.user.apikey; - resolve({ - aToken: body.data.at, - apiKey: body.data.user.apikey, - httpHost: this.httpHost, - }); - }) - .catch(err => { - reject(err); + dataToSign = []; + Object.keys(params).forEach(k => { + dataToSign.push({ + key: k, + value: params.k, }); - }); - } - getHost() { - let data = { - appid: constants.appId, - country_code: this.config.countryCode.toString().replace("+", "").replace(" ", ""), - nonce: Math.random().toString(36).substr(2, 8), - ts: Math.floor(new Date().getTime() / 1000), - version: 8, - }, - dataToSign = []; - Object.keys(data).forEach(function (key) { - dataToSign.push({ - key: key, - value: data[key], }); - }); - dataToSign.sort(function (a, b) { - return a.key < b.key ? -1 : 1; - }); - dataToSign = dataToSign - .map(function (kv) { - return kv.key + "=" + kv.value; - }) - .join("&"); - dataToSign = crypto - .createHmac("sha256", constants.appSecret) - .update(dataToSign) - .digest("base64"); - return new Promise((resolve, reject) => { + dataToSign.sort((a, b) => (a.key < b.key ? -1 : 1)); + dataToSign = dataToSign.map(k => k.key + "=" + k.value).join("&"); + dataToSign = crypto + .createHmac("sha256", constants.appSecret) + .update(dataToSign) + .digest("base64"); + if (this.debugReqRes) { + this.log.warn( + "Sending HTTP getHost request. This text is yellow for clarity.\n%s", + JSON.stringify(params, null, 2) + ); + } else if (this.debug) { + this.log("Sending HTTP getHost request."); + } axios .get("https://api.coolkit.cc:8080/api/user/region", { headers: { Authorization: "Sign " + dataToSign, "Content-Type": "application/json", }, - params: data, + params, }) .then(res => { let body = res.data; @@ -147,10 +74,87 @@ module.exports = class eWeLinkHTTP { resolve(this.httpHost); }) .catch(err => { - reject(err); + if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { + this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); + this.delay().then(() => resolve(this.getHost())); + } else { + reject(err.message || err); + } }); }); } + login() { + return new Promise((resolve, reject) => { + let data = { + countryCode: this.cCode, + password: this.password, + }; + this.username.includes("@") + ? (data.email = this.username) + : (data.phoneNumber = this.username); + if (this.debugReqRes) { + let msg = JSON.stringify(data, null, 2) + .replace(this.password, "**hidden**") + .replace(this.username, "**hidden**"); + this.log.warn("Sending HTTP login request. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("Sending HTTP login request."); + } + let dataToSign = crypto + .createHmac("sha256", constants.appSecret) + .update(JSON.stringify(data)) + .digest("base64"); + axios + .post("https://" + this.httpHost + "/v2/user/login", data, { + headers: { + Authorization: "Sign " + dataToSign, + "Content-Type": "application/json", + Host: this.httpHost, + "X-CK-Appid": constants.appId, + "X-CK-Nonce": Math.random().toString(36).substr(2, 8), + }, + }) + .then(res => { + let body = res.data; + if ( + body.hasOwnProperty("error") && + body.error === 10004 && + body.hasOwnProperty("data") && + body.data.hasOwnProperty("region") + ) { + let givenRegion = body.data.region; + switch (givenRegion) { + case "eu": + case "us": + case "as": + this.httpHost = givenRegion + "-apia.coolkit.cc"; + break; + case "cn": + this.httpHost = "cn-apia.coolkit.cn"; + break; + default: + throw "No valid region received - [" + givenRegion + "]."; + } + if (this.debug) { + this.log("New HTTP API host received [%s].", this.httpHost); + } + resolve(this.login()); + return; + } + if (!body.data.at) { + throw "No auth token received.\n" + JSON.stringify(body, null, 2); + } + this.aToken = body.data.at; + this.apiKey = body.data.user.apikey; + resolve({ + aToken: this.aToken, + apiKey: this.apiKey, + httpHost: this.httpHost, + }); + }) + .catch(err => reject(err.message || err)); + }); + } getDevices() { return new Promise((resolve, reject) => { axios @@ -165,18 +169,82 @@ module.exports = class eWeLinkHTTP { }) .then(res => { let body = res.data; - if (!body.hasOwnProperty("error") || (body.hasOwnProperty("error") && body.error !== 0)) { + if ( + !body.hasOwnProperty("data") || + !body.hasOwnProperty("error") || + (body.hasOwnProperty("error") && body.error !== 0) + ) { throw JSON.stringify(body, null, 2); } let deviceList = []; if (body.data.thingList && body.data.thingList.length > 0) { body.data.thingList.forEach(device => deviceList.push(device.itemData)); } + deviceList + .filter(d => d.hasOwnProperty("extra") && d.extra.hasOwnProperty("uiid")) + .filter(d => !this.hideDevFromHB.includes(d.deviceid)); resolve(deviceList); }) .catch(err => { - reject(err); + if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { + this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); + this.delay().then(() => resolve(this.getDevices())); + } else { + reject(err.message || err); + } + }); + }); + } + + getDevice(deviceId) { + return new Promise((resolve, reject) => { + axios + .post( + "https://" + this.httpHost + "/v2/device/thing", + { + thingList: [ + { + itemType: 1, + id: deviceId, + }, + ], + }, + { + headers: { + Authorization: "Bearer " + this.aToken, + "Content-Type": "application/json", + Host: this.httpHost, + "X-CK-Appid": constants.appId, + "X-CK-Nonce": Math.random().toString(36).substr(2, 8), + }, + } + ) + .then(res => { + let body = res.data; + if ( + !body.hasOwnProperty("data") || + !body.hasOwnProperty("error") || + (body.hasOwnProperty("error") && body.error !== 0) + ) { + throw JSON.stringify(body, null, 2); + } + if (body.data.thingList && body.data.thingList.length === 1) { + resolve(body.data.thingList[0].itemData); + } else { + throw "device not found in eWeLink"; + } + }) + .catch(err => { + if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { + this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); + this.delay().then(() => resolve(this.getDevice(deviceId))); + } else { + reject(err.message || err); + } }); }); } + delay() { + return new Promise(resolve => setTimeout(resolve, 30000)); + } }; diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 9701fa06..c996e682 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -1,19 +1,18 @@ /* jshint esversion: 9, -W030, node: true */ "use strict"; const axios = require("axios"), - constants = require("./constants"), + cns = require("./constants"), crypto = require("crypto"), dns = require("node-dns-sd"), eventemitter = require("events"); module.exports = class eWeLinkLAN { constructor(config, log, devices) { - this.config = config; this.log = log; this.devices = devices; - this.ipOverrides = this.config.ipOverride || {}; - let deviceMap = new Map(); + this.ipOverrides = config.ipOverride || {}; + this.deviceMap = new Map(); devices.forEach(device => { - deviceMap.set(device.deviceid, { + this.deviceMap.set(device.deviceid, { apiKey: device.devicekey, online: this.ipOverrides.hasOwnProperty(device.deviceid) ? true : false, ip: this.ipOverrides.hasOwnProperty(device.deviceid) @@ -21,9 +20,8 @@ module.exports = class eWeLinkLAN { : null, }); }); - this.deviceMap = deviceMap; - this.debug = this.config.debug || false; - this.debugReqRes = this.config.debugReqRes || false; + this.debug = config.debug || false; + this.debugReqRes = config.debugReqRes || false; this.emitter = new eventemitter(); } getHosts() { @@ -53,9 +51,7 @@ module.exports = class eWeLinkLAN { count: onlineCount, }); }) - .catch(err => { - reject(err); - }); + .catch(err => reject(err)); }); } startMonitor() { @@ -101,16 +97,16 @@ module.exports = class eWeLinkLAN { } for (let param in params) { if (params.hasOwnProperty(param)) { - if (!constants.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { + if (!cns.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { delete params[param]; } } } if (Object.keys(params).length > 0) { params.updateSource = "LAN"; + params.online = true; let returnTemplate = { deviceid: rdata.id, - action: "update", params, }; if (this.debugReqRes) { @@ -127,18 +123,14 @@ module.exports = class eWeLinkLAN { return new Promise((resolve, reject) => { dns .startMonitoring() - .then(() => { - resolve(); - }) - .catch(err => { - reject(err); - }); + .then(() => resolve()) + .catch(err => reject(err)); }); } sendUpdate(json) { return new Promise((resolve, reject) => { if (!this.deviceMap.get(json.deviceid).online) { - throw "device does not support LAN mode"; + throw "device isn't reachable by LAN mode"; } let apiKey, suffix, @@ -190,9 +182,7 @@ module.exports = class eWeLinkLAN { } throw res.data; }) - .catch(err => { - reject(err); - }); + .catch(err => reject(err)); } }); } diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 70e0a209..1d8cab1c 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -1,9 +1,10 @@ /* jshint esversion: 9, -W030, node: true */ "use strict"; const axios = require("axios"), - constants = require("./constants"), + cns = require("./constants"), eventemitter = require("events"), - ws = require("ws"); + ws = require("ws"), + wsp = require("websocket-as-promised"); module.exports = class eWeLinkWS { constructor(config, log, res) { this.config = config; @@ -27,7 +28,7 @@ module.exports = class eWeLinkWS { "Content-Type": "application/json", }, data: { - appid: constants.appId, + appid: cns.appId, nonce: Math.random().toString(36).substr(2, 8), ts: Math.floor(new Date().getTime() / 1000), version: 8, @@ -45,26 +46,47 @@ module.exports = class eWeLinkWS { resolve(body.domain); }) .catch(err => { - reject(err); + if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { + this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); + this.delay().then(() => resolve(this.getDevices())); + } else { + reject(err.message || err); + } }); }); } login() { - this.ws = new ws("wss://" + this.wsHost + ":8080/api/ws"); - this.ws.on("open", () => { + this.wsp = new wsp("wss://" + this.wsHost + ":8080/api/ws", { + createWebSocket: url => new ws(url), + extractMessageData: event => event, + attachRequestId: (data, requestId) => + Object.assign( + { + sequence: requestId, + }, + data + ), + extractRequestId: data => data && data.sequence, + packMessage: data => JSON.stringify(data), + unpackMessage: data => { + return data === "pong" ? data : JSON.parse(data); + }, + }); + this.wsp.open(); + this.wsp.onOpen.addListener(() => { this.wsIsOpen = true; - let payload = { - action: "userOnline", - apikey: this.apiKey, - appid: constants.appId, - at: this.aToken, - nonce: Math.random().toString(36).substr(2, 8), - sequence: Math.floor(new Date()), - ts: Math.floor(new Date() / 1000), - userAgent: "app", - version: 8, - }; - this.ws.send(JSON.stringify(payload)); + let sequence = Math.floor(new Date()).toString(), + payload = { + action: "userOnline", + apikey: this.apiKey, + appid: cns.appId, + at: this.aToken, + nonce: Math.random().toString(36).substr(2, 8), + sequence, + ts: Math.floor(new Date() / 1000), + userAgent: "app", + version: 8, + }; if (this.debugReqRes) { let msg = JSON.stringify(payload, null, 2) .replace(this.aToken, "**hidden**") @@ -73,79 +95,55 @@ module.exports = class eWeLinkWS { } else if (this.debug) { this.log("Sending WS login request."); } + this.wsp + .sendRequest(payload, { + requestId: sequence, + }) + .then(res => { + if ( + res.hasOwnProperty("config") && + res.config.hb && + res.config.hbInterval && + !this.hbInterval + ) { + this.hbInterval = setInterval(() => { + this.wsp.send("ping"); + }, (res.config.hbInterval + 7) * 1000); + } else { + throw "Unknown parameters received"; + } + }) + .catch(err => { + this.log.error("WS login failed [%s].", err); + }); }); - this.ws.on("message", m => { - if (m === "pong") { - return; - } - let device; - try { - device = JSON.parse(m); - } catch (e) { - this.log.warn("An error occured reading the web socket message [%s]", e); - return; - } - // for requestUpdate response - if ( - device.hasOwnProperty("deviceid") && - device.hasOwnProperty("params") && - device.hasOwnProperty("error") && - device.error === 0 - ) { + this.wsp.onUnpackedMessage.addListener(device => { + if (device === "pong") return; + let onlineStatus = true; + if (!device.hasOwnProperty("params")) device.params = {}; + if (device.hasOwnProperty("deviceid") && device.hasOwnProperty("error")) { device.action = "update"; - } else if ( - device.hasOwnProperty("deviceid") && - device.hasOwnProperty("error") && - device.error === 504 - ) { - device.action = "sysmsg"; - device.params = { - online: false, - }; + onlineStatus = device.error === 0; } - // for external updates - if ( - device.hasOwnProperty("config") && - device.config.hb && - device.config.hbInterval && - !this.hbInterval - ) { - this.hbInterval = setInterval(() => { - this.ws.send("ping"); - }, (device.config.hbInterval + 7) * 1000); - } else if (device.hasOwnProperty("action")) { + if (device.hasOwnProperty("action")) { switch (device.action) { + case "update": case "sysmsg": - device.params.updateSource = "WS"; - let returnTemplate = { - deviceid: device.deviceid, - action: "sysmsg", - params: device.params, - }; - if (this.debugReqRes) { - let msg = JSON.stringify(returnTemplate, null, 2).replace( - device.deviceid, - "**hidden**" - ); - this.log("WS message received.\n%s", msg); - } else if (this.debug) { - this.log("WS message received."); + if (device.action === "sysmsg" && device.params.hasOwnProperty("online")) { + onlineStatus = device.params.online; } - this.emitter.emit("update", returnTemplate); - break; - case "update": for (let param in device.params) { if (device.params.hasOwnProperty(param)) { - if (!constants.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { + if (!cns.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { delete device.params[param]; } } } + device.params.online = onlineStatus; + device.params.updateSource = "WS"; if (Object.keys(device.params).length > 0) { - device.params.updateSource = "WS"; let returnTemplate = { deviceid: device.deviceid, - action: "update", params: device.params, }; if (this.debugReqRes) { @@ -177,16 +175,14 @@ module.exports = class eWeLinkWS { } } }); - this.ws.on("close", (e, m) => { - if (m === "Stopping Homebridge") { + this.wsp.onClose.addListener(e => { + if (e.reason === "Stopping Homebridge") { this.log("Web socket gracefully closed."); } else { - this.log.warn("Web socket closed - [%s - %s].", e, m); + this.log.warn("Web socket closed - [%s - %s].", e.code, e.reason); if (e !== 1000) { this.log("Web socket will try to reconnect in five seconds."); - setTimeout(() => { - this.login(); - }, 5000); + setTimeout(() => this.login(), 5000); } else { this.log("Please try restarting Homebridge so that this plugin can work again."); } @@ -196,89 +192,88 @@ module.exports = class eWeLinkWS { clearInterval(this.hbInterval); this.hbInterval = null; } - this.ws.removeAllListeners(); + this.wsp.removeAllListeners(); }); - this.ws.on("error", e => { + this.wsp.onError.addListener(e => { this.log.error("Web socket error - [%s].", e); if (e.code === "ECONNREFUSED") { this.log.warn( "Web socket will try to reconnect in five seconds then try the command again." ); - this.ws.removeAllListeners(); - setTimeout(() => { - this.login(); - }, 5000); + this.wsp.removeAllListeners(); + setTimeout(() => this.login(), 5000); } else { this.log.warn("If this was unexpected then please try restarting Homebridge."); } }); } sendUpdate(json) { - json = { - ...json, - ...{ - action: "update", - sequence: Math.floor(new Date()), - userAgent: "app", - }, - }; - let sendOperation = req => { - if (!this.wsIsOpen) { - setTimeout(() => { - sendOperation(req); - }, 280); - return; - } - if (this.ws) { - this.ws.send(req); - if (this.debugReqRes) { - let msg = JSON.stringify(json, null, 2) - .replace(json.apikey, "**hidden**") - .replace(json.apiKey, "**hidden**") - .replace(json.deviceid, "**hidden**"); - this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("WS message sent."); + return new Promise((resolve, reject) => { + let sequence = Math.floor(new Date()).toString(); + json = { + ...json, + ...{ + action: "update", + sequence, + userAgent: "app", + }, + }; + let sendOperation = () => { + this.wsp + .sendRequest(json, { + requestId: sequence, + }) + .then(device => { + if (this.debugReqRes) { + let msg = JSON.stringify(json, null, 2) + .replace(json.apikey, "**hidden**") + .replace(json.apiKey, "**hidden**") + .replace(json.deviceid, "**hidden**"); + this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("WS message sent."); + } + device.error = device.hasOwnProperty("error") ? device.error : 504; // mimic ewelink device offline + switch (device.error) { + case 0: + resolve(); + break; + case 504: + default: + throw "Unknown response"; + } + }) + .catch(err => reject("Device update failed [" + err + "].")); + }; + let checkToSend = () => { + if (this.wsp && this.wsIsOpen) { + sendOperation(); + } else { + this.delay(2500).then(() => { + if (this.debug) { + this.log.warn("Will resend command when WS is reconnected."); + } + checkToSend(); + }); } - return; - } - this.delaySend = this.delaySend <= 0 ? 0 : (this.delaySend -= 280); - }; - let string = JSON.stringify(json); - if (this.wsIsOpen) { - setTimeout(sendOperation, this.delaySend, string); - this.delaySend += 280; - } else { - this.log.warn("Web socket is currently reconnecting. Command will be resent."); - let interval, - waitToSend = req => { - if (this.wsIsOpen) { - clearInterval(interval); - sendOperation(req); - } - }; - interval = setInterval(waitToSend, 2500, string); - } + }; + checkToSend(); + }); } requestUpdate(accessory) { - let json = { - action: "query", - apikey: accessory.context.eweApiKey, - deviceid: accessory.context.eweDeviceId, - params: [], - sequence: Math.floor(new Date()), - ts: 0, - userAgent: "app", - }, - sendOperation = req => { - if (!this.wsIsOpen) { - setTimeout(() => { - sendOperation(req); - }, 280); - return; - } - if (this.ws) { - this.ws.send(req); + return new Promise(resolve => { + let sequence = Math.floor(new Date()).toString(), + json = { + action: "query", + apikey: accessory.context.eweApiKey, + deviceid: accessory.context.eweDeviceId, + params: [], + sequence, + ts: 0, + userAgent: "app", + }, + sendOperation = () => { + this.wsp.send(json); if (this.debugReqRes) { let msg = JSON.stringify(json, null, 2) .replace(json.apikey, "**hidden**") @@ -288,32 +283,31 @@ module.exports = class eWeLinkWS { } else if (this.debug) { this.log("WS message sent."); } - return; - } - this.delaySend = this.delaySend <= 0 ? 0 : (this.delaySend -= 280); - }, - string = JSON.stringify(json); - if (this.wsIsOpen) { - setTimeout(sendOperation, this.delaySend, string); - this.delaySend += 280; - } else { - this.log.warn("Web socket is currently reconnecting. Command will be resent."); - let interval, - waitToSend = req => { - if (this.wsIsOpen) { - clearInterval(interval); - sendOperation(req); + }, + checkToSend = () => { + if (this.wsp && this.wsIsOpen) { + sendOperation(); + } else { + this.delay(2500).then(() => { + if (this.debug) { + this.log.warn("Will resend command when WS is reconnected."); + } + checkToSend(); + }); } }; - interval = setInterval(waitToSend, 2500, string); - } + checkToSend(); + }); } receiveUpdate(f) { this.emitter.addListener("update", f); } closeConnection() { if (this.ws && this.wsIsOpen) { - this.ws.close(1000, "Stopping Homebridge"); + this.wsp.close(1000, "Stopping Homebridge"); } } + delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } }; diff --git a/package-lock.json b/package-lock.json index 93c75ca5..f6b09335 100644 --- a/package-lock.json +++ b/package-lock.json @@ -122,6 +122,11 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "color-temp": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/color-temp/-/color-temp-0.0.2.tgz", + "integrity": "sha1-GxTzI9nLdq0fn1p140DWHW2WA/s=" + }, "correcting-interval": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/correcting-interval/-/correcting-interval-2.0.0.tgz", diff --git a/package.json b/package.json index 7750d662..b54b8f8c 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "dependencies": { "axios": "0.20.0", "color-convert": "2.0.1", + "color-temp": "0.0.2", "correcting-interval": "2.0.0", "fakegato-history": "0.5.6", "homebridge-lib": "4.7.14", From f3528162a218eb9015e5e641951609ed53eb4074 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 20 Sep 2020 13:10:32 +0100 Subject: [PATCH 0172/3183] 3.0.0-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f6b09335..b2ff8a53 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.27.2", + "version": "3.0.0-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index b54b8f8c..52cd1d9a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "2.27.2", + "version": "3.0.0-0", "author": "bwp91", "contributors": [ "gbro115", From b7bb52fe7a8cf74f486b1be8774b1704c6c27fb6 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 20 Sep 2020 15:12:43 +0100 Subject: [PATCH 0173/3183] update deps --- package-lock.json | 54 +++++++++++++++++++++++++++++++++++------------ package.json | 2 +- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index b2ff8a53..e100f5ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -351,9 +351,9 @@ "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" }, "homebridge-lib": { - "version": "4.7.14", - "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-4.7.14.tgz", - "integrity": "sha512-8eUGTVrCRd7WHwEH49CgqYUu2q9WjeTVDnEA5WXL2ZvPevTMCck5GcVIXtvVWxr9we8Ay0ybFp0N5RRlrIzH/g==", + "version": "4.7.15", + "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-4.7.15.tgz", + "integrity": "sha512-654DQEwyhcHbZ1++1qv0k4lhoYWaZsHcriFRts4XHnGFQOgdO1G6VyP3hUjt/+y5FemoRVjqf6Tv0/IKNPDC4w==", "requires": { "bonjour": "^3.5.0", "chalk": "^4.1.0", @@ -362,11 +362,11 @@ }, "dependencies": { "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "ms": { @@ -420,6 +420,11 @@ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" }, + "is-negative-zero": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", + "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=" + }, "is-regex": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", @@ -540,14 +545,35 @@ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", + "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.0", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.18.0-next.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.0.tgz", + "integrity": "sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "prettier": { diff --git a/package.json b/package.json index 52cd1d9a..0ebc8b68 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "color-temp": "0.0.2", "correcting-interval": "2.0.0", "fakegato-history": "0.5.6", - "homebridge-lib": "4.7.14", + "homebridge-lib": "4.7.15", "node-dns-sd": "0.4.1", "ws": "7.3.1" }, From 63799d1d7cbe48004aa0ff8a88a6caf40acf97d8 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 20 Sep 2020 15:13:31 +0100 Subject: [PATCH 0174/3183] syntax error --- lib/eWeLinkWS.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 1d8cab1c..fd077cff 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -303,7 +303,7 @@ module.exports = class eWeLinkWS { this.emitter.addListener("update", f); } closeConnection() { - if (this.ws && this.wsIsOpen) { + if (this.wsp && this.wsIsOpen) { this.wsp.close(1000, "Stopping Homebridge"); } } From b08561b41b86cdfe26a72da48126fcf85ede6972 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 20 Sep 2020 15:13:46 +0100 Subject: [PATCH 0175/3183] batt --- config.schema.json | 9 +++++++++ lib/eWeLink.js | 10 ++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/config.schema.json b/config.schema.json index e9a2b321..e1d15c4d 100644 --- a/config.schema.json +++ b/config.schema.json @@ -58,6 +58,14 @@ "description": "A list of device channels to hide from Homebridge. For example '10009553c8SW1' or multiple channels separated with a comma '10009553c8SW1,10009553c9SW2'. Only channels from switches, lights and irrigation valves can be hidden.", "default": "" }, + "lowBattThreshold": { + "type": "integer", + "title": "Low Battery Threshold", + "description": "Homebridge will set the low battery status for supported devices when the device battery reaches this pecentage level.", + "default": 25, + "minimum": 5, + "maximum": 50 + }, "sensorTimeLength": { "type": "integer", "title": "Sensor Length", @@ -233,6 +241,7 @@ "hideDevFromHB", "hideMasters", "hideFromHB", + "lowBattThreshold", "sensorTimeLength", "sensorTimeDifference", "valveTimeLength", diff --git a/lib/eWeLink.js b/lib/eWeLink.js index d8b093a1..16af13da 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1925,7 +1925,10 @@ class eWeLink { accessory.addService(Service.BatteryService), scaledBattery = Math.round(params.battery * 33.3); batteryService.updateCharacteristic(Characteristic.BatteryLevel, scaledBattery); - batteryService.updateCharacteristic(Characteristic.StatusLowBattery, scaledBattery < 25); + batteryService.updateCharacteristic( + Characteristic.StatusLowBattery, + scaledBattery < (this.config.lowBattThreshold || 25) + ); } let newState = params.switch === "on" ? 1 : 0, oAccessory = false, @@ -2372,7 +2375,10 @@ class eWeLink { accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); batteryService.updateCharacteristic(Characteristic.BatteryLevel, params.battery); - batteryService.updateCharacteristic(Characteristic.StatusLowBattery, params.battery < 25); + batteryService.updateCharacteristic( + Characteristic.StatusLowBattery, + params.battery < (this.config.lowBattThreshold || 25) + ); } switch (accessory.context.eweUIID) { case 1000: From ae2e12a83a2c3cda25fdc80d373f29c31e7b89a2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 21 Sep 2020 11:31:58 +0100 Subject: [PATCH 0176/3183] 3.0.0-1 bump --- lib/constants.js | 2 +- lib/eWeLink.js | 386 ++++++++++++++++++++------------------------- lib/eWeLinkHTTP.js | 13 +- lib/eWeLinkWS.js | 11 +- package-lock.json | 70 ++++---- package.json | 1 + 6 files changed, 227 insertions(+), 256 deletions(-) diff --git a/lib/constants.js b/lib/constants.js index a89a48c0..faa906f4 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -6,7 +6,7 @@ module.exports = { // appSecret: "mXLOjea0woSMvK9gw7Fjsy7YlFO4iSu6", appSecret: "6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM", devicesHideable: ["switch", "light"], - devicesNonLAN: [22, 59, 102], + devicesNonLAN: [22, 28, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], devicesSingleSwitchParams: ["switch"], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 16af13da..fd4aa371 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -166,7 +166,9 @@ class eWeLink { else if (cns.devicesThermostat.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "thermostat"); + : this.addAccessory(device, device.deviceid + "SWX", "thermostat", false, { + sensorType: device.params.sensorType, + }); } //*** OUTLETS ***\\ @@ -276,55 +278,94 @@ class eWeLink { //*** RF BRIDGES ***\\ else if (cns.devicesRFBridge.includes(device.extra.uiid)) { + let accessory, + rfChlCounter = 0, + rfMap = []; + + if (device.hasOwnProperty("tags") && device.tags.hasOwnProperty("zyx_info")) { + device.tags.zyx_info.forEach(remote => + rfMap.push({ + name: remote.name, + type: remote.remote_type, + buttons: Object.assign({}, ...remote.buttonName), + }) + ); + } + accessory = this.devicesInHB.has(device.deviceid + "SW0") ? this.devicesInHB.get(device.deviceid + "SW0") - : this.addAccessory(device, device.deviceid + "SW0", "rf_pri"); - if (Object.keys((device.tags && device.tags.zyx_info) || []).length > 0) { - let rfBridgeChange = false; - for (let i = 1; i <= Object.keys(device.tags.zyx_info).length; i++) { - let oAccessory = this.devicesInHB.has(device.deviceid + "SW" + i) - ? this.devicesInHB.get(device.deviceid + "SW" + i) - : this.addAccessory(device, device.deviceid + "SW" + i, "rf_sub"); - oAccessory - .getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); - oAccessory.context.reachableWAN = device.online; - oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; - this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); - if (oAccessory.context.sensorType !== "button" && !rfBridgeChange) { - let ct = this.cusS.has(oAccessory.context.hbDeviceId) - ? this.cusS.get(oAccessory.context.hbDeviceId).type + : this.addAccessory(device, device.deviceid + "SW0", "rf_pri", true, { + rfMap, + }); + + this.log.error(JSON.stringify(accessory.context, null, 2)); + + rfMap.forEach(subDevice => { + let swNumber = rfChlCounter + 1, + subAccessory, + subType, + subExtraContext = {}; + switch (subDevice.type) { + case "1": + case "2": + case "3": + case "4": + subType = "button"; + break; + case "6": + subType = this.cusS.has(device.deviceid + "SW" + swNumber) + ? this.cusS.get(device.deviceid + "SW" + swNumber).type : "motion"; - if (ct !== oAccessory.context.sensorType) rfBridgeChange = true; - } + break; + default: + return; } - if (rfBridgeChange) { - this.log.warn( - "[%s] bridge configuration changed so devices will be removed and readded.", - accessory.displayName - ); - for (let i = 0; i <= accessory.context.channelCount; i++) { - let oAccessory = this.devicesInHB.get(device.deviceid + "SW" + i); - this.removeAccessory(oAccessory); + subExtraContext = { + buttons: subDevice.buttons, + subType, + swNumber, + }; + if ((subAccessory = this.devicesInHB.get(device.deviceid + "SW" + swNumber))) { + if ( + subAccessory.context.subType !== subType || + subAccessory.context.swNumber !== swNumber + ) { + this.removeAccessory(subAccessory); } - this.initialiseDevice(device); - return; } - } + + subAccessory = this.devicesInHB.has(device.deviceid + "SW" + swNumber) + ? this.devicesInHB.get(device.deviceid + "SW" + swNumber) + : this.addAccessory( + device, + device.deviceid + "SW" + swNumber, + "rf_sub", + false, + subExtraContext + ); + subAccessory + .getService(Service.AccessoryInformation) + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); + subAccessory.context.reachableWAN = device.online; + subAccessory.context.reachableLAN = false; + this.devicesInHB.set(subAccessory.context.hbDeviceId, subAccessory); + this.log.warn(JSON.stringify(subAccessory.context, null, 2)); + rfChlCounter += Object.keys(subDevice.buttons || {}).length; + }); + accessory.context.channelCount = rfChlCounter; + this.devicesInHB.set(accessory.context.hbDeviceId, accessory); } //*** ZIGBEE BRIDGES ***\\ else if (cns.devicesZBBridge.includes(device.extra.uiid)) { - accessory = this.devicesInHB.has(device.deviceid + "SWX") - ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "zb_pri"); + // Nothing to do here but needed to avoid the below not supported error } //*** ZIGBEE DEVICES ***\\ else if (cns.devicesZB.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "zb_sub"); + : this.addAccessory(device, device.deviceid + "SWX", "zb_dev"); } //*** SONOFF CAMERAS ***\\ @@ -383,7 +424,7 @@ class eWeLink { ); } } - addAccessory(device, hbDeviceId, type, hidden = false) { + addAccessory(device, hbDeviceId, type, hidden = false, extraContext = {}) { let switchNumber = hbDeviceId.substr(-1).toString(), newDeviceName = type === "rf_sub" ? device.tags.zyx_info[switchNumber - 1].name : device.name, channelCount = @@ -411,14 +452,17 @@ class eWeLink { .setCharacteristic(Characteristic.Identify, false); } accessory.context = { - hbDeviceId, - eweDeviceId: device.deviceid, - eweUIID: device.extra.uiid, - eweModel: device.productModel, - eweApiKey: device.apikey, - switchNumber, - channelCount, - type, + ...{ + hbDeviceId, + eweDeviceId: device.deviceid, + eweUIID: device.extra.uiid, + eweModel: device.productModel, + eweApiKey: device.apikey, + switchNumber, + channelCount, + type, + }, + ...extraContext, }; if (!hidden) { this.api.registerPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); @@ -474,8 +518,8 @@ class eWeLink { if (!(wcService = accessory.getService(Service.WindowCovering))) { accessory .addService(Service.WindowCovering) - .setCharacteristic(Characteristic.CurrentPosition, 100) - .setCharacteristic(Characteristic.TargetPosition, 100) + .setCharacteristic(Characteristic.CurrentPosition, 0) + .setCharacteristic(Characteristic.TargetPosition, 0) .setCharacteristic(Characteristic.PositionState, 2); wcService = accessory.getService(Service.WindowCovering); } @@ -543,7 +587,7 @@ class eWeLink { accessory.getService(Service.TemperatureSensor) || accessory.addService(Service.TemperatureSensor), humiService = false; - if (this.devicesInEW.get(accessory.context.eweDeviceId).params.sensorType !== "DS18B20") { + if (accessory.context.sensorType !== "DS18B20") { humiService = accessory.getService(Service.HumiditySensor) || accessory.addService(Service.HumiditySensor); @@ -735,100 +779,52 @@ class eWeLink { .getCharacteristic(Characteristic.On) .on("set", (value, callback) => this.internalSwitchUpdate(accessory, value, callback)); break; - case "rf_pri": - if (!accessory.context.hasOwnProperty("rfChlMap")) { - accessory.context.rfChlMap = {}; - } - break; case "rf_sub": - if (!accessory.context.hasOwnProperty("rfChls")) { - accessory.context.rfChls = {}; - } - switch ( - this.devicesInEW.get(accessory.context.eweDeviceId).tags.zyx_info[ - parseInt(accessory.context.switchNumber) - 1 - ].remote_type - ) { - case "1": - case "2": - case "3": - case "4": - accessory.context.sensorType = "button"; + switch (accessory.context.subType) { + case "water": + accessory.getService(Service.LeakSensor) || accessory.addService(Service.LeakSensor); break; - case "6": - accessory.context.sensorType = this.cusS.has(accessory.context.hbDeviceId) - ? this.cusS.get(accessory.context.hbDeviceId).type - : "motion"; + case "fire": + case "smoke": + accessory.getService(Service.SmokeSensor) || + accessory.addService(Service.SmokeSensor); + break; + case "co": + accessory.getService(Service.CarbonMonoxideSensor) || + accessory.addService(Service.CarbonMonoxideSensor); + break; + case "co2": + accessory.getService(Service.CarbonDioxideSensor) || + accessory.addService(Service.CarbonDioxideSensor); + break; + case "contact": + accessory.getService(Service.ContactSensor) || + accessory.addService(Service.ContactSensor); + break; + case "occupancy": + accessory.getService(Service.OccupancySensor) || + accessory.addService(Service.OccupancySensor); + break; + default: + accessory.getService(Service.MotionSensor) || + accessory.addService(Service.MotionSensor); + break; + case "button": + Object.entries(accessory.context.buttons).forEach(([chan, name]) => { + accessory.getService(name) || + accessory.addService(Service.Switch, name, "switch" + chan); + accessory.getService(name).updateCharacteristic(Characteristic.On, false); + accessory + .getService(name) + .getCharacteristic(Characteristic.On) + .on("set", (value, callback) => { + value ? this.internalRFDeviceUpdate(accessory, k, callback) : callback(); + }); + }); break; } - let mAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - this.devicesInEW - .get(mAccessory.context.eweDeviceId) - .tags.zyx_info[parseInt(accessory.context.switchNumber) - 1].buttonName.forEach( - button => { - let rfData; - Object.entries(button).forEach( - ([k, v]) => - (rfData = { - rfChan: k, - name: v, - }) - ); - accessory.context.rfChls[rfData.rfChan] = rfData.name; - mAccessory.context.rfChlMap[rfData.rfChan] = accessory.context.switchNumber; - this.devicesInHB.set(mAccessory.context.hbDeviceId, mAccessory); - switch (accessory.context.sensorType) { - case "button": - accessory.getService(rfData.name) || - accessory.addService(Service.Switch, rfData.name, "switch" + rfData.rfChan); - break; - case "water": - accessory.getService(Service.LeakSensor) || - accessory.addService(Service.LeakSensor); - break; - case "fire": - case "smoke": - accessory.getService(Service.SmokeSensor) || - accessory.addService(Service.SmokeSensor); - break; - case "co": - accessory.getService(Service.CarbonMonoxideSensor) || - accessory.addService(Service.CarbonMonoxideSensor); - break; - case "co2": - accessory.getService(Service.CarbonDioxideSensor) || - accessory.addService(Service.CarbonDioxideSensor); - break; - case "contact": - accessory.getService(Service.ContactSensor) || - accessory.addService(Service.ContactSensor); - break; - case "occupancy": - accessory.getService(Service.OccupancySensor) || - accessory.addService(Service.OccupancySensor); - break; - default: - accessory.getService(Service.MotionSensor) || - accessory.addService(Service.MotionSensor); - break; - } - } - ); - accessory.context.rfChls = accessory.context.rfChls || {}; - if (accessory.context.sensorType === "button") { - Object.entries(accessory.context.rfChls).forEach(([k, v]) => { - accessory.getService(v).updateCharacteristic(Characteristic.On, false); - accessory - .getService(v) - .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => { - value ? this.internalRFDeviceUpdate(accessory, k, callback) : callback(); - }); - }); - } - break; - case "zb_sub": //*** credit @tasict ***\\ + case "zb_dev": //*** credit @tasict ***\\ accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); switch (accessory.context.eweUIID) { @@ -988,9 +984,8 @@ class eWeLink { } return true; case "rf_sub": - case "zb_pri": return true; - case "zb_sub": + case "zb_dev": if (Object.keys(newParams).some(v => cns.devicesZBBridgeParams.includes(v))) { this.externalZBDeviceUpdate(accessory, newParams); } @@ -1808,7 +1803,7 @@ class eWeLink { if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } - if (blindConfig.type !== "blind" || ["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { + if (blindConfig.type !== "blind" || !["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { throw "improper configuration"; } switch (blindConfig.setup) { @@ -2237,25 +2232,27 @@ class eWeLink { externalRFDeviceUpdate(accessory, params) { try { if (!params.hasOwnProperty("updateSource")) return; - let idToCheck = accessory.context.hbDeviceId.slice(0, -1), - timeNow = new Date(); + let timeNow = new Date(); if ( params.hasOwnProperty("cmd") && params.cmd === "transmit" && params.hasOwnProperty("rfChl") ) { - // RF Button - let bAccessory; - if ( - (bAccessory = this.devicesInHB.get(idToCheck + accessory.context.rfChlMap[params.rfChl])) - ) { - bAccessory - .getService(bAccessory.context.rfChls[params.rfChl]) + //*** RF Button ***\\ + let oAccessory, + accObject = this.devicesInHB + .filter(a => a.context.type === "rf_sub") + .filter(a => a.context.eweDeviceId === accessory.context.eweDeviceId) + .filter(a => a.context.buttons.hasOwnProperty(params.rfChl)); + + if ((oAccessory = accObject[0])) { + oAccessory + .getService(oAccessory.context.buttons[params.rfChl]) .updateCharacteristic(Characteristic.On, 1); setTimeout( () => - bAccessory - .getService(bAccessory.context.rfChls[params.rfChl]) + oAccessory + .getService(oAccessory.context.buttons[params.rfChl]) .updateCharacteristic(Characteristic.On, 0), 3000 ); @@ -2263,92 +2260,59 @@ class eWeLink { throw "rf button not found in Homebridge"; } } else if (params.hasOwnProperty("cmd") && params.cmd === "trigger") { - // RF Sensor + //*** RF Sensor ***\\ Object.keys(params) .filter(name => /rfTrig/.test(name)) .forEach(chan => { - let chanNum = chan.substr(-1).toString(), - accessoryNum = accessory.context.rfChlMap[chanNum], - oAccessory; - if ((oAccessory = this.devicesInHB.get(idToCheck + accessoryNum))) { + let rfChanToUpdate = chan.substr(-1).toString(), + oAccessory, + accObject = this.devicesInHB + .filter(acc => acc.context.type === "rf_sub") + .filter(acc => acc.context.eweDeviceId === accessory.context.eweDeviceId) + .filter(acc => acc.context.buttons.hasOwnProperty(rfChanToUpdate)); + if ((oAccessory = accObject[0])) { let timeOfMotion = new Date(params[chan]), - diff = (timeNow.getTime() - timeOfMotion.getTime()) / 1000; + diff = (timeNow.getTime() - timeOfMotion.getTime()) / 1000, + serv, + char; if (diff < (this.config.sensorTimeDifference || 120)) { switch (oAccessory.context.sensorType) { case "button": break; case "water": - oAccessory - .getService(Service.LeakSensor) - .updateCharacteristic(Characteristic.LeakDetected, 1); - setTimeout(() => { - oAccessory - .getService(Service.LeakSensor) - .updateCharacteristic(Characteristic.LeakDetected, 0); - }, (this.config.sensorTimeLength || 2) * 1000); + serv = Service.LeakSensor; + char = Characteristic.LeakDetected; break; case "fire": case "smoke": - oAccessory - .getService(Service.SmokeSensor) - .updateCharacteristic(Characteristic.SmokeDetected, 1); - setTimeout(() => { - oAccessory - .getService(Service.SmokeSensor) - .updateCharacteristic(Characteristic.SmokeDetected, 0); - }, (this.config.sensorTimeLength || 2) * 1000); + serv = Service.SmokeSensor; + char = Characteristic.LeakDetected; break; case "co": - oAccessory - .getService(Service.CarbonMonoxideSensor) - .updateCharacteristic(Characteristic.CarbonMonoxideDetected, 1); - setTimeout(() => { - oAccessory - .getService(Service.CarbonMonoxideSensor) - .updateCharacteristic(Characteristic.CarbonMonoxideDetected, 0); - }, (this.config.sensorTimeLength || 2) * 1000); + serv = Service.CarbonMonoxideSensor; + char = Characteristic.CarbonMonoxideDetected; break; case "co2": - oAccessory - .getService(Service.CarbonDioxideSensor) - .updateCharacteristic(Characteristic.CarbonDioxideDetected, 1); - setTimeout(() => { - oAccessory - .getService(Service.CarbonDioxideSensor) - .updateCharacteristic(Characteristic.CarbonDioxideDetected, 0); - }, (this.config.sensorTimeLength || 2) * 1000); + serv = Service.CarbonDioxideSensor; + char = Characteristic.CarbonDioxideDetected; break; case "contact": - oAccessory - .getService(Service.ContactSensor) - .updateCharacteristic(Characteristic.ContactSensorState, 1); - setTimeout(() => { - oAccessory - .getService(Service.ContactSensor) - .updateCharacteristic(Characteristic.ContactSensorState, 0); - }, (this.config.sensorTimeLength || 2) * 1000); + serv = Service.ContactSensor; + char = Characteristic.ContactSensorState; break; case "occupancy": - oAccessory - .getService(Service.OccupancySensor) - .updateCharacteristic(Characteristic.OccupancyDetected, 1); - setTimeout(() => { - oAccessory - .getService(Service.OccupancySensor) - .updateCharacteristic(Characteristic.OccupancyDetected, 0); - }, (this.config.sensorTimeLength || 2) * 1000); + serv = Service.OccupancySensor; + char = Characteristic.OccupancyDetected; break; default: - oAccessory - .getService(Service.MotionSensor) - .updateCharacteristic(Characteristic.MotionDetected, true); - setTimeout(() => { - oAccessory - .getService(Service.MotionSensor) - .updateCharacteristic(Characteristic.MotionDetected, false); - }, (this.config.sensorTimeLength || 2) * 1000); + serv = Service.MotionSensor; + char = Characteristic.MotionDetected; break; } + oAccessory.getService(serv).updateCharacteristic(char, 1); + setTimeout(() => { + oAccessory.getService(serv).updateCharacteristic(char, 0); + }, (this.config.sensorTimeLength || 2) * 1000); if (this.debug) { this.log( "[%s] has detected [%s].", diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 48ffefb8..7f2410b0 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -74,8 +74,11 @@ module.exports = class eWeLinkHTTP { resolve(this.httpHost); }) .catch(err => { - if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { - this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); + if ( + err.hasOwnProperty("code") && + ["ENOTFOUND", "ETIMEDOUT", "EAI_AGAIN"].includes(err.code) + ) { + this.log.warn("Unable to reach eWeLink. Retrying in 15 seconds."); this.delay().then(() => resolve(this.getHost())); } else { reject(err.message || err); @@ -187,7 +190,7 @@ module.exports = class eWeLinkHTTP { }) .catch(err => { if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { - this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); + this.log.warn("Unable to reach eWeLink. Retrying in 15 seconds."); this.delay().then(() => resolve(this.getDevices())); } else { reject(err.message || err); @@ -236,7 +239,7 @@ module.exports = class eWeLinkHTTP { }) .catch(err => { if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { - this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); + this.log.warn("Unable to reach eWeLink. Retrying in 15 seconds."); this.delay().then(() => resolve(this.getDevice(deviceId))); } else { reject(err.message || err); @@ -245,6 +248,6 @@ module.exports = class eWeLinkHTTP { }); } delay() { - return new Promise(resolve => setTimeout(resolve, 30000)); + return new Promise(resolve => setTimeout(resolve, 15000)); } }; diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index fd077cff..df427482 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -175,11 +175,9 @@ module.exports = class eWeLinkWS { } } }); - this.wsp.onClose.addListener(e => { - if (e.reason === "Stopping Homebridge") { - this.log("Web socket gracefully closed."); - } else { - this.log.warn("Web socket closed - [%s - %s].", e.code, e.reason); + this.wsp.onClose.addListener((e, m) => { + if (e !== 1005) { + this.log.warn("Web socket closed [%s].", e); if (e !== 1000) { this.log("Web socket will try to reconnect in five seconds."); setTimeout(() => this.login(), 5000); @@ -304,7 +302,8 @@ module.exports = class eWeLinkWS { } closeConnection() { if (this.wsp && this.wsIsOpen) { - this.wsp.close(1000, "Stopping Homebridge"); + this.wsp.close(); + this.log("Web socket gracefully closed."); } } delay(ms) { diff --git a/package-lock.json b/package-lock.json index e100f5ec..7cd45f9b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -109,6 +109,11 @@ "supports-color": "^7.1.0" } }, + "chnl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/chnl/-/chnl-1.2.0.tgz", + "integrity": "sha512-g5gJb59edwCliFbX2j7G6sBfY4sX9YLy211yctONI2GRaiX0f2zIbKWmBm+sPqFNEpM7Ljzm7IJX/xrjiEbPrw==" + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -420,11 +425,6 @@ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" }, - "is-negative-zero": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", - "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=" - }, "is-regex": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", @@ -545,35 +545,14 @@ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "object.assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", - "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.0", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.0-next.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.0.tgz", - "integrity": "sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" } }, "prettier": { @@ -582,6 +561,21 @@ "integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==", "dev": true }, + "promise-controller": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/promise-controller/-/promise-controller-1.0.0.tgz", + "integrity": "sha512-goA0zA9L91tuQbUmiMinSYqlyUtEgg4fxJcjYnLYOQnrktb4o4UqciXDNXiRUPiDBPACmsr1k8jDW4r7UDq9Qw==" + }, + "promise.prototype.finally": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/promise.prototype.finally/-/promise.prototype.finally-3.1.2.tgz", + "integrity": "sha512-A2HuJWl2opDH0EafgdjwEw7HysI8ff/n4lW4QEVBCUXFk9QeGecBWv0Deph0UmLe3tTNYegz8MOjsVuE6SMoJA==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.0", + "function-bind": "^1.1.1" + } + }, "qs": { "version": "6.9.4", "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", @@ -647,6 +641,16 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.0.tgz", "integrity": "sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==" }, + "websocket-as-promised": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/websocket-as-promised/-/websocket-as-promised-1.0.1.tgz", + "integrity": "sha512-+gBevna4yxisb8cigL8NxcS8s241cvfMeyy1fNFcFgBcX/6vknMT84MwMmBNLYmsYH2giVoxOSEiAeeb7txFOw==", + "requires": { + "chnl": "^1.0.0", + "promise-controller": "^1.0.0", + "promise.prototype.finally": "^3.1.1" + } + }, "ws": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz", diff --git a/package.json b/package.json index 0ebc8b68..251d9f95 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "fakegato-history": "0.5.6", "homebridge-lib": "4.7.15", "node-dns-sd": "0.4.1", + "websocket-as-promised": "1.0.1", "ws": "7.3.1" }, "devDependencies": { From cd9bb9efa0a93df33b27b92db1462a4ad460f9db Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 21 Sep 2020 11:34:16 +0100 Subject: [PATCH 0177/3183] 3.0.0-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7cd45f9b..d113ad56 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.0-0", + "version": "3.0.0-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 251d9f95..db5f1146 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.0-0", + "version": "3.0.0-1", "author": "bwp91", "contributors": [ "gbro115", From 66b924f74f712a2c9b3f1054f5ea4bc99fe513c1 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 21 Sep 2020 11:43:55 +0100 Subject: [PATCH 0178/3183] Update stale.yml --- .github/stale.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/stale.yml b/.github/stale.yml index 89b61309..c75e5812 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -4,6 +4,8 @@ daysUntilStale: 7 daysUntilClose: 7 # Issues with these labels will never be considered stale exemptLabels: + - "feedback wanted" + - "don't close" # Label to use when marking an issue as stale staleLabel: inactive # Comment to post when marking an issue as stale. Set to `false` to disable From ebd9a69ef0b6b829e4973ad7269a603f149b96bf Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 21 Sep 2020 15:18:00 +0100 Subject: [PATCH 0179/3183] misc --- index.js | 2 +- lib/constants.js | 2 +- lib/eWeLinkHTTP.js | 2 +- lib/eWeLinkLAN.js | 2 +- lib/eWeLinkWS.js | 2 +- package.json | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index d25bb094..01e13ba7 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,4 @@ -/* jshint esversion: 9, -W030, node: true */ +/* jshint esversion: 9, -W014, -W030, node: true */ "use strict"; module.exports = function (homebridge) { const eWeLink = require("./lib/eWeLink.js")(homebridge); diff --git a/lib/constants.js b/lib/constants.js index faa906f4..3da14a6e 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -1,4 +1,4 @@ -/* jshint esversion: 9, -W030, node: true */ +/* jshint esversion: 9, -W014, -W030, node: true */ "use strict"; module.exports = { // appId: "Uw83EKZFxdif7XFXEsrpduz5YyjP7nTl", diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 7f2410b0..817bbade 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -1,4 +1,4 @@ -/* jshint esversion: 9, -W030, node: true */ +/* jshint esversion: 9, -W014, -W030, node: true */ "use strict"; const axios = require("axios"), constants = require("./constants"), diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index c996e682..3923e97d 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -1,4 +1,4 @@ -/* jshint esversion: 9, -W030, node: true */ +/* jshint esversion: 9, -W014, -W030, node: true */ "use strict"; const axios = require("axios"), cns = require("./constants"), diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index df427482..31192209 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -1,4 +1,4 @@ -/* jshint esversion: 9, -W030, node: true */ +/* jshint esversion: 9, -W014, -W030, node: true */ "use strict"; const axios = require("axios"), cns = require("./constants"), diff --git a/package.json b/package.json index db5f1146..f7f0b9d9 100644 --- a/package.json +++ b/package.json @@ -32,8 +32,8 @@ "ewelink" ], "engines": { - "node": ">=6.0.0", - "homebridge": ">=0.2.0" + "node": ">=10.0.0", + "homebridge": ">=1.0.0" }, "repository": { "type": "git", From 45e6502e0d201f4d3ca3bcd44cc3dc126f303fda Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 21 Sep 2020 15:18:22 +0100 Subject: [PATCH 0180/3183] rf --- lib/eWeLink.js | 53 +++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index fd4aa371..23f4b93c 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1,4 +1,4 @@ -/* jshint esversion: 9, -W030, node: true */ +/* jshint esversion: 9, -W014, -W030, node: true */ "use strict"; let Accessory, Characteristic, EveService, EveHistoryService, Service, UUIDGen; const cns = require("./constants"), @@ -411,10 +411,8 @@ class eWeLink { str += "is unreachable"; } } - this.log(" → [%s] initialised %s.", device.name, str); this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - if (!this.refreshAccessory(accessory, device.params)) { this.log.warn( "[%s] could not be initialised. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.) [debug:%s:%s].", @@ -818,7 +816,7 @@ class eWeLink { .getService(name) .getCharacteristic(Characteristic.On) .on("set", (value, callback) => { - value ? this.internalRFDeviceUpdate(accessory, k, callback) : callback(); + value ? this.internalRFUpdate(accessory, chan, name, callback) : callback(); }); }); break; @@ -980,14 +978,14 @@ class eWeLink { return true; case "rf_pri": if (Object.keys(newParams).some(v => cns.devicesRFBridgeParams.includes(v))) { - this.externalRFDeviceUpdate(accessory, newParams); + this.externalRFUpdate(accessory, newParams); } return true; case "rf_sub": return true; case "zb_dev": if (Object.keys(newParams).some(v => cns.devicesZBBridgeParams.includes(v))) { - this.externalZBDeviceUpdate(accessory, newParams); + this.externalZBUpdate(accessory, newParams); } return true; default: @@ -1746,7 +1744,7 @@ class eWeLink { callback(str); } } - internalRFDeviceUpdate(accessory, rfChl, callback) { + internalRFUpdate(accessory, rfChl, service, callback) { try { if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { throw "it is currently offline"; @@ -1756,7 +1754,7 @@ class eWeLink { cmd: "transmit", rfChl, }, - rfService = accessory.getService(accessory.context.rfChls[rfChl]); + rfService = accessory.getService(service); if (this.debug) { this.log( "[%s %s] mimicking RF button press.", @@ -2229,23 +2227,28 @@ class eWeLink { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } - externalRFDeviceUpdate(accessory, params) { + externalRFUpdate(accessory, params) { try { if (!params.hasOwnProperty("updateSource")) return; - let timeNow = new Date(); + let timeNow = new Date(), + oAccessory = false; if ( params.hasOwnProperty("cmd") && params.cmd === "transmit" && params.hasOwnProperty("rfChl") ) { //*** RF Button ***\\ - let oAccessory, - accObject = this.devicesInHB - .filter(a => a.context.type === "rf_sub") - .filter(a => a.context.eweDeviceId === accessory.context.eweDeviceId) - .filter(a => a.context.buttons.hasOwnProperty(params.rfChl)); + // the device needed is SW% corresponding to params.rfChl - if ((oAccessory = accObject[0])) { + this.devicesInHB.forEach(acc => { + if ( + acc.context.eweDeviceId === accessory.context.eweDeviceId && + acc.context.buttons.hasOwnProperty(params.rfChl.toString()) + ) { + oAccessory = acc; + } + }); + if (oAccessory) { oAccessory .getService(oAccessory.context.buttons[params.rfChl]) .updateCharacteristic(Characteristic.On, 1); @@ -2264,13 +2267,15 @@ class eWeLink { Object.keys(params) .filter(name => /rfTrig/.test(name)) .forEach(chan => { - let rfChanToUpdate = chan.substr(-1).toString(), - oAccessory, - accObject = this.devicesInHB - .filter(acc => acc.context.type === "rf_sub") - .filter(acc => acc.context.eweDeviceId === accessory.context.eweDeviceId) - .filter(acc => acc.context.buttons.hasOwnProperty(rfChanToUpdate)); - if ((oAccessory = accObject[0])) { + this.devicesInHB.forEach(acc => { + if ( + acc.context.eweDeviceId === accessory.context.eweDeviceId && + acc.context.buttons.hasOwnProperty(chan.substr(-1).toString()) + ) { + oAccessory = acc; + } + }); + if (oAccessory) { let timeOfMotion = new Date(params[chan]), diff = (timeNow.getTime() - timeOfMotion.getTime()) / 1000, serv, @@ -2328,7 +2333,7 @@ class eWeLink { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } - externalZBDeviceUpdate(accessory, params) { + externalZBUpdate(accessory, params) { try { //*** credit @tasict ***\\ if (params.hasOwnProperty("battery")) { From a0bdc5a0a8e9e92cf266c2aa7367bbfe1e4cf8b9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 21 Sep 2020 15:32:53 +0100 Subject: [PATCH 0181/3183] check th sensor --- lib/eWeLink.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 23f4b93c..e0bd27c2 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -169,6 +169,10 @@ class eWeLink { : this.addAccessory(device, device.deviceid + "SWX", "thermostat", false, { sensorType: device.params.sensorType, }); + if (accessory.context.sensorType !== device.params.sensorType) { + accessory.context.sensorType = device.params.sensorType; + this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + } } //*** OUTLETS ***\\ @@ -589,6 +593,10 @@ class eWeLink { humiService = accessory.getService(Service.HumiditySensor) || accessory.addService(Service.HumiditySensor); + } else { + if (accessory.getService(Service.HumiditySensor)) { + accessory.removeService(Service.HumiditySensor); + } } if (!this.config.hideTHSwitch) { let switchService = From 73fd656d8c6fae673dda170ae737858ca5e8710c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 21 Sep 2020 17:31:34 +0100 Subject: [PATCH 0182/3183] blinds --- lib/eWeLink.js | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index e0bd27c2..07123396 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1179,6 +1179,7 @@ class eWeLink { if (blindConfig.type !== "blind" || !["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { throw "improper configuration"; } + let oldPos, params = {}, wcService = accessory.getService(Service.WindowCovering); @@ -1191,6 +1192,10 @@ class eWeLink { callback(); return; } + + // target position -> 0 for closed 100 for open (value) + // current position -> 0 going down, 1 going up + switch (blindConfig.setup) { case "oneSwitch": params.switch = "on"; @@ -1211,8 +1216,22 @@ class eWeLink { wcService .updateCharacteristic(Characteristic.CurrentPosition, value) .updateCharacteristic(Characteristic.PositionState, 2); - callback(); + + switch (blindConfig.setup) { + case "oneSwitch": + params.switch = "off"; + break; + case "twoSwitch": + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = "off"; + params.switches[1].switch = "off"; + break; + } + this.sendDeviceUpdate(accessory, params, function () { + return; + }); }, parseInt(blindConfig.operationTime) * 100); + callback(); } catch (err) { let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; this.log.error(str); @@ -1804,7 +1823,7 @@ class eWeLink { externalBlindUpdate(accessory, params) { try { let blindConfig, - nSte, + newPosition, wcService = accessory.getService(Service.WindowCovering); if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; @@ -1812,12 +1831,16 @@ class eWeLink { if (blindConfig.type !== "blind" || !["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { throw "improper configuration"; } + // target position -> 0 for closed 100 for open (value) + // current position -> 0 going down, 1 going up + switch (blindConfig.setup) { case "oneSwitch": if (params.switch === "off") { return; } - nSte = wcService.getCharacteristic(Characteristic.PositionState).value === 0 ? 1 : 0; + newPosition = + wcService.getCharacteristic(Characteristic.PositionState).value === 0 ? 1 : 0; break; case "twoSwitch": if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { @@ -1825,16 +1848,16 @@ class eWeLink { } let switchUp = params.switches[0].switch === "on" ? -1 : 0, // matrix of numbers to get switchDown = params.switches[1].switch === "on" ? 0 : 2; // ... the correct HomeKit value - nSte = switchUp + switchDown; + newPosition = switchUp + switchDown; break; } wcService - .updateCharacteristic(Characteristic.PositionState, nSte) - .updateCharacteristic(Characteristic.TargetPosition, nSte * 100); + .updateCharacteristic(Characteristic.PositionState, newPosition) + .updateCharacteristic(Characteristic.TargetPosition, newPosition * 100); setTimeout(() => { wcService .updateCharacteristic(Characteristic.PositionState, 2) - .updateCharacteristic(Characteristic.CurrentPosition, nSte * 100); + .updateCharacteristic(Characteristic.CurrentPosition, newPosition * 100); }, parseInt(blindConfig.operationTime) * 100); } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); From 6f734f81a7317711a246d883c4d6b8e545156b12 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 21 Sep 2020 17:34:28 +0100 Subject: [PATCH 0183/3183] 3.0.0-2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index d113ad56..447393fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.0-1", + "version": "3.0.0-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f7f0b9d9..d1803b2b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.0-1", + "version": "3.0.0-2", "author": "bwp91", "contributors": [ "gbro115", From 03e4a232e860c0a9e473a30a030feea7b2e9ca07 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 21 Sep 2020 18:20:34 +0100 Subject: [PATCH 0184/3183] http change --- lib/eWeLink.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 07123396..2a9a2f2e 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -417,13 +417,15 @@ class eWeLink { } this.log(" → [%s] initialised %s.", device.name, str); this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - if (!this.refreshAccessory(accessory, device.params)) { - this.log.warn( - "[%s] could not be initialised. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.) [debug:%s:%s].", - accessory.displayName, - accessory.context.type, - accessory.context.channelCount - ); + if (!(this.config.disableHTTPRefresh || false)) { + if (!this.refreshAccessory(accessory, device.params)) { + this.log.warn( + "[%s] could not be initialised. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.) [debug:%s:%s].", + accessory.displayName, + accessory.context.type, + accessory.context.channelCount + ); + } } } addAccessory(device, hbDeviceId, type, hidden = false, extraContext = {}) { From 6671e0203b01c9266280c1da7847852e66791235 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 21 Sep 2020 18:21:50 +0100 Subject: [PATCH 0185/3183] 3.0.0-3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 447393fd..d5c2bc87 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.0-2", + "version": "3.0.0-3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index d1803b2b..a442dbb2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.0-2", + "version": "3.0.0-3", "author": "bwp91", "contributors": [ "gbro115", From 21e7b7a8c0ec12d7c535e61587d054609a0c8010 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 21 Sep 2020 19:03:29 +0100 Subject: [PATCH 0186/3183] blinds to twoSwitch only --- config.schema.json | 4 ++-- lib/eWeLink.js | 56 +++++++++++++--------------------------------- 2 files changed, 18 insertions(+), 42 deletions(-) diff --git a/config.schema.json b/config.schema.json index e1d15c4d..f44541f9 100644 --- a/config.schema.json +++ b/config.schema.json @@ -138,7 +138,7 @@ "type": "string", "title": "Device Setup", "default": "null", - "description": "The device setup. Please ignore this setting for locks", + "description": "The device setup. Blinds must be set up with two switches. Please ignore this setting for locks.", "oneOf": [ { "title": "One Switch - for up and down", @@ -161,7 +161,7 @@ "sensorId": { "type": "string", "title": "Sensor", - "description": "A Sonoff DW2 sensor can optionally be used for blinds and garage doors. This is to determine the current open/closed state of the device. Please enter the 10 digit device ID (normally in the format 1000ab23cd). Otherwise leave this blank." + "description": "A Sonoff DW2 sensor can optionally be used for garage doors. This is to determine the current open/closed state of the garage door. Please enter the 10 digit device ID (normally in the format 1000ab23cd). Otherwise leave this blank." } } } diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 2a9a2f2e..e8952e3a 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1178,7 +1178,7 @@ class eWeLink { if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } - if (blindConfig.type !== "blind" || !["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { + if (blindConfig.type !== "blind" || blindConfig.setup !== "twoSwitch") { throw "improper configuration"; } @@ -1198,16 +1198,11 @@ class eWeLink { // target position -> 0 for closed 100 for open (value) // current position -> 0 going down, 1 going up - switch (blindConfig.setup) { - case "oneSwitch": - params.switch = "on"; - break; - case "twoSwitch": - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = value === 100 ? "on" : "off"; - params.switches[1].switch = value === 0 ? "on" : "off"; - break; - } + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = value === 100 ? "on" : "off"; + params.switches[1].switch = value === 0 ? "on" : "off"; + break; + this.sendDeviceUpdate(accessory, params, function () { return; }); @@ -1218,17 +1213,9 @@ class eWeLink { wcService .updateCharacteristic(Characteristic.CurrentPosition, value) .updateCharacteristic(Characteristic.PositionState, 2); - - switch (blindConfig.setup) { - case "oneSwitch": - params.switch = "off"; - break; - case "twoSwitch": - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = "off"; - params.switches[1].switch = "off"; - break; - } + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = "off"; + params.switches[1].switch = "off"; this.sendDeviceUpdate(accessory, params, function () { return; }); @@ -1830,29 +1817,18 @@ class eWeLink { if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } - if (blindConfig.type !== "blind" || !["oneSwitch", "twoSwitch"].includes(blindConfig.setup)) { + if (blindConfig.type !== "blind" || blindConfig.setup !== "twoSwitch") { throw "improper configuration"; } // target position -> 0 for closed 100 for open (value) // current position -> 0 going down, 1 going up - - switch (blindConfig.setup) { - case "oneSwitch": - if (params.switch === "off") { - return; - } - newPosition = - wcService.getCharacteristic(Characteristic.PositionState).value === 0 ? 1 : 0; - break; - case "twoSwitch": - if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { - return; - } - let switchUp = params.switches[0].switch === "on" ? -1 : 0, // matrix of numbers to get - switchDown = params.switches[1].switch === "on" ? 0 : 2; // ... the correct HomeKit value - newPosition = switchUp + switchDown; - break; + if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { + return; } + let switchUp = params.switches[0].switch === "on" ? -1 : 0, // matrix of numbers to get + switchDown = params.switches[1].switch === "on" ? 0 : 2; // ... the correct HomeKit value + newPosition = switchUp + switchDown; + wcService .updateCharacteristic(Characteristic.PositionState, newPosition) .updateCharacteristic(Characteristic.TargetPosition, newPosition * 100); From 8749a526cda23ecb4e52a77fb5ebe82c10aa4fb2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 22 Sep 2020 08:25:04 +0100 Subject: [PATCH 0187/3183] king q4 try --- lib/constants.js | 5 ++- lib/eWeLink.js | 91 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 91 insertions(+), 5 deletions(-) diff --git a/lib/constants.js b/lib/constants.js index 3da14a6e..75e59b9e 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -37,6 +37,8 @@ module.exports = { devicesMultiSwitchLightParams: ["switches"], devicesBrightable: [36, 44], devicesColourable: [22, 59], + devicesCurtain: [11], + devicesCurtainParams: ["switch", "setclose"], devicesSensor: [102], devicesSensorParams: ["switch", "battery"], devicesThermostat: [15], @@ -94,6 +96,7 @@ module.exports = { "rfList", "rfTrig", "sensorType", + "setclose", "speed", "state", "switch", @@ -115,7 +118,7 @@ module.exports = { 8: 3, // "SWITCH_3" \\ T1 3C, TX3C 9: 4, // "SWITCH_4" \\ 10: 0, // "OSPF" \\ - 11: 0, // "CURTAIN" \\ King Q4 Cover + 11: 1, // "CURTAIN" \\ King Q4 Cover 12: 0, // "EW-RE" \\ 13: 0, // "FIREPLACE" \\ 14: 1, // "SWITCH_CHANGE" \\ diff --git a/lib/eWeLink.js b/lib/eWeLink.js index e8952e3a..cdd80fca 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -125,7 +125,11 @@ class eWeLink { ) { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "blind"); + : this.addAccessory(device, device.deviceid + "SWX", "blind", false, { + cacheLastPosition: 0, + cachePositionState: 2, + cacheTargetPosition: 0, + }); } //*** GARAGES ***\\ @@ -148,6 +152,13 @@ class eWeLink { : this.addAccessory(device, device.deviceid + "SWX", "lock"); } + //*** CURTAINS ***\\ + else if (cns.devicesCurtain.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + "SWX") + ? this.devicesInHB.get(device.deviceid + "SWX") + : this.addAccessory(device, device.deviceid + "SWX", "curtain"); + } + //*** DW2 SENSORS ***\\ else if (cns.devicesSensor.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + "SWX") @@ -534,6 +545,23 @@ class eWeLink { minStep: 100, }); break; + case "curtain": + let cService; + if (!(cService = accessory.getService(Service.WindowCovering))) { + accessory + .addService(Service.WindowCovering) + .setCharacteristic(Characteristic.CurrentPosition, 0) + .setCharacteristic(Characteristic.TargetPosition, 0) + .setCharacteristic(Characteristic.PositionState, 2); + cService = accessory.getService(Service.WindowCovering); + } + cService + .getCharacteristic(Characteristic.TargetPosition) + .on("set", (value, callback) => this.internalCurtainUpdate(accessory, value, callback)) + .setProps({ + minStep: 100, + }); + break; case "garage": let gdService; if (!(gdService = accessory.getService(Service.GarageDoorOpener))) { @@ -916,6 +944,11 @@ class eWeLink { this.externalLockUpdate(accessory, newParams); } return true; + case "curtain": + if (Object.keys(newParams).some(v => cns.devicesCurtainParams.includes(v))) { + this.externalCurtainUpdate(accessory, newParams); + } + return true; case "sensor": if (Object.keys(newParams).some(v => cns.devicesSensorParams.includes(v))) { this.externalSensorUpdate(accessory, newParams); @@ -1201,7 +1234,6 @@ class eWeLink { params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; params.switches[0].switch = value === 100 ? "on" : "off"; params.switches[1].switch = value === 0 ? "on" : "off"; - break; this.sendDeviceUpdate(accessory, params, function () { return; @@ -1341,6 +1373,40 @@ class eWeLink { callback(str); } } + internalCurtainUpdate(accessory, value, callback) { + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let params, + cService = accessory.getService(Service.WindowCovering), + prevPos = accessory.context.prevPos; + + if (value === prevPos) { + //nothing to do as no change + callback(); + return; + } + if (value === 0 || value === 100) { + // so to fully open, our $value will be 100, we send switch: "on" + // to fully shut, our $value will be 0, we send switch: "off" + params = { switch: value === 100 ? "on" : "off" }; + } else { + // for a % midway, scale the $value >--< 100 and setclose: newVal AS INT + params = { setclose: Math.abs(100 - value) }; + } + cService + .updateCharacteristic(Characteristic.TargetPosition, value) + .updateCharacteristic(Characteristic.PositionState, value > prevPos ? 1 : 0); + // TargetPosition -> 0 for closed 100 for open (value) + // CurrentPosition -> 0 for closed 100 for open + // PositionState -> 0 going down, 1 going up, 2 = stopped + + this.sendDeviceUpdate(accessory, params, callback); + } catch (err) { + callback("[" + accessory.displayName + "] " + err + "."); + } + } internalFanUpdate(accessory, type, value, callback) { try { if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { @@ -1820,8 +1886,9 @@ class eWeLink { if (blindConfig.type !== "blind" || blindConfig.setup !== "twoSwitch") { throw "improper configuration"; } - // target position -> 0 for closed 100 for open (value) - // current position -> 0 going down, 1 going up + // TargetPosition -> 0 for closed 100 for open (value) + // CurrentPosition -> 0 for closed 100 for open + // PositionState -> 0 going down, 1 going up, 2 = stopped if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { return; } @@ -1919,6 +1986,22 @@ class eWeLink { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } + externalCurtainUpdate(accessory, params) { + try { + let cService = accessory.getService(Service.WindowCovering); + if (params.hasOwnProperty("switch") && params.hasOwnProperty("setclose")) { + cService + .updateCharacteristic( + Characteristic.TargetPosition, + Math.abs(100 - parseInt(params.setclose)) + ) + .updateCharacteristic(Characteristic.PositionState, 2); + return; + } + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } externalSensorUpdate(accessory, params) { try { if (params.hasOwnProperty("battery")) { From f7cd49c889b3d42eef98a207cd2daed99febc630 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 22 Sep 2020 16:13:19 +0100 Subject: [PATCH 0188/3183] 3.0.0-4 updates --- lib/eWeLink.js | 866 ++++++++++++++++++++++++--------------------- lib/eWeLinkHTTP.js | 14 +- lib/eWeLinkLAN.js | 8 +- lib/eWeLinkWS.js | 22 +- 4 files changed, 496 insertions(+), 414 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index cdd80fca..acd6c6a7 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -33,6 +33,7 @@ class eWeLink { .on("shutdown", () => { if (this.lanClient) this.lanClient.closeConnection(); if (this.wsClient) this.wsClient.closeConnection(); + if (this.wsRefresh) clearInterval(this.wsRefresh); }); } eWeLinkSync() { @@ -53,6 +54,18 @@ class eWeLink { }) .then(() => { this.wsClient.login(); + this.wsRefresh = setInterval(() => { + if (this.wsClient) { + this.wsClient + .getHost() + .then(() => this.wsClient.closeConnection()) + .then(() => { + return new Promise(resolve => setTimeout(resolve, 250)); + }) + .then(() => this.wsClient.login()) + .catch(err => this.log.warn(err)); + } + }, 1800000); return this.lanClient.getHosts(); }) .then(res => { @@ -106,7 +119,6 @@ class eWeLink { initialiseDevice(device) { let accessory; //*** First add the device if it isn't already in Homebridge ***\\ - //*** IRRIGATION VALVES ***\\ if ( device.extra.uiid === 2 && @@ -117,7 +129,6 @@ class eWeLink { ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "valve"); } - //*** WINDOW BLINDS ***\\ else if ( this.cusG.has(device.deviceid + "SWX") && @@ -131,7 +142,6 @@ class eWeLink { cacheTargetPosition: 0, }); } - //*** GARAGES ***\\ else if ( this.cusG.has(device.deviceid + "SWX") && @@ -141,7 +151,6 @@ class eWeLink { ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "garage"); } - //*** LOCKS ***\\ else if ( this.cusG.has(device.deviceid + "SWX") && @@ -151,28 +160,26 @@ class eWeLink { ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "lock"); } - //*** CURTAINS ***\\ else if (cns.devicesCurtain.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "curtain"); + : this.addAccessory(device, device.deviceid + "SWX", "curtain", false, { + prevPos: 0, + }); } - //*** DW2 SENSORS ***\\ else if (cns.devicesSensor.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "sensor"); } - //*** FANS ***\\ else if (cns.devicesFan.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "fan"); } - //*** THERMOSTATS ***\\ else if (cns.devicesThermostat.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + "SWX") @@ -185,28 +192,27 @@ class eWeLink { this.devicesInHB.set(accessory.context.hbDeviceId, accessory); } } - //*** OUTLETS ***\\ - else if (cns.devicesOutlet.includes(device.extra.uiid)) { + else if ( + cns.devicesOutlet.includes(device.extra.uiid) || + device.productModel === "Sonoff Pow" + ) { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "outlet"); } - //*** USB OUTLETS ***\\ else if (cns.devicesUSB.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "usb"); } - //*** SINGLE CHANNEL [MULTI CHANNEL HARDWARE] ***\\ else if (cns.devicesSCM.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "scm"); } - //*** SINGLE CHANNEL LIGHTS ***\\ else if ( cns.devicesSingleSwitch.includes(device.extra.uiid) && @@ -216,7 +222,6 @@ class eWeLink { ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "light"); } - //*** MULTI CHANNEL LIGHTS ***\\ else if ( cns.devicesMultiSwitch.includes(device.extra.uiid) && @@ -251,14 +256,12 @@ class eWeLink { } } } - //*** SINGLE CHANNEL SWITCHES ***\\ else if (cns.devicesSingleSwitch.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "switch"); } - //*** MULTI CHANNEL SWITCHES ***\\ else if (cns.devicesMultiSwitch.includes(device.extra.uiid)) { if (this.config.hideMasters) { @@ -290,13 +293,11 @@ class eWeLink { } } } - //*** RF BRIDGES ***\\ else if (cns.devicesRFBridge.includes(device.extra.uiid)) { let accessory, rfChlCounter = 0, rfMap = []; - if (device.hasOwnProperty("tags") && device.tags.hasOwnProperty("zyx_info")) { device.tags.zyx_info.forEach(remote => rfMap.push({ @@ -306,15 +307,12 @@ class eWeLink { }) ); } - accessory = this.devicesInHB.has(device.deviceid + "SW0") ? this.devicesInHB.get(device.deviceid + "SW0") : this.addAccessory(device, device.deviceid + "SW0", "rf_pri", true, { rfMap, }); - this.log.error(JSON.stringify(accessory.context, null, 2)); - rfMap.forEach(subDevice => { let swNumber = rfChlCounter + 1, subAccessory, @@ -348,7 +346,6 @@ class eWeLink { this.removeAccessory(subAccessory); } } - subAccessory = this.devicesInHB.has(device.deviceid + "SW" + swNumber) ? this.devicesInHB.get(device.deviceid + "SW" + swNumber) : this.addAccessory( @@ -370,19 +367,16 @@ class eWeLink { accessory.context.channelCount = rfChlCounter; this.devicesInHB.set(accessory.context.hbDeviceId, accessory); } - //*** ZIGBEE BRIDGES ***\\ else if (cns.devicesZBBridge.includes(device.extra.uiid)) { // Nothing to do here but needed to avoid the below not supported error } - //*** ZIGBEE DEVICES ***\\ else if (cns.devicesZB.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "zb_dev"); } - //*** SONOFF CAMERAS ***\\ else if (cns.devicesCamera.includes(device.extra.uiid)) { this.log.warn( @@ -391,7 +385,6 @@ class eWeLink { ); return; } - //*** ALL OTHER = UNSUPPORTED ***\\ else { this.log.warn( @@ -400,7 +393,6 @@ class eWeLink { ); return; } - if (!accessory) { return; } @@ -413,7 +405,6 @@ class eWeLink { accessory.context.reachableWAN = device.online; accessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; accessory.context.inUse = false; - let str = accessory.context.reachableLAN ? "and found locally with IP [" + this.lanDevices.get(device.deviceid).ip + "]" : "but LAN mode unavailable as device "; @@ -1044,39 +1035,40 @@ class eWeLink { this.log.warn(" → [%s] wasn't removed as %s.", accessory.displayName, err); } } - sendDeviceUpdate(accessory, params, callback) { - let payload = { - apikey: accessory.context.eweApiKey, - deviceid: accessory.context.eweDeviceId, - params, - }; - let sendViaWS = () => { - if (accessory.context.reachableWAN) { - this.wsClient - .sendUpdate(payload) - .then(() => callback()) - .catch(err => callback(err)); + sendDeviceUpdate(accessory, params) { + return new Promise((resolve, reject) => { + let payload = { + apikey: accessory.context.eweApiKey, + deviceid: accessory.context.eweDeviceId, + params, + }; + let sendViaWS = () => { + if (accessory.context.reachableWAN) { + this.wsClient + .sendUpdate(payload) + .then(() => resolve()) + .catch(err => reject(err)); + } else { + reject("it is unreachable"); + } + }; + if ( + cns.devicesNonLAN.includes(accessory.context.eweUIID) || + !accessory.context.reachableLAN + ) { + sendViaWS(); } else { - this.log.error( - "[%s] could not be updated as it appears to be offline.", - accessory.displayName - ); - callback("Device has failed to update"); + this.lanClient + .sendUpdate(payload) + .then(() => resolve()) + .catch(err => { + if (this.debug) { + this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); + } + sendViaWS(); + }); } - }; - if (cns.devicesNonLAN.includes(accessory.context.eweUIID) || !accessory.context.reachableLAN) { - sendViaWS(); - } else { - this.lanClient - .sendUpdate(payload) - .then(() => callback()) - .catch(err => { - if (this.debug) { - this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); - } - sendViaWS(); - }); - } + }); } receiveDeviceUpdate(device) { let accessory, @@ -1149,29 +1141,10 @@ class eWeLink { } } internalValveUpdate(accessory, valve, value, callback) { + callback(); try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } let params = {}, serviceValve = accessory.getService(valve); - serviceValve - .updateCharacteristic(Characteristic.Active, value) - .updateCharacteristic(Characteristic.InUse, value); - switch (value) { - case 0: - serviceValve.updateCharacteristic(Characteristic.RemainingDuration, 0); - clearTimeout(accessory.getService(valve).timer); - break; - case 1: - let timer = serviceValve.getCharacteristic(Characteristic.SetDuration).value; - serviceValve.updateCharacteristic(Characteristic.RemainingDuration, timer); - serviceValve.timer = setTimeout( - () => serviceValve.setCharacteristic(Characteristic.Active, 0), - timer * 1000 - ); - break; - } params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; switch (valve) { case "Valve A": @@ -1190,80 +1163,103 @@ class eWeLink { : "off"; params.switches[1].switch = value ? "on" : "off"; break; - default: - throw "unknown valve [" + valve + "]"; } params.switches[2].switch = "off"; params.switches[3].switch = "off"; - this.sendDeviceUpdate(accessory, params, callback); + //2. send the request + //3a. update the accessory if (2) is resolved + //3b. revert the device status if (2) is rejected with a requestDeviceStatus. + this.sendDeviceUpdate(accessory, params) + .then(() => { + serviceValve + .updateCharacteristic(Characteristic.Active, value) + .updateCharacteristic(Characteristic.InUse, value); + switch (value) { + case 0: + serviceValve.updateCharacteristic(Characteristic.RemainingDuration, 0); + clearTimeout(accessory.getService(valve).timer); + break; + case 1: + let timer = serviceValve.getCharacteristic(Characteristic.SetDuration).value; + serviceValve.updateCharacteristic(Characteristic.RemainingDuration, timer); + serviceValve.timer = setTimeout( + () => serviceValve.setCharacteristic(Characteristic.Active, 0), + timer * 1000 + ); + break; + } + }) + .catch(err => { + throw err; + }); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory).catch(() => {}); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName + ); + } } } internalBlindUpdate(accessory, value, callback) { + callback(); try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } - let blindConfig; + let blindConfig, + params = {}, + wcService = accessory.getService(Service.WindowCovering), + oldPos = wcService.getCharacteristic(Characteristic.PositionState).value; if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } if (blindConfig.type !== "blind" || blindConfig.setup !== "twoSwitch") { throw "improper configuration"; } - - let oldPos, - params = {}, - wcService = accessory.getService(Service.WindowCovering); value = value >= 50 ? 100 : 0; - oldPos = wcService.getCharacteristic(Characteristic.PositionState).value; - if (value === oldPos * 100) { - wcService - .updateCharacteristic(Characteristic.TargetPosition, value) - .updateCharacteristic(Characteristic.PositionState, oldPos); - callback(); - return; - } - + if (value === oldPos * 100) return; // target position -> 0 for closed 100 for open (value) // current position -> 0 going down, 1 going up - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; params.switches[0].switch = value === 100 ? "on" : "off"; params.switches[1].switch = value === 0 ? "on" : "off"; - - this.sendDeviceUpdate(accessory, params, function () { - return; - }); - wcService - .updateCharacteristic(Characteristic.TargetPosition, value) - .updateCharacteristic(Characteristic.PositionState, value / 100); - setTimeout(() => { - wcService - .updateCharacteristic(Characteristic.CurrentPosition, value) - .updateCharacteristic(Characteristic.PositionState, 2); - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = "off"; - params.switches[1].switch = "off"; - this.sendDeviceUpdate(accessory, params, function () { - return; + this.sendDeviceUpdate(accessory, params) + .then(() => { + wcService + .updateCharacteristic(Characteristic.TargetPosition, value) + .updateCharacteristic(Characteristic.PositionState, value / 100); + return new Promise(resolve => + setTimeout(resolve, parseInt(blindConfig.operationTime) * 100) + ); + }) + .then(() => { + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = "off"; + params.switches[1].switch = "off"; + return this.sendDeviceUpdate(accessory, params); + }) + .then(() => { + wcService + .updateCharacteristic(Characteristic.CurrentPosition, value) + .updateCharacteristic(Characteristic.PositionState, 2); + }) + .catch(err => { + throw err; }); - }, parseInt(blindConfig.operationTime) * 100); - callback(); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory).catch(() => {}); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName + ); + } } } internalGarageUpdate(accessory, value, callback) { + callback(); try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } let garageConfig; if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; @@ -1274,8 +1270,6 @@ class eWeLink { ) { throw "improper configuration"; } - accessory.context.inUse = true; - accessory.context.state = value; let sensorDefinition = garageConfig.sensorId || false, sAccessory = false, oldPos, @@ -1296,17 +1290,17 @@ class eWeLink { ? 1 : 0 : gdService.getCharacteristic(Characteristic.CurrentDoorState).value; - if (newPos === oldPos % 2) { - accessory.context.inUse = false; - callback(); - return; - } + if (newPos === oldPos % 2) return; + accessory.context.inUse = true; + accessory.context.state = value; if (garageConfig.setup === "oneSwitch" && [2, 3].includes(oldPos)) { gdService.updateCharacteristic(Characteristic.CurrentDoorState, ((oldPos * 2) % 3) + 2); delay = 1500; } - setTimeout(() => { - if (accessory.context.state === newPos) { + if (accessory.context.state !== newPos) return; + let delayPromise = new Promise(resolve => setTimeout(resolve, delay)); + delayPromise + .then(() => { gdService .updateCharacteristic(Characteristic.TargetDoorState, newPos) .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2); @@ -1320,32 +1314,41 @@ class eWeLink { params.switches[1].switch = newPos === 1 ? "on" : "off"; break; } - this.sendDeviceUpdate(accessory, params, function () { - return; - }); - setTimeout(() => { - if (!sAccessory) { - gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos); - } - accessory.context.inUse = false; - }, parseInt(garageConfig.operationTime) * 100); - } - }, delay); - callback(); + return this.sendDeviceUpdate(accessory, params); + }) + .then(() => { + return new Promise(resolve => + setTimeout(resolve, parseInt(garageConfig.operationTime) * 100) + ); + }) + .then(() => { + if (!sAccessory) { + gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos); + } + accessory.context.inUse = false; + }) + .catch(err => { + throw err; + }); } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); accessory.context.inUse = false; - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory).catch(() => {}); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName + ); + } } } internalLockUpdate(accessory, value, callback) { + callback(); try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } let lockConfig, - params = {}, + params = { + switch: "on", + }, lmService = accessory.getService(Service.LockMechanism); if (!(lockConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; @@ -1354,64 +1357,79 @@ class eWeLink { throw "improper configuration"; } accessory.context.inUse = true; - this.log("[%s] has received request to unlock.", accessory.displayName); - lmService - .updateCharacteristic(Characteristic.LockTargetState, 0) - .updateCharacteristic(Characteristic.LockCurrentState, 0); - params.switch = "on"; - this.sendDeviceUpdate(accessory, params, callback); - setTimeout(() => { - lmService - .updateCharacteristic(Characteristic.LockTargetState, 1) - .updateCharacteristic(Characteristic.LockCurrentState, 1); - accessory.context.inUse = false; - }, parseInt(lockConfig.operationTime) * 100); + this.sendDeviceUpdate(accessory, params) + .then(() => { + lmService + .updateCharacteristic(Characteristic.LockTargetState, 0) + .updateCharacteristic(Characteristic.LockCurrentState, 0); + setTimeout(() => { + lmService + .updateCharacteristic(Characteristic.LockTargetState, 1) + .updateCharacteristic(Characteristic.LockCurrentState, 1); + accessory.context.inUse = false; + }, parseInt(lockConfig.operationTime) * 100); + }) + .catch(err => { + throw err; + }); } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); accessory.context.inUse = false; - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory).catch(() => {}); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName + ); + } } } internalCurtainUpdate(accessory, value, callback) { + callback(); try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } let params, cService = accessory.getService(Service.WindowCovering), prevPos = accessory.context.prevPos; - - if (value === prevPos) { - //nothing to do as no change - callback(); - return; - } + if (value === prevPos) return; if (value === 0 || value === 100) { // so to fully open, our $value will be 100, we send switch: "on" // to fully shut, our $value will be 0, we send switch: "off" - params = { switch: value === 100 ? "on" : "off" }; + params = { + switch: value === 100 ? "on" : "off", + }; } else { // for a % midway, scale the $value >--< 100 and setclose: newVal AS INT - params = { setclose: Math.abs(100 - value) }; + params = { + setclose: Math.abs(100 - value), + }; } - cService - .updateCharacteristic(Characteristic.TargetPosition, value) - .updateCharacteristic(Characteristic.PositionState, value > prevPos ? 1 : 0); - // TargetPosition -> 0 for closed 100 for open (value) - // CurrentPosition -> 0 for closed 100 for open - // PositionState -> 0 going down, 1 going up, 2 = stopped - - this.sendDeviceUpdate(accessory, params, callback); + this.sendDeviceUpdate(accessory, params) + .then(() => { + cService + .updateCharacteristic(Characteristic.TargetPosition, value) + .updateCharacteristic(Characteristic.PositionState, value > prevPos ? 1 : 0); + // TargetPosition -> 0 for closed 100 for open (value) + // CurrentPosition -> 0 for closed 100 for open + // PositionState -> 0 going down, 1 going up, 2 = stopped + accessory.context.prevPos = value; + }) + .catch(err => { + throw err; + }); } catch (err) { - callback("[" + accessory.displayName + "] " + err + "."); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory).catch(() => {}); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName + ); + } } } internalFanUpdate(accessory, type, value, callback) { + callback(); try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } let newPower, newSpeed, newLight, @@ -1434,10 +1452,6 @@ class eWeLink { newLight = value; break; } - lightService.updateCharacteristic(Characteristic.On, newLight); - fanService - .updateCharacteristic(Characteristic.Active, newPower) - .updateCharacteristic(Characteristic.RotationSpeed, newSpeed); let params = { switches: this.devicesInEW.get(accessory.context.eweDeviceId).params.switches, }; @@ -1445,105 +1459,133 @@ class eWeLink { params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? "on" : "off"; params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? "on" : "off"; params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? "on" : "off"; - if (this.debug) { - this.log.warn("Fan Update - setting " + type + " to " + value); - this.log( - "[%s] new stats: power [%s], speed [%s%], light [%s].", - accessory.displayName, - newPower, - newSpeed, - newLight + this.sendDeviceUpdate(accessory, params) + .then(() => { + lightService.updateCharacteristic(Characteristic.On, newLight); + fanService + .updateCharacteristic(Characteristic.Active, newPower) + .updateCharacteristic(Characteristic.RotationSpeed, newSpeed); + }) + .catch(err => { + throw err; + }); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory).catch(() => {}); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName ); } - this.sendDeviceUpdate(accessory, params, callback); - } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); } } internalThermostatUpdate(accessory, value, callback) { + callback(); try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } let params = { switch: value ? "on" : "off", mainSwitch: value ? "on" : "off", }, switchService = accessory.getService(Service.Switch); - if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - switchService.updateCharacteristic(Characteristic.On, value); - this.sendDeviceUpdate(accessory, params, callback); + this.sendDeviceUpdate(accessory, params) + .then(() => { + switchService.updateCharacteristic(Characteristic.On, value); + }) + .catch(err => { + throw err; + }); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory).catch(() => {}); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName + ); + } } } internalOutletUpdate(accessory, value, callback) { + callback(); try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } let params = { switch: value ? "on" : "off", }, outletService = accessory.getService(Service.Outlet); - if (this.debug) { - this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - outletService.updateCharacteristic(Characteristic.On, value); - this.sendDeviceUpdate(accessory, params, callback); + this.sendDeviceUpdate(accessory, params) + .then(() => { + outletService.updateCharacteristic(Characteristic.On, value); + }) + .catch(err => { + throw err; + }); } catch (err) { - callback("[" + accessory.displayName + "] " + err + "."); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory).catch(() => {}); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName + ); + } } } internalUSBUpdate(accessory, value, callback) { + callback(); try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } let params = { switches: this.devicesInEW.get(accessory.context.eweDeviceId).params.switches, }, outletService = accessory.getService(Service.Outlet); params.switches[0].switch = value ? "on" : "off"; - if (this.debug) { - this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - outletService.updateCharacteristic(Characteristic.On, value); - this.sendDeviceUpdate(accessory, params, callback); + this.sendDeviceUpdate(accessory, params) + .then(() => { + outletService.updateCharacteristic(Characteristic.On, value); + }) + .catch(err => { + throw err; + }); } catch (err) { - callback("[" + accessory.displayName + "] " + err + "."); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory).catch(() => {}); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName + ); + } } } internalSCMUpdate(accessory, value, callback) { + callback(); try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } let params = { switches: this.devicesInEW.get(accessory.context.eweDeviceId).params.switches, }, switchService = accessory.getService(Service.Switch); params.switches[0].switch = value ? "on" : "off"; - if (this.debug) { - this.log("[%s] requesting to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - switchService.updateCharacteristic(Characteristic.On, value); - this.sendDeviceUpdate(accessory, params, callback); + this.sendDeviceUpdate(accessory, params) + .then(() => { + switchService.updateCharacteristic(Characteristic.On, value); + }) + .catch(err => { + throw err; + }); } catch (err) { - callback("[" + accessory.displayName + "] " + err + "."); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory).catch(() => {}); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName + ); + } } } internalLightbulbUpdate(accessory, value, callback) { + callback(); try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } let oAccessory, params = {}, lightService = accessory.getService(Service.Lightbulb); @@ -1555,10 +1597,6 @@ class eWeLink { } else { params.switch = value ? "on" : "off"; } - if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - lightService.updateCharacteristic(Characteristic.On, value); break; case "0": params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; @@ -1566,79 +1604,88 @@ class eWeLink { params.switches[1].switch = value ? "on" : "off"; params.switches[2].switch = value ? "on" : "off"; params.switches[3].switch = value ? "on" : "off"; - if (this.debug) { - this.log( - "[%s] updating to turn group [%s].", - accessory.displayName, - value ? "on" : "off" - ); - } - lightService.updateCharacteristic(Characteristic.On, value); - for (let i = 1; i <= 4; i++) { - if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); - oAccessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, value); - } - } break; case "1": case "2": case "3": case "4": - if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - lightService.updateCharacteristic(Characteristic.On, value); - let tAccessory, - masterState = "off"; params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; for (let i = 1; i <= 4; i++) { - if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { i === parseInt(accessory.context.switchNumber) ? (params.switches[i - 1].switch = value ? "on" : "off") - : (params.switches[i - 1].switch = tAccessory + : (params.switches[i - 1].switch = oAccessory .getService(Service.Lightbulb) .getCharacteristic(Characteristic.On).value ? "on" : "off"); - if ( - tAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value - ) { - masterState = "on"; - } } else { params.switches[i - 1].switch = "off"; } } - if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - oAccessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, masterState === "on"); - } break; - default: - throw "unknown switch number [" + accessory.context.switchNumber + "]"; } - this.sendDeviceUpdate(accessory, params, callback); + this.sendDeviceUpdate(accessory, params) + .then(() => { + switch (accessory.context.switchNumber) { + case "X": + lightService.updateCharacteristic(Characteristic.On, value); + break; + case "0": + for (let i = 0; i <= 4; i++) { + if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + oAccessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, value); + } + } + break; + case "1": + case "2": + case "3": + case "4": + lightService.updateCharacteristic(Characteristic.On, value); + let masterState = "off"; + for (let i = 1; i <= 4; i++) { + if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + if ( + oAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) + .value + ) { + masterState = "on"; + } + } + } + if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); + oAccessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, masterState === "on"); + } + break; + } + }) + .catch(err => { + throw err; + }); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory).catch(() => {}); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName + ); + } } } internalBrightnessUpdate(accessory, value, callback) { + callback(); try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } let params = {}, lightService = accessory.getService(Service.Lightbulb); if (value === 0) { params.switch = "off"; - lightService.updateCharacteristic(Characteristic.On, false); } else { if (!lightService.getCharacteristic(Characteristic.On).value) { params.switch = "on"; @@ -1651,22 +1698,34 @@ class eWeLink { params.brightness = value; params.mode = 0; break; - default: - throw "unknown device UIID"; } - lightService.updateCharacteristic(Characteristic.Brightness, value); } - if (this.debug) { - this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); - } - setTimeout(() => this.sendDeviceUpdate(accessory, params, callback), 250); + setTimeout(() => { + this.sendDeviceUpdate(accessory, params) + .then(() => { + if (value === 0) { + lightService.updateCharacteristic(Characteristic.On, false); + } else { + lightService.updateCharacteristic(Characteristic.Brightness, value); + } + }) + .catch(err => { + throw err; + }); + }, 250); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory).catch(() => {}); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName + ); + } } } internalHSBUpdate(accessory, type, value, callback) { + callback(); try { if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { throw "it is currently offline"; @@ -1699,13 +1758,7 @@ class eWeLink { colorB: newRGB[2], }; break; - default: - throw "unknown device UIID"; - } - if (this.debug) { - this.log("[%s] updating hue to [%s°].", accessory.displayName, value); } - lightService.updateCharacteristic(Characteristic.Hue, value); break; case "bri": switch (accessory.context.eweUIID) { @@ -1728,36 +1781,44 @@ class eWeLink { }; break; } - if (this.debug) { - this.log("[%s] updating brightness to [%s%].", accessory.displayName, value); - } - lightService.updateCharacteristic(Characteristic.Brightness, value); break; - default: - throw "unknown device UIID"; } - setTimeout(() => this.sendDeviceUpdate(accessory, params, callback), 250); + setTimeout(() => { + this.sendDeviceUpdate(accessory, params) + .then(() => { + switch (type) { + case "hue": + lightService.updateCharacteristic(Characteristic.Hue, value); + break; + case "bri": + lightService.updateCharacteristic(Characteristic.Brightness, value); + break; + } + }) + .catch(err => { + throw err; + }); + }, 250); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory).catch(() => {}); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName + ); + } } } internalSwitchUpdate(accessory, value, callback) { + callback(); try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } let oAccessory, params = {}, switchService = accessory.getService(Service.Switch); switch (accessory.context.switchNumber) { case "X": params.switch = value ? "on" : "off"; - if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - switchService.updateCharacteristic(Characteristic.On, value); break; case "0": params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; @@ -1765,92 +1826,105 @@ class eWeLink { params.switches[1].switch = value ? "on" : "off"; params.switches[2].switch = value ? "on" : "off"; params.switches[3].switch = value ? "on" : "off"; - if (this.debug) { - this.log( - "[%s] updating to turn group [%s].", - accessory.displayName, - value ? "on" : "off" - ); - } - switchService.updateCharacteristic(Characteristic.On, value); - for (let i = 1; i <= 4; i++) { - if (this.devicesInHB.has(accessory.context.eweDeviceId + "SW" + i)) { - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i); - oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); - } - } break; case "1": case "2": case "3": case "4": - if (this.debug) { - this.log("[%s] updating to turn [%s].", accessory.displayName, value ? "on" : "off"); - } - switchService.updateCharacteristic(Characteristic.On, value); - let tAccessory, - masterState = "off"; params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; for (let i = 1; i <= 4; i++) { - if ((tAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { i === parseInt(accessory.context.switchNumber) ? (params.switches[i - 1].switch = value ? "on" : "off") - : (params.switches[i - 1].switch = tAccessory + : (params.switches[i - 1].switch = oAccessory .getService(Service.Switch) .getCharacteristic(Characteristic.On).value ? "on" : "off"); - if ( - tAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value - ) { - masterState = "on"; - } } else { params.switches[i - 1].switch = "off"; } } - if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - oAccessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, masterState === "on"); - } break; - default: - throw "unknown switch number [" + accessory.context.switchNumber + "]"; } - this.sendDeviceUpdate(accessory, params, callback); + this.sendDeviceUpdate(accessory, params) + .then(() => { + switch (accessory.context.switchNumber) { + case "X": + switchService.updateCharacteristic(Characteristic.On, value); + break; + case "0": + for (let i = 0; i <= 4; i++) { + if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + oAccessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, value); + } + } + break; + case "1": + case "2": + case "3": + case "4": + switchService.updateCharacteristic(Characteristic.On, value); + let masterState = "off"; + for (let i = 1; i <= 4; i++) { + if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + if ( + oAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value + ) { + masterState = "on"; + } + } + } + if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); + oAccessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, masterState === "on"); + } + break; + } + }) + .catch(err => { + throw err; + }); } catch (err) { - let str = "[" + accessory.displayName + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory).catch(() => {}); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName + ); + } } } internalRFUpdate(accessory, rfChl, service, callback) { + callback(); try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } - rfChl = parseInt(rfChl); let params = { cmd: "transmit", - rfChl, + rfChl: parseInt(rfChl), }, rfService = accessory.getService(service); - if (this.debug) { - this.log( - "[%s %s] mimicking RF button press.", - accessory.displayName, - accessory.context.rfChls[rfChl] + this.sendDeviceUpdate(accessory, params) + .then(() => { + rfService.updateCharacteristic(Characteristic.On, true); + setTimeout(() => rfService.updateCharacteristic(Characteristic.On, false), 3000); + }) + .catch(err => { + throw err; + }); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory).catch(() => {}); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName ); } - rfService.updateCharacteristic(Characteristic.On, true); - this.sendDeviceUpdate(accessory, params, callback); - setTimeout(() => rfService.updateCharacteristic(Characteristic.On, false), 3000); - } catch (err) { - let str = "[" + accessory.displayName + " " + name + "] could not be updated as " + err + "."; - this.log.error(str); - callback(str); } } externalValveUpdate(accessory, params) { @@ -1895,7 +1969,6 @@ class eWeLink { let switchUp = params.switches[0].switch === "on" ? -1 : 0, // matrix of numbers to get switchDown = params.switches[1].switch === "on" ? 0 : 2; // ... the correct HomeKit value newPosition = switchUp + switchDown; - wcService .updateCharacteristic(Characteristic.PositionState, newPosition) .updateCharacteristic(Characteristic.TargetPosition, newPosition * 100); @@ -1990,12 +2063,12 @@ class eWeLink { try { let cService = accessory.getService(Service.WindowCovering); if (params.hasOwnProperty("switch") && params.hasOwnProperty("setclose")) { + let newPos = Math.abs(100 - parseInt(params.setclose)); cService - .updateCharacteristic( - Characteristic.TargetPosition, - Math.abs(100 - parseInt(params.setclose)) - ) + .updateCharacteristic(Characteristic.TargetPosition, newPos) + .updateCharacteristic(Characteristic.CurrentPosition, newPos) .updateCharacteristic(Characteristic.PositionState, 2); + accessory.context.prevPos = Math.abs(100 - parseInt(params.setclose)); return; } } catch (err) { @@ -2148,7 +2221,7 @@ class eWeLink { ); outletService.updateCharacteristic( Characteristic.OutletInUse, - parseFloat(params.power) > 0 + parseFloat(params.power) > (this.config.inUsePowerThreshold || 0) ); let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value; accessory.eveLogger.addEntry({ @@ -2331,7 +2404,6 @@ class eWeLink { ) { //*** RF Button ***\\ // the device needed is SW% corresponding to params.rfChl - this.devicesInHB.forEach(acc => { if ( acc.context.eweDeviceId === accessory.context.eweDeviceId && diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 817bbade..3301c18e 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -54,7 +54,7 @@ module.exports = class eWeLinkHTTP { .then(res => { let body = res.data; if (!body.region) { - throw "Server did not respond with a region.\n" + JSON.stringify(body, null, 2); + reject("Server did not respond with a region.\n" + JSON.stringify(body, null, 2)); } switch (body.region) { case "eu": @@ -66,7 +66,7 @@ module.exports = class eWeLinkHTTP { this.httpHost = "cn-apia.coolkit.cn"; break; default: - throw "No valid region received - [" + body.region + "]."; + reject("No valid region received - [" + body.region + "]."); } if (this.debug) { this.log("HTTP API host received [%s].", this.httpHost); @@ -136,7 +136,7 @@ module.exports = class eWeLinkHTTP { this.httpHost = "cn-apia.coolkit.cn"; break; default: - throw "No valid region received - [" + givenRegion + "]."; + reject("No valid region received - [" + givenRegion + "]."); } if (this.debug) { this.log("New HTTP API host received [%s].", this.httpHost); @@ -145,7 +145,7 @@ module.exports = class eWeLinkHTTP { return; } if (!body.data.at) { - throw "No auth token received.\n" + JSON.stringify(body, null, 2); + reject("No auth token received.\n" + JSON.stringify(body, null, 2)); } this.aToken = body.data.at; this.apiKey = body.data.user.apikey; @@ -177,7 +177,7 @@ module.exports = class eWeLinkHTTP { !body.hasOwnProperty("error") || (body.hasOwnProperty("error") && body.error !== 0) ) { - throw JSON.stringify(body, null, 2); + reject(JSON.stringify(body, null, 2)); } let deviceList = []; if (body.data.thingList && body.data.thingList.length > 0) { @@ -229,12 +229,12 @@ module.exports = class eWeLinkHTTP { !body.hasOwnProperty("error") || (body.hasOwnProperty("error") && body.error !== 0) ) { - throw JSON.stringify(body, null, 2); + reject(JSON.stringify(body, null, 2)); } if (body.data.thingList && body.data.thingList.length === 1) { resolve(body.data.thingList[0].itemData); } else { - throw "device not found in eWeLink"; + reject("device not found in eWeLink"); } }) .catch(err => { diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 3923e97d..da6bfe8d 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -130,7 +130,7 @@ module.exports = class eWeLinkLAN { sendUpdate(json) { return new Promise((resolve, reject) => { if (!this.deviceMap.get(json.deviceid).online) { - throw "device isn't reachable by LAN mode"; + reject("device isn't reachable by LAN mode"); } let apiKey, suffix, @@ -142,7 +142,9 @@ module.exports = class eWeLinkLAN { params.switch = json.params.switch; suffix = "switch"; } else { - throw "plugin does not support lan mode for this device yet - feel free to create a github issue"; + reject( + "plugin does not support lan mode for this device yet - feel free to create a github issue" + ); } if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { let key = crypto.createHash("md5").update(Buffer.from(apiKey, "utf8")).digest(), @@ -180,7 +182,7 @@ module.exports = class eWeLinkLAN { if (res.data.hasOwnProperty("error") && res.data.error === 0) { resolve(); } - throw res.data; + reject(res.data); }) .catch(err => reject(err)); } diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 31192209..e925836c 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -37,7 +37,7 @@ module.exports = class eWeLinkWS { .then(res => { let body = res.data; if (!body.domain) { - throw "Server did not respond with a web socket host."; + reject("Server did not respond with a web socket host."); } if (this.debug) { this.log("Web socket host received [%s].", body.domain); @@ -176,6 +176,7 @@ module.exports = class eWeLinkWS { } }); this.wsp.onClose.addListener((e, m) => { + this.wsIsOpen = false; if (e !== 1005) { this.log.warn("Web socket closed [%s].", e); if (e !== 1000) { @@ -185,7 +186,6 @@ module.exports = class eWeLinkWS { this.log("Please try restarting Homebridge so that this plugin can work again."); } } - this.wsIsOpen = false; if (this.hbInterval) { clearInterval(this.hbInterval); this.hbInterval = null; @@ -238,7 +238,7 @@ module.exports = class eWeLinkWS { break; case 504: default: - throw "Unknown response"; + reject("Unknown response"); } }) .catch(err => reject("Device update failed [" + err + "].")); @@ -301,10 +301,18 @@ module.exports = class eWeLinkWS { this.emitter.addListener("update", f); } closeConnection() { - if (this.wsp && this.wsIsOpen) { - this.wsp.close(); - this.log("Web socket gracefully closed."); - } + return new Promise((resolve, reject) => { + if (this.wsp && this.wsIsOpen) { + this.wsp + .close() + .then(() => { + this.log("Web socket gracefully closed."); + resolve(); + }) + .catch(err => reject(err)); + } + resolve(); + }); } delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); From 0ddfa292fc874167325e09e7990c830e21de9af9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 22 Sep 2020 16:14:03 +0100 Subject: [PATCH 0189/3183] 3.0.0-4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index d5c2bc87..2760225f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.0-3", + "version": "3.0.0-4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a442dbb2..a08b6aa2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.0-3", + "version": "3.0.0-4", "author": "bwp91", "contributors": [ "gbro115", From 906c2a55ee5d87c7a5f2223c273885ae0152e3a7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 22 Sep 2020 16:56:02 +0100 Subject: [PATCH 0190/3183] next --- lib/eWeLink.js | 5 +---- lib/eWeLinkHTTP.js | 14 +++++++------- lib/eWeLinkWS.js | 4 ++-- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index acd6c6a7..b779d1e3 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -548,10 +548,7 @@ class eWeLink { } cService .getCharacteristic(Characteristic.TargetPosition) - .on("set", (value, callback) => this.internalCurtainUpdate(accessory, value, callback)) - .setProps({ - minStep: 100, - }); + .on("set", (value, callback) => this.internalCurtainUpdate(accessory, value, callback)); break; case "garage": let gdService; diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 3301c18e..817bbade 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -54,7 +54,7 @@ module.exports = class eWeLinkHTTP { .then(res => { let body = res.data; if (!body.region) { - reject("Server did not respond with a region.\n" + JSON.stringify(body, null, 2)); + throw "Server did not respond with a region.\n" + JSON.stringify(body, null, 2); } switch (body.region) { case "eu": @@ -66,7 +66,7 @@ module.exports = class eWeLinkHTTP { this.httpHost = "cn-apia.coolkit.cn"; break; default: - reject("No valid region received - [" + body.region + "]."); + throw "No valid region received - [" + body.region + "]."; } if (this.debug) { this.log("HTTP API host received [%s].", this.httpHost); @@ -136,7 +136,7 @@ module.exports = class eWeLinkHTTP { this.httpHost = "cn-apia.coolkit.cn"; break; default: - reject("No valid region received - [" + givenRegion + "]."); + throw "No valid region received - [" + givenRegion + "]."; } if (this.debug) { this.log("New HTTP API host received [%s].", this.httpHost); @@ -145,7 +145,7 @@ module.exports = class eWeLinkHTTP { return; } if (!body.data.at) { - reject("No auth token received.\n" + JSON.stringify(body, null, 2)); + throw "No auth token received.\n" + JSON.stringify(body, null, 2); } this.aToken = body.data.at; this.apiKey = body.data.user.apikey; @@ -177,7 +177,7 @@ module.exports = class eWeLinkHTTP { !body.hasOwnProperty("error") || (body.hasOwnProperty("error") && body.error !== 0) ) { - reject(JSON.stringify(body, null, 2)); + throw JSON.stringify(body, null, 2); } let deviceList = []; if (body.data.thingList && body.data.thingList.length > 0) { @@ -229,12 +229,12 @@ module.exports = class eWeLinkHTTP { !body.hasOwnProperty("error") || (body.hasOwnProperty("error") && body.error !== 0) ) { - reject(JSON.stringify(body, null, 2)); + throw JSON.stringify(body, null, 2); } if (body.data.thingList && body.data.thingList.length === 1) { resolve(body.data.thingList[0].itemData); } else { - reject("device not found in eWeLink"); + throw "device not found in eWeLink"; } }) .catch(err => { diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index e925836c..e99df8fd 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -37,7 +37,7 @@ module.exports = class eWeLinkWS { .then(res => { let body = res.data; if (!body.domain) { - reject("Server did not respond with a web socket host."); + throw "Server did not respond with a web socket host."; } if (this.debug) { this.log("Web socket host received [%s].", body.domain); @@ -238,7 +238,7 @@ module.exports = class eWeLinkWS { break; case 504: default: - reject("Unknown response"); + throw "Unknown response"; } }) .catch(err => reject("Device update failed [" + err + "].")); From de2bc9fe077ab87fe1e6fb1d0e2390a024731a65 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 22 Sep 2020 16:56:45 +0100 Subject: [PATCH 0191/3183] 3.0.0-5 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2760225f..e096c48a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.0-4", + "version": "3.0.0-5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a08b6aa2..38bcdaab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.0-4", + "version": "3.0.0-5", "author": "bwp91", "contributors": [ "gbro115", From e807c07d1786f4b149ea58d3feb4bbee03102e38 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 22 Sep 2020 22:23:23 +0100 Subject: [PATCH 0192/3183] 3.0 new settings --- config.schema.json | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/config.schema.json b/config.schema.json index f44541f9..f1e23146 100644 --- a/config.schema.json +++ b/config.schema.json @@ -55,9 +55,15 @@ "hideFromHB": { "type": "string", "title": "Hide Device Channels", - "description": "A list of device channels to hide from Homebridge. For example '10009553c8SW1' or multiple channels separated with a comma '10009553c8SW1,10009553c9SW2'. Only channels from switches, lights and irrigation valves can be hidden.", + "description": "A list of SW1, SW2, SW3 and SW4 to hide from Homebridge. For example '10009553c8SW1' or multiple channels separated with a comma '10009553c8SW1,10009553c9SW2'. Only channels from switches and lights can be hidden. This setting cannot be used to hide master devices (SW0).", "default": "" }, + "disableHTTPRefresh": { + "type": "boolean", + "title": "Disable Initial Device Refresh", + "description": "If enabled, devices will not be refreshed with their most recent status from eWeLink when Homebridge starts. This setting can be useful for users who block their devices from accessing the internet.", + "default": false + }, "lowBattThreshold": { "type": "integer", "title": "Low Battery Threshold", @@ -90,14 +96,22 @@ "minimum": 10, "maximum": 1800 }, + "inUsePowerThreshold": { + "type": "integer", + "title": "Outlet 'In Use' Threshold", + "description": "Homebridge will set the 'In Use' status of outlet devices to true when the wattage is above this number.", + "default": 0, + "minimum": 0, + "maximum": 100 + }, "hideTHSwitch": { - "title": "Hide TH10/TH16 Switch", + "title": "TH10/TH16 Hide Switch", "type": "boolean", "description": "If enabled, the switch for the TH10/TH16 devices will be hidden from Homebridge.", "default": false }, "hideZBLDPress": { - "title": "Hide Double/Long Press", + "title": "Zigbee Button Hide Double/Long Press", "type": "boolean", "description": "If enabled, double and long press options will be hidden for the ZigBee button.", "default": false @@ -228,12 +242,14 @@ "layout": [ { "type": "fieldset", + "title": "Required Settings", + "description": "These are the basic settings that are required for this plugin to work.", "items": ["countryCode", "username", "password"] }, { "type": "fieldset", - "title": "Optional", - "description": "Only adjust these settings if you know what you are doing.", + "title": "Optional Settings (General)", + "description": "A variety of optional settings for general use of this plugin.", "expandable": true, "items": [ "debug", @@ -241,7 +257,17 @@ "hideDevFromHB", "hideMasters", "hideFromHB", + "disableHTTPRefresh" + ] + }, + { + "type": "fieldset", + "title": "Optional Settings (Device Specific)", + "description": "A variety of optional settings for specific device types.", + "expandable": true, + "items": [ "lowBattThreshold", + "inUsePowerThreshold", "sensorTimeLength", "sensorTimeDifference", "valveTimeLength", From 5799bc1af6bc7469d93954b618a6850368b63625 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 22 Sep 2020 22:41:09 +0100 Subject: [PATCH 0193/3183] Update eWeLinkHTTP.js --- lib/eWeLinkHTTP.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 817bbade..beb48f3b 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -198,7 +198,6 @@ module.exports = class eWeLinkHTTP { }); }); } - getDevice(deviceId) { return new Promise((resolve, reject) => { axios From 79ab91a2ec32d58ff3417777640cb977d231c571 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 22 Sep 2020 22:41:38 +0100 Subject: [PATCH 0194/3183] add device to lan map --- lib/eWeLink.js | 11 ++++++++--- lib/eWeLinkLAN.js | 9 +++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index b779d1e3..c355fc74 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -403,7 +403,9 @@ class eWeLink { .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); } accessory.context.reachableWAN = device.online; - accessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; + accessory.context.reachableLAN = this.lanDevices.has(device.deviceid) + ? this.lanDevices.get(device.deviceid).online + : false; accessory.context.inUse = false; let str = accessory.context.reachableLAN ? "and found locally with IP [" + this.lanDevices.get(device.deviceid).ip + "]" @@ -1132,7 +1134,10 @@ class eWeLink { ); this.httpClient .getDevice(deviceId) - .then(res => this.initialiseDevice(res)) + .then(device => { + this.initialiseDevice(device); + this.lanClient.addDeviceToMap(device); + }) .catch(err => this.log.error("[%s] error getting info [%s]", deviceId, err)); } } @@ -2550,7 +2555,7 @@ class eWeLink { Characteristic.MotionDetected, params.hasOwnProperty("updateSource") && params.motion === 1 && - diff < (this.config.sensortimeDifference || 120) + diff < (this.config.sensorTimeDifference || 120) ); break; } diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index da6bfe8d..6958c166 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -191,6 +191,15 @@ module.exports = class eWeLinkLAN { receiveUpdate(f) { this.emitter.addListener("update", f); } + addDeviceToMap(device) { + this.deviceMap.set(device.deviceid, { + apiKey: device.devicekey, + online: this.ipOverrides.hasOwnProperty(device.deviceid) ? true : false, + ip: this.ipOverrides.hasOwnProperty(device.deviceid) + ? this.ipOverrides[device.deviceid] + : null, + }); + } closeConnection() { dns.stopMonitoring(); this.log("LAN monitoring gracefully stopped."); From e47c72478813e2a6479bc20e6f03b059f9d463a5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 22 Sep 2020 22:50:50 +0100 Subject: [PATCH 0195/3183] format blind service --- lib/eWeLink.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index c355fc74..c9e4b958 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -533,10 +533,7 @@ class eWeLink { } wcService .getCharacteristic(Characteristic.TargetPosition) - .on("set", (value, callback) => this.internalBlindUpdate(accessory, value, callback)) - .setProps({ - minStep: 100, - }); + .on("set", (value, callback) => this.internalBlindUpdate(accessory, value, callback)); break; case "curtain": let cService; @@ -1168,9 +1165,6 @@ class eWeLink { } params.switches[2].switch = "off"; params.switches[3].switch = "off"; - //2. send the request - //3a. update the accessory if (2) is resolved - //3b. revert the device status if (2) is rejected with a requestDeviceStatus. this.sendDeviceUpdate(accessory, params) .then(() => { serviceValve From 7408bff113cf22ec69677d4bac794034cfa4f911 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 22 Sep 2020 22:56:36 +0100 Subject: [PATCH 0196/3183] code formatting --- lib/eWeLinkWS.js | 321 +---------------------------------------------- 1 file changed, 1 insertion(+), 320 deletions(-) diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index e99df8fd..8bca24bb 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -1,320 +1 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -const axios = require("axios"), - cns = require("./constants"), - eventemitter = require("events"), - ws = require("ws"), - wsp = require("websocket-as-promised"); -module.exports = class eWeLinkWS { - constructor(config, log, res) { - this.config = config; - this.log = log; - this.debug = this.config.debug || false; - this.debugReqRes = this.config.debugReqRes || false; - this.httpHost = res.httpHost; - this.aToken = res.aToken; - this.apiKey = res.apiKey; - this.wsIsOpen = false; - this.emitter = new eventemitter(); - this.delaySend = 0; - } - getHost() { - return new Promise((resolve, reject) => { - axios({ - method: "post", - url: "https://" + this.httpHost.replace("-api", "-disp") + "/dispatch/app", - headers: { - Authorization: "Bearer " + this.aToken, - "Content-Type": "application/json", - }, - data: { - appid: cns.appId, - nonce: Math.random().toString(36).substr(2, 8), - ts: Math.floor(new Date().getTime() / 1000), - version: 8, - }, - }) - .then(res => { - let body = res.data; - if (!body.domain) { - throw "Server did not respond with a web socket host."; - } - if (this.debug) { - this.log("Web socket host received [%s].", body.domain); - } - this.wsHost = body.domain; - resolve(body.domain); - }) - .catch(err => { - if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { - this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); - this.delay().then(() => resolve(this.getDevices())); - } else { - reject(err.message || err); - } - }); - }); - } - login() { - this.wsp = new wsp("wss://" + this.wsHost + ":8080/api/ws", { - createWebSocket: url => new ws(url), - extractMessageData: event => event, - attachRequestId: (data, requestId) => - Object.assign( - { - sequence: requestId, - }, - data - ), - extractRequestId: data => data && data.sequence, - packMessage: data => JSON.stringify(data), - unpackMessage: data => { - return data === "pong" ? data : JSON.parse(data); - }, - }); - this.wsp.open(); - this.wsp.onOpen.addListener(() => { - this.wsIsOpen = true; - let sequence = Math.floor(new Date()).toString(), - payload = { - action: "userOnline", - apikey: this.apiKey, - appid: cns.appId, - at: this.aToken, - nonce: Math.random().toString(36).substr(2, 8), - sequence, - ts: Math.floor(new Date() / 1000), - userAgent: "app", - version: 8, - }; - if (this.debugReqRes) { - let msg = JSON.stringify(payload, null, 2) - .replace(this.aToken, "**hidden**") - .replace(this.apiKey, "**hidden**"); - this.log.warn("Sending WS login request. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("Sending WS login request."); - } - this.wsp - .sendRequest(payload, { - requestId: sequence, - }) - .then(res => { - if ( - res.hasOwnProperty("config") && - res.config.hb && - res.config.hbInterval && - !this.hbInterval - ) { - this.hbInterval = setInterval(() => { - this.wsp.send("ping"); - }, (res.config.hbInterval + 7) * 1000); - } else { - throw "Unknown parameters received"; - } - }) - .catch(err => { - this.log.error("WS login failed [%s].", err); - }); - }); - this.wsp.onUnpackedMessage.addListener(device => { - if (device === "pong") return; - let onlineStatus = true; - if (!device.hasOwnProperty("params")) device.params = {}; - if (device.hasOwnProperty("deviceid") && device.hasOwnProperty("error")) { - device.action = "update"; - onlineStatus = device.error === 0; - } - if (device.hasOwnProperty("action")) { - switch (device.action) { - case "update": - case "sysmsg": - if (device.action === "sysmsg" && device.params.hasOwnProperty("online")) { - onlineStatus = device.params.online; - } - for (let param in device.params) { - if (device.params.hasOwnProperty(param)) { - if (!cns.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { - delete device.params[param]; - } - } - } - device.params.online = onlineStatus; - device.params.updateSource = "WS"; - if (Object.keys(device.params).length > 0) { - let returnTemplate = { - deviceid: device.deviceid, - params: device.params, - }; - if (this.debugReqRes) { - let msg = JSON.stringify(returnTemplate, null, 2).replace( - device.deviceid, - "**hidden**" - ); - this.log("WS message received.\n%s", msg); - } else if (this.debug) { - this.log("WS message received."); - } - this.emitter.emit("update", returnTemplate); - } - break; - case "reportSubDevice": - return; - default: - this.log.warn( - "[%s] WS message has unknown action.\n" + JSON.stringify(device, null, 2), - device.deviceid - ); - return; - } - } else if (device.hasOwnProperty("error") && device.error === 0) { - // *** Safe to ignore these messages *** \\ - } else { - if (this.debug) { - this.log.warn("WS unknown command received.\n" + JSON.stringify(device, null, 2)); - } - } - }); - this.wsp.onClose.addListener((e, m) => { - this.wsIsOpen = false; - if (e !== 1005) { - this.log.warn("Web socket closed [%s].", e); - if (e !== 1000) { - this.log("Web socket will try to reconnect in five seconds."); - setTimeout(() => this.login(), 5000); - } else { - this.log("Please try restarting Homebridge so that this plugin can work again."); - } - } - if (this.hbInterval) { - clearInterval(this.hbInterval); - this.hbInterval = null; - } - this.wsp.removeAllListeners(); - }); - this.wsp.onError.addListener(e => { - this.log.error("Web socket error - [%s].", e); - if (e.code === "ECONNREFUSED") { - this.log.warn( - "Web socket will try to reconnect in five seconds then try the command again." - ); - this.wsp.removeAllListeners(); - setTimeout(() => this.login(), 5000); - } else { - this.log.warn("If this was unexpected then please try restarting Homebridge."); - } - }); - } - sendUpdate(json) { - return new Promise((resolve, reject) => { - let sequence = Math.floor(new Date()).toString(); - json = { - ...json, - ...{ - action: "update", - sequence, - userAgent: "app", - }, - }; - let sendOperation = () => { - this.wsp - .sendRequest(json, { - requestId: sequence, - }) - .then(device => { - if (this.debugReqRes) { - let msg = JSON.stringify(json, null, 2) - .replace(json.apikey, "**hidden**") - .replace(json.apiKey, "**hidden**") - .replace(json.deviceid, "**hidden**"); - this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("WS message sent."); - } - device.error = device.hasOwnProperty("error") ? device.error : 504; // mimic ewelink device offline - switch (device.error) { - case 0: - resolve(); - break; - case 504: - default: - throw "Unknown response"; - } - }) - .catch(err => reject("Device update failed [" + err + "].")); - }; - let checkToSend = () => { - if (this.wsp && this.wsIsOpen) { - sendOperation(); - } else { - this.delay(2500).then(() => { - if (this.debug) { - this.log.warn("Will resend command when WS is reconnected."); - } - checkToSend(); - }); - } - }; - checkToSend(); - }); - } - requestUpdate(accessory) { - return new Promise(resolve => { - let sequence = Math.floor(new Date()).toString(), - json = { - action: "query", - apikey: accessory.context.eweApiKey, - deviceid: accessory.context.eweDeviceId, - params: [], - sequence, - ts: 0, - userAgent: "app", - }, - sendOperation = () => { - this.wsp.send(json); - if (this.debugReqRes) { - let msg = JSON.stringify(json, null, 2) - .replace(json.apikey, "**hidden**") - .replace(json.apiKey, "**hidden**") - .replace(json.deviceid, "**hidden**"); - this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("WS message sent."); - } - }, - checkToSend = () => { - if (this.wsp && this.wsIsOpen) { - sendOperation(); - } else { - this.delay(2500).then(() => { - if (this.debug) { - this.log.warn("Will resend command when WS is reconnected."); - } - checkToSend(); - }); - } - }; - checkToSend(); - }); - } - receiveUpdate(f) { - this.emitter.addListener("update", f); - } - closeConnection() { - return new Promise((resolve, reject) => { - if (this.wsp && this.wsIsOpen) { - this.wsp - .close() - .then(() => { - this.log("Web socket gracefully closed."); - resolve(); - }) - .catch(err => reject(err)); - } - resolve(); - }); - } - delay(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); - } -}; +zb_dev; From 8aec5f067ec5e39859e90be9c38678541daccf99 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 22 Sep 2020 22:57:44 +0100 Subject: [PATCH 0197/3183] 3.0.0-6 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index e096c48a..fbe82755 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.0-5", + "version": "3.0.0-6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 38bcdaab..9d03ce36 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.0-5", + "version": "3.0.0-6", "author": "bwp91", "contributors": [ "gbro115", From 651ec7ad329a337dbfa76c8f0cc431aaf595797d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 23 Sep 2020 09:44:02 +0100 Subject: [PATCH 0198/3183] remove lan count --- lib/eWeLinkLAN.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 6958c166..68aa7eb7 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -31,7 +31,6 @@ module.exports = class eWeLinkLAN { name: "_ewelink._tcp.local", }) .then(res => { - let onlineCount = 0; res.forEach(device => { let d, deviceId = device.fqdn.replace("._ewelink._tcp.local", "").replace("eWeLink_", ""); @@ -43,13 +42,9 @@ module.exports = class eWeLinkLAN { ip: device.address, }); } - onlineCount++; } }); - resolve({ - map: this.deviceMap, - count: onlineCount, - }); + resolve(this.deviceMap); }) .catch(err => reject(err)); }); From 286387f143ceb715e181f4a7969fa78bb7ae72f9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 23 Sep 2020 09:44:12 +0100 Subject: [PATCH 0199/3183] Update eWeLinkWS.js --- lib/eWeLinkWS.js | 321 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 320 insertions(+), 1 deletion(-) diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 8bca24bb..e99df8fd 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -1 +1,320 @@ -zb_dev; +/* jshint esversion: 9, -W014, -W030, node: true */ +"use strict"; +const axios = require("axios"), + cns = require("./constants"), + eventemitter = require("events"), + ws = require("ws"), + wsp = require("websocket-as-promised"); +module.exports = class eWeLinkWS { + constructor(config, log, res) { + this.config = config; + this.log = log; + this.debug = this.config.debug || false; + this.debugReqRes = this.config.debugReqRes || false; + this.httpHost = res.httpHost; + this.aToken = res.aToken; + this.apiKey = res.apiKey; + this.wsIsOpen = false; + this.emitter = new eventemitter(); + this.delaySend = 0; + } + getHost() { + return new Promise((resolve, reject) => { + axios({ + method: "post", + url: "https://" + this.httpHost.replace("-api", "-disp") + "/dispatch/app", + headers: { + Authorization: "Bearer " + this.aToken, + "Content-Type": "application/json", + }, + data: { + appid: cns.appId, + nonce: Math.random().toString(36).substr(2, 8), + ts: Math.floor(new Date().getTime() / 1000), + version: 8, + }, + }) + .then(res => { + let body = res.data; + if (!body.domain) { + throw "Server did not respond with a web socket host."; + } + if (this.debug) { + this.log("Web socket host received [%s].", body.domain); + } + this.wsHost = body.domain; + resolve(body.domain); + }) + .catch(err => { + if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { + this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); + this.delay().then(() => resolve(this.getDevices())); + } else { + reject(err.message || err); + } + }); + }); + } + login() { + this.wsp = new wsp("wss://" + this.wsHost + ":8080/api/ws", { + createWebSocket: url => new ws(url), + extractMessageData: event => event, + attachRequestId: (data, requestId) => + Object.assign( + { + sequence: requestId, + }, + data + ), + extractRequestId: data => data && data.sequence, + packMessage: data => JSON.stringify(data), + unpackMessage: data => { + return data === "pong" ? data : JSON.parse(data); + }, + }); + this.wsp.open(); + this.wsp.onOpen.addListener(() => { + this.wsIsOpen = true; + let sequence = Math.floor(new Date()).toString(), + payload = { + action: "userOnline", + apikey: this.apiKey, + appid: cns.appId, + at: this.aToken, + nonce: Math.random().toString(36).substr(2, 8), + sequence, + ts: Math.floor(new Date() / 1000), + userAgent: "app", + version: 8, + }; + if (this.debugReqRes) { + let msg = JSON.stringify(payload, null, 2) + .replace(this.aToken, "**hidden**") + .replace(this.apiKey, "**hidden**"); + this.log.warn("Sending WS login request. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("Sending WS login request."); + } + this.wsp + .sendRequest(payload, { + requestId: sequence, + }) + .then(res => { + if ( + res.hasOwnProperty("config") && + res.config.hb && + res.config.hbInterval && + !this.hbInterval + ) { + this.hbInterval = setInterval(() => { + this.wsp.send("ping"); + }, (res.config.hbInterval + 7) * 1000); + } else { + throw "Unknown parameters received"; + } + }) + .catch(err => { + this.log.error("WS login failed [%s].", err); + }); + }); + this.wsp.onUnpackedMessage.addListener(device => { + if (device === "pong") return; + let onlineStatus = true; + if (!device.hasOwnProperty("params")) device.params = {}; + if (device.hasOwnProperty("deviceid") && device.hasOwnProperty("error")) { + device.action = "update"; + onlineStatus = device.error === 0; + } + if (device.hasOwnProperty("action")) { + switch (device.action) { + case "update": + case "sysmsg": + if (device.action === "sysmsg" && device.params.hasOwnProperty("online")) { + onlineStatus = device.params.online; + } + for (let param in device.params) { + if (device.params.hasOwnProperty(param)) { + if (!cns.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { + delete device.params[param]; + } + } + } + device.params.online = onlineStatus; + device.params.updateSource = "WS"; + if (Object.keys(device.params).length > 0) { + let returnTemplate = { + deviceid: device.deviceid, + params: device.params, + }; + if (this.debugReqRes) { + let msg = JSON.stringify(returnTemplate, null, 2).replace( + device.deviceid, + "**hidden**" + ); + this.log("WS message received.\n%s", msg); + } else if (this.debug) { + this.log("WS message received."); + } + this.emitter.emit("update", returnTemplate); + } + break; + case "reportSubDevice": + return; + default: + this.log.warn( + "[%s] WS message has unknown action.\n" + JSON.stringify(device, null, 2), + device.deviceid + ); + return; + } + } else if (device.hasOwnProperty("error") && device.error === 0) { + // *** Safe to ignore these messages *** \\ + } else { + if (this.debug) { + this.log.warn("WS unknown command received.\n" + JSON.stringify(device, null, 2)); + } + } + }); + this.wsp.onClose.addListener((e, m) => { + this.wsIsOpen = false; + if (e !== 1005) { + this.log.warn("Web socket closed [%s].", e); + if (e !== 1000) { + this.log("Web socket will try to reconnect in five seconds."); + setTimeout(() => this.login(), 5000); + } else { + this.log("Please try restarting Homebridge so that this plugin can work again."); + } + } + if (this.hbInterval) { + clearInterval(this.hbInterval); + this.hbInterval = null; + } + this.wsp.removeAllListeners(); + }); + this.wsp.onError.addListener(e => { + this.log.error("Web socket error - [%s].", e); + if (e.code === "ECONNREFUSED") { + this.log.warn( + "Web socket will try to reconnect in five seconds then try the command again." + ); + this.wsp.removeAllListeners(); + setTimeout(() => this.login(), 5000); + } else { + this.log.warn("If this was unexpected then please try restarting Homebridge."); + } + }); + } + sendUpdate(json) { + return new Promise((resolve, reject) => { + let sequence = Math.floor(new Date()).toString(); + json = { + ...json, + ...{ + action: "update", + sequence, + userAgent: "app", + }, + }; + let sendOperation = () => { + this.wsp + .sendRequest(json, { + requestId: sequence, + }) + .then(device => { + if (this.debugReqRes) { + let msg = JSON.stringify(json, null, 2) + .replace(json.apikey, "**hidden**") + .replace(json.apiKey, "**hidden**") + .replace(json.deviceid, "**hidden**"); + this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("WS message sent."); + } + device.error = device.hasOwnProperty("error") ? device.error : 504; // mimic ewelink device offline + switch (device.error) { + case 0: + resolve(); + break; + case 504: + default: + throw "Unknown response"; + } + }) + .catch(err => reject("Device update failed [" + err + "].")); + }; + let checkToSend = () => { + if (this.wsp && this.wsIsOpen) { + sendOperation(); + } else { + this.delay(2500).then(() => { + if (this.debug) { + this.log.warn("Will resend command when WS is reconnected."); + } + checkToSend(); + }); + } + }; + checkToSend(); + }); + } + requestUpdate(accessory) { + return new Promise(resolve => { + let sequence = Math.floor(new Date()).toString(), + json = { + action: "query", + apikey: accessory.context.eweApiKey, + deviceid: accessory.context.eweDeviceId, + params: [], + sequence, + ts: 0, + userAgent: "app", + }, + sendOperation = () => { + this.wsp.send(json); + if (this.debugReqRes) { + let msg = JSON.stringify(json, null, 2) + .replace(json.apikey, "**hidden**") + .replace(json.apiKey, "**hidden**") + .replace(json.deviceid, "**hidden**"); + this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("WS message sent."); + } + }, + checkToSend = () => { + if (this.wsp && this.wsIsOpen) { + sendOperation(); + } else { + this.delay(2500).then(() => { + if (this.debug) { + this.log.warn("Will resend command when WS is reconnected."); + } + checkToSend(); + }); + } + }; + checkToSend(); + }); + } + receiveUpdate(f) { + this.emitter.addListener("update", f); + } + closeConnection() { + return new Promise((resolve, reject) => { + if (this.wsp && this.wsIsOpen) { + this.wsp + .close() + .then(() => { + this.log("Web socket gracefully closed."); + resolve(); + }) + .catch(err => reject(err)); + } + resolve(); + }); + } + delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } +}; From 6a011a41f5f8792dd5b72bc91eb34c9eeb0d9619 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 23 Sep 2020 09:44:33 +0100 Subject: [PATCH 0200/3183] reorder functions for ease --- lib/eWeLink.js | 1078 ++++++++++++++++++++++++------------------------ 1 file changed, 539 insertions(+), 539 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index c9e4b958..76fe7030 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -69,8 +69,7 @@ class eWeLink { return this.lanClient.getHosts(); }) .then(res => { - this.lanDevices = res.map; - this.lanCount = res.count; + this.lanDevices = res; return this.lanClient.startMonitor(); }) .then(() => { @@ -91,7 +90,6 @@ class eWeLink { //*** Logging always helps to see if everything is okay so far ***\\ this.log("[%s] eWeLink devices loaded from the Homebridge cache.", this.devicesInHB.size); this.log("[%s] primary devices loaded from your eWeLink account.", this.devicesInEW.size); - this.log("[%s] primary devices were discovered on your local network.", this.lanCount); //*** Remove Homebridge accessories that don't appear in eWeLink ***\\ this.devicesInHB.forEach(a => { if (!this.devicesInEW.has(a.context.eweDeviceId)) { @@ -118,7 +116,6 @@ class eWeLink { } initialiseDevice(device) { let accessory; - //*** First add the device if it isn't already in Homebridge ***\\ //*** IRRIGATION VALVES ***\\ if ( device.extra.uiid === 2 && @@ -129,6 +126,14 @@ class eWeLink { ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "valve"); } + //*** CURTAINS ***\\ + else if (cns.devicesCurtain.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + "SWX") + ? this.devicesInHB.get(device.deviceid + "SWX") + : this.addAccessory(device, device.deviceid + "SWX", "curtain", false, { + prevPos: 0, + }); + } //*** WINDOW BLINDS ***\\ else if ( this.cusG.has(device.deviceid + "SWX") && @@ -142,7 +147,7 @@ class eWeLink { cacheTargetPosition: 0, }); } - //*** GARAGES ***\\ + //*** GARAGE DOORS ***\\ else if ( this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "garage" @@ -160,15 +165,7 @@ class eWeLink { ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "lock"); } - //*** CURTAINS ***\\ - else if (cns.devicesCurtain.includes(device.extra.uiid)) { - accessory = this.devicesInHB.has(device.deviceid + "SWX") - ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "curtain", false, { - prevPos: 0, - }); - } - //*** DW2 SENSORS ***\\ + //*** SENSORS (DW2) ***\\ else if (cns.devicesSensor.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") @@ -393,10 +390,7 @@ class eWeLink { ); return; } - if (!accessory) { - return; - } - //*** Next refresh the device ***\\ + if (!accessory) return; if (!this.hiddenMasters.includes(device.deviceid)) { accessory .getService(Service.AccessoryInformation) @@ -429,6 +423,9 @@ class eWeLink { accessory.context.type, accessory.context.channelCount ); + this.log.warn( + 'If you are unsure how to do this, please see "https://github.com/bwp91/homebridge-ewelink/wiki/How-to-remove-an-accessory-from-the-cache' + ); } } } @@ -521,33 +518,33 @@ class eWeLink { }); }); break; - case "blind": - let wcService; - if (!(wcService = accessory.getService(Service.WindowCovering))) { + case "curtain": + let cService; + if (!(cService = accessory.getService(Service.WindowCovering))) { accessory .addService(Service.WindowCovering) .setCharacteristic(Characteristic.CurrentPosition, 0) .setCharacteristic(Characteristic.TargetPosition, 0) .setCharacteristic(Characteristic.PositionState, 2); - wcService = accessory.getService(Service.WindowCovering); + cService = accessory.getService(Service.WindowCovering); } - wcService + cService .getCharacteristic(Characteristic.TargetPosition) - .on("set", (value, callback) => this.internalBlindUpdate(accessory, value, callback)); + .on("set", (value, callback) => this.internalCurtainUpdate(accessory, value, callback)); break; - case "curtain": - let cService; - if (!(cService = accessory.getService(Service.WindowCovering))) { + case "blind": + let wcService; + if (!(wcService = accessory.getService(Service.WindowCovering))) { accessory .addService(Service.WindowCovering) .setCharacteristic(Characteristic.CurrentPosition, 0) .setCharacteristic(Characteristic.TargetPosition, 0) .setCharacteristic(Characteristic.PositionState, 2); - cService = accessory.getService(Service.WindowCovering); + wcService = accessory.getService(Service.WindowCovering); } - cService + wcService .getCharacteristic(Characteristic.TargetPosition) - .on("set", (value, callback) => this.internalCurtainUpdate(accessory, value, callback)); + .on("set", (value, callback) => this.internalBlindUpdate(accessory, value, callback)); break; case "garage": let gdService; @@ -910,6 +907,11 @@ class eWeLink { this.externalValveUpdate(accessory, newParams); } return true; + case "curtain": + if (Object.keys(newParams).some(v => cns.devicesCurtainParams.includes(v))) { + this.externalCurtainUpdate(accessory, newParams); + } + return true; case "blind": if ( Object.keys(newParams).some(v => cns.devicesBlindParams.includes(v)) && @@ -931,11 +933,6 @@ class eWeLink { this.externalLockUpdate(accessory, newParams); } return true; - case "curtain": - if (Object.keys(newParams).some(v => cns.devicesCurtainParams.includes(v))) { - this.externalCurtainUpdate(accessory, newParams); - } - return true; case "sensor": if (Object.keys(newParams).some(v => cns.devicesSensorParams.includes(v))) { this.externalSensorUpdate(accessory, newParams); @@ -1121,6 +1118,9 @@ class eWeLink { accessory.context.type, accessory.context.channelCount ); + this.log.warn( + 'If you are unsure how to do this, please see "https://github.com/bwp91/homebridge-ewelink/wiki/How-to-remove-an-accessory-from-the-cache' + ); } } else { if (!(this.config.hideDevFromHB || "").includes(deviceId)) { @@ -1135,7 +1135,13 @@ class eWeLink { this.initialiseDevice(device); this.lanClient.addDeviceToMap(device); }) - .catch(err => this.log.error("[%s] error getting info [%s]", deviceId, err)); + .catch(err => { + this.log.error("[%s] error getting info [%s]", deviceId, err); + this.log.error( + "[%s] Please try restarting Homebridge so this device is added.", + deviceId + ); + }); } } } @@ -1199,6 +1205,81 @@ class eWeLink { } } } + externalValveUpdate(accessory, params) { + try { + ["A", "B"].forEach((v, k) => { + let valveService = accessory.getService("Valve " + v); + valveService + .updateCharacteristic(Characteristic.Active, params.switches[k].switch === "on") + .updateCharacteristic(Characteristic.InUse, params.switches[k].switch === "on"); + if (params.switches[k].switch === "on") { + let timer = valveService.getCharacteristic(Characteristic.SetDuration).value; + valveService.updateCharacteristic(Characteristic.RemainingDuration, timer); + valveService.timer = setTimeout(() => { + valveService.setCharacteristic(Characteristic.Active, 0); + }, timer * 1000); + } else { + valveService.updateCharacteristic(Characteristic.RemainingDuration, 0); + clearTimeout(valveService.timer); + } + }); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } + internalCurtainUpdate(accessory, value, callback) { + callback(); + try { + let params, + cService = accessory.getService(Service.WindowCovering), + prevPos = accessory.context.prevPos; + if (value === prevPos) return; + if (value === 0 || value === 100) { + params = { + switch: value === 100 ? "on" : "off", + }; + } else { + params = { + setclose: Math.abs(100 - value), + }; + } + this.sendDeviceUpdate(accessory, params) + .then(() => { + cService + .updateCharacteristic(Characteristic.TargetPosition, value) + .updateCharacteristic(Characteristic.PositionState, value > prevPos ? 1 : 0); + accessory.context.prevPos = value; + }) + .catch(err => { + throw err; + }); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory).catch(() => {}); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName + ); + } + } + } + externalCurtainUpdate(accessory, params) { + try { + let cService = accessory.getService(Service.WindowCovering); + if (params.hasOwnProperty("switch") && params.hasOwnProperty("setclose")) { + let newPos = Math.abs(100 - parseInt(params.setclose)); + cService + .updateCharacteristic(Characteristic.TargetPosition, newPos) + .updateCharacteristic(Characteristic.CurrentPosition, newPos) + .updateCharacteristic(Characteristic.PositionState, 2); + accessory.context.prevPos = Math.abs(100 - parseInt(params.setclose)); + return; + } + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } internalBlindUpdate(accessory, value, callback) { callback(); try { @@ -1253,6 +1334,38 @@ class eWeLink { } } } + externalBlindUpdate(accessory, params) { + try { + let blindConfig, + newPosition, + wcService = accessory.getService(Service.WindowCovering); + if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; + } + if (blindConfig.type !== "blind" || blindConfig.setup !== "twoSwitch") { + throw "improper configuration"; + } + // TargetPosition -> 0 for closed 100 for open (value) + // CurrentPosition -> 0 for closed 100 for open + // PositionState -> 0 going down, 1 going up, 2 = stopped + if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { + return; + } + let switchUp = params.switches[0].switch === "on" ? -1 : 0, // matrix of numbers to get + switchDown = params.switches[1].switch === "on" ? 0 : 2; // ... the correct HomeKit value + newPosition = switchUp + switchDown; + wcService + .updateCharacteristic(Characteristic.PositionState, newPosition) + .updateCharacteristic(Characteristic.TargetPosition, newPosition * 100); + setTimeout(() => { + wcService + .updateCharacteristic(Characteristic.PositionState, 2) + .updateCharacteristic(Characteristic.CurrentPosition, newPosition * 100); + }, parseInt(blindConfig.operationTime) * 100); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } internalGarageUpdate(accessory, value, callback) { callback(); try { @@ -1338,6 +1451,56 @@ class eWeLink { } } } + externalGarageUpdate(accessory, params) { + try { + let garageConfig, + gcService = accessory.getService(Service.GarageDoorOpener), + oldPos = gcService.getCharacteristic(Characteristic.CurrentDoorState).value, + newPos = [0, 2].includes(oldPos) ? 3 : 2; + if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; + } + if ( + garageConfig.type !== "garage" || + !["oneSwitch", "twoSwitch"].includes(garageConfig.setup) + ) { + throw "improper configuration"; + } + if (accessory.context.inUse || garageConfig.sensorId) { + return; + } + switch (garageConfig.setup) { + case "oneSwitch": + if (params.switch === "off") { + return; + } + break; + case "twoSwitch": + if ( + params.switches[0].switch === params.switches[1].switch || + params.switches[oldPos % 2].switch === "on" + ) { + return; + } + break; + } + accessory.context.inUse = true; + if (!garageConfig.sensorId) { + gcService + .updateCharacteristic(Characteristic.CurrentDoorState, newPos) + .updateCharacteristic(Characteristic.TargetDoorState, newPos - 2); + setTimeout(() => { + gcService.updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2); + }, parseInt(garageConfig.operationTime) * 100); + } + setTimeout(() => { + accessory.context.inUse = false; + }, parseInt(garageConfig.operationTime) * 100); + } catch (err) { + accessory.context.inUse = false; + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } internalLockUpdate(accessory, value, callback) { callback(); try { @@ -1380,48 +1543,78 @@ class eWeLink { } } } - internalCurtainUpdate(accessory, value, callback) { - callback(); + externalLockUpdate(accessory, params) { try { - let params, - cService = accessory.getService(Service.WindowCovering), - prevPos = accessory.context.prevPos; - if (value === prevPos) return; - if (value === 0 || value === 100) { - // so to fully open, our $value will be 100, we send switch: "on" - // to fully shut, our $value will be 0, we send switch: "off" - params = { - switch: value === 100 ? "on" : "off", - }; - } else { - // for a % midway, scale the $value >--< 100 and setclose: newVal AS INT - params = { - setclose: Math.abs(100 - value), - }; + let lockConfig, + lmService = accessory.getService(Service.LockMechanism); + if (!(lockConfig = this.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; } - this.sendDeviceUpdate(accessory, params) - .then(() => { - cService - .updateCharacteristic(Characteristic.TargetPosition, value) - .updateCharacteristic(Characteristic.PositionState, value > prevPos ? 1 : 0); - // TargetPosition -> 0 for closed 100 for open (value) - // CurrentPosition -> 0 for closed 100 for open - // PositionState -> 0 going down, 1 going up, 2 = stopped - accessory.context.prevPos = value; - }) - .catch(err => { - throw err; - }); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory).catch(() => {}); - this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", - accessory.displayName - ); + if (lockConfig.type !== "lock") { + throw "improper configuration"; } - } + if (params.switch === "off" || accessory.context.inUse) { + return; + } + accessory.context.inUse = true; + lmService + .updateCharacteristic(Characteristic.LockCurrentState, 0) + .updateCharacteristic(Characteristic.LockTargetState, 0); + setTimeout(() => { + lmService + .updateCharacteristic(Characteristic.LockCurrentState, 1) + .updateCharacteristic(Characteristic.LockTargetState, 1); + accessory.context.inUse = false; + }, parseInt(lockConfig.operationTime) * 100); + } catch (err) { + accessory.context.inUse = false; + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } + externalSensorUpdate(accessory, params) { + try { + if (params.hasOwnProperty("battery")) { + let batteryService = + accessory.getService(Service.BatteryService) || + accessory.addService(Service.BatteryService), + scaledBattery = Math.round(params.battery * 33.3); + batteryService.updateCharacteristic(Characteristic.BatteryLevel, scaledBattery); + batteryService.updateCharacteristic( + Characteristic.StatusLowBattery, + scaledBattery < (this.config.lowBattThreshold || 25) + ); + } + let newState = params.switch === "on" ? 1 : 0, + oAccessory = false, + contactService = accessory.getService(Service.ContactSensor); + contactService.updateCharacteristic(Characteristic.ContactSensorState, newState); + this.cusG.forEach(group => { + if (group.sensorId === accessory.context.eweDeviceId && group.type === "garage") { + if ((oAccessory = this.devicesInHB.get(group.deviceId + "SWX"))) { + switch (newState) { + case 0: + oAccessory + .getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.TargetDoorState, 1) + .updateCharacteristic(Characteristic.CurrentDoorState, 1); + break; + case 1: + setTimeout(() => { + oAccessory + .getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.TargetDoorState, 0) + .updateCharacteristic(Characteristic.CurrentDoorState, 0); + }, group.operationTime * 100); + break; + default: + throw "unknown sensor status received [" + newState + "]"; + } + } + } + }); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } } internalFanUpdate(accessory, type, value, callback) { callback(); @@ -1476,6 +1669,51 @@ class eWeLink { } } } + externalFanUpdate(accessory, params) { + try { + let light, + status, + speed, + lightService = accessory.getService(Service.Lightbulb), + fanService = accessory.getService(Service.Fanv2); + if (Array.isArray(params.switches)) { + light = params.switches[0].switch === "on"; + switch (params.switches[1].switch + params.switches[2].switch + params.switches[3].switch) { + default: + status = 0; + speed = 0; + break; + case "onoffoff": + status = 1; + speed = 33; + break; + case "ononoff": + status = 1; + speed = 66; + break; + case "onoffon": + status = 1; + speed = 99; + } + } else if ( + params.hasOwnProperty("light") && + params.hasOwnProperty("fan") && + params.hasOwnProperty("speed") + ) { + light = params.light === "on"; + status = params.fan === "on" ? 1 : 0; + speed = params.speed * 33 * status; + } else { + throw "unknown parameters received"; + } + lightService.updateCharacteristic(Characteristic.On, light); + fanService + .updateCharacteristic(Characteristic.Active, status) + .updateCharacteristic(Characteristic.RotationSpeed, speed); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } internalThermostatUpdate(accessory, value, callback) { callback(); try { @@ -1502,6 +1740,49 @@ class eWeLink { } } } + externalThermostatUpdate(accessory, params) { + try { + if ( + !this.config.hideTHSwitch && + (params.hasOwnProperty("switch") || params.hasOwnProperty("mainSwitch")) + ) { + let newState = params.hasOwnProperty("switch") + ? params.switch === "on" + : params.mainSwitch === "on", + switchService = accessory.getService(Service.Switch); + switchService.updateCharacteristic(Characteristic.On, newState); + } + let eveLog = { + time: Date.now(), + }; + if ( + params.hasOwnProperty("currentTemperature") && + accessory.getService(Service.TemperatureSensor) + ) { + let currentTemp = + params.currentTemperature !== "unavailable" ? params.currentTemperature : 0; + accessory + .getService(Service.TemperatureSensor) + .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); + eveLog.temp = parseFloat(currentTemp); + } + if ( + params.hasOwnProperty("currentHumidity") && + accessory.getService(Service.HumiditySensor) + ) { + let currentHumi = params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; + accessory + .getService(Service.HumiditySensor) + .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); + eveLog.humidity = parseFloat(currentHumi); + } + if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { + accessory.eveLogger.addEntry(eveLog); + } + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } internalOutletUpdate(accessory, value, callback) { callback(); try { @@ -1527,6 +1808,43 @@ class eWeLink { } } } + externalOutletUpdate(accessory, params) { + try { + let outletService = accessory.getService(Service.Outlet); + if (params.hasOwnProperty("switch")) { + outletService.updateCharacteristic(Characteristic.On, params.switch === "on"); + } + if (params.hasOwnProperty("power")) { + outletService.updateCharacteristic( + EveService.Characteristics.CurrentConsumption, + parseFloat(params.power) + ); + outletService.updateCharacteristic( + Characteristic.OutletInUse, + parseFloat(params.power) > (this.config.inUsePowerThreshold || 0) + ); + let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value; + accessory.eveLogger.addEntry({ + time: Date.now(), + power: isOn ? parseFloat(params.power) : 0, + }); + } + if (params.hasOwnProperty("voltage")) { + outletService.updateCharacteristic( + EveService.Characteristics.Voltage, + parseFloat(params.voltage) + ); + } + if (params.hasOwnProperty("current")) { + outletService.updateCharacteristic( + EveService.Characteristics.ElectricCurrent, + parseFloat(params.current) + ); + } + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } internalUSBUpdate(accessory, value, callback) { callback(); try { @@ -1553,6 +1871,15 @@ class eWeLink { } } } + externalUSBUpdate(accessory, params) { + try { + accessory + .getService(Service.Outlet) + .updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } internalSCMUpdate(accessory, value, callback) { callback(); try { @@ -1579,6 +1906,15 @@ class eWeLink { } } } + externalSCMUpdate(accessory, params) { + try { + accessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } internalLightbulbUpdate(accessory, value, callback) { callback(); try { @@ -1806,471 +2142,18 @@ class eWeLink { } } } - internalSwitchUpdate(accessory, value, callback) { - callback(); + externalSingleLightUpdate(accessory, params) { try { - let oAccessory, - params = {}, - switchService = accessory.getService(Service.Switch); - switch (accessory.context.switchNumber) { - case "X": - params.switch = value ? "on" : "off"; - break; - case "0": - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = value ? "on" : "off"; - params.switches[1].switch = value ? "on" : "off"; - params.switches[2].switch = value ? "on" : "off"; - params.switches[3].switch = value ? "on" : "off"; - break; - case "1": - case "2": - case "3": - case "4": - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; - for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - i === parseInt(accessory.context.switchNumber) - ? (params.switches[i - 1].switch = value ? "on" : "off") - : (params.switches[i - 1].switch = oAccessory - .getService(Service.Switch) - .getCharacteristic(Characteristic.On).value - ? "on" - : "off"); - } else { - params.switches[i - 1].switch = "off"; - } - } - break; - } - this.sendDeviceUpdate(accessory, params) - .then(() => { - switch (accessory.context.switchNumber) { - case "X": - switchService.updateCharacteristic(Characteristic.On, value); - break; - case "0": - for (let i = 0; i <= 4; i++) { - if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - oAccessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, value); - } - } - break; - case "1": - case "2": - case "3": - case "4": - switchService.updateCharacteristic(Characteristic.On, value); - let masterState = "off"; - for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - if ( - oAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value - ) { - masterState = "on"; - } - } - } - if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - oAccessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, masterState === "on"); - } - break; - } - }) - .catch(err => { - throw err; - }); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory).catch(() => {}); - this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", - accessory.displayName - ); - } - } - } - internalRFUpdate(accessory, rfChl, service, callback) { - callback(); - try { - let params = { - cmd: "transmit", - rfChl: parseInt(rfChl), - }, - rfService = accessory.getService(service); - this.sendDeviceUpdate(accessory, params) - .then(() => { - rfService.updateCharacteristic(Characteristic.On, true); - setTimeout(() => rfService.updateCharacteristic(Characteristic.On, false), 3000); - }) - .catch(err => { - throw err; - }); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory).catch(() => {}); - this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", - accessory.displayName - ); - } - } - } - externalValveUpdate(accessory, params) { - try { - ["A", "B"].forEach((v, k) => { - let valveService = accessory.getService("Valve " + v); - valveService - .updateCharacteristic(Characteristic.Active, params.switches[k].switch === "on") - .updateCharacteristic(Characteristic.InUse, params.switches[k].switch === "on"); - if (params.switches[k].switch === "on") { - let timer = valveService.getCharacteristic(Characteristic.SetDuration).value; - valveService.updateCharacteristic(Characteristic.RemainingDuration, timer); - valveService.timer = setTimeout(() => { - valveService.setCharacteristic(Characteristic.Active, 0); - }, timer * 1000); - } else { - valveService.updateCharacteristic(Characteristic.RemainingDuration, 0); - clearTimeout(valveService.timer); - } - }); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalBlindUpdate(accessory, params) { - try { - let blindConfig, - newPosition, - wcService = accessory.getService(Service.WindowCovering); - if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; - } - if (blindConfig.type !== "blind" || blindConfig.setup !== "twoSwitch") { - throw "improper configuration"; - } - // TargetPosition -> 0 for closed 100 for open (value) - // CurrentPosition -> 0 for closed 100 for open - // PositionState -> 0 going down, 1 going up, 2 = stopped - if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { - return; - } - let switchUp = params.switches[0].switch === "on" ? -1 : 0, // matrix of numbers to get - switchDown = params.switches[1].switch === "on" ? 0 : 2; // ... the correct HomeKit value - newPosition = switchUp + switchDown; - wcService - .updateCharacteristic(Characteristic.PositionState, newPosition) - .updateCharacteristic(Characteristic.TargetPosition, newPosition * 100); - setTimeout(() => { - wcService - .updateCharacteristic(Characteristic.PositionState, 2) - .updateCharacteristic(Characteristic.CurrentPosition, newPosition * 100); - }, parseInt(blindConfig.operationTime) * 100); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalGarageUpdate(accessory, params) { - try { - let garageConfig, - gcService = accessory.getService(Service.GarageDoorOpener), - oldPos = gcService.getCharacteristic(Characteristic.CurrentDoorState).value, - newPos = [0, 2].includes(oldPos) ? 3 : 2; - if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; - } - if ( - garageConfig.type !== "garage" || - !["oneSwitch", "twoSwitch"].includes(garageConfig.setup) - ) { - throw "improper configuration"; - } - if (accessory.context.inUse || garageConfig.sensorId) { - return; - } - switch (garageConfig.setup) { - case "oneSwitch": - if (params.switch === "off") { - return; - } - break; - case "twoSwitch": - if ( - params.switches[0].switch === params.switches[1].switch || - params.switches[oldPos % 2].switch === "on" - ) { - return; - } - break; - } - accessory.context.inUse = true; - if (!garageConfig.sensorId) { - gcService - .updateCharacteristic(Characteristic.CurrentDoorState, newPos) - .updateCharacteristic(Characteristic.TargetDoorState, newPos - 2); - setTimeout(() => { - gcService.updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2); - }, parseInt(garageConfig.operationTime) * 100); - } - setTimeout(() => { - accessory.context.inUse = false; - }, parseInt(garageConfig.operationTime) * 100); - } catch (err) { - accessory.context.inUse = false; - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalLockUpdate(accessory, params) { - try { - let lockConfig, - lmService = accessory.getService(Service.LockMechanism); - if (!(lockConfig = this.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; - } - if (lockConfig.type !== "lock") { - throw "improper configuration"; - } - if (params.switch === "off" || accessory.context.inUse) { - return; - } - accessory.context.inUse = true; - lmService - .updateCharacteristic(Characteristic.LockCurrentState, 0) - .updateCharacteristic(Characteristic.LockTargetState, 0); - setTimeout(() => { - lmService - .updateCharacteristic(Characteristic.LockCurrentState, 1) - .updateCharacteristic(Characteristic.LockTargetState, 1); - accessory.context.inUse = false; - }, parseInt(lockConfig.operationTime) * 100); - } catch (err) { - accessory.context.inUse = false; - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalCurtainUpdate(accessory, params) { - try { - let cService = accessory.getService(Service.WindowCovering); - if (params.hasOwnProperty("switch") && params.hasOwnProperty("setclose")) { - let newPos = Math.abs(100 - parseInt(params.setclose)); - cService - .updateCharacteristic(Characteristic.TargetPosition, newPos) - .updateCharacteristic(Characteristic.CurrentPosition, newPos) - .updateCharacteristic(Characteristic.PositionState, 2); - accessory.context.prevPos = Math.abs(100 - parseInt(params.setclose)); - return; - } - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalSensorUpdate(accessory, params) { - try { - if (params.hasOwnProperty("battery")) { - let batteryService = - accessory.getService(Service.BatteryService) || - accessory.addService(Service.BatteryService), - scaledBattery = Math.round(params.battery * 33.3); - batteryService.updateCharacteristic(Characteristic.BatteryLevel, scaledBattery); - batteryService.updateCharacteristic( - Characteristic.StatusLowBattery, - scaledBattery < (this.config.lowBattThreshold || 25) - ); - } - let newState = params.switch === "on" ? 1 : 0, - oAccessory = false, - contactService = accessory.getService(Service.ContactSensor); - contactService.updateCharacteristic(Characteristic.ContactSensorState, newState); - this.cusG.forEach(group => { - if (group.sensorId === accessory.context.eweDeviceId && group.type === "garage") { - if ((oAccessory = this.devicesInHB.get(group.deviceId + "SWX"))) { - switch (newState) { - case 0: - oAccessory - .getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.TargetDoorState, 1) - .updateCharacteristic(Characteristic.CurrentDoorState, 1); - break; - case 1: - setTimeout(() => { - oAccessory - .getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.TargetDoorState, 0) - .updateCharacteristic(Characteristic.CurrentDoorState, 0); - }, group.operationTime * 100); - break; - default: - throw "unknown sensor status received [" + newState + "]"; - } - } - } - }); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalFanUpdate(accessory, params) { - try { - let light, - status, - speed, - lightService = accessory.getService(Service.Lightbulb), - fanService = accessory.getService(Service.Fanv2); - if (Array.isArray(params.switches)) { - light = params.switches[0].switch === "on"; - switch (params.switches[1].switch + params.switches[2].switch + params.switches[3].switch) { - default: - status = 0; - speed = 0; - break; - case "onoffoff": - status = 1; - speed = 33; - break; - case "ononoff": - status = 1; - speed = 66; - break; - case "onoffon": - status = 1; - speed = 99; - } - } else if ( - params.hasOwnProperty("light") && - params.hasOwnProperty("fan") && - params.hasOwnProperty("speed") - ) { - light = params.light === "on"; - status = params.fan === "on" ? 1 : 0; - speed = params.speed * 33 * status; - } else { - throw "unknown parameters received"; - } - lightService.updateCharacteristic(Characteristic.On, light); - fanService - .updateCharacteristic(Characteristic.Active, status) - .updateCharacteristic(Characteristic.RotationSpeed, speed); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalThermostatUpdate(accessory, params) { - try { - if ( - !this.config.hideTHSwitch && - (params.hasOwnProperty("switch") || params.hasOwnProperty("mainSwitch")) - ) { - let newState = params.hasOwnProperty("switch") - ? params.switch === "on" - : params.mainSwitch === "on", - switchService = accessory.getService(Service.Switch); - switchService.updateCharacteristic(Characteristic.On, newState); - } - let eveLog = { - time: Date.now(), - }; - if ( - params.hasOwnProperty("currentTemperature") && - accessory.getService(Service.TemperatureSensor) - ) { - let currentTemp = - params.currentTemperature !== "unavailable" ? params.currentTemperature : 0; - accessory - .getService(Service.TemperatureSensor) - .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); - eveLog.temp = parseFloat(currentTemp); - } - if ( - params.hasOwnProperty("currentHumidity") && - accessory.getService(Service.HumiditySensor) - ) { - let currentHumi = params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; - accessory - .getService(Service.HumiditySensor) - .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); - eveLog.humidity = parseFloat(currentHumi); - } - if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { - accessory.eveLogger.addEntry(eveLog); - } - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalOutletUpdate(accessory, params) { - try { - let outletService = accessory.getService(Service.Outlet); - if (params.hasOwnProperty("switch")) { - outletService.updateCharacteristic(Characteristic.On, params.switch === "on"); - } - if (params.hasOwnProperty("power")) { - outletService.updateCharacteristic( - EveService.Characteristics.CurrentConsumption, - parseFloat(params.power) - ); - outletService.updateCharacteristic( - Characteristic.OutletInUse, - parseFloat(params.power) > (this.config.inUsePowerThreshold || 0) - ); - let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value; - accessory.eveLogger.addEntry({ - time: Date.now(), - power: isOn ? parseFloat(params.power) : 0, - }); - } - if (params.hasOwnProperty("voltage")) { - outletService.updateCharacteristic( - EveService.Characteristics.Voltage, - parseFloat(params.voltage) - ); - } - if (params.hasOwnProperty("current")) { - outletService.updateCharacteristic( - EveService.Characteristics.ElectricCurrent, - parseFloat(params.current) - ); - } - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalUSBUpdate(accessory, params) { - try { - accessory - .getService(Service.Outlet) - .updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalSCMUpdate(accessory, params) { - try { - accessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalSingleLightUpdate(accessory, params) { - try { - let newColour, - mode, - isOn = false, - lightService = accessory.getService(Service.Lightbulb); - if (accessory.context.eweUIID === 22 && params.hasOwnProperty("state")) { - isOn = params.state === "on"; - } else if (accessory.context.eweUIID !== 22 && params.hasOwnProperty("switch")) { - isOn = params.switch === "on"; - } else { - isOn = lightService.getCharacteristic(Characteristic.On).value; + let newColour, + mode, + isOn = false, + lightService = accessory.getService(Service.Lightbulb); + if (accessory.context.eweUIID === 22 && params.hasOwnProperty("state")) { + isOn = params.state === "on"; + } else if (accessory.context.eweUIID !== 22 && params.hasOwnProperty("switch")) { + isOn = params.switch === "on"; + } else { + isOn = lightService.getCharacteristic(Characteristic.On).value; } if (isOn) { lightService.updateCharacteristic(Characteristic.On, true); @@ -2357,6 +2240,96 @@ class eWeLink { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } + internalSwitchUpdate(accessory, value, callback) { + callback(); + try { + let oAccessory, + params = {}, + switchService = accessory.getService(Service.Switch); + switch (accessory.context.switchNumber) { + case "X": + params.switch = value ? "on" : "off"; + break; + case "0": + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = value ? "on" : "off"; + params.switches[1].switch = value ? "on" : "off"; + params.switches[2].switch = value ? "on" : "off"; + params.switches[3].switch = value ? "on" : "off"; + break; + case "1": + case "2": + case "3": + case "4": + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + for (let i = 1; i <= 4; i++) { + if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + i === parseInt(accessory.context.switchNumber) + ? (params.switches[i - 1].switch = value ? "on" : "off") + : (params.switches[i - 1].switch = oAccessory + .getService(Service.Switch) + .getCharacteristic(Characteristic.On).value + ? "on" + : "off"); + } else { + params.switches[i - 1].switch = "off"; + } + } + break; + } + this.sendDeviceUpdate(accessory, params) + .then(() => { + switch (accessory.context.switchNumber) { + case "X": + switchService.updateCharacteristic(Characteristic.On, value); + break; + case "0": + for (let i = 0; i <= 4; i++) { + if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + oAccessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, value); + } + } + break; + case "1": + case "2": + case "3": + case "4": + switchService.updateCharacteristic(Characteristic.On, value); + let masterState = "off"; + for (let i = 1; i <= 4; i++) { + if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + if ( + oAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value + ) { + masterState = "on"; + } + } + } + if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); + oAccessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, masterState === "on"); + } + break; + } + }) + .catch(err => { + throw err; + }); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory).catch(() => {}); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName + ); + } + } + } externalSingleSwitchUpdate(accessory, params) { try { accessory @@ -2388,6 +2361,33 @@ class eWeLink { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } + internalRFUpdate(accessory, rfChl, service, callback) { + callback(); + try { + let params = { + cmd: "transmit", + rfChl: parseInt(rfChl), + }, + rfService = accessory.getService(service); + this.sendDeviceUpdate(accessory, params) + .then(() => { + rfService.updateCharacteristic(Characteristic.On, true); + setTimeout(() => rfService.updateCharacteristic(Characteristic.On, false), 3000); + }) + .catch(err => { + throw err; + }); + } catch (err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory).catch(() => {}); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName + ); + } + } + } externalRFUpdate(accessory, params) { try { if (!params.hasOwnProperty("updateSource")) return; From faefd89cb5d566ff0325dd8bde99760e480b253e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 23 Sep 2020 11:56:38 +0100 Subject: [PATCH 0201/3183] 3.0.0-7 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index fbe82755..c0bf7d5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.0-6", + "version": "3.0.0-7", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 9d03ce36..60292074 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.0-6", + "version": "3.0.0-7", "author": "bwp91", "contributors": [ "gbro115", From 1746d4c46772876195d2fd32308c1c701f264d54 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 23 Sep 2020 13:43:02 +0100 Subject: [PATCH 0202/3183] blind and garage caching --- lib/constants.js | 1 + lib/eWeLink.js | 83 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/lib/constants.js b/lib/constants.js index 75e59b9e..75bdeaf1 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -9,6 +9,7 @@ module.exports = { devicesNonLAN: [22, 28, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], devicesSingleSwitchParams: ["switch"], + devicesSingleSwitchOutlet: ["Sonoff Pow"], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], devicesMultiSwitchParams: ["switches"], devicesSingleSwitchLight: [ diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 76fe7030..ea6fb02f 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -131,8 +131,18 @@ class eWeLink { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "curtain", false, { - prevPos: 0, + cacheCurrentPosition: 0, }); + //*** @UPGRADE from v2 -> v3 23.09.2020 ***\\ + if (accessory.context.hasOwnProperty("prevPos")) { + accessory.context.cacheCurrentPosition = accessory.context.prevPos; + delete accessory.context.prevPos; + //*** @ENDUPGRADE ***\\ + } + if (!accessory.context.hasOwnProperty("cacheCurrentPosition")) { + accessory.context.cacheCurrentPosition = 0; + //*** @ENDUPGRADE ***\\ + } } //*** WINDOW BLINDS ***\\ else if ( @@ -142,10 +152,17 @@ class eWeLink { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "blind", false, { - cacheLastPosition: 0, + cacheCurrentPosition: 0, cachePositionState: 2, cacheTargetPosition: 0, }); + //*** @UPGRADE from v2 -> v3 23.09.2020 ***\\ + if (!accessory.context.hasOwnProperty("cacheCurrentPosition")) { + accessory.context.cacheCurrentPosition = 0; + accessory.context.cachePositionState = 2; + accessory.context.cacheTargetPosition = 0; + } + //*** @ENDUPGRADE ***\\ } //*** GARAGE DOORS ***\\ else if ( @@ -154,7 +171,16 @@ class eWeLink { ) { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "garage"); + : this.addAccessory(device, device.deviceid + "SWX", "garage", false, { + cacheCurrentDoorState: 1, + cacheTargetDoorState: 1, + }); + //*** @UPGRADE from v2 -> v3 23.09.2020 ***\\ + if (!accessory.context.hasOwnProperty("cacheCurrentDoorState")) { + accessory.context.cacheCurrentDoorState = 1; + accessory.context.cacheTargetDoorState = 1; + } + //*** @ENDUPGRADE ***\\ } //*** LOCKS ***\\ else if ( @@ -184,6 +210,11 @@ class eWeLink { : this.addAccessory(device, device.deviceid + "SWX", "thermostat", false, { sensorType: device.params.sensorType, }); + //*** @UPGRADE from v2 -> v3 23.09.2020 ***\\ + if (!accessory.context.hasOwnProperty("sensorType")) { + accessory.context.sensorType = device.params.sensorType; + } + //*** @ENDUPGRADE ***\\ if (accessory.context.sensorType !== device.params.sensorType) { accessory.context.sensorType = device.params.sensorType; this.devicesInHB.set(accessory.context.hbDeviceId, accessory); @@ -192,7 +223,8 @@ class eWeLink { //*** OUTLETS ***\\ else if ( cns.devicesOutlet.includes(device.extra.uiid) || - device.productModel === "Sonoff Pow" + (cns.devicesSingleSwitch.includes(device.extra.uiid) && + cns.devicesSingleSwitchOutlet.includes(device.productModel)) ) { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") @@ -367,12 +399,22 @@ class eWeLink { //*** ZIGBEE BRIDGES ***\\ else if (cns.devicesZBBridge.includes(device.extra.uiid)) { // Nothing to do here but needed to avoid the below not supported error + //*** @UPGRADE from v2 -> v3 23.09.2020 ***\\ + if ((accessory = this.devicesInHB.get(device.deviceid + "SWX"))) { + this.removeAccessory(accessory); + } + //*** @ENDUPGRADE ***\\ } //*** ZIGBEE DEVICES ***\\ else if (cns.devicesZB.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "zb_dev"); + //*** @UPGRADE from v2 -> v3 23.09.2020 ***\\ + if (accessory.context.type === "zb_sub") { + accessory.context.type = "zb_dev"; + } + //*** @ENDUPGRADE ***\\ } //*** SONOFF CAMERAS ***\\ else if (cns.devicesCamera.includes(device.extra.uiid)) { @@ -1232,7 +1274,7 @@ class eWeLink { try { let params, cService = accessory.getService(Service.WindowCovering), - prevPos = accessory.context.prevPos; + prevPos = accessory.context.cacheCurrentPosition; if (value === prevPos) return; if (value === 0 || value === 100) { params = { @@ -1248,7 +1290,7 @@ class eWeLink { cService .updateCharacteristic(Characteristic.TargetPosition, value) .updateCharacteristic(Characteristic.PositionState, value > prevPos ? 1 : 0); - accessory.context.prevPos = value; + accessory.context.cacheCurrentPosition = value; }) .catch(err => { throw err; @@ -1273,7 +1315,7 @@ class eWeLink { .updateCharacteristic(Characteristic.TargetPosition, newPos) .updateCharacteristic(Characteristic.CurrentPosition, newPos) .updateCharacteristic(Characteristic.PositionState, 2); - accessory.context.prevPos = Math.abs(100 - parseInt(params.setclose)); + accessory.context.cacheCurrentPosition = Math.abs(100 - parseInt(params.setclose)); return; } } catch (err) { @@ -1286,7 +1328,7 @@ class eWeLink { let blindConfig, params = {}, wcService = accessory.getService(Service.WindowCovering), - oldPos = wcService.getCharacteristic(Characteristic.PositionState).value; + oldPos = accessory.context.cachePositionState; if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } @@ -1297,6 +1339,9 @@ class eWeLink { if (value === oldPos * 100) return; // target position -> 0 for closed 100 for open (value) // current position -> 0 going down, 1 going up + accessory.context.cacheCurrentPosition = wcService.getCharacteristic( + Characteristic.CurrentPosition + ).value; params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; params.switches[0].switch = value === 100 ? "on" : "off"; params.switches[1].switch = value === 0 ? "on" : "off"; @@ -1305,6 +1350,8 @@ class eWeLink { wcService .updateCharacteristic(Characteristic.TargetPosition, value) .updateCharacteristic(Characteristic.PositionState, value / 100); + accessory.context.cachePositionState = value / 100; + accessory.context.cacheTargetPosition = value; return new Promise(resolve => setTimeout(resolve, parseInt(blindConfig.operationTime) * 100) ); @@ -1319,6 +1366,8 @@ class eWeLink { wcService .updateCharacteristic(Characteristic.CurrentPosition, value) .updateCharacteristic(Characteristic.PositionState, 2); + accessory.context.cachePositionState = 2; + accessory.context.cacheCurrentPosition = value; }) .catch(err => { throw err; @@ -1345,9 +1394,6 @@ class eWeLink { if (blindConfig.type !== "blind" || blindConfig.setup !== "twoSwitch") { throw "improper configuration"; } - // TargetPosition -> 0 for closed 100 for open (value) - // CurrentPosition -> 0 for closed 100 for open - // PositionState -> 0 going down, 1 going up, 2 = stopped if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { return; } @@ -1357,10 +1403,14 @@ class eWeLink { wcService .updateCharacteristic(Characteristic.PositionState, newPosition) .updateCharacteristic(Characteristic.TargetPosition, newPosition * 100); + accessory.context.cachePositionState = newPosition; + accessory.context.cacheTargetPosition = newPosition * 100; setTimeout(() => { wcService .updateCharacteristic(Characteristic.PositionState, 2) .updateCharacteristic(Characteristic.CurrentPosition, newPosition * 100); + accessory.context.cachePositionState = 2; + accessory.context.cacheCurrentPosition = newPosition * 100; }, parseInt(blindConfig.operationTime) * 100); } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); @@ -1398,12 +1448,13 @@ class eWeLink { .getCharacteristic(Characteristic.ContactSensorState).value === 0 ? 1 : 0 - : gdService.getCharacteristic(Characteristic.CurrentDoorState).value; + : accessory.context.cacheCurrentDoorState; if (newPos === oldPos % 2) return; accessory.context.inUse = true; accessory.context.state = value; if (garageConfig.setup === "oneSwitch" && [2, 3].includes(oldPos)) { gdService.updateCharacteristic(Characteristic.CurrentDoorState, ((oldPos * 2) % 3) + 2); + accessory.context.cacheCurrentDoorState = ((oldPos * 2) % 3) + 2; delay = 1500; } if (accessory.context.state !== newPos) return; @@ -1413,6 +1464,8 @@ class eWeLink { gdService .updateCharacteristic(Characteristic.TargetDoorState, newPos) .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2); + accessory.context.cacheTargetDoorState = newPos; + accessory.context.cacheCurrentDoorState = newPos + 2; switch (garageConfig.setup) { case "oneSwitch": params.switch = "on"; @@ -1433,6 +1486,7 @@ class eWeLink { .then(() => { if (!sAccessory) { gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos); + accessory.context.cacheCurrentDoorState = newPos; } accessory.context.inUse = false; }) @@ -1455,7 +1509,7 @@ class eWeLink { try { let garageConfig, gcService = accessory.getService(Service.GarageDoorOpener), - oldPos = gcService.getCharacteristic(Characteristic.CurrentDoorState).value, + oldPos = accessory.context.cacheCurrentDoorState, newPos = [0, 2].includes(oldPos) ? 3 : 2; if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; @@ -1489,8 +1543,11 @@ class eWeLink { gcService .updateCharacteristic(Characteristic.CurrentDoorState, newPos) .updateCharacteristic(Characteristic.TargetDoorState, newPos - 2); + accessory.context.cacheCurrentDoorState = newPos; + accessory.context.cacheTargetDoorState = newPos - 2; setTimeout(() => { gcService.updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2); + accessory.context.cacheCurrentDoorState = newPos - 2; }, parseInt(garageConfig.operationTime) * 100); } setTimeout(() => { From 08b7b9a31011a1715ef4098af74e3f1964079503 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 23 Sep 2020 13:50:37 +0100 Subject: [PATCH 0203/3183] 3.0.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index c0bf7d5d..5f52a260 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.0-7", + "version": "3.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 60292074..497d1edf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.0-7", + "version": "3.0.0", "author": "bwp91", "contributors": [ "gbro115", From c6a1a4a45a5c667fdf861e88dc06112f68d38538 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 23 Sep 2020 18:41:57 +0100 Subject: [PATCH 0204/3183] Update eWeLink.js --- lib/eWeLink.js | 57 +++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index ea6fb02f..aaa22f0f 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1071,38 +1071,47 @@ class eWeLink { } } sendDeviceUpdate(accessory, params) { - return new Promise((resolve, reject) => { - let payload = { + let payload = { apikey: accessory.context.eweApiKey, deviceid: accessory.context.eweDeviceId, params, + }, + delayPromise = new Promise(resolve => setTimeout(resolve, Math.random() * 150 + 350)), + sendViaWS = () => { + return new Promise((resolve, reject) => { + if (accessory.context.reachableWAN) { + this.wsClient + .sendUpdate(payload) + .then(() => resolve()) + .catch(err => reject(err)); + } else { + reject("it is unreachable"); + } + }); }; - let sendViaWS = () => { - if (accessory.context.reachableWAN) { - this.wsClient - .sendUpdate(payload) + return new Promise((resolve, reject) => { + delayPromise.then(() => { + if ( + cns.devicesNonLAN.includes(accessory.context.eweUIID) || + !accessory.context.reachableLAN + ) { + sendViaWS() .then(() => resolve()) .catch(err => reject(err)); } else { - reject("it is unreachable"); + this.lanClient + .sendUpdate(payload) + .then(() => resolve()) + .catch(err => { + if (this.debug) { + this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); + } + sendViaWS() + .then(() => resolve()) + .catch(err => reject(err)); + }); } - }; - if ( - cns.devicesNonLAN.includes(accessory.context.eweUIID) || - !accessory.context.reachableLAN - ) { - sendViaWS(); - } else { - this.lanClient - .sendUpdate(payload) - .then(() => resolve()) - .catch(err => { - if (this.debug) { - this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); - } - sendViaWS(); - }); - } + }); }); } receiveDeviceUpdate(device) { From a484e29fddc23f88b52a77e67b23573591b0ab71 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 23 Sep 2020 18:42:40 +0100 Subject: [PATCH 0205/3183] 3.0.1-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5f52a260..4b4267f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.0", + "version": "3.0.1-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 497d1edf..f8f82af6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.0", + "version": "3.0.1-0", "author": "bwp91", "contributors": [ "gbro115", From ef8b19d04546f715c0607c99ddb8d0df3c531cdc Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 24 Sep 2020 14:29:30 +0100 Subject: [PATCH 0206/3183] more updates --- lib/eWeLink.js | 192 +++++++++++++++++++++++++++------------------- lib/eWeLinkLAN.js | 6 +- lib/eWeLinkWS.js | 45 +++++------ 3 files changed, 132 insertions(+), 111 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index aaa22f0f..9b29b4da 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1,6 +1,6 @@ /* jshint esversion: 9, -W014, -W030, node: true */ "use strict"; -let Accessory, Characteristic, EveService, EveHistoryService, Service, UUIDGen; +let Accessory, Characteristic, EveService, EveHistoryService, Service; const cns = require("./constants"), convert = require("color-convert"), corrInterval = require("correcting-interval"), @@ -485,7 +485,10 @@ class eWeLink { newDeviceName = this.config.nameOverride[hbDeviceId]; } try { - const accessory = new Accessory(newDeviceName, UUIDGen.generate(hbDeviceId).toString()); + const accessory = new Accessory( + newDeviceName, + this.api.hap.uuid.generate(hbDeviceId).toString() + ); if (!hidden) { accessory .getService(Service.AccessoryInformation) @@ -1071,46 +1074,30 @@ class eWeLink { } } sendDeviceUpdate(accessory, params) { - let payload = { - apikey: accessory.context.eweApiKey, - deviceid: accessory.context.eweDeviceId, - params, - }, - delayPromise = new Promise(resolve => setTimeout(resolve, Math.random() * 150 + 350)), - sendViaWS = () => { - return new Promise((resolve, reject) => { - if (accessory.context.reachableWAN) { - this.wsClient - .sendUpdate(payload) - .then(() => resolve()) - .catch(err => reject(err)); - } else { - reject("it is unreachable"); - } - }); - }; return new Promise((resolve, reject) => { + let payload = { + apikey: accessory.context.eweApiKey, + deviceid: accessory.context.eweDeviceId, + params, + }, + delayPromise = new Promise(resolve => setTimeout(resolve, Math.random() * 100 + 200)); delayPromise.then(() => { - if ( - cns.devicesNonLAN.includes(accessory.context.eweUIID) || - !accessory.context.reachableLAN - ) { - sendViaWS() - .then(() => resolve()) - .catch(err => reject(err)); - } else { - this.lanClient - .sendUpdate(payload) - .then(() => resolve()) - .catch(err => { - if (this.debug) { - this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); - } - sendViaWS() + this.lanClient + .sendUpdate(payload) + .then(() => resolve()) + .catch(err => { + if (this.debug) { + this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); + } + if (accessory.context.reachableWAN) { + this.wsClient + .sendUpdate(payload) .then(() => resolve()) .catch(err => reject(err)); - }); - } + } else { + reject("it is unreachable"); + } + }); }); }); } @@ -1283,23 +1270,24 @@ class eWeLink { try { let params, cService = accessory.getService(Service.WindowCovering), - prevPos = accessory.context.cacheCurrentPosition; - if (value === prevPos) return; - if (value === 0 || value === 100) { + prevPos = accessory.context.cacheCurrentPosition, + newPos = value; + if (newPos === prevPos) return; + if (newPos === 0 || newPos === 100) { params = { - switch: value === 100 ? "on" : "off", + switch: newPos === 100 ? "on" : "off", }; } else { params = { - setclose: Math.abs(100 - value), + setclose: Math.abs(100 - newPos), }; } this.sendDeviceUpdate(accessory, params) .then(() => { cService - .updateCharacteristic(Characteristic.TargetPosition, value) - .updateCharacteristic(Characteristic.PositionState, value > prevPos ? 1 : 0); - accessory.context.cacheCurrentPosition = value; + .updateCharacteristic(Characteristic.TargetPosition, newPos) + .updateCharacteristic(Characteristic.PositionState, newPos > prevPos ? 1 : 0); + accessory.context.cacheCurrentPosition = newPos; }) .catch(err => { throw err; @@ -1324,7 +1312,7 @@ class eWeLink { .updateCharacteristic(Characteristic.TargetPosition, newPos) .updateCharacteristic(Characteristic.CurrentPosition, newPos) .updateCharacteristic(Characteristic.PositionState, 2); - accessory.context.cacheCurrentPosition = Math.abs(100 - parseInt(params.setclose)); + accessory.context.cacheCurrentPosition = newPos; return; } } catch (err) { @@ -1337,52 +1325,81 @@ class eWeLink { let blindConfig, params = {}, wcService = accessory.getService(Service.WindowCovering), - oldPos = accessory.context.cachePositionState; + prevState = accessory.context.cachePositionState, + prevPos = accessory.context.cacheCurrentPosition, + newTarget = value, + timeNow = Date.now(); if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } if (blindConfig.type !== "blind" || blindConfig.setup !== "twoSwitch") { throw "improper configuration"; } - value = value >= 50 ? 100 : 0; - if (value === oldPos * 100) return; - // target position -> 0 for closed 100 for open (value) - // current position -> 0 going down, 1 going up - accessory.context.cacheCurrentPosition = wcService.getCharacteristic( - Characteristic.CurrentPosition - ).value; - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = value === 100 ? "on" : "off"; - params.switches[1].switch = value === 0 ? "on" : "off"; + if (newTarget === prevPos) return; + params.switches = [ + { + switch: "off", + outlet: 0, + }, + { + switch: "off", + outlet: 1, + }, + { + switch: "off", + outlet: 2, + }, + { + switch: "off", + outlet: 3, + }, + ]; + let logger = str => this.log.warn("[%s] %s.", accessory.displayName, str); + accessory.context.inUse = true; + if (prevState !== 2) { + this.log.warn( + "[%s] tried to move the blinds to [%s%] but they are already moving.", + accessory.displayName, + newTarget + ); + wcService.updateCharacteristic( + Characteristic.TargetPosition, + accessory.context.cacheTargetPosition + ); + return; + } + wcService.updateCharacteristic(Characteristic.TargetPosition, newTarget); + accessory.context.cacheTargetPosition = newTarget; + let moveUp = newTarget > prevPos, + duration = Math.round(Math.abs(newTarget - prevPos) * blindConfig.operationTime); + accessory.context.startTimestamp = timeNow; + accessory.context.targetTimestamp = timeNow + duration; + params.switches[0].switch = moveUp ? "on" : "off"; + params.switches[1].switch = moveUp ? "off" : "on"; this.sendDeviceUpdate(accessory, params) .then(() => { - wcService - .updateCharacteristic(Characteristic.TargetPosition, value) - .updateCharacteristic(Characteristic.PositionState, value / 100); - accessory.context.cachePositionState = value / 100; - accessory.context.cacheTargetPosition = value; - return new Promise(resolve => - setTimeout(resolve, parseInt(blindConfig.operationTime) * 100) - ); + wcService.updateCharacteristic(Characteristic.PositionState, moveUp ? 0 : 1); + accessory.context.cachePositionState = moveUp ? 0 : 1; + return new Promise(resolve => setTimeout(resolve, duration)); }) .then(() => { - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; params.switches[0].switch = "off"; params.switches[1].switch = "off"; return this.sendDeviceUpdate(accessory, params); }) .then(() => { - wcService - .updateCharacteristic(Characteristic.CurrentPosition, value) - .updateCharacteristic(Characteristic.PositionState, 2); + wcService.updateCharacteristic(Characteristic.PositionState, 2); + wcService.updateCharacteristic(Characteristic.CurrentPosition, newTarget); + accessory.context.cacheCurrentPosition = newTarget; accessory.context.cachePositionState = 2; - accessory.context.cacheCurrentPosition = value; + accessory.context.inUse = false; }) .catch(err => { throw err; }); } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + accessory.context.inUse = false; if (accessory.context.reachableWAN) { this.wsClient.requestUpdate(accessory).catch(() => {}); this.log.warn( @@ -1403,6 +1420,20 @@ class eWeLink { if (blindConfig.type !== "blind" || blindConfig.setup !== "twoSwitch") { throw "improper configuration"; } + if (!params.hasOwnProperty("updateSource")) { + wcService + .updateCharacteristic(Characteristic.PositionState, accessory.context.cachePositionState) + .updateCharacteristic( + Characteristic.TargetPosition, + accessory.context.cacheTargetPosition + ) + .updateCharacteristic( + Characteristic.CurrentPosition, + accessory.context.cacheCurrentPosition + ); + return; + } + if (accessory.context.inUse) return; if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { return; } @@ -1440,7 +1471,7 @@ class eWeLink { } let sensorDefinition = garageConfig.sensorId || false, sAccessory = false, - oldPos, + prevState, newPos = value, params = {}, delay = 0, @@ -1451,19 +1482,19 @@ class eWeLink { if (sensorDefinition && sAccessory.context.type !== "sensor") { throw "defined DW2 sensor isn't a sensor"; } - oldPos = sAccessory + prevState = sAccessory ? sAccessory .getService(Service.ContactSensor) .getCharacteristic(Characteristic.ContactSensorState).value === 0 ? 1 : 0 : accessory.context.cacheCurrentDoorState; - if (newPos === oldPos % 2) return; + if (newPos === prevState % 2) return; accessory.context.inUse = true; accessory.context.state = value; - if (garageConfig.setup === "oneSwitch" && [2, 3].includes(oldPos)) { - gdService.updateCharacteristic(Characteristic.CurrentDoorState, ((oldPos * 2) % 3) + 2); - accessory.context.cacheCurrentDoorState = ((oldPos * 2) % 3) + 2; + if (garageConfig.setup === "oneSwitch" && [2, 3].includes(prevState)) { + gdService.updateCharacteristic(Characteristic.CurrentDoorState, ((prevState * 2) % 3) + 2); + accessory.context.cacheCurrentDoorState = ((prevState * 2) % 3) + 2; delay = 1500; } if (accessory.context.state !== newPos) return; @@ -1518,8 +1549,8 @@ class eWeLink { try { let garageConfig, gcService = accessory.getService(Service.GarageDoorOpener), - oldPos = accessory.context.cacheCurrentDoorState, - newPos = [0, 2].includes(oldPos) ? 3 : 2; + prevState = accessory.context.cacheCurrentDoorState, + newPos = [0, 2].includes(prevState) ? 3 : 2; if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } @@ -1541,7 +1572,7 @@ class eWeLink { case "twoSwitch": if ( params.switches[0].switch === params.switches[1].switch || - params.switches[oldPos % 2].switch === "on" + params.switches[prevState % 2].switch === "on" ) { return; } @@ -2639,6 +2670,5 @@ module.exports = function (homebridge) { EveService = new hbLib.EveHomeKitTypes(homebridge); EveHistoryService = fakegato(homebridge); Service = homebridge.hap.Service; - UUIDGen = homebridge.hap.uuid; return eWeLink; }; diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 68aa7eb7..56a983ec 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -125,7 +125,7 @@ module.exports = class eWeLinkLAN { sendUpdate(json) { return new Promise((resolve, reject) => { if (!this.deviceMap.get(json.deviceid).online) { - reject("device isn't reachable by LAN mode"); + throw "device isn't reachable by LAN mode"; } let apiKey, suffix, @@ -137,9 +137,7 @@ module.exports = class eWeLinkLAN { params.switch = json.params.switch; suffix = "switch"; } else { - reject( - "plugin does not support lan mode for this device yet - feel free to create a github issue" - ); + throw "plugin does not support lan mode for this device yet - feel free to create a github issue"; } if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { let key = crypto.createHash("md5").update(Buffer.from(apiKey, "utf8")).digest(), diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index e99df8fd..6f30b2ea 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -207,18 +207,18 @@ module.exports = class eWeLinkWS { } sendUpdate(json) { return new Promise((resolve, reject) => { - let sequence = Math.floor(new Date()).toString(); - json = { - ...json, - ...{ - action: "update", - sequence, - userAgent: "app", - }, - }; - let sendOperation = () => { + let sequence = Math.floor(new Date()).toString(), + jsonToSend = { + ...json, + ...{ + action: "update", + sequence, + userAgent: "app", + }, + }; + if (this.wsp && this.wsIsOpen) { this.wsp - .sendRequest(json, { + .sendRequest(jsonToSend, { requestId: sequence, }) .then(device => { @@ -236,26 +236,19 @@ module.exports = class eWeLinkWS { case 0: resolve(); break; - case 504: default: throw "Unknown response"; } }) .catch(err => reject("Device update failed [" + err + "].")); - }; - let checkToSend = () => { - if (this.wsp && this.wsIsOpen) { - sendOperation(); - } else { - this.delay(2500).then(() => { - if (this.debug) { - this.log.warn("Will resend command when WS is reconnected."); - } - checkToSend(); - }); - } - }; - checkToSend(); + } else { + this.delay(2500).then(() => { + if (this.debug) { + this.log.warn("Will resend command when WS is reconnected."); + } + resolve(this.sendUpdate(json)); + }); + } }); } requestUpdate(accessory) { From ea8ae45de9cc50a5a9f3d51dac4667dd639ac79c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 24 Sep 2020 14:30:38 +0100 Subject: [PATCH 0207/3183] 3.0.1-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4b4267f1..1ec031ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.1-0", + "version": "3.0.1-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f8f82af6..f5a71fc9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.1-0", + "version": "3.0.1-1", "author": "bwp91", "contributors": [ "gbro115", From 622ce4a1df1330f8a33340f8d50a4bcb9486b3fc Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 24 Sep 2020 17:10:29 +0100 Subject: [PATCH 0208/3183] fixing broken promises --- lib/eWeLink.js | 98 ++++++++++++++++++++++------------------------ lib/eWeLinkHTTP.js | 32 +++++++++------ lib/eWeLinkLAN.js | 4 +- 3 files changed, 67 insertions(+), 67 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 9b29b4da..db8502ed 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -59,9 +59,7 @@ class eWeLink { this.wsClient .getHost() .then(() => this.wsClient.closeConnection()) - .then(() => { - return new Promise(resolve => setTimeout(resolve, 250)); - }) + .then(() => Promise(resolve => setTimeout(resolve, 250))) .then(() => this.wsClient.login()) .catch(err => this.log.warn(err)); } @@ -1081,24 +1079,22 @@ class eWeLink { params, }, delayPromise = new Promise(resolve => setTimeout(resolve, Math.random() * 100 + 200)); - delayPromise.then(() => { - this.lanClient - .sendUpdate(payload) - .then(() => resolve()) - .catch(err => { + delayPromise + .then(() => this.lanClient.sendUpdate(payload)) + .then(() => resolve()) + .catch(err => { + if (accessory.context.reachableWAN) { if (this.debug) { this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); } - if (accessory.context.reachableWAN) { - this.wsClient - .sendUpdate(payload) - .then(() => resolve()) - .catch(err => reject(err)); - } else { - reject("it is unreachable"); - } - }); - }); + this.wsClient + .sendUpdate(payload) + .then(() => resolve()) + .catch(err => reject(err)); + } else { + reject("it is unreachable"); + } + }); }); } receiveDeviceUpdate(device) { @@ -1518,11 +1514,9 @@ class eWeLink { } return this.sendDeviceUpdate(accessory, params); }) - .then(() => { - return new Promise(resolve => - setTimeout(resolve, parseInt(garageConfig.operationTime) * 100) - ); - }) + .then(() => + Promise(resolve => setTimeout(resolve, parseInt(garageConfig.operationTime) * 100)) + ) .then(() => { if (!sAccessory) { gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos); @@ -2129,19 +2123,19 @@ class eWeLink { break; } } - setTimeout(() => { - this.sendDeviceUpdate(accessory, params) - .then(() => { - if (value === 0) { - lightService.updateCharacteristic(Characteristic.On, false); - } else { - lightService.updateCharacteristic(Characteristic.Brightness, value); - } - }) - .catch(err => { - throw err; - }); - }, 250); + let delayPromise = new Promise(resolve => setTimeout(resolve, 250)); + delayPromise + .then(() => this.sendDeviceUpdate(accessory, params)) + .then(() => { + if (value === 0) { + lightService.updateCharacteristic(Characteristic.On, false); + } else { + lightService.updateCharacteristic(Characteristic.Brightness, value); + } + }) + .catch(err => { + throw err; + }); } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); if (accessory.context.reachableWAN) { @@ -2212,22 +2206,22 @@ class eWeLink { } break; } - setTimeout(() => { - this.sendDeviceUpdate(accessory, params) - .then(() => { - switch (type) { - case "hue": - lightService.updateCharacteristic(Characteristic.Hue, value); - break; - case "bri": - lightService.updateCharacteristic(Characteristic.Brightness, value); - break; - } - }) - .catch(err => { - throw err; - }); - }, 250); + let delayPromise = new Promise(resolve => setTimeout(resolve, 250)); + delayPromise + .then(() => this.sendDeviceUpdate(accessory, params)) + .then(() => { + switch (type) { + case "hue": + lightService.updateCharacteristic(Characteristic.Hue, value); + break; + case "bri": + lightService.updateCharacteristic(Characteristic.Brightness, value); + break; + } + }) + .catch(err => { + throw err; + }); } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); if (accessory.context.reachableWAN) { diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index beb48f3b..36d099cf 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -78,7 +78,7 @@ module.exports = class eWeLinkHTTP { err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT", "EAI_AGAIN"].includes(err.code) ) { - this.log.warn("Unable to reach eWeLink. Retrying in 15 seconds."); + this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); this.delay().then(() => resolve(this.getHost())); } else { reject(err.message || err); @@ -144,16 +144,22 @@ module.exports = class eWeLinkHTTP { resolve(this.login()); return; } - if (!body.data.at) { - throw "No auth token received.\n" + JSON.stringify(body, null, 2); + if (body.data.at) { + this.aToken = body.data.at; + this.apiKey = body.data.user.apikey; + resolve({ + aToken: this.aToken, + apiKey: this.apiKey, + httpHost: this.httpHost, + }); + } else { + if (body.error === 500) { + this.log.warn("An eWeLink error [500] occured. Retrying in 30 seconds."); + this.delay().then(() => resolve(this.login())); + } else { + throw "No auth token received.\n" + JSON.stringify(body, null, 2); + } } - this.aToken = body.data.at; - this.apiKey = body.data.user.apikey; - resolve({ - aToken: this.aToken, - apiKey: this.apiKey, - httpHost: this.httpHost, - }); }) .catch(err => reject(err.message || err)); }); @@ -190,7 +196,7 @@ module.exports = class eWeLinkHTTP { }) .catch(err => { if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { - this.log.warn("Unable to reach eWeLink. Retrying in 15 seconds."); + this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); this.delay().then(() => resolve(this.getDevices())); } else { reject(err.message || err); @@ -238,7 +244,7 @@ module.exports = class eWeLinkHTTP { }) .catch(err => { if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { - this.log.warn("Unable to reach eWeLink. Retrying in 15 seconds."); + this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); this.delay().then(() => resolve(this.getDevice(deviceId))); } else { reject(err.message || err); @@ -247,6 +253,6 @@ module.exports = class eWeLinkHTTP { }); } delay() { - return new Promise(resolve => setTimeout(resolve, 15000)); + return new Promise(resolve => setTimeout(resolve, 30000)); } }; diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 56a983ec..647e2c1c 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -125,7 +125,7 @@ module.exports = class eWeLinkLAN { sendUpdate(json) { return new Promise((resolve, reject) => { if (!this.deviceMap.get(json.deviceid).online) { - throw "device isn't reachable by LAN mode"; + throw "device isn't reachable via LAN mode"; } let apiKey, suffix, @@ -137,7 +137,7 @@ module.exports = class eWeLinkLAN { params.switch = json.params.switch; suffix = "switch"; } else { - throw "plugin does not support lan mode for this device yet - feel free to create a github issue"; + throw "device isn't reachable via LAN mode"; } if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { let key = crypto.createHash("md5").update(Buffer.from(apiKey, "utf8")).digest(), From fa841abb6dfdd224b7216725b6bc3b2e951f0913 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 24 Sep 2020 17:11:49 +0100 Subject: [PATCH 0209/3183] 3.0.1-2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1ec031ed..88ddc263 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.1-1", + "version": "3.0.1-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f5a71fc9..91e793dc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.1-1", + "version": "3.0.1-2", "author": "bwp91", "contributors": [ "gbro115", From b6f81f48cd3f5cf652854f64c4d04964c399b65b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 24 Sep 2020 19:36:08 +0100 Subject: [PATCH 0210/3183] promises --- lib/constants.js | 2 +- lib/eWeLink.js | 170 +++++++++++++++++++++++++---------------------- lib/eWeLinkWS.js | 2 +- 3 files changed, 91 insertions(+), 83 deletions(-) diff --git a/lib/constants.js b/lib/constants.js index 75bdeaf1..9e1ce0d4 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -9,7 +9,7 @@ module.exports = { devicesNonLAN: [22, 28, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], devicesSingleSwitchParams: ["switch"], - devicesSingleSwitchOutlet: ["Sonoff Pow"], + devicesSingleSwitchOutlet: ["Sonoff Pow", "S26"], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], devicesMultiSwitchParams: ["switches"], devicesSingleSwitchLight: [ diff --git a/lib/eWeLink.js b/lib/eWeLink.js index db8502ed..08ece724 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -59,7 +59,7 @@ class eWeLink { this.wsClient .getHost() .then(() => this.wsClient.closeConnection()) - .then(() => Promise(resolve => setTimeout(resolve, 250))) + .then(() => new Promise(resolve => setTimeout(resolve, 250))) .then(() => this.wsClient.login()) .catch(err => this.log.warn(err)); } @@ -686,92 +686,96 @@ class eWeLink { if (!(outletService = accessory.getService(Service.Outlet))) { accessory.addService(Service.Outlet); outletService = accessory.getService(Service.Outlet); - outletService.addCharacteristic(EveService.Characteristics.Voltage); - outletService.addCharacteristic(EveService.Characteristics.CurrentConsumption); - outletService.addCharacteristic(EveService.Characteristics.ElectricCurrent); - outletService.addCharacteristic(EveService.Characteristics.TotalConsumption); - outletService.addCharacteristic(EveService.Characteristics.ResetTotal); - accessory.context = { - ...accessory.context, - ...{ - extraPersistedData: {}, - lastReset: 0, - totalEnergy: 0, - totalEnergyTemp: 0, - }, - }; + if (accessory.context.eweModel !== "S26" && !(this.config.disableEveLogging || false)) { + outletService.addCharacteristic(EveService.Characteristics.Voltage); + outletService.addCharacteristic(EveService.Characteristics.CurrentConsumption); + outletService.addCharacteristic(EveService.Characteristics.ElectricCurrent); + outletService.addCharacteristic(EveService.Characteristics.TotalConsumption); + outletService.addCharacteristic(EveService.Characteristics.ResetTotal); + accessory.context = { + ...accessory.context, + ...{ + extraPersistedData: {}, + lastReset: 0, + totalEnergy: 0, + totalEnergyTemp: 0, + }, + }; + } } outletService .getCharacteristic(Characteristic.On) .on("set", (value, callback) => this.internalOutletUpdate(accessory, value, callback)); - accessory.log = this.log; - accessory.eveLogger = new EveHistoryService("energy", accessory, { - storage: "fs", - minutes: 5, - path: this.eveLogPath, - }); - corrInterval.setCorrectingInterval(() => { - let isOn = outletService.getCharacteristic(Characteristic.On).value, - currentWatt = isOn - ? outletService.getCharacteristic(EveService.Characteristics.CurrentConsumption) - .value - : 0; - if (accessory.eveLogger.isHistoryLoaded()) { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalEnergy = - accessory.context.extraPersistedData.totalenergy + - accessory.context.totalEnergyTemp + - (currentWatt * 10) / 3600 / 1000; - accessory.eveLogger.setExtraPersistedData({ - totalenergy: accessory.context.totalEnergy, - lastReset: accessory.context.extraPersistedData.lastReset, - }); + if (accessory.context.eweModel !== "S26" && !(this.config.disableEveLogging || false)) { + accessory.log = this.log; + accessory.eveLogger = new EveHistoryService("energy", accessory, { + storage: "fs", + minutes: 5, + path: this.eveLogPath, + }); + corrInterval.setCorrectingInterval(() => { + let isOn = outletService.getCharacteristic(Characteristic.On).value, + currentWatt = isOn + ? outletService.getCharacteristic(EveService.Characteristics.CurrentConsumption) + .value + : 0; + if (accessory.eveLogger.isHistoryLoaded()) { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.totalEnergy = + accessory.context.extraPersistedData.totalenergy + + accessory.context.totalEnergyTemp + + (currentWatt * 10) / 3600 / 1000; + accessory.eveLogger.setExtraPersistedData({ + totalenergy: accessory.context.totalEnergy, + lastReset: accessory.context.extraPersistedData.lastReset, + }); + } else { + accessory.context.totalEnergy = + accessory.context.totalEnergyTemp + (currentWatt * 10) / 3600 / 1000; + accessory.eveLogger.setExtraPersistedData({ + totalenergy: accessory.context.totalEnergy, + lastReset: 0, + }); + } + accessory.context.totalEnergytemp = 0; } else { - accessory.context.totalEnergy = - accessory.context.totalEnergyTemp + (currentWatt * 10) / 3600 / 1000; + accessory.context.totalEnergyTemp += (currentWatt * 10) / 3600 / 1000; + accessory.context.totalEnergy = accessory.context.totalEnergyTemp; + } + accessory.eveLogger.addEntry({ + time: Date.now(), + power: currentWatt, + }); + }, 300000); + outletService + .getCharacteristic(EveService.Characteristics.TotalConsumption) + .on("get", callback => { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower; + } + callback(null, accessory.context.totalEnergy); + }); + outletService + .getCharacteristic(EveService.Characteristics.ResetTotal) + .on("set", (value, callback) => { + accessory.context.totalEnergy = 0; + accessory.context.lastReset = value; accessory.eveLogger.setExtraPersistedData({ - totalenergy: accessory.context.totalEnergy, - lastReset: 0, + totalPower: 0, + lastReset: value, }); - } - accessory.context.totalEnergytemp = 0; - } else { - accessory.context.totalEnergyTemp += (currentWatt * 10) / 3600 / 1000; - accessory.context.totalEnergy = accessory.context.totalEnergyTemp; - } - accessory.eveLogger.addEntry({ - time: Date.now(), - power: currentWatt, - }); - }, 300000); - outletService - .getCharacteristic(EveService.Characteristics.TotalConsumption) - .on("get", callback => { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower; - } - callback(null, accessory.context.totalEnergy); - }); - outletService - .getCharacteristic(EveService.Characteristics.ResetTotal) - .on("set", (value, callback) => { - accessory.context.totalEnergy = 0; - accessory.context.lastReset = value; - accessory.eveLogger.setExtraPersistedData({ - totalPower: 0, - lastReset: value, + callback(); + }) + .on("get", callback => { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.lastReset = accessory.context.extraPersistedData.lastReset; + } + callback(null, accessory.context.lastReset); }); - callback(); - }) - .on("get", callback => { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.lastReset = accessory.context.extraPersistedData.lastReset; - } - callback(null, accessory.context.lastReset); - }); + } break; case "usb": let usbService = @@ -1514,8 +1518,9 @@ class eWeLink { } return this.sendDeviceUpdate(accessory, params); }) - .then(() => - Promise(resolve => setTimeout(resolve, parseInt(garageConfig.operationTime) * 100)) + .then( + () => + new Promise(resolve => setTimeout(resolve, parseInt(garageConfig.operationTime) * 100)) ) .then(() => { if (!sAccessory) { @@ -1904,6 +1909,9 @@ class eWeLink { let outletService = accessory.getService(Service.Outlet); if (params.hasOwnProperty("switch")) { outletService.updateCharacteristic(Characteristic.On, params.switch === "on"); + if (accessory.context.eweModel === "S26" || this.config.disableEveLogging || false) { + outletService.updateCharacteristic(Characteristic.OutletInUse, params.switch === "on"); + } } if (params.hasOwnProperty("power")) { outletService.updateCharacteristic( diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 6f30b2ea..bdfae75d 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -237,7 +237,7 @@ module.exports = class eWeLinkWS { resolve(); break; default: - throw "Unknown response"; + reject("Unknown response"); } }) .catch(err => reject("Device update failed [" + err + "].")); From 68a1cd2e04e02e7b919e93bb2cdd4c64b22cb530 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 25 Sep 2020 05:48:34 +0100 Subject: [PATCH 0211/3183] Update eWeLinkLAN.js --- lib/eWeLinkLAN.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 647e2c1c..09c6f749 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -174,8 +174,9 @@ module.exports = class eWeLinkLAN { .then(res => { if (res.data.hasOwnProperty("error") && res.data.error === 0) { resolve(); + } else { + throw res.data; } - reject(res.data); }) .catch(err => reject(err)); } From 92005bcec9cbfb121f1d8eb6927b4b7179192a18 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 25 Sep 2020 05:48:37 +0100 Subject: [PATCH 0212/3183] Update eWeLinkWS.js --- lib/eWeLinkWS.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index bdfae75d..6f30b2ea 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -237,7 +237,7 @@ module.exports = class eWeLinkWS { resolve(); break; default: - reject("Unknown response"); + throw "Unknown response"; } }) .catch(err => reject("Device update failed [" + err + "].")); From aa319b12a02da919af83ae6bf93667b7116b2012 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 25 Sep 2020 06:12:46 +0100 Subject: [PATCH 0213/3183] Create discord.md --- lib/discord.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 lib/discord.md diff --git a/lib/discord.md b/lib/discord.md new file mode 100644 index 00000000..c53fcd66 --- /dev/null +++ b/lib/discord.md @@ -0,0 +1,26 @@ +Situation: I am trying to control a smart plug which itself is not plugged in. +`Characteristic.On` calls `internalOutletUpdate()` for it's `.on("set")` event. +When trying to turn the outlet on I receive the warning at the end of this file. + + +Code can be seen at: +https://github.com/bwp91/homebridge-ewelink/tree/master/lib + +In a nutshell: + +* /eWeLink.js line 1078 `internalOutletUpdate()`, which calls +* /eWeLink.js line 1310 `sendDeviceUpdate()`, which calls + * /eWeLinkLAN.js line 125 `sendUpdate()`, and if this fails, + * /eWeLinkWS.js line 208 `sendUpdate()` + +``` +(node:1229) UnhandledPromiseRejectionWarning: it is unreachable + at emitUnhandledRejectionWarning (internal/process/promises.js:170:15) + at processPromiseRejections (internal/process/promises.js:247:11) + at processTicksAndRejections (internal/process/task_queues.js:94:32) +(node:1229) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 3) +(node:1229) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. + at emitDeprecationWarning (internal/process/promises.js:180:11) + at processPromiseRejections (internal/process/promises.js:249:13) + at processTicksAndRejections (internal/process/task_queues.js:94:32) +``` From 93861cae2fa9a97ff780145508c9168e32b1c485 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 25 Sep 2020 10:29:40 +0100 Subject: [PATCH 0214/3183] fix catch errors --- lib/eWeLink.js | 210 ++++++++++--------------------------------------- 1 file changed, 41 insertions(+), 169 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 08ece724..1edf88c3 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1096,7 +1096,7 @@ class eWeLink { .then(() => resolve()) .catch(err => reject(err)); } else { - reject("it is unreachable"); + reject("it is unreachable. I's status will be corrected once it is reachable"); } }); }); @@ -1183,6 +1183,16 @@ class eWeLink { } } } + requestDeviceRefresh(accessory, err) { + this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + if (accessory.context.reachableWAN) { + this.wsClient.requestUpdate(accessory).catch(() => {}); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName + ); + } + } internalValveUpdate(accessory, valve, value, callback) { callback(); try { @@ -1229,18 +1239,9 @@ class eWeLink { break; } }) - .catch(err => { - throw err; - }); + .catch(err => this.requestDeviceRefresh(accessory, err)); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory).catch(() => {}); - this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", - accessory.displayName - ); - } + this.requestDeviceRefresh(accessory, err); } } externalValveUpdate(accessory, params) { @@ -1289,18 +1290,9 @@ class eWeLink { .updateCharacteristic(Characteristic.PositionState, newPos > prevPos ? 1 : 0); accessory.context.cacheCurrentPosition = newPos; }) - .catch(err => { - throw err; - }); + .catch(err => this.requestDeviceRefresh(accessory, err)); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory).catch(() => {}); - this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", - accessory.displayName - ); - } + this.requestDeviceRefresh(accessory, err); } } externalCurtainUpdate(accessory, params) { @@ -1394,19 +1386,9 @@ class eWeLink { accessory.context.cachePositionState = 2; accessory.context.inUse = false; }) - .catch(err => { - throw err; - }); + .catch(err => this.requestDeviceRefresh(accessory, err)); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - accessory.context.inUse = false; - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory).catch(() => {}); - this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", - accessory.displayName - ); - } + this.requestDeviceRefresh(accessory, err); } } externalBlindUpdate(accessory, params) { @@ -1529,19 +1511,9 @@ class eWeLink { } accessory.context.inUse = false; }) - .catch(err => { - throw err; - }); + .catch(err => this.requestDeviceRefresh(accessory, err)); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - accessory.context.inUse = false; - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory).catch(() => {}); - this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", - accessory.displayName - ); - } + this.requestDeviceRefresh(accessory, err); } } externalGarageUpdate(accessory, params) { @@ -1624,19 +1596,9 @@ class eWeLink { accessory.context.inUse = false; }, parseInt(lockConfig.operationTime) * 100); }) - .catch(err => { - throw err; - }); + .catch(err => this.requestDeviceRefresh(accessory, err)); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - accessory.context.inUse = false; - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory).catch(() => {}); - this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", - accessory.displayName - ); - } + this.requestDeviceRefresh(accessory, err); } } externalLockUpdate(accessory, params) { @@ -1751,18 +1713,9 @@ class eWeLink { .updateCharacteristic(Characteristic.Active, newPower) .updateCharacteristic(Characteristic.RotationSpeed, newSpeed); }) - .catch(err => { - throw err; - }); + .catch(err => this.requestDeviceRefresh(accessory, err)); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory).catch(() => {}); - this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", - accessory.displayName - ); - } + this.requestDeviceRefresh(accessory, err); } } externalFanUpdate(accessory, params) { @@ -1822,18 +1775,9 @@ class eWeLink { .then(() => { switchService.updateCharacteristic(Characteristic.On, value); }) - .catch(err => { - throw err; - }); + .catch(err => this.requestDeviceRefresh(accessory, err)); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory).catch(() => {}); - this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", - accessory.displayName - ); - } + this.requestDeviceRefresh(accessory, err); } } externalThermostatUpdate(accessory, params) { @@ -1890,18 +1834,9 @@ class eWeLink { .then(() => { outletService.updateCharacteristic(Characteristic.On, value); }) - .catch(err => { - throw err; - }); + .catch(err => this.requestDeviceRefresh(accessory, err)); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory).catch(() => {}); - this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", - accessory.displayName - ); - } + this.requestDeviceRefresh(accessory, err); } } externalOutletUpdate(accessory, params) { @@ -1956,18 +1891,9 @@ class eWeLink { .then(() => { outletService.updateCharacteristic(Characteristic.On, value); }) - .catch(err => { - throw err; - }); + .catch(err => this.requestDeviceRefresh(accessory, err)); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory).catch(() => {}); - this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", - accessory.displayName - ); - } + this.requestDeviceRefresh(accessory, err); } } externalUSBUpdate(accessory, params) { @@ -1991,18 +1917,9 @@ class eWeLink { .then(() => { switchService.updateCharacteristic(Characteristic.On, value); }) - .catch(err => { - throw err; - }); + .catch(err => this.requestDeviceRefresh(accessory, err)); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory).catch(() => {}); - this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", - accessory.displayName - ); - } + this.requestDeviceRefresh(accessory, err); } } externalSCMUpdate(accessory, params) { @@ -2096,18 +2013,9 @@ class eWeLink { break; } }) - .catch(err => { - throw err; - }); + .catch(err => this.requestDeviceRefresh(accessory, err)); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory).catch(() => {}); - this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", - accessory.displayName - ); - } + this.requestDeviceRefresh(accessory, err); } } internalBrightnessUpdate(accessory, value, callback) { @@ -2141,18 +2049,9 @@ class eWeLink { lightService.updateCharacteristic(Characteristic.Brightness, value); } }) - .catch(err => { - throw err; - }); + .catch(err => this.requestDeviceRefresh(accessory, err)); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory).catch(() => {}); - this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", - accessory.displayName - ); - } + this.requestDeviceRefresh(accessory, err); } } internalHSBUpdate(accessory, type, value, callback) { @@ -2227,18 +2126,9 @@ class eWeLink { break; } }) - .catch(err => { - throw err; - }); + .catch(err => this.requestDeviceRefresh(accessory, err)); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory).catch(() => {}); - this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", - accessory.displayName - ); - } + this.requestDeviceRefresh(accessory, err); } } externalSingleLightUpdate(accessory, params) { @@ -2415,18 +2305,9 @@ class eWeLink { break; } }) - .catch(err => { - throw err; - }); + .catch(err => this.requestDeviceRefresh(accessory, err)); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory).catch(() => {}); - this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", - accessory.displayName - ); - } + this.requestDeviceRefresh(accessory, err); } } externalSingleSwitchUpdate(accessory, params) { @@ -2473,18 +2354,9 @@ class eWeLink { rfService.updateCharacteristic(Characteristic.On, true); setTimeout(() => rfService.updateCharacteristic(Characteristic.On, false), 3000); }) - .catch(err => { - throw err; - }); + .catch(err => this.requestDeviceRefresh(accessory, err)); } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory).catch(() => {}); - this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", - accessory.displayName - ); - } + this.requestDeviceRefresh(accessory, err); } } externalRFUpdate(accessory, params) { From 56d51191ee3b7085fd669f86bce8263a6450e156 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 25 Sep 2020 10:35:44 +0100 Subject: [PATCH 0215/3183] 3.0.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 88ddc263..24611c34 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.1-2", + "version": "3.0.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 91e793dc..82cf0b07 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.1-2", + "version": "3.0.1", "author": "bwp91", "contributors": [ "gbro115", From b206f415ffe4adb4904b642e7b32b685bd9e41e0 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 25 Sep 2020 14:45:56 +0100 Subject: [PATCH 0216/3183] async/awaits --- lib/discord.md | 26 -- lib/eWeLink.js | 751 +++++++++++++++++++++------------------------ lib/eWeLinkHTTP.js | 348 +++++++++++---------- lib/eWeLinkLAN.js | 158 +++++----- lib/eWeLinkWS.js | 196 ++++++------ lib/utils.js | 7 + package-lock.json | 5 + package.json | 1 + 8 files changed, 706 insertions(+), 786 deletions(-) delete mode 100644 lib/discord.md create mode 100644 lib/utils.js diff --git a/lib/discord.md b/lib/discord.md deleted file mode 100644 index c53fcd66..00000000 --- a/lib/discord.md +++ /dev/null @@ -1,26 +0,0 @@ -Situation: I am trying to control a smart plug which itself is not plugged in. -`Characteristic.On` calls `internalOutletUpdate()` for it's `.on("set")` event. -When trying to turn the outlet on I receive the warning at the end of this file. - - -Code can be seen at: -https://github.com/bwp91/homebridge-ewelink/tree/master/lib - -In a nutshell: - -* /eWeLink.js line 1078 `internalOutletUpdate()`, which calls -* /eWeLink.js line 1310 `sendDeviceUpdate()`, which calls - * /eWeLinkLAN.js line 125 `sendUpdate()`, and if this fails, - * /eWeLinkWS.js line 208 `sendUpdate()` - -``` -(node:1229) UnhandledPromiseRejectionWarning: it is unreachable - at emitUnhandledRejectionWarning (internal/process/promises.js:170:15) - at processPromiseRejections (internal/process/promises.js:247:11) - at processTicksAndRejections (internal/process/task_queues.js:94:32) -(node:1229) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 3) -(node:1229) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. - at emitDeprecationWarning (internal/process/promises.js:180:11) - at processPromiseRejections (internal/process/promises.js:249:13) - at processTicksAndRejections (internal/process/task_queues.js:94:32) -``` diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 1edf88c3..d66cbdaf 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -8,7 +8,9 @@ const cns = require("./constants"), eWeLinkWS = require("./eWeLinkWS"), eWeLinkLAN = require("./eWeLinkLAN"), fakegato = require("fakegato-history"), - hbLib = require("homebridge-lib"); + hbLib = require("homebridge-lib"), + promInterval = require("interval-promise"), + utils = require("./utils"); class eWeLink { constructor(log, config, api) { if (!log || !api || !config) return; @@ -28,89 +30,89 @@ class eWeLink { this.cusS = new Map(); this.hiddenMasters = []; this.eveLogPath = this.api.user.storagePath() + "/homebridge-ewelink/"; + this.wsRefreshFlag = true; this.api .on("didFinishLaunching", () => this.eWeLinkSync()) .on("shutdown", () => { if (this.lanClient) this.lanClient.closeConnection(); if (this.wsClient) this.wsClient.closeConnection(); - if (this.wsRefresh) clearInterval(this.wsRefresh); + this.wsRefreshFlag = false; }); } - eWeLinkSync() { - this.log("Plugin has finished initialising. Synching with eWeLink."); - this.httpClient = new eWeLinkHTTP(this.config, this.log); - this.httpClient - .getHost() - .then(() => this.httpClient.login()) - .then(res => { - this.authData = res; - return this.httpClient.getDevices(); - }) - .then(res => { - res.forEach(device => this.devicesInEW.set(device.deviceid, device)); - this.wsClient = new eWeLinkWS(this.config, this.log, this.authData); - this.lanClient = new eWeLinkLAN(this.config, this.log, res); - return this.wsClient.getHost(); - }) - .then(() => { - this.wsClient.login(); - this.wsRefresh = setInterval(() => { - if (this.wsClient) { - this.wsClient - .getHost() - .then(() => this.wsClient.closeConnection()) - .then(() => new Promise(resolve => setTimeout(resolve, 250))) - .then(() => this.wsClient.login()) - .catch(err => this.log.warn(err)); - } - }, 1800000); - return this.lanClient.getHosts(); - }) - .then(res => { - this.lanDevices = res; - return this.lanClient.startMonitor(); - }) - .then(() => { - (() => { - //*** Make a map of custom groups from Homebridge config ***\\ - if (Object.keys(this.config.groups || []).length > 0) { - this.config.groups - .filter(g => g.hasOwnProperty("type") && cns.allowedGroups.includes(g.type)) - .filter(g => g.hasOwnProperty("deviceId") && this.devicesInEW.has(g.deviceId)) - .forEach(g => this.cusG.set(g.deviceId + "SWX", g)); - } - //*** Make a map of RF Bridge custom sensors from Homebridge config ***\\ - if (Object.keys(this.config.bridgeSensors || []).length > 0) { - this.config.bridgeSensors - .filter(s => s.hasOwnProperty("deviceId") && this.devicesInEW.has(s.deviceId)) - .forEach(s => this.cusS.set(s.fullDeviceId, s)); + async eWeLinkSync() { + try { + this.log("Plugin has finished initialising. Synching with eWeLink."); + this.httpClient = new eWeLinkHTTP(this.config, this.log); + await this.httpClient.getHost(); + this.authData = await this.httpClient.login(); + let deviceList = await this.httpClient.getDevices(); + deviceList.forEach(device => this.devicesInEW.set(device.deviceid, device)); + this.wsClient = new eWeLinkWS(this.config, this.log, this.authData); + this.lanClient = new eWeLinkLAN(this.config, this.log, deviceList); + await this.wsClient.getHost(); + this.wsClient.login(); + this.lanDevices = await this.lanClient.getHosts(); + await this.lanClient.startMonitor(); + (() => { + //*** Make a map of custom groups from Homebridge config ***\\ + if (Object.keys(this.config.groups || []).length > 0) { + this.config.groups + .filter(g => g.hasOwnProperty("type") && cns.allowedGroups.includes(g.type)) + .filter(g => g.hasOwnProperty("deviceId") && this.devicesInEW.has(g.deviceId)) + .forEach(g => this.cusG.set(g.deviceId + "SWX", g)); + } + //*** Make a map of RF Bridge custom sensors from Homebridge config ***\\ + if (Object.keys(this.config.bridgeSensors || []).length > 0) { + this.config.bridgeSensors + .filter(s => s.hasOwnProperty("deviceId") && this.devicesInEW.has(s.deviceId)) + .forEach(s => this.cusS.set(s.fullDeviceId, s)); + } + //*** Logging always helps to see if everything is okay so far ***\\ + this.log("[%s] eWeLink devices loaded from the Homebridge cache.", this.devicesInHB.size); + this.log("[%s] primary devices loaded from your eWeLink account.", this.devicesInEW.size); + //*** Remove Homebridge accessories that don't appear in eWeLink ***\\ + this.devicesInHB.forEach(a => { + if (!this.devicesInEW.has(a.context.eweDeviceId)) { + this.removeAccessory(a); } - //*** Logging always helps to see if everything is okay so far ***\\ - this.log("[%s] eWeLink devices loaded from the Homebridge cache.", this.devicesInHB.size); - this.log("[%s] primary devices loaded from your eWeLink account.", this.devicesInEW.size); - //*** Remove Homebridge accessories that don't appear in eWeLink ***\\ - this.devicesInHB.forEach(a => { - if (!this.devicesInEW.has(a.context.eweDeviceId)) { - this.removeAccessory(a); + }); + //*** Synchronise devices between eWeLink and Homebridge and set up ws/lan listeners ***\\ + this.devicesInEW.forEach(d => this.initialiseDevice(d)); + this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); + this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); + this.wsRefresh = promInterval( + async () => { + if (this.wsRefreshFlag) { + try { + if (this.wsClient) { + await this.wsClient.getHost(); + await this.wsClient.closeConnection(); + await utils.sleep(250); + await this.wsClient.login(); + } + } catch (err) { + this.log.warn(err); + } } - }); - //*** Synchronise devices between eWeLink and Homebridge and set up ws/lan listeners ***\\ - this.devicesInEW.forEach(d => this.initialiseDevice(d)); - this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); - this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); - this.log("eWeLink sync complete. Don't forget to ⭐ī¸ this plugin on GitHub!"); - if (this.config.debugReqRes || false) { - this.log.warn("Note: 'Request & Response Logging' is not advised for long-term use."); + }, + 1800000, + { + stopOnError: false, } - })(); - }) - .catch(err => { - this.log.error("************** Cannot load homebridge-ewelink **************"); - this.log.error(err); - this.log.error("************************************************************"); - if (this.lanClient) this.lanClient.closeConnection(); - if (this.wsClient) this.wsClient.closeConnection(); - }); + ); + this.log("eWeLink sync complete. Don't forget to ⭐ī¸ this plugin on GitHub!"); + if (this.config.debugReqRes || false) { + this.log.warn("Note: 'Request & Response Logging' is not advised for long-term use."); + } + })(); + } catch (err) { + this.log.error("************** Cannot load homebridge-ewelink **************"); + this.log.error(err); + this.log.error("************************************************************"); + if (this.lanClient) this.lanClient.closeConnection(); + if (this.wsClient) this.wsClient.closeConnection(); + this.wsRefreshFlag = false; + } } initialiseDevice(device) { let accessory; @@ -664,22 +666,24 @@ class eWeLink { this.internalThermostatUpdate(accessory, value, callback) ); } - accessory.log = this.log; - accessory.eveLogger = new EveHistoryService("weather", accessory, { - storage: "fs", - minutes: 5, - path: this.eveLogPath, - }); - corrInterval.setCorrectingInterval(() => { - let dataToAdd = { - time: Date.now(), - temp: tempService.getCharacteristic(Characteristic.CurrentTemperature).value, - }; - if (humiService) { - humiService.getCharacteristic(Characteristic.CurrentRelativeHumidity).value; - } - accessory.eveLogger.addEntry(dataToAdd); - }, 300000); + if (!(this.config.disableEveLogging || false)) { + accessory.log = this.log; + accessory.eveLogger = new EveHistoryService("weather", accessory, { + storage: "fs", + minutes: 5, + path: this.eveLogPath, + }); + corrInterval.setCorrectingInterval(() => { + let dataToAdd = { + time: Date.now(), + temp: tempService.getCharacteristic(Characteristic.CurrentTemperature).value, + }; + if (humiService) { + humiService.getCharacteristic(Characteristic.CurrentRelativeHumidity).value; + } + accessory.eveLogger.addEntry(dataToAdd); + }, 300000); + } break; case "outlet": let outletService; @@ -1076,32 +1080,34 @@ class eWeLink { } } sendDeviceUpdate(accessory, params) { - return new Promise((resolve, reject) => { + return new Promise(async (resolve, reject) => { let payload = { - apikey: accessory.context.eweApiKey, - deviceid: accessory.context.eweDeviceId, - params, - }, - delayPromise = new Promise(resolve => setTimeout(resolve, Math.random() * 100 + 200)); - delayPromise - .then(() => this.lanClient.sendUpdate(payload)) - .then(() => resolve()) - .catch(err => { - if (accessory.context.reachableWAN) { - if (this.debug) { - this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); - } - this.wsClient - .sendUpdate(payload) - .then(() => resolve()) - .catch(err => reject(err)); - } else { - reject("it is unreachable. I's status will be corrected once it is reachable"); + apikey: accessory.context.eweApiKey, + deviceid: accessory.context.eweDeviceId, + params, + }; + try { + await utils.sleep(Math.random() * 100 + 200); + await this.lanClient.sendUpdate(payload); + resolve(); + } catch (err) { + if (accessory.context.reachableWAN) { + if (this.debug) { + this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); } - }); + try { + await this.wsClient.sendUpdate(payload); + resolve(); + } catch (err) { + reject(err); + } + } else { + reject("it is unreachable. I's status will be corrected once it is reachable"); + } + } }); } - receiveDeviceUpdate(device) { + async receiveDeviceUpdate(device) { let accessory, deviceId = device.deviceid, reachableChange = false; @@ -1167,33 +1173,33 @@ class eWeLink { deviceId, device.params.updateSource ); - this.httpClient - .getDevice(deviceId) - .then(device => { - this.initialiseDevice(device); - this.lanClient.addDeviceToMap(device); - }) - .catch(err => { - this.log.error("[%s] error getting info [%s]", deviceId, err); - this.log.error( - "[%s] Please try restarting Homebridge so this device is added.", - deviceId - ); - }); + try { + let device = await this.httpClient.getDevice(deviceId); + this.initialiseDevice(device); + this.lanClient.addDeviceToMap(device); + } catch (err) { + this.log.error("[%s] error getting info [%s]", deviceId, err); + this.log.error( + "[%s] Please try restarting Homebridge so this device is added.", + deviceId + ); + } } } } - requestDeviceRefresh(accessory, err) { + async requestDeviceRefresh(accessory, err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); if (accessory.context.reachableWAN) { - this.wsClient.requestUpdate(accessory).catch(() => {}); - this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", - accessory.displayName - ); + try { + await this.wsClient.requestUpdate(accessory); + this.log.warn( + "[%s] requesting previous state to revert Homebridge status.", + accessory.displayName + ); + } catch (err) {} } } - internalValveUpdate(accessory, valve, value, callback) { + async internalValveUpdate(accessory, valve, value, callback) { callback(); try { let params = {}, @@ -1219,27 +1225,24 @@ class eWeLink { } params.switches[2].switch = "off"; params.switches[3].switch = "off"; - this.sendDeviceUpdate(accessory, params) - .then(() => { - serviceValve - .updateCharacteristic(Characteristic.Active, value) - .updateCharacteristic(Characteristic.InUse, value); - switch (value) { - case 0: - serviceValve.updateCharacteristic(Characteristic.RemainingDuration, 0); - clearTimeout(accessory.getService(valve).timer); - break; - case 1: - let timer = serviceValve.getCharacteristic(Characteristic.SetDuration).value; - serviceValve.updateCharacteristic(Characteristic.RemainingDuration, timer); - serviceValve.timer = setTimeout( - () => serviceValve.setCharacteristic(Characteristic.Active, 0), - timer * 1000 - ); - break; - } - }) - .catch(err => this.requestDeviceRefresh(accessory, err)); + await this.sendDeviceUpdate(accessory, params); + serviceValve + .updateCharacteristic(Characteristic.Active, value) + .updateCharacteristic(Characteristic.InUse, value); + switch (value) { + case 0: + serviceValve.updateCharacteristic(Characteristic.RemainingDuration, 0); + clearTimeout(accessory.getService(valve).timer); + break; + case 1: + let timer = serviceValve.getCharacteristic(Characteristic.SetDuration).value; + serviceValve.updateCharacteristic(Characteristic.RemainingDuration, timer); + serviceValve.timer = setTimeout( + () => serviceValve.setCharacteristic(Characteristic.Active, 0), + timer * 1000 + ); + break; + } } catch (err) { this.requestDeviceRefresh(accessory, err); } @@ -1266,7 +1269,7 @@ class eWeLink { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } - internalCurtainUpdate(accessory, value, callback) { + async internalCurtainUpdate(accessory, value, callback) { callback(); try { let params, @@ -1283,14 +1286,11 @@ class eWeLink { setclose: Math.abs(100 - newPos), }; } - this.sendDeviceUpdate(accessory, params) - .then(() => { - cService - .updateCharacteristic(Characteristic.TargetPosition, newPos) - .updateCharacteristic(Characteristic.PositionState, newPos > prevPos ? 1 : 0); - accessory.context.cacheCurrentPosition = newPos; - }) - .catch(err => this.requestDeviceRefresh(accessory, err)); + await this.sendDeviceUpdate(accessory, params); + cService + .updateCharacteristic(Characteristic.TargetPosition, newPos) + .updateCharacteristic(Characteristic.PositionState, newPos > prevPos ? 1 : 0); + accessory.context.cacheCurrentPosition = newPos; } catch (err) { this.requestDeviceRefresh(accessory, err); } @@ -1311,7 +1311,7 @@ class eWeLink { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } - internalBlindUpdate(accessory, value, callback) { + async internalBlindUpdate(accessory, value, callback) { callback(); try { let blindConfig, @@ -1346,7 +1346,6 @@ class eWeLink { outlet: 3, }, ]; - let logger = str => this.log.warn("[%s] %s.", accessory.displayName, str); accessory.context.inUse = true; if (prevState !== 2) { this.log.warn( @@ -1368,25 +1367,18 @@ class eWeLink { accessory.context.targetTimestamp = timeNow + duration; params.switches[0].switch = moveUp ? "on" : "off"; params.switches[1].switch = moveUp ? "off" : "on"; - this.sendDeviceUpdate(accessory, params) - .then(() => { - wcService.updateCharacteristic(Characteristic.PositionState, moveUp ? 0 : 1); - accessory.context.cachePositionState = moveUp ? 0 : 1; - return new Promise(resolve => setTimeout(resolve, duration)); - }) - .then(() => { - params.switches[0].switch = "off"; - params.switches[1].switch = "off"; - return this.sendDeviceUpdate(accessory, params); - }) - .then(() => { - wcService.updateCharacteristic(Characteristic.PositionState, 2); - wcService.updateCharacteristic(Characteristic.CurrentPosition, newTarget); - accessory.context.cacheCurrentPosition = newTarget; - accessory.context.cachePositionState = 2; - accessory.context.inUse = false; - }) - .catch(err => this.requestDeviceRefresh(accessory, err)); + await this.sendDeviceUpdate(accessory, params); + wcService.updateCharacteristic(Characteristic.PositionState, moveUp ? 0 : 1); + accessory.context.cachePositionState = moveUp ? 0 : 1; + await utils.sleep(duration); + params.switches[0].switch = "off"; + params.switches[1].switch = "off"; + await this.sendDeviceUpdate(accessory, params); + wcService.updateCharacteristic(Characteristic.PositionState, 2); + wcService.updateCharacteristic(Characteristic.CurrentPosition, newTarget); + accessory.context.cacheCurrentPosition = newTarget; + accessory.context.cachePositionState = 2; + accessory.context.inUse = false; } catch (err) { this.requestDeviceRefresh(accessory, err); } @@ -1438,7 +1430,7 @@ class eWeLink { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } - internalGarageUpdate(accessory, value, callback) { + async internalGarageUpdate(accessory, value, callback) { callback(); try { let garageConfig; @@ -1480,38 +1472,29 @@ class eWeLink { delay = 1500; } if (accessory.context.state !== newPos) return; - let delayPromise = new Promise(resolve => setTimeout(resolve, delay)); - delayPromise - .then(() => { - gdService - .updateCharacteristic(Characteristic.TargetDoorState, newPos) - .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2); - accessory.context.cacheTargetDoorState = newPos; - accessory.context.cacheCurrentDoorState = newPos + 2; - switch (garageConfig.setup) { - case "oneSwitch": - params.switch = "on"; - break; - case "twoSwitch": - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = newPos === 0 ? "on" : "off"; - params.switches[1].switch = newPos === 1 ? "on" : "off"; - break; - } - return this.sendDeviceUpdate(accessory, params); - }) - .then( - () => - new Promise(resolve => setTimeout(resolve, parseInt(garageConfig.operationTime) * 100)) - ) - .then(() => { - if (!sAccessory) { - gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos); - accessory.context.cacheCurrentDoorState = newPos; - } - accessory.context.inUse = false; - }) - .catch(err => this.requestDeviceRefresh(accessory, err)); + await utils.sleep(delay); + gdService + .updateCharacteristic(Characteristic.TargetDoorState, newPos) + .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2); + accessory.context.cacheTargetDoorState = newPos; + accessory.context.cacheCurrentDoorState = newPos + 2; + switch (garageConfig.setup) { + case "oneSwitch": + params.switch = "on"; + break; + case "twoSwitch": + params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = newPos === 0 ? "on" : "off"; + params.switches[1].switch = newPos === 1 ? "on" : "off"; + break; + } + await this.sendDeviceUpdate(accessory, params); + await utils.sleep(garageConfig.operationTime * 100); + if (!sAccessory) { + gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos); + accessory.context.cacheCurrentDoorState = newPos; + } + accessory.context.inUse = false; } catch (err) { this.requestDeviceRefresh(accessory, err); } @@ -1569,7 +1552,7 @@ class eWeLink { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } - internalLockUpdate(accessory, value, callback) { + async internalLockUpdate(accessory, value, callback) { callback(); try { let lockConfig, @@ -1584,19 +1567,15 @@ class eWeLink { throw "improper configuration"; } accessory.context.inUse = true; - this.sendDeviceUpdate(accessory, params) - .then(() => { - lmService - .updateCharacteristic(Characteristic.LockTargetState, 0) - .updateCharacteristic(Characteristic.LockCurrentState, 0); - setTimeout(() => { - lmService - .updateCharacteristic(Characteristic.LockTargetState, 1) - .updateCharacteristic(Characteristic.LockCurrentState, 1); - accessory.context.inUse = false; - }, parseInt(lockConfig.operationTime) * 100); - }) - .catch(err => this.requestDeviceRefresh(accessory, err)); + await this.sendDeviceUpdate(accessory, params); + lmService + .updateCharacteristic(Characteristic.LockTargetState, 0) + .updateCharacteristic(Characteristic.LockCurrentState, 0); + await utils.sleep(lockConfig.operationTime * 100); + lmService + .updateCharacteristic(Characteristic.LockTargetState, 1) + .updateCharacteristic(Characteristic.LockCurrentState, 1); + accessory.context.inUse = false; } catch (err) { this.requestDeviceRefresh(accessory, err); } @@ -1674,7 +1653,7 @@ class eWeLink { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } - internalFanUpdate(accessory, type, value, callback) { + async internalFanUpdate(accessory, type, value, callback) { callback(); try { let newPower, @@ -1706,14 +1685,11 @@ class eWeLink { params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? "on" : "off"; params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? "on" : "off"; params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? "on" : "off"; - this.sendDeviceUpdate(accessory, params) - .then(() => { - lightService.updateCharacteristic(Characteristic.On, newLight); - fanService - .updateCharacteristic(Characteristic.Active, newPower) - .updateCharacteristic(Characteristic.RotationSpeed, newSpeed); - }) - .catch(err => this.requestDeviceRefresh(accessory, err)); + await this.sendDeviceUpdate(accessory, params); + lightService.updateCharacteristic(Characteristic.On, newLight); + fanService + .updateCharacteristic(Characteristic.Active, newPower) + .updateCharacteristic(Characteristic.RotationSpeed, newSpeed); } catch (err) { this.requestDeviceRefresh(accessory, err); } @@ -1763,7 +1739,7 @@ class eWeLink { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } - internalThermostatUpdate(accessory, value, callback) { + async internalThermostatUpdate(accessory, value, callback) { callback(); try { let params = { @@ -1771,11 +1747,8 @@ class eWeLink { mainSwitch: value ? "on" : "off", }, switchService = accessory.getService(Service.Switch); - this.sendDeviceUpdate(accessory, params) - .then(() => { - switchService.updateCharacteristic(Characteristic.On, value); - }) - .catch(err => this.requestDeviceRefresh(accessory, err)); + await this.sendDeviceUpdate(accessory, params); + switchService.updateCharacteristic(Characteristic.On, value); } catch (err) { this.requestDeviceRefresh(accessory, err); } @@ -1792,49 +1765,48 @@ class eWeLink { switchService = accessory.getService(Service.Switch); switchService.updateCharacteristic(Characteristic.On, newState); } - let eveLog = { - time: Date.now(), - }; - if ( - params.hasOwnProperty("currentTemperature") && - accessory.getService(Service.TemperatureSensor) - ) { - let currentTemp = - params.currentTemperature !== "unavailable" ? params.currentTemperature : 0; - accessory - .getService(Service.TemperatureSensor) - .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); - eveLog.temp = parseFloat(currentTemp); - } - if ( - params.hasOwnProperty("currentHumidity") && - accessory.getService(Service.HumiditySensor) - ) { - let currentHumi = params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; - accessory - .getService(Service.HumiditySensor) - .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); - eveLog.humidity = parseFloat(currentHumi); - } - if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { - accessory.eveLogger.addEntry(eveLog); + if (!(this.config.disableEveLogging || false)) { + let eveLog = { + time: Date.now(), + }; + if ( + params.hasOwnProperty("currentTemperature") && + accessory.getService(Service.TemperatureSensor) + ) { + let currentTemp = + params.currentTemperature !== "unavailable" ? params.currentTemperature : 0; + accessory + .getService(Service.TemperatureSensor) + .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); + eveLog.temp = parseFloat(currentTemp); + } + if ( + params.hasOwnProperty("currentHumidity") && + accessory.getService(Service.HumiditySensor) + ) { + let currentHumi = params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; + accessory + .getService(Service.HumiditySensor) + .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); + eveLog.humidity = parseFloat(currentHumi); + } + if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { + accessory.eveLogger.addEntry(eveLog); + } } } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } - internalOutletUpdate(accessory, value, callback) { + async internalOutletUpdate(accessory, value, callback) { callback(); try { let params = { switch: value ? "on" : "off", }, outletService = accessory.getService(Service.Outlet); - this.sendDeviceUpdate(accessory, params) - .then(() => { - outletService.updateCharacteristic(Characteristic.On, value); - }) - .catch(err => this.requestDeviceRefresh(accessory, err)); + await this.sendDeviceUpdate(accessory, params); + outletService.updateCharacteristic(Characteristic.On, value); } catch (err) { this.requestDeviceRefresh(accessory, err); } @@ -1879,7 +1851,7 @@ class eWeLink { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } - internalUSBUpdate(accessory, value, callback) { + async internalUSBUpdate(accessory, value, callback) { callback(); try { let params = { @@ -1887,11 +1859,8 @@ class eWeLink { }, outletService = accessory.getService(Service.Outlet); params.switches[0].switch = value ? "on" : "off"; - this.sendDeviceUpdate(accessory, params) - .then(() => { - outletService.updateCharacteristic(Characteristic.On, value); - }) - .catch(err => this.requestDeviceRefresh(accessory, err)); + await this.sendDeviceUpdate(accessory, params); + outletService.updateCharacteristic(Characteristic.On, value); } catch (err) { this.requestDeviceRefresh(accessory, err); } @@ -1905,7 +1874,7 @@ class eWeLink { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } - internalSCMUpdate(accessory, value, callback) { + async internalSCMUpdate(accessory, value, callback) { callback(); try { let params = { @@ -1913,11 +1882,8 @@ class eWeLink { }, switchService = accessory.getService(Service.Switch); params.switches[0].switch = value ? "on" : "off"; - this.sendDeviceUpdate(accessory, params) - .then(() => { - switchService.updateCharacteristic(Characteristic.On, value); - }) - .catch(err => this.requestDeviceRefresh(accessory, err)); + await this.sendDeviceUpdate(accessory, params); + switchService.updateCharacteristic(Characteristic.On, value); } catch (err) { this.requestDeviceRefresh(accessory, err); } @@ -1931,7 +1897,7 @@ class eWeLink { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } - internalLightbulbUpdate(accessory, value, callback) { + async internalLightbulbUpdate(accessory, value, callback) { callback(); try { let oAccessory, @@ -1973,52 +1939,48 @@ class eWeLink { } break; } - this.sendDeviceUpdate(accessory, params) - .then(() => { - switch (accessory.context.switchNumber) { - case "X": - lightService.updateCharacteristic(Characteristic.On, value); - break; - case "0": - for (let i = 0; i <= 4; i++) { - if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - oAccessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, value); - } - } - break; - case "1": - case "2": - case "3": - case "4": - lightService.updateCharacteristic(Characteristic.On, value); - let masterState = "off"; - for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - if ( - oAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On) - .value - ) { - masterState = "on"; - } - } - } - if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - oAccessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, masterState === "on"); + await this.sendDeviceUpdate(accessory, params); + switch (accessory.context.switchNumber) { + case "X": + lightService.updateCharacteristic(Characteristic.On, value); + break; + case "0": + for (let i = 0; i <= 4; i++) { + if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + oAccessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, value); + } + } + break; + case "1": + case "2": + case "3": + case "4": + lightService.updateCharacteristic(Characteristic.On, value); + let masterState = "off"; + for (let i = 1; i <= 4; i++) { + if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + if ( + oAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value + ) { + masterState = "on"; } - break; + } + } + if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); + oAccessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, masterState === "on"); } - }) - .catch(err => this.requestDeviceRefresh(accessory, err)); + break; + } } catch (err) { this.requestDeviceRefresh(accessory, err); } } - internalBrightnessUpdate(accessory, value, callback) { + async internalBrightnessUpdate(accessory, value, callback) { callback(); try { let params = {}, @@ -2039,22 +2001,18 @@ class eWeLink { break; } } - let delayPromise = new Promise(resolve => setTimeout(resolve, 250)); - delayPromise - .then(() => this.sendDeviceUpdate(accessory, params)) - .then(() => { - if (value === 0) { - lightService.updateCharacteristic(Characteristic.On, false); - } else { - lightService.updateCharacteristic(Characteristic.Brightness, value); - } - }) - .catch(err => this.requestDeviceRefresh(accessory, err)); + await utils.sleep(250); + await this.sendDeviceUpdate(accessory, params); + if (value === 0) { + lightService.updateCharacteristic(Characteristic.On, false); + } else { + lightService.updateCharacteristic(Characteristic.Brightness, value); + } } catch (err) { this.requestDeviceRefresh(accessory, err); } } - internalHSBUpdate(accessory, type, value, callback) { + async internalHSBUpdate(accessory, type, value, callback) { callback(); try { if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { @@ -2113,20 +2071,16 @@ class eWeLink { } break; } - let delayPromise = new Promise(resolve => setTimeout(resolve, 250)); - delayPromise - .then(() => this.sendDeviceUpdate(accessory, params)) - .then(() => { - switch (type) { - case "hue": - lightService.updateCharacteristic(Characteristic.Hue, value); - break; - case "bri": - lightService.updateCharacteristic(Characteristic.Brightness, value); - break; - } - }) - .catch(err => this.requestDeviceRefresh(accessory, err)); + await utils.sleep(250); + await this.sendDeviceUpdate(accessory, params); + switch (type) { + case "hue": + lightService.updateCharacteristic(Characteristic.Hue, value); + break; + case "bri": + lightService.updateCharacteristic(Characteristic.Brightness, value); + break; + } } catch (err) { this.requestDeviceRefresh(accessory, err); } @@ -2229,7 +2183,7 @@ class eWeLink { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } - internalSwitchUpdate(accessory, value, callback) { + async internalSwitchUpdate(accessory, value, callback) { callback(); try { let oAccessory, @@ -2266,46 +2220,41 @@ class eWeLink { } break; } - this.sendDeviceUpdate(accessory, params) - .then(() => { - switch (accessory.context.switchNumber) { - case "X": - switchService.updateCharacteristic(Characteristic.On, value); - break; - case "0": - for (let i = 0; i <= 4; i++) { - if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - oAccessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, value); - } - } - break; - case "1": - case "2": - case "3": - case "4": - switchService.updateCharacteristic(Characteristic.On, value); - let masterState = "off"; - for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - if ( - oAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value - ) { - masterState = "on"; - } - } - } - if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - oAccessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, masterState === "on"); + await this.sendDeviceUpdate(accessory, params); + switch (accessory.context.switchNumber) { + case "X": + switchService.updateCharacteristic(Characteristic.On, value); + break; + case "0": + for (let i = 0; i <= 4; i++) { + if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + } + } + break; + case "1": + case "2": + case "3": + case "4": + switchService.updateCharacteristic(Characteristic.On, value); + let masterState = "off"; + for (let i = 1; i <= 4; i++) { + if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + if ( + oAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value + ) { + masterState = "on"; } - break; + } + } + if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { + oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); + oAccessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, masterState === "on"); } - }) - .catch(err => this.requestDeviceRefresh(accessory, err)); + break; + } } catch (err) { this.requestDeviceRefresh(accessory, err); } @@ -2341,7 +2290,7 @@ class eWeLink { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } } - internalRFUpdate(accessory, rfChl, service, callback) { + async internalRFUpdate(accessory, rfChl, service, callback) { callback(); try { let params = { @@ -2349,12 +2298,10 @@ class eWeLink { rfChl: parseInt(rfChl), }, rfService = accessory.getService(service); - this.sendDeviceUpdate(accessory, params) - .then(() => { - rfService.updateCharacteristic(Characteristic.On, true); - setTimeout(() => rfService.updateCharacteristic(Characteristic.On, false), 3000); - }) - .catch(err => this.requestDeviceRefresh(accessory, err)); + await this.sendDeviceUpdate(accessory, params); + rfService.updateCharacteristic(Characteristic.On, true); + await utils.sleep(3000); + rfService.updateCharacteristic(Characteristic.On, false); } catch (err) { this.requestDeviceRefresh(accessory, err); } diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 36d099cf..4076d982 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -2,7 +2,8 @@ "use strict"; const axios = require("axios"), constants = require("./constants"), - crypto = require("crypto"); + crypto = require("crypto"), + utils = require("./utils"); module.exports = class eWeLinkHTTP { constructor(config, log) { this.log = log; @@ -14,7 +15,7 @@ module.exports = class eWeLinkHTTP { this.cCode = "+" + config.countryCode.toString().replace("+", "").replace(" ", ""); } getHost() { - return new Promise((resolve, reject) => { + return new Promise(async (resolve, reject) => { let params = { appid: constants.appId, country_code: this.cCode, @@ -23,92 +24,91 @@ module.exports = class eWeLinkHTTP { version: 8, }, dataToSign = []; - Object.keys(params).forEach(k => { - dataToSign.push({ - key: k, - value: params.k, + try { + Object.keys(params).forEach(k => { + dataToSign.push({ + key: k, + value: params.k, + }); }); - }); - dataToSign.sort((a, b) => (a.key < b.key ? -1 : 1)); - dataToSign = dataToSign.map(k => k.key + "=" + k.value).join("&"); - dataToSign = crypto - .createHmac("sha256", constants.appSecret) - .update(dataToSign) - .digest("base64"); - if (this.debugReqRes) { - this.log.warn( - "Sending HTTP getHost request. This text is yellow for clarity.\n%s", - JSON.stringify(params, null, 2) - ); - } else if (this.debug) { - this.log("Sending HTTP getHost request."); - } - axios - .get("https://api.coolkit.cc:8080/api/user/region", { + dataToSign.sort((a, b) => (a.key < b.key ? -1 : 1)); + dataToSign = dataToSign.map(k => k.key + "=" + k.value).join("&"); + dataToSign = crypto + .createHmac("sha256", constants.appSecret) + .update(dataToSign) + .digest("base64"); + if (this.debugReqRes) { + this.log.warn( + "Sending HTTP getHost request. This text is yellow for clarity.\n%s", + JSON.stringify(params, null, 2) + ); + } else if (this.debug) { + this.log("Sending HTTP getHost request."); + } + let res = await axios.get("https://api.coolkit.cc:8080/api/user/region", { headers: { Authorization: "Sign " + dataToSign, "Content-Type": "application/json", }, params, - }) - .then(res => { - let body = res.data; - if (!body.region) { - throw "Server did not respond with a region.\n" + JSON.stringify(body, null, 2); - } - switch (body.region) { - case "eu": - case "us": - case "as": - this.httpHost = body.region + "-apia.coolkit.cc"; - break; - case "cn": - this.httpHost = "cn-apia.coolkit.cn"; - break; - default: - throw "No valid region received - [" + body.region + "]."; - } - if (this.debug) { - this.log("HTTP API host received [%s].", this.httpHost); - } - resolve(this.httpHost); - }) - .catch(err => { - if ( - err.hasOwnProperty("code") && - ["ENOTFOUND", "ETIMEDOUT", "EAI_AGAIN"].includes(err.code) - ) { - this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); - this.delay().then(() => resolve(this.getHost())); - } else { - reject(err.message || err); - } }); + let body = res.data; + if (!body.region) { + throw "Server did not respond with a region.\n" + JSON.stringify(body, null, 2); + } + switch (body.region) { + case "eu": + case "us": + case "as": + this.httpHost = body.region + "-apia.coolkit.cc"; + break; + case "cn": + this.httpHost = "cn-apia.coolkit.cn"; + break; + default: + throw "No valid region received - [" + body.region + "]."; + } + if (this.debug) { + this.log("HTTP API host received [%s].", this.httpHost); + } + resolve(this.httpHost); + } catch (err) { + if ( + err.hasOwnProperty("code") && + ["ENOTFOUND", "ETIMEDOUT", "EAI_AGAIN"].includes(err.code) + ) { + this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); + await utils.sleep(30000); + resolve(this.getHost()); + } else { + reject(err.message || err); + } + } }); } login() { - return new Promise((resolve, reject) => { + return new Promise(async (resolve, reject) => { let data = { countryCode: this.cCode, password: this.password, }; - this.username.includes("@") - ? (data.email = this.username) - : (data.phoneNumber = this.username); - if (this.debugReqRes) { - let msg = JSON.stringify(data, null, 2) - .replace(this.password, "**hidden**") - .replace(this.username, "**hidden**"); - this.log.warn("Sending HTTP login request. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("Sending HTTP login request."); - } - let dataToSign = crypto - .createHmac("sha256", constants.appSecret) - .update(JSON.stringify(data)) - .digest("base64"); - axios - .post("https://" + this.httpHost + "/v2/user/login", data, { + try { + this.username.includes("@") + ? (data.email = this.username) + : (data.phoneNumber = this.username); + if (this.debugReqRes) { + let msg = JSON.stringify(data, null, 2) + .replace(this.password, "**hidden**") + .replace(this.username, "**hidden**"); + this.log.warn("Sending HTTP login request. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("Sending HTTP login request."); + } + let dataToSign = crypto + .createHmac("sha256", constants.appSecret) + .update(JSON.stringify(data)) + .digest("base64"); + let res = await axios.post("https://" + this.httpHost + "/v2/user/login", data, { headers: { Authorization: "Sign " + dataToSign, "Content-Type": "application/json", @@ -116,58 +116,59 @@ module.exports = class eWeLinkHTTP { "X-CK-Appid": constants.appId, "X-CK-Nonce": Math.random().toString(36).substr(2, 8), }, - }) - .then(res => { - let body = res.data; - if ( - body.hasOwnProperty("error") && - body.error === 10004 && - body.hasOwnProperty("data") && - body.data.hasOwnProperty("region") - ) { - let givenRegion = body.data.region; - switch (givenRegion) { - case "eu": - case "us": - case "as": - this.httpHost = givenRegion + "-apia.coolkit.cc"; - break; - case "cn": - this.httpHost = "cn-apia.coolkit.cn"; - break; - default: - throw "No valid region received - [" + givenRegion + "]."; - } - if (this.debug) { - this.log("New HTTP API host received [%s].", this.httpHost); - } - resolve(this.login()); - return; + }); + let body = res.data; + if ( + body.hasOwnProperty("error") && + body.error === 10004 && + body.hasOwnProperty("data") && + body.data.hasOwnProperty("region") + ) { + let givenRegion = body.data.region; + switch (givenRegion) { + case "eu": + case "us": + case "as": + this.httpHost = givenRegion + "-apia.coolkit.cc"; + break; + case "cn": + this.httpHost = "cn-apia.coolkit.cn"; + break; + default: + throw "No valid region received - [" + givenRegion + "]."; + } + if (this.debug) { + this.log("New HTTP API host received [%s].", this.httpHost); } - if (body.data.at) { - this.aToken = body.data.at; - this.apiKey = body.data.user.apikey; - resolve({ - aToken: this.aToken, - apiKey: this.apiKey, - httpHost: this.httpHost, - }); + resolve(this.login()); + return; + } + if (body.data.at) { + this.aToken = body.data.at; + this.apiKey = body.data.user.apikey; + resolve({ + aToken: this.aToken, + apiKey: this.apiKey, + httpHost: this.httpHost, + }); + } else { + if (body.error === 500) { + this.log.warn("An eWeLink error [500] occured. Retrying in 30 seconds."); + await utils.sleep(30000); + resolve(this.login()); } else { - if (body.error === 500) { - this.log.warn("An eWeLink error [500] occured. Retrying in 30 seconds."); - this.delay().then(() => resolve(this.login())); - } else { - throw "No auth token received.\n" + JSON.stringify(body, null, 2); - } + throw "No auth token received.\n" + JSON.stringify(body, null, 2); } - }) - .catch(err => reject(err.message || err)); + } + } catch (err) { + reject(err.message || err); + } }); } getDevices() { - return new Promise((resolve, reject) => { - axios - .get("https://" + this.httpHost + "/v2/device/thing", { + return new Promise(async (resolve, reject) => { + try { + let res = await axios.get("https://" + this.httpHost + "/v2/device/thing", { headers: { Authorization: "Bearer " + this.aToken, "Content-Type": "application/json", @@ -175,39 +176,38 @@ module.exports = class eWeLinkHTTP { "X-CK-Appid": constants.appId, "X-CK-Nonce": Math.random().toString(36).substr(2, 8), }, - }) - .then(res => { - let body = res.data; - if ( - !body.hasOwnProperty("data") || - !body.hasOwnProperty("error") || - (body.hasOwnProperty("error") && body.error !== 0) - ) { - throw JSON.stringify(body, null, 2); - } - let deviceList = []; - if (body.data.thingList && body.data.thingList.length > 0) { - body.data.thingList.forEach(device => deviceList.push(device.itemData)); - } - deviceList - .filter(d => d.hasOwnProperty("extra") && d.extra.hasOwnProperty("uiid")) - .filter(d => !this.hideDevFromHB.includes(d.deviceid)); - resolve(deviceList); - }) - .catch(err => { - if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { - this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); - this.delay().then(() => resolve(this.getDevices())); - } else { - reject(err.message || err); - } }); + let body = res.data; + if ( + !body.hasOwnProperty("data") || + !body.hasOwnProperty("error") || + (body.hasOwnProperty("error") && body.error !== 0) + ) { + throw JSON.stringify(body, null, 2); + } + let deviceList = []; + if (body.data.thingList && body.data.thingList.length > 0) { + body.data.thingList.forEach(device => deviceList.push(device.itemData)); + } + deviceList + .filter(d => d.hasOwnProperty("extra") && d.extra.hasOwnProperty("uiid")) + .filter(d => !this.hideDevFromHB.includes(d.deviceid)); + resolve(deviceList); + } catch (err) { + if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { + this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); + await utils.sleep(30000); + resolve(this.getDevices()); + } else { + reject(err.message || err); + } + } }); } getDevice(deviceId) { - return new Promise((resolve, reject) => { - axios - .post( + return new Promise(async (resolve, reject) => { + try { + let res = await axios.post( "https://" + this.httpHost + "/v2/device/thing", { thingList: [ @@ -226,33 +226,29 @@ module.exports = class eWeLinkHTTP { "X-CK-Nonce": Math.random().toString(36).substr(2, 8), }, } - ) - .then(res => { - let body = res.data; - if ( - !body.hasOwnProperty("data") || - !body.hasOwnProperty("error") || - (body.hasOwnProperty("error") && body.error !== 0) - ) { - throw JSON.stringify(body, null, 2); - } - if (body.data.thingList && body.data.thingList.length === 1) { - resolve(body.data.thingList[0].itemData); - } else { - throw "device not found in eWeLink"; - } - }) - .catch(err => { - if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { - this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); - this.delay().then(() => resolve(this.getDevice(deviceId))); - } else { - reject(err.message || err); - } - }); + ); + let body = res.data; + if ( + !body.hasOwnProperty("data") || + !body.hasOwnProperty("error") || + (body.hasOwnProperty("error") && body.error !== 0) + ) { + throw JSON.stringify(body, null, 2); + } + if (body.data.thingList && body.data.thingList.length === 1) { + resolve(body.data.thingList[0].itemData); + } else { + throw "device not found in eWeLink"; + } + } catch (err) { + if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { + this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); + await utils.sleep(30000); + resolve(this.getDevice(deviceId)); + } else { + reject(err.message || err); + } + } }); } - delay() { - return new Promise(resolve => setTimeout(resolve, 30000)); - } }; diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 09c6f749..b046db46 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -25,28 +25,28 @@ module.exports = class eWeLinkLAN { this.emitter = new eventemitter(); } getHosts() { - return new Promise((resolve, reject) => { - dns - .discover({ + return new Promise(async (resolve, reject) => { + try { + let res = await dns.discover({ name: "_ewelink._tcp.local", - }) - .then(res => { - res.forEach(device => { - let d, - deviceId = device.fqdn.replace("._ewelink._tcp.local", "").replace("eWeLink_", ""); - if ((d = this.deviceMap.get(deviceId))) { - if (!this.ipOverrides.hasOwnProperty(deviceId)) { - this.deviceMap.set(deviceId, { - apiKey: d.apiKey, - online: true, - ip: device.address, - }); - } + }); + res.forEach(device => { + let d, + deviceId = device.fqdn.replace("._ewelink._tcp.local", "").replace("eWeLink_", ""); + if ((d = this.deviceMap.get(deviceId))) { + if (!this.ipOverrides.hasOwnProperty(deviceId)) { + this.deviceMap.set(deviceId, { + apiKey: d.apiKey, + online: true, + ip: device.address, + }); } - }); - resolve(this.deviceMap); - }) - .catch(err => reject(err)); + } + }); + resolve(this.deviceMap); + } catch (err) { + reject(err); + } }); } startMonitor() { @@ -115,70 +115,66 @@ module.exports = class eWeLinkLAN { }); } }; - return new Promise((resolve, reject) => { - dns - .startMonitoring() - .then(() => resolve()) - .catch(err => reject(err)); - }); + dns.startMonitoring(); } sendUpdate(json) { - return new Promise((resolve, reject) => { - if (!this.deviceMap.get(json.deviceid).online) { - throw "device isn't reachable via LAN mode"; - } - let apiKey, - suffix, - params = {}; - if (json.params.hasOwnProperty("switches")) { - params.switches = json.params.switches; - suffix = "switches"; - } else if (json.params.hasOwnProperty("switch")) { - params.switch = json.params.switch; - suffix = "switch"; - } else { - throw "device isn't reachable via LAN mode"; - } - if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { - let key = crypto.createHash("md5").update(Buffer.from(apiKey, "utf8")).digest(), - iv = crypto.randomBytes(16), - enc = crypto.createCipheriv("aes-128-cbc", key, iv), - data = { - data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString( - "base64" - ), - deviceid: json.deviceid, - encrypt: true, - iv: iv.toString("base64"), - selfApikey: "123", - sequence: Date.now().toString(), - }; - if (this.debugReqRes) { - let msg = JSON.stringify(json, null, 2) - .replace(json.apikey, "**hidden**") - .replace(json.apikey, "**hidden**") - .replace(json.deviceid, "**hidden**"); - this.log.warn("LAN message sent. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("LAN message sent."); + return new Promise(async (resolve, reject) => { + try { + if (!this.deviceMap.get(json.deviceid).online) { + throw "device isn't reachable via LAN mode"; } - axios({ - method: "post", - url: "http://" + this.deviceMap.get(json.deviceid).ip + ":8081/zeroconf/" + suffix, - headers: { - Accept: "application/json", - "Content-Type": "application/json", - }, - data, - }) - .then(res => { - if (res.data.hasOwnProperty("error") && res.data.error === 0) { - resolve(); - } else { - throw res.data; - } - }) - .catch(err => reject(err)); + let apiKey, + suffix, + params = {}; + if (json.params.hasOwnProperty("switches")) { + params.switches = json.params.switches; + suffix = "switches"; + } else if (json.params.hasOwnProperty("switch")) { + params.switch = json.params.switch; + suffix = "switch"; + } else { + throw "device isn't reachable via LAN mode"; + } + if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { + let key = crypto.createHash("md5").update(Buffer.from(apiKey, "utf8")).digest(), + iv = crypto.randomBytes(16), + enc = crypto.createCipheriv("aes-128-cbc", key, iv), + data = { + data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString( + "base64" + ), + deviceid: json.deviceid, + encrypt: true, + iv: iv.toString("base64"), + selfApikey: "123", + sequence: Date.now().toString(), + }; + if (this.debugReqRes) { + let msg = JSON.stringify(json, null, 2) + .replace(json.apikey, "**hidden**") + .replace(json.apikey, "**hidden**") + .replace(json.deviceid, "**hidden**"); + this.log.warn("LAN message sent. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("LAN message sent."); + } + let res = await axios({ + method: "post", + url: "http://" + this.deviceMap.get(json.deviceid).ip + ":8081/zeroconf/" + suffix, + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + data, + }); + if (res.data.hasOwnProperty("error") && res.data.error === 0) { + resolve(); + } else { + throw res.data; + } + } + } catch (err) { + reject(err); } }); } diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 6f30b2ea..f6a63e26 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -3,6 +3,7 @@ const axios = require("axios"), cns = require("./constants"), eventemitter = require("events"), + utils = require("./utils"), ws = require("ws"), wsp = require("websocket-as-promised"); module.exports = class eWeLinkWS { @@ -19,40 +20,40 @@ module.exports = class eWeLinkWS { this.delaySend = 0; } getHost() { - return new Promise((resolve, reject) => { - axios({ - method: "post", - url: "https://" + this.httpHost.replace("-api", "-disp") + "/dispatch/app", - headers: { - Authorization: "Bearer " + this.aToken, - "Content-Type": "application/json", - }, - data: { - appid: cns.appId, - nonce: Math.random().toString(36).substr(2, 8), - ts: Math.floor(new Date().getTime() / 1000), - version: 8, - }, - }) - .then(res => { - let body = res.data; - if (!body.domain) { - throw "Server did not respond with a web socket host."; - } - if (this.debug) { - this.log("Web socket host received [%s].", body.domain); - } - this.wsHost = body.domain; - resolve(body.domain); - }) - .catch(err => { - if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { - this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); - this.delay().then(() => resolve(this.getDevices())); - } else { - reject(err.message || err); - } + return new Promise(async (resolve, reject) => { + try { + let res = await axios({ + method: "post", + url: "https://" + this.httpHost.replace("-api", "-disp") + "/dispatch/app", + headers: { + Authorization: "Bearer " + this.aToken, + "Content-Type": "application/json", + }, + data: { + appid: cns.appId, + nonce: Math.random().toString(36).substr(2, 8), + ts: Math.floor(new Date().getTime() / 1000), + version: 8, + }, }); + let body = res.data; + if (!body.domain) { + throw "Server did not respond with a web socket host."; + } + if (this.debug) { + this.log("Web socket host received [%s].", body.domain); + } + this.wsHost = body.domain; + resolve(body.domain); + } catch (err) { + if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { + this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); + await utils.sleep(30000); + resolve(this.getDevices()); + } else { + reject(err.message || err); + } + } }); } login() { @@ -73,7 +74,7 @@ module.exports = class eWeLinkWS { }, }); this.wsp.open(); - this.wsp.onOpen.addListener(() => { + this.wsp.onOpen.addListener(async () => { this.wsIsOpen = true; let sequence = Math.floor(new Date()).toString(), payload = { @@ -95,27 +96,25 @@ module.exports = class eWeLinkWS { } else if (this.debug) { this.log("Sending WS login request."); } - this.wsp - .sendRequest(payload, { + try { + let res = await this.wsp.sendRequest(payload, { requestId: sequence, - }) - .then(res => { - if ( - res.hasOwnProperty("config") && - res.config.hb && - res.config.hbInterval && - !this.hbInterval - ) { - this.hbInterval = setInterval(() => { - this.wsp.send("ping"); - }, (res.config.hbInterval + 7) * 1000); - } else { - throw "Unknown parameters received"; - } - }) - .catch(err => { - this.log.error("WS login failed [%s].", err); }); + if ( + res.hasOwnProperty("config") && + res.config.hb && + res.config.hbInterval && + !this.hbInterval + ) { + this.hbInterval = setInterval(() => { + this.wsp.send("ping"); + }, (res.config.hbInterval + 7) * 1000); + } else { + throw "Unknown parameters received"; + } + } catch (err) { + this.log.error("WS login failed [%s].", err); + } }); this.wsp.onUnpackedMessage.addListener(device => { if (device === "pong") return; @@ -206,7 +205,7 @@ module.exports = class eWeLinkWS { }); } sendUpdate(json) { - return new Promise((resolve, reject) => { + return new Promise(async (resolve, reject) => { let sequence = Math.floor(new Date()).toString(), jsonToSend = { ...json, @@ -217,37 +216,36 @@ module.exports = class eWeLinkWS { }, }; if (this.wsp && this.wsIsOpen) { - this.wsp - .sendRequest(jsonToSend, { + try { + let device = await this.wsp.sendRequest(jsonToSend, { requestId: sequence, - }) - .then(device => { - if (this.debugReqRes) { - let msg = JSON.stringify(json, null, 2) - .replace(json.apikey, "**hidden**") - .replace(json.apiKey, "**hidden**") - .replace(json.deviceid, "**hidden**"); - this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("WS message sent."); - } - device.error = device.hasOwnProperty("error") ? device.error : 504; // mimic ewelink device offline - switch (device.error) { - case 0: - resolve(); - break; - default: - throw "Unknown response"; - } - }) - .catch(err => reject("Device update failed [" + err + "].")); - } else { - this.delay(2500).then(() => { - if (this.debug) { - this.log.warn("Will resend command when WS is reconnected."); + }); + if (this.debugReqRes) { + let msg = JSON.stringify(json, null, 2) + .replace(json.apikey, "**hidden**") + .replace(json.apiKey, "**hidden**") + .replace(json.deviceid, "**hidden**"); + this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("WS message sent."); } - resolve(this.sendUpdate(json)); - }); + device.error = device.hasOwnProperty("error") ? device.error : 504; // mimic ewelink device offline + switch (device.error) { + case 0: + resolve(); + break; + default: + throw "Unknown response"; + } + } catch (err) { + reject("Device update failed [" + err + "]."); + } + } else { + if (this.debug) { + this.log.warn("Command will be resent when WS is reconnected."); + } + await utils.sleep(30000); + resolve(this.sendUpdate(json)); } }); } @@ -275,16 +273,15 @@ module.exports = class eWeLinkWS { this.log("WS message sent."); } }, - checkToSend = () => { + checkToSend = async () => { if (this.wsp && this.wsIsOpen) { sendOperation(); } else { - this.delay(2500).then(() => { - if (this.debug) { - this.log.warn("Will resend command when WS is reconnected."); - } - checkToSend(); - }); + await utils.sleep(2500); + if (this.debug) { + this.log.warn("Will resend command when WS is reconnected."); + } + checkToSend(); } }; checkToSend(); @@ -294,20 +291,17 @@ module.exports = class eWeLinkWS { this.emitter.addListener("update", f); } closeConnection() { - return new Promise((resolve, reject) => { + return new Promise(async (resolve, reject) => { if (this.wsp && this.wsIsOpen) { - this.wsp - .close() - .then(() => { - this.log("Web socket gracefully closed."); - resolve(); - }) - .catch(err => reject(err)); + try { + await this.wsp.close(); + this.log("Web socket gracefully closed."); + resolve(); + } catch (err) { + reject(err); + } } resolve(); }); } - delay(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); - } }; diff --git a/lib/utils.js b/lib/utils.js new file mode 100644 index 00000000..5cb638ad --- /dev/null +++ b/lib/utils.js @@ -0,0 +1,7 @@ +/* jshint esversion: 9, -W014, -W030, node: true */ +"use strict"; +module.exports = { + sleep: ms => { + return new Promise(resolve => setTimeout(resolve, ms)); + }, +}; diff --git a/package-lock.json b/package-lock.json index 24611c34..4560d366 100644 --- a/package-lock.json +++ b/package-lock.json @@ -405,6 +405,11 @@ } } }, + "interval-promise": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interval-promise/-/interval-promise-1.4.0.tgz", + "integrity": "sha512-PUwEmGqUglJhb6M01JNvMDvxr4DA8FCeYoYCLHPEcBBZiq/8yOpCchfs1VJui7fXj69l170gAxzF1FeSA0nSlg==" + }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", diff --git a/package.json b/package.json index 82cf0b07..46a2e2e3 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "correcting-interval": "2.0.0", "fakegato-history": "0.5.6", "homebridge-lib": "4.7.15", + "interval-promise": "1.4.0", "node-dns-sd": "0.4.1", "websocket-as-promised": "1.0.1", "ws": "7.3.1" From 07c13122da42c915959bbeeccd1bc481a8521e3e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 25 Sep 2020 15:44:08 +0100 Subject: [PATCH 0217/3183] requestUpdate bugfix --- lib/eWeLinkWS.js | 47 +++++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index f6a63e26..a9df48ca 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -238,7 +238,7 @@ module.exports = class eWeLinkWS { throw "Unknown response"; } } catch (err) { - reject("Device update failed [" + err + "]."); + reject("device update failed [" + err + "]"); } } else { if (this.debug) { @@ -250,7 +250,7 @@ module.exports = class eWeLinkWS { }); } requestUpdate(accessory) { - return new Promise(resolve => { + return new Promise(async resolve => { let sequence = Math.floor(new Date()).toString(), json = { action: "query", @@ -260,31 +260,26 @@ module.exports = class eWeLinkWS { sequence, ts: 0, userAgent: "app", - }, - sendOperation = () => { - this.wsp.send(json); - if (this.debugReqRes) { - let msg = JSON.stringify(json, null, 2) - .replace(json.apikey, "**hidden**") - .replace(json.apiKey, "**hidden**") - .replace(json.deviceid, "**hidden**"); - this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("WS message sent."); - } - }, - checkToSend = async () => { - if (this.wsp && this.wsIsOpen) { - sendOperation(); - } else { - await utils.sleep(2500); - if (this.debug) { - this.log.warn("Will resend command when WS is reconnected."); - } - checkToSend(); - } }; - checkToSend(); + + if (this.wsp && this.wsIsOpen) { + this.wsp.send(JSON.stringify(json)); + if (this.debugReqRes) { + let msg = JSON.stringify(json, null, 2) + .replace(json.apikey, "**hidden**") + .replace(json.apiKey, "**hidden**") + .replace(json.deviceid, "**hidden**"); + this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); + } else if (this.debug) { + this.log("WS message sent."); + } + } else { + if (this.debug) { + this.log.warn("Command will be resent when WS is reconnected."); + } + await utils.sleep(30000); + resolve(this.requestUpdate(accessory)); + } }); } receiveUpdate(f) { From 78ddb14eee5db355bc7f15d058750a9b8f48f781 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 25 Sep 2020 15:44:24 +0100 Subject: [PATCH 0218/3183] improved logging --- lib/eWeLink.js | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index d66cbdaf..7bc0cc34 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1193,10 +1193,15 @@ class eWeLink { try { await this.wsClient.requestUpdate(accessory); this.log.warn( - "[%s] requesting previous state to revert Homebridge status.", + "[%s] requesting previous state to revert Homebridge state.", accessory.displayName ); } catch (err) {} + } else { + this.log.warn( + "[%s] Homebridge state will be synced once the device comes back online.", + accessory.displayName + ); } } async internalValveUpdate(accessory, valve, value, callback) { @@ -1346,19 +1351,23 @@ class eWeLink { outlet: 3, }, ]; - accessory.context.inUse = true; - if (prevState !== 2) { + + if (prevState !== 2 || accessory.context.inUse) { + await utils.sleep(500); this.log.warn( "[%s] tried to move the blinds to [%s%] but they are already moving.", accessory.displayName, newTarget ); - wcService.updateCharacteristic( - Characteristic.TargetPosition, - accessory.context.cacheTargetPosition - ); + wcService + .updateCharacteristic( + Characteristic.TargetPosition, + accessory.context.cacheTargetPosition + ) + .updateCharacteristic(Characteristic.PositionState, accessory.context.cachePositionState); return; } + accessory.context.inUse = true; wcService.updateCharacteristic(Characteristic.TargetPosition, newTarget); accessory.context.cacheTargetPosition = newTarget; let moveUp = newTarget > prevPos, From 8436eb28f7924ee36979af6b642f5150a395a2ff Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 25 Sep 2020 15:45:28 +0100 Subject: [PATCH 0219/3183] 3.0.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4560d366..16b95537 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.1", + "version": "3.0.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 46a2e2e3..cf8c488f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.1", + "version": "3.0.2", "author": "bwp91", "contributors": [ "gbro115", From fe636c6ad2a1f6b3d1c5f1d7874f9fd36189d6d1 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 26 Sep 2020 17:49:41 +0100 Subject: [PATCH 0220/3183] blinds relative % --- .prettierrc.json | 2 +- lib/constants.js | 41 ++-- lib/eWeLink.js | 584 ++++++++++++++------------------------------- lib/eWeLinkHTTP.js | 19 +- lib/eWeLinkLAN.js | 22 +- lib/eWeLinkWS.js | 21 +- 6 files changed, 209 insertions(+), 480 deletions(-) diff --git a/.prettierrc.json b/.prettierrc.json index 87f5e5e8..163a0a7e 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,4 +1,4 @@ { "arrowParens": "avoid", - "printWidth": 100 + "printWidth": 120 } diff --git a/lib/constants.js b/lib/constants.js index 9e1ce0d4..555488c5 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -12,18 +12,7 @@ module.exports = { devicesSingleSwitchOutlet: ["Sonoff Pow", "S26"], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], devicesMultiSwitchParams: ["switches"], - devicesSingleSwitchLight: [ - "T1 1C", - "L1", - "B1", - "B1_R2", - "TX1C", - "D1", - "D1R1", - "KING-M4", - "Slampher", - "GTTA59", - ], + devicesSingleSwitchLight: ["T1 1C", "L1", "B1", "B1_R2", "TX1C", "D1", "D1R1", "KING-M4", "Slampher", "GTTA59"], devicesSingleSwitchLightParams: [ "switch", "state", @@ -56,15 +45,7 @@ module.exports = { devicesRFBridge: [28], devicesRFBridgeParams: ["cmd"], devicesZBBridge: [66], - devicesZBBridgeParams: [ - "key", - "temperature", - "humidity", - "motion", - "lock", - "trigTime", - "battery", - ], + devicesZBBridgeParams: ["key", "temperature", "humidity", "motion", "lock", "trigTime", "battery"], devicesZB: [1000, 1770, 2026, 3026], devicesValveParams: ["switches"], devicesBlindParams: ["switch", "switches"], @@ -108,6 +89,24 @@ module.exports = { "voltage", "zyx_mode", ], + defaultMultiSwitchOff: [ + { + switch: "off", + outlet: 0, + }, + { + switch: "off", + outlet: 1, + }, + { + switch: "off", + outlet: 2, + }, + { + switch: "off", + outlet: 3, + }, + ], chansFromUiid: { 1: 1, // "SOCKET" \\ 20, MINI, BASIC, S26 2: 2, // "SOCKET_2" \\ diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 7bc0cc34..57e64c9d 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -116,18 +116,9 @@ class eWeLink { } initialiseDevice(device) { let accessory; - //*** IRRIGATION VALVES ***\\ - if ( - device.extra.uiid === 2 && - device.brandName === "coolkit" && - device.productModel === "0285" - ) { - accessory = this.devicesInHB.has(device.deviceid + "SWX") - ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "valve"); - } + //*** CURTAINS ***\\ - else if (cns.devicesCurtain.includes(device.extra.uiid)) { + if (cns.devicesCurtain.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "curtain", false, { @@ -145,10 +136,7 @@ class eWeLink { } } //*** WINDOW BLINDS ***\\ - else if ( - this.cusG.has(device.deviceid + "SWX") && - this.cusG.get(device.deviceid + "SWX").type === "blind" - ) { + else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "blind") { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "blind", false, { @@ -165,10 +153,7 @@ class eWeLink { //*** @ENDUPGRADE ***\\ } //*** GARAGE DOORS ***\\ - else if ( - this.cusG.has(device.deviceid + "SWX") && - this.cusG.get(device.deviceid + "SWX").type === "garage" - ) { + else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "garage") { accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "garage", false, { @@ -182,14 +167,11 @@ class eWeLink { } //*** @ENDUPGRADE ***\\ } - //*** LOCKS ***\\ - else if ( - this.cusG.has(device.deviceid + "SWX") && - this.cusG.get(device.deviceid + "SWX").type === "lock" - ) { - accessory = this.devicesInHB.has(device.deviceid + "SWX") + //*** SINGLE LOCKS ***\\ + else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "lock") { + let lockConfig = (accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "lock"); + : this.addAccessory(device, device.deviceid + "SWX", "lock")); } //*** SENSORS (DW2) ***\\ else if (cns.devicesSensor.includes(device.extra.uiid)) { @@ -197,6 +179,12 @@ class eWeLink { ? this.devicesInHB.get(device.deviceid + "SWX") : this.addAccessory(device, device.deviceid + "SWX", "sensor"); } + //*** IRRIGATION VALVES ***\\ + else if (device.extra.uiid === 2 && device.brandName === "coolkit" && device.productModel === "0285") { + accessory = this.devicesInHB.has(device.deviceid + "SWX") + ? this.devicesInHB.get(device.deviceid + "SWX") + : this.addAccessory(device, device.deviceid + "SWX", "valve"); + } //*** FANS ***\\ else if (cns.devicesFan.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + "SWX") @@ -368,22 +356,13 @@ class eWeLink { swNumber, }; if ((subAccessory = this.devicesInHB.get(device.deviceid + "SW" + swNumber))) { - if ( - subAccessory.context.subType !== subType || - subAccessory.context.swNumber !== swNumber - ) { + if (subAccessory.context.subType !== subType || subAccessory.context.swNumber !== swNumber) { this.removeAccessory(subAccessory); } } subAccessory = this.devicesInHB.has(device.deviceid + "SW" + swNumber) ? this.devicesInHB.get(device.deviceid + "SW" + swNumber) - : this.addAccessory( - device, - device.deviceid + "SW" + swNumber, - "rf_sub", - false, - subExtraContext - ); + : this.addAccessory(device, device.deviceid + "SW" + swNumber, "rf_sub", false, subExtraContext); subAccessory .getService(Service.AccessoryInformation) .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); @@ -485,19 +464,13 @@ class eWeLink { newDeviceName = this.config.nameOverride[hbDeviceId]; } try { - const accessory = new Accessory( - newDeviceName, - this.api.hap.uuid.generate(hbDeviceId).toString() - ); + const accessory = new Accessory(newDeviceName, this.api.hap.uuid.generate(hbDeviceId).toString()); if (!hidden) { accessory .getService(Service.AccessoryInformation) .setCharacteristic(Characteristic.SerialNumber, hbDeviceId) .setCharacteristic(Characteristic.Manufacturer, device.brandName) - .setCharacteristic( - Characteristic.Model, - device.productModel + " (" + device.extra.model + ")" - ) + .setCharacteristic(Characteristic.Model, device.productModel + " (" + device.extra.model + ")") .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) .setCharacteristic(Characteristic.Identify, false); } @@ -546,21 +519,17 @@ class eWeLink { } valveService .getCharacteristic(Characteristic.Active) - .on("set", (value, callback) => - this.internalValveUpdate(accessory, "Valve " + v, value, callback) - ); - valveService - .getCharacteristic(Characteristic.SetDuration) - .on("set", (value, callback) => { - if (valveService.getCharacteristic(Characteristic.InUse).value) { - valveService.updateCharacteristic(Characteristic.RemainingDuration, value); - clearTimeout(valveService.timer); - valveService.timer = setTimeout(() => { - valveService.setCharacteristic(Characteristic.Active, 0); - }, value * 1000); - } - callback(); - }); + .on("set", (value, callback) => this.internalValveUpdate(accessory, "Valve " + v, value, callback)); + valveService.getCharacteristic(Characteristic.SetDuration).on("set", (value, callback) => { + if (valveService.getCharacteristic(Characteristic.InUse).value) { + valveService.updateCharacteristic(Characteristic.RemainingDuration, value); + clearTimeout(valveService.timer); + valveService.timer = setTimeout(() => { + valveService.setCharacteristic(Characteristic.Active, 0); + }, value * 1000); + } + callback(); + }); }); break; case "curtain": @@ -606,65 +575,47 @@ class eWeLink { .on("set", (value, callback) => this.internalGarageUpdate(accessory, value, callback)); break; case "lock": - let lmService = - accessory.getService(Service.LockMechanism) || - accessory.addService(Service.LockMechanism); + let lmService = accessory.getService(Service.LockMechanism) || accessory.addService(Service.LockMechanism); lmService .getCharacteristic(Characteristic.LockTargetState) .on("set", (value, callback) => this.internalLockUpdate(accessory, value, callback)); break; case "sensor": - accessory.getService(Service.ContactSensor) || - accessory.addService(Service.ContactSensor); - accessory.getService(Service.BatteryService) || - accessory.addService(Service.BatteryService); + accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor); + accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); break; case "fan": - let fanService = - accessory.getService(Service.Fanv2) || accessory.addService(Service.Fanv2), - fanLightService = - accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb); + let fanService = accessory.getService(Service.Fanv2) || accessory.addService(Service.Fanv2), + fanLightService = accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb); fanService .getCharacteristic(Characteristic.Active) - .on("set", (value, callback) => - this.internalFanUpdate(accessory, "power", value, callback) - ); + .on("set", (value, callback) => this.internalFanUpdate(accessory, "power", value, callback)); fanService .getCharacteristic(Characteristic.RotationSpeed) - .on("set", (value, callback) => - this.internalFanUpdate(accessory, "speed", value, callback) - ) + .on("set", (value, callback) => this.internalFanUpdate(accessory, "speed", value, callback)) .setProps({ minStep: 33, }); fanLightService .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => - this.internalFanUpdate(accessory, "light", value, callback) - ); + .on("set", (value, callback) => this.internalFanUpdate(accessory, "light", value, callback)); break; case "thermostat": let tempService = - accessory.getService(Service.TemperatureSensor) || - accessory.addService(Service.TemperatureSensor), + accessory.getService(Service.TemperatureSensor) || accessory.addService(Service.TemperatureSensor), humiService = false; if (accessory.context.sensorType !== "DS18B20") { - humiService = - accessory.getService(Service.HumiditySensor) || - accessory.addService(Service.HumiditySensor); + humiService = accessory.getService(Service.HumiditySensor) || accessory.addService(Service.HumiditySensor); } else { if (accessory.getService(Service.HumiditySensor)) { accessory.removeService(Service.HumiditySensor); } } if (!this.config.hideTHSwitch) { - let switchService = - accessory.getService(Service.Switch) || accessory.addService(Service.Switch); + let switchService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch); switchService .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => - this.internalThermostatUpdate(accessory, value, callback) - ); + .on("set", (value, callback) => this.internalThermostatUpdate(accessory, value, callback)); } if (!(this.config.disableEveLogging || false)) { accessory.log = this.log; @@ -720,8 +671,7 @@ class eWeLink { corrInterval.setCorrectingInterval(() => { let isOn = outletService.getCharacteristic(Characteristic.On).value, currentWatt = isOn - ? outletService.getCharacteristic(EveService.Characteristics.CurrentConsumption) - .value + ? outletService.getCharacteristic(EveService.Characteristics.CurrentConsumption).value : 0; if (accessory.eveLogger.isHistoryLoaded()) { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); @@ -735,8 +685,7 @@ class eWeLink { lastReset: accessory.context.extraPersistedData.lastReset, }); } else { - accessory.context.totalEnergy = - accessory.context.totalEnergyTemp + (currentWatt * 10) / 3600 / 1000; + accessory.context.totalEnergy = accessory.context.totalEnergyTemp + (currentWatt * 10) / 3600 / 1000; accessory.eveLogger.setExtraPersistedData({ totalenergy: accessory.context.totalEnergy, lastReset: 0, @@ -752,15 +701,13 @@ class eWeLink { power: currentWatt, }); }, 300000); - outletService - .getCharacteristic(EveService.Characteristics.TotalConsumption) - .on("get", callback => { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower; - } - callback(null, accessory.context.totalEnergy); - }); + outletService.getCharacteristic(EveService.Characteristics.TotalConsumption).on("get", callback => { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower; + } + callback(null, accessory.context.totalEnergy); + }); outletService .getCharacteristic(EveService.Characteristics.ResetTotal) .on("set", (value, callback) => { @@ -782,70 +729,56 @@ class eWeLink { } break; case "usb": - let usbService = - accessory.getService(Service.Outlet) || accessory.addService(Service.Outlet); + let usbService = accessory.getService(Service.Outlet) || accessory.addService(Service.Outlet); usbService .getCharacteristic(Characteristic.On) .on("set", (value, callback) => this.internalUSBUpdate(accessory, value, callback)); break; case "scm": - let scmService = - accessory.getService(Service.Switch) || accessory.addService(Service.Switch); + let scmService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch); scmService .getCharacteristic(Characteristic.On) .on("set", (value, callback) => this.internalSCMUpdate(accessory, value, callback)); break; case "light": - let lightService = - accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb); + let lightService = accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb); lightService .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => - this.internalLightbulbUpdate(accessory, value, callback) - ); + .on("set", (value, callback) => this.internalLightbulbUpdate(accessory, value, callback)); if (cns.devicesBrightable.includes(accessory.context.eweUIID)) { - lightService - .getCharacteristic(Characteristic.Brightness) - .on("set", (value, callback) => { - if (value > 0) { - if (!lightService.getCharacteristic(Characteristic.On).value) { - this.internalLightbulbUpdate(accessory, true, function () { - return; - }); - } - this.internalBrightnessUpdate(accessory, value, callback); - } else { - this.internalLightbulbUpdate(accessory, false, callback); + lightService.getCharacteristic(Characteristic.Brightness).on("set", (value, callback) => { + if (value > 0) { + if (!lightService.getCharacteristic(Characteristic.On).value) { + this.internalLightbulbUpdate(accessory, true, function () { + return; + }); } - }); + this.internalBrightnessUpdate(accessory, value, callback); + } else { + this.internalLightbulbUpdate(accessory, false, callback); + } + }); } else if (cns.devicesColourable.includes(accessory.context.eweUIID)) { - lightService - .getCharacteristic(Characteristic.Brightness) - .on("set", (value, callback) => { - if (value > 0) { - if (!lightService.getCharacteristic(Characteristic.On).value) { - this.internalLightbulbUpdate(accessory, true, function () { - return; - }); - } - this.internalHSBUpdate(accessory, "bri", value, callback); - } else { - this.internalLightbulbUpdate(accessory, false, callback); + lightService.getCharacteristic(Characteristic.Brightness).on("set", (value, callback) => { + if (value > 0) { + if (!lightService.getCharacteristic(Characteristic.On).value) { + this.internalLightbulbUpdate(accessory, true, function () { + return; + }); } - }); + this.internalHSBUpdate(accessory, "bri", value, callback); + } else { + this.internalLightbulbUpdate(accessory, false, callback); + } + }); lightService .getCharacteristic(Characteristic.Hue) - .on("set", (value, callback) => - this.internalHSBUpdate(accessory, "hue", value, callback) - ); - lightService - .getCharacteristic(Characteristic.Saturation) - .on("set", (value, callback) => callback()); + .on("set", (value, callback) => this.internalHSBUpdate(accessory, "hue", value, callback)); + lightService.getCharacteristic(Characteristic.Saturation).on("set", (value, callback) => callback()); } break; case "switch": - let switchService = - accessory.getService(Service.Switch) || accessory.addService(Service.Switch); + let switchService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch); switchService .getCharacteristic(Characteristic.On) .on("set", (value, callback) => this.internalSwitchUpdate(accessory, value, callback)); @@ -857,33 +790,26 @@ class eWeLink { break; case "fire": case "smoke": - accessory.getService(Service.SmokeSensor) || - accessory.addService(Service.SmokeSensor); + accessory.getService(Service.SmokeSensor) || accessory.addService(Service.SmokeSensor); break; case "co": - accessory.getService(Service.CarbonMonoxideSensor) || - accessory.addService(Service.CarbonMonoxideSensor); + accessory.getService(Service.CarbonMonoxideSensor) || accessory.addService(Service.CarbonMonoxideSensor); break; case "co2": - accessory.getService(Service.CarbonDioxideSensor) || - accessory.addService(Service.CarbonDioxideSensor); + accessory.getService(Service.CarbonDioxideSensor) || accessory.addService(Service.CarbonDioxideSensor); break; case "contact": - accessory.getService(Service.ContactSensor) || - accessory.addService(Service.ContactSensor); + accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor); break; case "occupancy": - accessory.getService(Service.OccupancySensor) || - accessory.addService(Service.OccupancySensor); + accessory.getService(Service.OccupancySensor) || accessory.addService(Service.OccupancySensor); break; default: - accessory.getService(Service.MotionSensor) || - accessory.addService(Service.MotionSensor); + accessory.getService(Service.MotionSensor) || accessory.addService(Service.MotionSensor); break; case "button": Object.entries(accessory.context.buttons).forEach(([chan, name]) => { - accessory.getService(name) || - accessory.addService(Service.Switch, name, "switch" + chan); + accessory.getService(name) || accessory.addService(Service.Switch, name, "switch" + chan); accessory.getService(name).updateCharacteristic(Characteristic.On, false); accessory .getService(name) @@ -896,8 +822,7 @@ class eWeLink { } break; case "zb_dev": //*** credit @tasict ***\\ - accessory.getService(Service.BatteryService) || - accessory.addService(Service.BatteryService); + accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); switch (accessory.context.eweUIID) { case 1000: let zbspsService = @@ -911,11 +836,9 @@ class eWeLink { break; case 1770: let zbTempService = - accessory.getService(Service.TemperatureSensor) || - accessory.addService(Service.TemperatureSensor); + accessory.getService(Service.TemperatureSensor) || accessory.addService(Service.TemperatureSensor); let zbHumiService = - accessory.getService(Service.HumiditySensor) || - accessory.addService(Service.HumiditySensor); + accessory.getService(Service.HumiditySensor) || accessory.addService(Service.HumiditySensor); accessory.log = this.log; accessory.eveLogger = new EveHistoryService("weather", accessory, { storage: "fs", @@ -926,19 +849,16 @@ class eWeLink { let dataToAdd = { time: Date.now(), temp: zbTempService.getCharacteristic(Characteristic.CurrentTemperature).value, - humidity: zbHumiService.getCharacteristic(Characteristic.CurrentRelativeHumidity) - .value, + humidity: zbHumiService.getCharacteristic(Characteristic.CurrentRelativeHumidity).value, }; accessory.eveLogger.addEntry(dataToAdd); }, 300000); break; case 2026: - accessory.getService(Service.MotionSensor) || - accessory.addService(Service.MotionSensor); + accessory.getService(Service.MotionSensor) || accessory.addService(Service.MotionSensor); break; case 3026: - accessory.getService(Service.ContactSensor) || - accessory.addService(Service.ContactSensor); + accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor); break; } break; @@ -951,10 +871,7 @@ class eWeLink { refreshAccessory(accessory, newParams) { switch (accessory.context.type) { case "valve": - if ( - Object.keys(newParams).some(v => cns.devicesValveParams.includes(v)) && - Array.isArray(newParams.switches) - ) { + if (Object.keys(newParams).some(v => cns.devicesValveParams.includes(v)) && Array.isArray(newParams.switches)) { this.externalValveUpdate(accessory, newParams); } return true; @@ -964,10 +881,7 @@ class eWeLink { } return true; case "blind": - if ( - Object.keys(newParams).some(v => cns.devicesBlindParams.includes(v)) && - Array.isArray(newParams.switches) - ) { + if (Object.keys(newParams).some(v => cns.devicesBlindParams.includes(v)) && Array.isArray(newParams.switches)) { this.externalBlindUpdate(accessory, newParams); } return true; @@ -1005,18 +919,12 @@ class eWeLink { } return true; case "usb": - if ( - Object.keys(newParams).some(v => cns.devicesUSBParams.includes(v)) && - Array.isArray(newParams.switches) - ) { + if (Object.keys(newParams).some(v => cns.devicesUSBParams.includes(v)) && Array.isArray(newParams.switches)) { this.externalUSBUpdate(accessory, newParams); } return true; case "scm": - if ( - Object.keys(newParams).some(v => cns.devicesSCMParams.includes(v)) && - Array.isArray(newParams.switches) - ) { + if (Object.keys(newParams).some(v => cns.devicesSCMParams.includes(v)) && Array.isArray(newParams.switches)) { this.externalSCMUpdate(accessory, newParams); } return true; @@ -1111,16 +1019,13 @@ class eWeLink { let accessory, deviceId = device.deviceid, reachableChange = false; - if ( - (accessory = this.devicesInHB.get(deviceId + "SWX") || this.devicesInHB.get(deviceId + "SW0")) - ) { + if ((accessory = this.devicesInHB.get(deviceId + "SWX") || this.devicesInHB.get(deviceId + "SW0"))) { let isX = accessory.context.hbDeviceId.substr(-1) === "X"; if (device.params.updateSource === "WS") { if (device.params.online != accessory.context.reachableWAN) { accessory.context.reachableWAN = device.params.online; this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - if (accessory.context.reachableWAN) - this.wsClient.requestUpdate(accessory).catch(() => {}); + if (accessory.context.reachableWAN) this.wsClient.requestUpdate(accessory).catch(() => {}); reachableChange = true; this.log.warn( "[%s] has been reported [%s] via [WS].", @@ -1179,10 +1084,7 @@ class eWeLink { this.lanClient.addDeviceToMap(device); } catch (err) { this.log.error("[%s] error getting info [%s]", deviceId, err); - this.log.error( - "[%s] Please try restarting Homebridge so this device is added.", - deviceId - ); + this.log.error("[%s] Please try restarting Homebridge so this device is added.", deviceId); } } } @@ -1192,16 +1094,10 @@ class eWeLink { if (accessory.context.reachableWAN) { try { await this.wsClient.requestUpdate(accessory); - this.log.warn( - "[%s] requesting previous state to revert Homebridge state.", - accessory.displayName - ); + this.log.warn("[%s] requesting previous state to revert Homebridge state.", accessory.displayName); } catch (err) {} } else { - this.log.warn( - "[%s] Homebridge state will be synced once the device comes back online.", - accessory.displayName - ); + this.log.warn("[%s] Homebridge state will be synced once the device comes back online.", accessory.displayName); } } async internalValveUpdate(accessory, valve, value, callback) { @@ -1213,16 +1109,12 @@ class eWeLink { switch (valve) { case "Valve A": params.switches[0].switch = value ? "on" : "off"; - params.switches[1].switch = accessory - .getService("Valve B") - .getCharacteristic(Characteristic.Active).value + params.switches[1].switch = accessory.getService("Valve B").getCharacteristic(Characteristic.Active).value ? "on" : "off"; break; case "Valve B": - params.switches[0].switch = accessory - .getService("Valve A") - .getCharacteristic(Characteristic.Active).value + params.switches[0].switch = accessory.getService("Valve A").getCharacteristic(Characteristic.Active).value ? "on" : "off"; params.switches[1].switch = value ? "on" : "off"; @@ -1231,9 +1123,7 @@ class eWeLink { params.switches[2].switch = "off"; params.switches[3].switch = "off"; await this.sendDeviceUpdate(accessory, params); - serviceValve - .updateCharacteristic(Characteristic.Active, value) - .updateCharacteristic(Characteristic.InUse, value); + serviceValve.updateCharacteristic(Characteristic.Active, value).updateCharacteristic(Characteristic.InUse, value); switch (value) { case 0: serviceValve.updateCharacteristic(Characteristic.RemainingDuration, 0); @@ -1242,10 +1132,7 @@ class eWeLink { case 1: let timer = serviceValve.getCharacteristic(Characteristic.SetDuration).value; serviceValve.updateCharacteristic(Characteristic.RemainingDuration, timer); - serviceValve.timer = setTimeout( - () => serviceValve.setCharacteristic(Characteristic.Active, 0), - timer * 1000 - ); + serviceValve.timer = setTimeout(() => serviceValve.setCharacteristic(Characteristic.Active, 0), timer * 1000); break; } } catch (err) { @@ -1323,118 +1210,63 @@ class eWeLink { params = {}, wcService = accessory.getService(Service.WindowCovering), prevState = accessory.context.cachePositionState, - prevPos = accessory.context.cacheCurrentPosition, + prevPosition = accessory.context.cacheCurrentPosition, + prevTarget = accessory.context.cacheTargetPosition, newTarget = value, - timeNow = Date.now(); + updateKey = Math.random().toString(36).substr(2, 8); if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } if (blindConfig.type !== "blind" || blindConfig.setup !== "twoSwitch") { throw "improper configuration"; } - if (newTarget === prevPos) return; - params.switches = [ - { - switch: "off", - outlet: 0, - }, - { - switch: "off", - outlet: 1, - }, - { - switch: "off", - outlet: 2, - }, - { - switch: "off", - outlet: 3, - }, - ]; - - if (prevState !== 2 || accessory.context.inUse) { - await utils.sleep(500); - this.log.warn( - "[%s] tried to move the blinds to [%s%] but they are already moving.", - accessory.displayName, - newTarget - ); - wcService - .updateCharacteristic( - Characteristic.TargetPosition, - accessory.context.cacheTargetPosition - ) - .updateCharacteristic(Characteristic.PositionState, accessory.context.cachePositionState); - return; - } - accessory.context.inUse = true; - wcService.updateCharacteristic(Characteristic.TargetPosition, newTarget); - accessory.context.cacheTargetPosition = newTarget; - let moveUp = newTarget > prevPos, - duration = Math.round(Math.abs(newTarget - prevPos) * blindConfig.operationTime); - accessory.context.startTimestamp = timeNow; - accessory.context.targetTimestamp = timeNow + duration; - params.switches[0].switch = moveUp ? "on" : "off"; - params.switches[1].switch = moveUp ? "off" : "on"; - await this.sendDeviceUpdate(accessory, params); - wcService.updateCharacteristic(Characteristic.PositionState, moveUp ? 0 : 1); - accessory.context.cachePositionState = moveUp ? 0 : 1; - await utils.sleep(duration); - params.switches[0].switch = "off"; - params.switches[1].switch = "off"; + if (newTarget === prevPosition) return; + params.switches = cns.defaultMultiSwitchOff; + accessory.context.updateKey = updateKey; + let percentStepPerDecisecond = blindConfig.operationTime / 100; + if (prevState !== 2) { + await this.sendDeviceUpdate(accessory, params); + let beenMovingAlreadyFor = Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime; + let positionPercentChange = Math.round(beenMovingAlreadyFor * percentStepPerDecisecond); + if (prevState === 1) { + prevPosition = prevPosition + positionPercentChange; + } else { + prevPosition = prevPosition - positionPercentChange; + } + wcService.updateCharacteristic(Characteristic.CurrentPosition, prevPosition); + accessory.context.cacheCurrentPosition = prevPosition; + } + let diffPosition = newTarget - prevPosition; + let setToMoveUp = diffPosition > 0; + let decisecondsToMove = Math.round(Math.abs(diffPosition) * percentStepPerDecisecond); + params.switches[0].switch = setToMoveUp ? "on" : "off"; + params.switches[1].switch = setToMoveUp ? "off" : "on"; await this.sendDeviceUpdate(accessory, params); - wcService.updateCharacteristic(Characteristic.PositionState, 2); - wcService.updateCharacteristic(Characteristic.CurrentPosition, newTarget); - accessory.context.cacheCurrentPosition = newTarget; - accessory.context.cachePositionState = 2; - accessory.context.inUse = false; + wcService + .updateCharacteristic(Characteristic.TargetPosition, newTarget) + .updateCharacteristic(Characteristic.PositionState, setToMoveUp); + accessory.context.cacheTargetPosition = newTarget; + accessory.context.cachePositionState = setToMoveUp; + accessory.context.cacheLastStartTime = Math.floor(Date.now() / 100); + this.log.warn(decisecondsToMove + " movement time in deciseconds"); + await utils.sleep(decisecondsToMove * 100); + if (accessory.context.updateKey === updateKey) { + params.switches[0].switch = "off"; + params.switches[1].switch = "off"; + await this.sendDeviceUpdate(accessory, params); + wcService.updateCharacteristic(Characteristic.PositionState, 2); + wcService.updateCharacteristic(Characteristic.CurrentPosition, newTarget); + accessory.context.cachePositionState = 2; + accessory.context.cacheCurrentPosition = newTarget; + accessory.context.inUse = false; + } } catch (err) { this.requestDeviceRefresh(accessory, err); } } externalBlindUpdate(accessory, params) { try { - let blindConfig, - newPosition, - wcService = accessory.getService(Service.WindowCovering); - if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; - } - if (blindConfig.type !== "blind" || blindConfig.setup !== "twoSwitch") { - throw "improper configuration"; - } - if (!params.hasOwnProperty("updateSource")) { - wcService - .updateCharacteristic(Characteristic.PositionState, accessory.context.cachePositionState) - .updateCharacteristic( - Characteristic.TargetPosition, - accessory.context.cacheTargetPosition - ) - .updateCharacteristic( - Characteristic.CurrentPosition, - accessory.context.cacheCurrentPosition - ); - return; - } - if (accessory.context.inUse) return; - if (params.switches[0].switch === "off" && params.switches[1].switch === "off") { - return; - } - let switchUp = params.switches[0].switch === "on" ? -1 : 0, // matrix of numbers to get - switchDown = params.switches[1].switch === "on" ? 0 : 2; // ... the correct HomeKit value - newPosition = switchUp + switchDown; - wcService - .updateCharacteristic(Characteristic.PositionState, newPosition) - .updateCharacteristic(Characteristic.TargetPosition, newPosition * 100); - accessory.context.cachePositionState = newPosition; - accessory.context.cacheTargetPosition = newPosition * 100; - setTimeout(() => { - wcService - .updateCharacteristic(Characteristic.PositionState, 2) - .updateCharacteristic(Characteristic.CurrentPosition, newPosition * 100); - accessory.context.cachePositionState = 2; - accessory.context.cacheCurrentPosition = newPosition * 100; - }, parseInt(blindConfig.operationTime) * 100); + // } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } @@ -1446,10 +1278,7 @@ class eWeLink { if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } - if ( - garageConfig.type !== "garage" || - !["oneSwitch", "twoSwitch"].includes(garageConfig.setup) - ) { + if (garageConfig.type !== "garage" || !["oneSwitch", "twoSwitch"].includes(garageConfig.setup)) { throw "improper configuration"; } let sensorDefinition = garageConfig.sensorId || false, @@ -1466,9 +1295,7 @@ class eWeLink { throw "defined DW2 sensor isn't a sensor"; } prevState = sAccessory - ? sAccessory - .getService(Service.ContactSensor) - .getCharacteristic(Characteristic.ContactSensorState).value === 0 + ? sAccessory.getService(Service.ContactSensor).getCharacteristic(Characteristic.ContactSensorState).value === 0 ? 1 : 0 : accessory.context.cacheCurrentDoorState; @@ -1517,10 +1344,7 @@ class eWeLink { if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } - if ( - garageConfig.type !== "garage" || - !["oneSwitch", "twoSwitch"].includes(garageConfig.setup) - ) { + if (garageConfig.type !== "garage" || !["oneSwitch", "twoSwitch"].includes(garageConfig.setup)) { throw "improper configuration"; } if (accessory.context.inUse || garageConfig.sensorId) { @@ -1621,8 +1445,7 @@ class eWeLink { try { if (params.hasOwnProperty("battery")) { let batteryService = - accessory.getService(Service.BatteryService) || - accessory.addService(Service.BatteryService), + accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService), scaledBattery = Math.round(params.battery * 33.3); batteryService.updateCharacteristic(Characteristic.BatteryLevel, scaledBattery); batteryService.updateCharacteristic( @@ -1729,11 +1552,7 @@ class eWeLink { status = 1; speed = 99; } - } else if ( - params.hasOwnProperty("light") && - params.hasOwnProperty("fan") && - params.hasOwnProperty("speed") - ) { + } else if (params.hasOwnProperty("light") && params.hasOwnProperty("fan") && params.hasOwnProperty("speed")) { light = params.light === "on"; status = params.fan === "on" ? 1 : 0; speed = params.speed * 33 * status; @@ -1764,13 +1583,8 @@ class eWeLink { } externalThermostatUpdate(accessory, params) { try { - if ( - !this.config.hideTHSwitch && - (params.hasOwnProperty("switch") || params.hasOwnProperty("mainSwitch")) - ) { - let newState = params.hasOwnProperty("switch") - ? params.switch === "on" - : params.mainSwitch === "on", + if (!this.config.hideTHSwitch && (params.hasOwnProperty("switch") || params.hasOwnProperty("mainSwitch"))) { + let newState = params.hasOwnProperty("switch") ? params.switch === "on" : params.mainSwitch === "on", switchService = accessory.getService(Service.Switch); switchService.updateCharacteristic(Characteristic.On, newState); } @@ -1778,21 +1592,14 @@ class eWeLink { let eveLog = { time: Date.now(), }; - if ( - params.hasOwnProperty("currentTemperature") && - accessory.getService(Service.TemperatureSensor) - ) { - let currentTemp = - params.currentTemperature !== "unavailable" ? params.currentTemperature : 0; + if (params.hasOwnProperty("currentTemperature") && accessory.getService(Service.TemperatureSensor)) { + let currentTemp = params.currentTemperature !== "unavailable" ? params.currentTemperature : 0; accessory .getService(Service.TemperatureSensor) .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); eveLog.temp = parseFloat(currentTemp); } - if ( - params.hasOwnProperty("currentHumidity") && - accessory.getService(Service.HumiditySensor) - ) { + if (params.hasOwnProperty("currentHumidity") && accessory.getService(Service.HumiditySensor)) { let currentHumi = params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; accessory .getService(Service.HumiditySensor) @@ -1830,10 +1637,7 @@ class eWeLink { } } if (params.hasOwnProperty("power")) { - outletService.updateCharacteristic( - EveService.Characteristics.CurrentConsumption, - parseFloat(params.power) - ); + outletService.updateCharacteristic(EveService.Characteristics.CurrentConsumption, parseFloat(params.power)); outletService.updateCharacteristic( Characteristic.OutletInUse, parseFloat(params.power) > (this.config.inUsePowerThreshold || 0) @@ -1845,16 +1649,10 @@ class eWeLink { }); } if (params.hasOwnProperty("voltage")) { - outletService.updateCharacteristic( - EveService.Characteristics.Voltage, - parseFloat(params.voltage) - ); + outletService.updateCharacteristic(EveService.Characteristics.Voltage, parseFloat(params.voltage)); } if (params.hasOwnProperty("current")) { - outletService.updateCharacteristic( - EveService.Characteristics.ElectricCurrent, - parseFloat(params.current) - ); + outletService.updateCharacteristic(EveService.Characteristics.ElectricCurrent, parseFloat(params.current)); } } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); @@ -1876,9 +1674,7 @@ class eWeLink { } externalUSBUpdate(accessory, params) { try { - accessory - .getService(Service.Outlet) - .updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); + accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } @@ -1899,9 +1695,7 @@ class eWeLink { } externalSCMUpdate(accessory, params) { try { - accessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } @@ -1956,9 +1750,7 @@ class eWeLink { case "0": for (let i = 0; i <= 4; i++) { if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - oAccessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, value); + oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); } } break; @@ -1970,18 +1762,14 @@ class eWeLink { let masterState = "off"; for (let i = 1; i <= 4; i++) { if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - if ( - oAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value - ) { + if (oAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { masterState = "on"; } } } if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - oAccessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, masterState === "on"); + oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, masterState === "on"); } break; } @@ -2124,10 +1912,7 @@ class eWeLink { case 22: // B1 if (params.hasOwnProperty("zyx_mode")) { mode = parseInt(params.zyx_mode); - } else if ( - params.hasOwnProperty("channel0") && - parseInt(params.channel0) + parseInt(params.channel1) > 0 - ) { + } else if (params.hasOwnProperty("channel0") && parseInt(params.channel0) + parseInt(params.channel1) > 0) { mode = 1; } else { mode = 2; @@ -2184,9 +1969,7 @@ class eWeLink { } } if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { - accessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, primaryState); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, primaryState); } } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); @@ -2249,18 +2032,14 @@ class eWeLink { let masterState = "off"; for (let i = 1; i <= 4; i++) { if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - if ( - oAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value - ) { + if (oAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value) { masterState = "on"; } } } if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - oAccessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, masterState === "on"); + oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, masterState === "on"); } break; } @@ -2270,9 +2049,7 @@ class eWeLink { } externalSingleSwitchUpdate(accessory, params) { try { - accessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, params.switch === "on"); + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switch === "on"); } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } @@ -2320,11 +2097,7 @@ class eWeLink { if (!params.hasOwnProperty("updateSource")) return; let timeNow = new Date(), oAccessory = false; - if ( - params.hasOwnProperty("cmd") && - params.cmd === "transmit" && - params.hasOwnProperty("rfChl") - ) { + if (params.hasOwnProperty("cmd") && params.cmd === "transmit" && params.hasOwnProperty("rfChl")) { //*** RF Button ***\\ // the device needed is SW% corresponding to params.rfChl this.devicesInHB.forEach(acc => { @@ -2336,9 +2109,7 @@ class eWeLink { } }); if (oAccessory) { - oAccessory - .getService(oAccessory.context.buttons[params.rfChl]) - .updateCharacteristic(Characteristic.On, 1); + oAccessory.getService(oAccessory.context.buttons[params.rfChl]).updateCharacteristic(Characteristic.On, 1); setTimeout( () => oAccessory @@ -2406,11 +2177,7 @@ class eWeLink { oAccessory.getService(serv).updateCharacteristic(char, 0); }, (this.config.sensorTimeLength || 2) * 1000); if (this.debug) { - this.log( - "[%s] has detected [%s].", - oAccessory.displayName, - oAccessory.context.sensorType - ); + this.log("[%s] has detected [%s].", oAccessory.displayName, oAccessory.context.sensorType); } } } @@ -2428,8 +2195,7 @@ class eWeLink { params.battery *= 10; } let batteryService = - accessory.getService(Service.BatteryService) || - accessory.addService(Service.BatteryService); + accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); batteryService.updateCharacteristic(Characteristic.BatteryLevel, params.battery); batteryService.updateCharacteristic( Characteristic.StatusLowBattery, diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 4076d982..03e24b06 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -33,10 +33,7 @@ module.exports = class eWeLinkHTTP { }); dataToSign.sort((a, b) => (a.key < b.key ? -1 : 1)); dataToSign = dataToSign.map(k => k.key + "=" + k.value).join("&"); - dataToSign = crypto - .createHmac("sha256", constants.appSecret) - .update(dataToSign) - .digest("base64"); + dataToSign = crypto.createHmac("sha256", constants.appSecret).update(dataToSign).digest("base64"); if (this.debugReqRes) { this.log.warn( "Sending HTTP getHost request. This text is yellow for clarity.\n%s", @@ -73,10 +70,7 @@ module.exports = class eWeLinkHTTP { } resolve(this.httpHost); } catch (err) { - if ( - err.hasOwnProperty("code") && - ["ENOTFOUND", "ETIMEDOUT", "EAI_AGAIN"].includes(err.code) - ) { + if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT", "EAI_AGAIN"].includes(err.code)) { this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); await utils.sleep(30000); resolve(this.getHost()); @@ -93,9 +87,7 @@ module.exports = class eWeLinkHTTP { password: this.password, }; try { - this.username.includes("@") - ? (data.email = this.username) - : (data.phoneNumber = this.username); + this.username.includes("@") ? (data.email = this.username) : (data.phoneNumber = this.username); if (this.debugReqRes) { let msg = JSON.stringify(data, null, 2) .replace(this.password, "**hidden**") @@ -104,10 +96,7 @@ module.exports = class eWeLinkHTTP { } else if (this.debug) { this.log("Sending HTTP login request."); } - let dataToSign = crypto - .createHmac("sha256", constants.appSecret) - .update(JSON.stringify(data)) - .digest("base64"); + let dataToSign = crypto.createHmac("sha256", constants.appSecret).update(JSON.stringify(data)).digest("base64"); let res = await axios.post("https://" + this.httpHost + "/v2/user/login", data, { headers: { Authorization: "Sign " + dataToSign, diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index b046db46..70d0c13c 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -15,9 +15,7 @@ module.exports = class eWeLinkLAN { this.deviceMap.set(device.deviceid, { apiKey: device.devicekey, online: this.ipOverrides.hasOwnProperty(device.deviceid) ? true : false, - ip: this.ipOverrides.hasOwnProperty(device.deviceid) - ? this.ipOverrides[device.deviceid] - : null, + ip: this.ipOverrides.hasOwnProperty(device.deviceid) ? this.ipOverrides[device.deviceid] : null, }); }); this.debug = config.debug || false; @@ -64,15 +62,9 @@ module.exports = class eWeLinkLAN { (rdata.hasOwnProperty("data2") ? rdata.data2 : "") + (rdata.hasOwnProperty("data3") ? rdata.data3 : "") + (rdata.hasOwnProperty("data4") ? rdata.data4 : ""), - key = crypto - .createHash("md5") - .update(Buffer.from(deviceInfo.apiKey, "utf8")) - .digest(), + key = crypto.createHash("md5").update(Buffer.from(deviceInfo.apiKey, "utf8")).digest(), dText = crypto.createDecipheriv("aes-128-cbc", key, Buffer.from(rdata.iv, "base64")), - pText = Buffer.concat([ - dText.update(Buffer.from(data, "base64")), - dText.final(), - ]).toString("utf8"), + pText = Buffer.concat([dText.update(Buffer.from(data, "base64")), dText.final()]).toString("utf8"), params; if (packet.address !== deviceInfo.ip && !this.ipOverrides.hasOwnProperty(rdata.id)) { this.deviceMap.set(rdata.id, { @@ -140,9 +132,7 @@ module.exports = class eWeLinkLAN { iv = crypto.randomBytes(16), enc = crypto.createCipheriv("aes-128-cbc", key, iv), data = { - data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString( - "base64" - ), + data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString("base64"), deviceid: json.deviceid, encrypt: true, iv: iv.toString("base64"), @@ -185,9 +175,7 @@ module.exports = class eWeLinkLAN { this.deviceMap.set(device.deviceid, { apiKey: device.devicekey, online: this.ipOverrides.hasOwnProperty(device.deviceid) ? true : false, - ip: this.ipOverrides.hasOwnProperty(device.deviceid) - ? this.ipOverrides[device.deviceid] - : null, + ip: this.ipOverrides.hasOwnProperty(device.deviceid) ? this.ipOverrides[device.deviceid] : null, }); } closeConnection() { diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index a9df48ca..c3201325 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -100,12 +100,7 @@ module.exports = class eWeLinkWS { let res = await this.wsp.sendRequest(payload, { requestId: sequence, }); - if ( - res.hasOwnProperty("config") && - res.config.hb && - res.config.hbInterval && - !this.hbInterval - ) { + if (res.hasOwnProperty("config") && res.config.hb && res.config.hbInterval && !this.hbInterval) { this.hbInterval = setInterval(() => { this.wsp.send("ping"); }, (res.config.hbInterval + 7) * 1000); @@ -146,10 +141,7 @@ module.exports = class eWeLinkWS { params: device.params, }; if (this.debugReqRes) { - let msg = JSON.stringify(returnTemplate, null, 2).replace( - device.deviceid, - "**hidden**" - ); + let msg = JSON.stringify(returnTemplate, null, 2).replace(device.deviceid, "**hidden**"); this.log("WS message received.\n%s", msg); } else if (this.debug) { this.log("WS message received."); @@ -160,10 +152,7 @@ module.exports = class eWeLinkWS { case "reportSubDevice": return; default: - this.log.warn( - "[%s] WS message has unknown action.\n" + JSON.stringify(device, null, 2), - device.deviceid - ); + this.log.warn("[%s] WS message has unknown action.\n" + JSON.stringify(device, null, 2), device.deviceid); return; } } else if (device.hasOwnProperty("error") && device.error === 0) { @@ -194,9 +183,7 @@ module.exports = class eWeLinkWS { this.wsp.onError.addListener(e => { this.log.error("Web socket error - [%s].", e); if (e.code === "ECONNREFUSED") { - this.log.warn( - "Web socket will try to reconnect in five seconds then try the command again." - ); + this.log.warn("Web socket will try to reconnect in five seconds then try the command again."); this.wsp.removeAllListeners(); setTimeout(() => this.login(), 5000); } else { From 11ae9127ac5266b2b30311fb5ab8389270089594 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 26 Sep 2020 17:51:24 +0100 Subject: [PATCH 0221/3183] 3.0.3-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 16b95537..0f7c5732 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.2", + "version": "3.0.3-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index cf8c488f..761b4ca3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.2", + "version": "3.0.3-0", "author": "bwp91", "contributors": [ "gbro115", From a6e3b516f5a167d9d171185361f58e8a24adf6ed Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 26 Sep 2020 18:55:39 +0100 Subject: [PATCH 0222/3183] blinds rel % fix --- lib/eWeLink.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 57e64c9d..53bc6241 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1211,7 +1211,6 @@ class eWeLink { wcService = accessory.getService(Service.WindowCovering), prevState = accessory.context.cachePositionState, prevPosition = accessory.context.cacheCurrentPosition, - prevTarget = accessory.context.cacheTargetPosition, newTarget = value, updateKey = Math.random().toString(36).substr(2, 8); if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { @@ -1226,12 +1225,13 @@ class eWeLink { let percentStepPerDecisecond = blindConfig.operationTime / 100; if (prevState !== 2) { await this.sendDeviceUpdate(accessory, params); - let beenMovingAlreadyFor = Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime; - let positionPercentChange = Math.round(beenMovingAlreadyFor * percentStepPerDecisecond); - if (prevState === 1) { - prevPosition = prevPosition + positionPercentChange; + let positionPercentChange = Math.round( + Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime * percentStepPerDecisecond + ); + if ((prevState === 0 && newTarget > prevPosition) || (prevState === 1 && newTarget < prevPosition)) { + prevPosition += positionPercentChange; } else { - prevPosition = prevPosition - positionPercentChange; + prevPosition -= positionPercentChange; } wcService.updateCharacteristic(Characteristic.CurrentPosition, prevPosition); accessory.context.cacheCurrentPosition = prevPosition; @@ -1258,7 +1258,6 @@ class eWeLink { wcService.updateCharacteristic(Characteristic.CurrentPosition, newTarget); accessory.context.cachePositionState = 2; accessory.context.cacheCurrentPosition = newTarget; - accessory.context.inUse = false; } } catch (err) { this.requestDeviceRefresh(accessory, err); @@ -1266,7 +1265,6 @@ class eWeLink { } externalBlindUpdate(accessory, params) { try { - // } catch (err) { this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); } From f6ca880243168b4db2ac15f275b377e3d90a02b0 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 26 Sep 2020 18:56:15 +0100 Subject: [PATCH 0223/3183] 3.0.3-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0f7c5732..cf967598 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.3-0", + "version": "3.0.3-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 761b4ca3..a50beb2b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.3-0", + "version": "3.0.3-1", "author": "bwp91", "contributors": [ "gbro115", From 825bfbcded98d7ae5953cae6eef3a13e3d10c814 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 26 Sep 2020 20:54:39 +0100 Subject: [PATCH 0224/3183] separate devices --- lib/constants.js | 1 - lib/device/blind.js | 73 +++ lib/device/curtain.js | 52 ++ lib/device/fan.js | 92 +++ lib/device/garage.js | 125 ++++ lib/device/light.js | 287 +++++++++ lib/device/lock.js | 67 ++ lib/device/outlet.js | 56 ++ lib/device/rf-sub.js | 122 ++++ lib/device/scm.js | 32 + lib/device/sensor.js | 54 ++ lib/device/switch.js | 111 ++++ lib/device/thermostat.js | 58 ++ lib/device/usb.js | 31 + lib/device/valve.js | 71 ++ lib/device/zb-dev.js | 82 +++ lib/eWeLink.js | 1327 +++----------------------------------- 17 files changed, 1412 insertions(+), 1229 deletions(-) create mode 100644 lib/device/blind.js create mode 100644 lib/device/curtain.js create mode 100644 lib/device/fan.js create mode 100644 lib/device/garage.js create mode 100644 lib/device/light.js create mode 100644 lib/device/lock.js create mode 100644 lib/device/outlet.js create mode 100644 lib/device/rf-sub.js create mode 100644 lib/device/scm.js create mode 100644 lib/device/sensor.js create mode 100644 lib/device/switch.js create mode 100644 lib/device/thermostat.js create mode 100644 lib/device/usb.js create mode 100644 lib/device/valve.js create mode 100644 lib/device/zb-dev.js diff --git a/lib/constants.js b/lib/constants.js index 555488c5..803a3423 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -48,7 +48,6 @@ module.exports = { devicesZBBridgeParams: ["key", "temperature", "humidity", "motion", "lock", "trigTime", "battery"], devicesZB: [1000, 1770, 2026, 3026], devicesValveParams: ["switches"], - devicesBlindParams: ["switch", "switches"], devicesGarageParams: ["switch", "switches"], devicesLockParams: ["switch"], allowedGroups: ["blind", "garage", "lock"], diff --git a/lib/device/blind.js b/lib/device/blind.js new file mode 100644 index 00000000..8057a852 --- /dev/null +++ b/lib/device/blind.js @@ -0,0 +1,73 @@ +/* jshint esversion: 9, -W014, -W030, node: true */ +"use strict"; +let Characteristic, Service; +const cns = require("./../constants"), + utils = require("./../utils"); +module.exports = class deviceBlind { + constructor(platform) { + this.platform = platform; + Service = platform.api.hap.Service; + Characteristic = platform.api.hap.Characteristic; + } + + async internalBlindUpdate(accessory, value, callback) { + callback(); + try { + let blindConfig, + params = {}, + wcService = accessory.getService(Service.WindowCovering), + prevState = accessory.context.cachePositionState, + prevPosition = accessory.context.cacheCurrentPosition, + newTarget = value, + updateKey = Math.random().toString(36).substr(2, 8); + if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; + } + if (blindConfig.type !== "blind" || blindConfig.setup !== "twoSwitch") { + throw "improper configuration"; + } + if (newTarget === prevPosition) return; + params.switches = cns.defaultMultiSwitchOff; + accessory.context.updateKey = updateKey; + let percentStepPerDecisecond = blindConfig.operationTime / 100; + if (prevState !== 2) { + await this.platform.sendDeviceUpdate(accessory, params); + let positionPercentChange = Math.round( + Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime * percentStepPerDecisecond + ); + if ((prevState === 0 && newTarget > prevPosition) || (prevState === 1 && newTarget < prevPosition)) { + prevPosition += positionPercentChange; + } else { + prevPosition -= positionPercentChange; + } + wcService.updateCharacteristic(Characteristic.CurrentPosition, prevPosition); + accessory.context.cacheCurrentPosition = prevPosition; + } + let diffPosition = newTarget - prevPosition; + let setToMoveUp = diffPosition > 0; + let decisecondsToMove = Math.round(Math.abs(diffPosition) * percentStepPerDecisecond); + params.switches[0].switch = setToMoveUp ? "on" : "off"; + params.switches[1].switch = setToMoveUp ? "off" : "on"; + await this.platform.sendDeviceUpdate(accessory, params); + wcService + .updateCharacteristic(Characteristic.TargetPosition, newTarget) + .updateCharacteristic(Characteristic.PositionState, setToMoveUp); + accessory.context.cacheTargetPosition = newTarget; + accessory.context.cachePositionState = setToMoveUp; + accessory.context.cacheLastStartTime = Math.floor(Date.now() / 100); + this.platform.log.warn(decisecondsToMove + " movement time in deciseconds"); + await utils.sleep(decisecondsToMove * 100); + if (accessory.context.updateKey === updateKey) { + params.switches[0].switch = "off"; + params.switches[1].switch = "off"; + await this.platform.sendDeviceUpdate(accessory, params); + wcService.updateCharacteristic(Characteristic.PositionState, 2); + wcService.updateCharacteristic(Characteristic.CurrentPosition, newTarget); + accessory.context.cachePositionState = 2; + accessory.context.cacheCurrentPosition = newTarget; + } + } catch (err) { + this.platform.requestDeviceRefresh(accessory, err); + } + } +}; diff --git a/lib/device/curtain.js b/lib/device/curtain.js new file mode 100644 index 00000000..d7a8cf8a --- /dev/null +++ b/lib/device/curtain.js @@ -0,0 +1,52 @@ +/* jshint esversion: 9, -W014, -W030, node: true */ +"use strict"; +let Characteristic, Service; +module.exports = class deviceCurtain { + constructor(platform) { + this.platform = platform; + Service = platform.api.hap.Service; + Characteristic = platform.api.hap.Characteristic; + } + async internalCurtainUpdate(accessory, value, callback) { + callback(); + try { + let params, + cService = accessory.getService(Service.WindowCovering), + prevPos = accessory.context.cacheCurrentPosition, + newPos = value; + if (newPos === prevPos) return; + if (newPos === 0 || newPos === 100) { + params = { + switch: newPos === 100 ? "on" : "off", + }; + } else { + params = { + setclose: Math.abs(100 - newPos), + }; + } + await this.platform.sendDeviceUpdate(accessory, params); + cService + .updateCharacteristic(Characteristic.TargetPosition, newPos) + .updateCharacteristic(Characteristic.PositionState, newPos > prevPos ? 1 : 0); + accessory.context.cacheCurrentPosition = newPos; + } catch (err) { + this.platform.requestDeviceRefresh(accessory, err); + } + } + externalCurtainUpdate(accessory, params) { + try { + let cService = accessory.getService(Service.WindowCovering); + if (params.hasOwnProperty("switch") && params.hasOwnProperty("setclose")) { + let newPos = Math.abs(100 - parseInt(params.setclose)); + cService + .updateCharacteristic(Characteristic.TargetPosition, newPos) + .updateCharacteristic(Characteristic.CurrentPosition, newPos) + .updateCharacteristic(Characteristic.PositionState, 2); + accessory.context.cacheCurrentPosition = newPos; + return; + } + } catch (err) { + this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } +}; diff --git a/lib/device/fan.js b/lib/device/fan.js new file mode 100644 index 00000000..2c12a5e7 --- /dev/null +++ b/lib/device/fan.js @@ -0,0 +1,92 @@ +/* jshint esversion: 9, -W014, -W030, node: true */ +"use strict"; +let Characteristic, Service; +module.exports = class deviceFan { + constructor(platform) { + this.platform = platform; + Service = platform.api.hap.Service; + Characteristic = platform.api.hap.Characteristic; + } + async internalFanUpdate(accessory, type, value, callback) { + callback(); + try { + let newPower, + newSpeed, + newLight, + lightService = accessory.getService(Service.Lightbulb), + fanService = accessory.getService(Service.Fanv2); + switch (type) { + case "power": + newPower = value; + newSpeed = value ? 33 : 0; + newLight = lightService.getCharacteristic(Characteristic.On).value; + break; + case "speed": + newPower = value >= 33 ? 1 : 0; + newSpeed = value; + newLight = lightService.getCharacteristic(Characteristic.On).value; + break; + case "light": + newPower = fanService.getCharacteristic(Characteristic.Active).value; + newSpeed = fanService.getCharacteristic(Characteristic.RotationSpeed).value; + newLight = value; + break; + } + let params = { + switches: this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches, + }; + params.switches[0].switch = newLight ? "on" : "off"; + params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? "on" : "off"; + params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? "on" : "off"; + params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? "on" : "off"; + await this.platform.sendDeviceUpdate(accessory, params); + lightService.updateCharacteristic(Characteristic.On, newLight); + fanService + .updateCharacteristic(Characteristic.Active, newPower) + .updateCharacteristic(Characteristic.RotationSpeed, newSpeed); + } catch (err) { + this.platform.requestDeviceRefresh(accessory, err); + } + } + externalFanUpdate(accessory, params) { + try { + let light, + status, + speed, + lightService = accessory.getService(Service.Lightbulb), + fanService = accessory.getService(Service.Fanv2); + if (Array.isArray(params.switches)) { + light = params.switches[0].switch === "on"; + switch (params.switches[1].switch + params.switches[2].switch + params.switches[3].switch) { + default: + status = 0; + speed = 0; + break; + case "onoffoff": + status = 1; + speed = 33; + break; + case "ononoff": + status = 1; + speed = 66; + break; + case "onoffon": + status = 1; + speed = 99; + } + } else if (params.hasOwnProperty("light") && params.hasOwnProperty("fan") && params.hasOwnProperty("speed")) { + light = params.light === "on"; + status = params.fan === "on" ? 1 : 0; + speed = params.speed * 33 * status; + } else { + throw "unknown parameters received"; + } + lightService.updateCharacteristic(Characteristic.On, light); + fanService + .updateCharacteristic(Characteristic.Active, status) + .updateCharacteristic(Characteristic.RotationSpeed, speed); + } catch (err) { + this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } +}; diff --git a/lib/device/garage.js b/lib/device/garage.js new file mode 100644 index 00000000..e888c551 --- /dev/null +++ b/lib/device/garage.js @@ -0,0 +1,125 @@ +/* jshint esversion: 9, -W014, -W030, node: true */ +"use strict"; +let Characteristic, Service; +const utils = require("./../utils"); +module.exports = class deviceGarage { + constructor(platform) { + this.platform = platform; + Service = platform.api.hap.Service; + Characteristic = platform.api.hap.Characteristic; + } + async internalGarageUpdate(accessory, value, callback) { + callback(); + try { + let garageConfig; + if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; + } + if (garageConfig.type !== "garage" || !["oneSwitch", "twoSwitch"].includes(garageConfig.setup)) { + throw "improper configuration"; + } + let sensorDefinition = garageConfig.sensorId || false, + sAccessory = false, + prevState, + newPos = value, + params = {}, + delay = 0, + gdService = accessory.getService(Service.GarageDoorOpener); + if (sensorDefinition && !(sAccessory = this.platform.devicesInHB.get(garageConfig.sensorId + "SWX"))) { + throw "defined DW2 sensor doesn't exist"; + } + if (sensorDefinition && sAccessory.context.type !== "sensor") { + throw "defined DW2 sensor isn't a sensor"; + } + prevState = sAccessory + ? sAccessory.getService(Service.ContactSensor).getCharacteristic(Characteristic.ContactSensorState).value === 0 + ? 1 + : 0 + : accessory.context.cacheCurrentDoorState; + if (newPos === prevState % 2) return; + accessory.context.inUse = true; + accessory.context.state = value; + if (garageConfig.setup === "oneSwitch" && [2, 3].includes(prevState)) { + gdService.updateCharacteristic(Characteristic.CurrentDoorState, ((prevState * 2) % 3) + 2); + accessory.context.cacheCurrentDoorState = ((prevState * 2) % 3) + 2; + delay = 1500; + } + if (accessory.context.state !== newPos) return; + await utils.sleep(delay); + gdService + .updateCharacteristic(Characteristic.TargetDoorState, newPos) + .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2); + accessory.context.cacheTargetDoorState = newPos; + accessory.context.cacheCurrentDoorState = newPos + 2; + switch (garageConfig.setup) { + case "oneSwitch": + params.switch = "on"; + break; + case "twoSwitch": + params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = newPos === 0 ? "on" : "off"; + params.switches[1].switch = newPos === 1 ? "on" : "off"; + break; + } + await this.platform.sendDeviceUpdate(accessory, params); + await utils.sleep(garageConfig.operationTime * 100); + if (!sAccessory) { + gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos); + accessory.context.cacheCurrentDoorState = newPos; + } + accessory.context.inUse = false; + } catch (err) { + this.platform.requestDeviceRefresh(accessory, err); + } + } + externalGarageUpdate(accessory, params) { + try { + let garageConfig, + gcService = accessory.getService(Service.GarageDoorOpener), + prevState = accessory.context.cacheCurrentDoorState, + newPos = [0, 2].includes(prevState) ? 3 : 2; + if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; + } + if (garageConfig.type !== "garage" || !["oneSwitch", "twoSwitch"].includes(garageConfig.setup)) { + throw "improper configuration"; + } + if (accessory.context.inUse || garageConfig.sensorId) { + return; + } + switch (garageConfig.setup) { + case "oneSwitch": + if (params.switch === "off") { + return; + } + break; + case "twoSwitch": + if ( + params.switches[0].switch === params.switches[1].switch || + params.switches[prevState % 2].switch === "on" + ) { + return; + } + break; + } + accessory.context.inUse = true; + if (!garageConfig.sensorId) { + gcService + .updateCharacteristic(Characteristic.CurrentDoorState, newPos) + .updateCharacteristic(Characteristic.TargetDoorState, newPos - 2); + accessory.context.cacheCurrentDoorState = newPos; + accessory.context.cacheTargetDoorState = newPos - 2; + setTimeout(() => { + gcService.updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2); + accessory.context.cacheCurrentDoorState = newPos - 2; + }, parseInt(garageConfig.operationTime) * 100); + } + setTimeout(() => { + accessory.context.inUse = false; + }, parseInt(garageConfig.operationTime) * 100); + } catch (err) { + accessory.context.inUse = false; + this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } +}; diff --git a/lib/device/light.js b/lib/device/light.js new file mode 100644 index 00000000..ac838310 --- /dev/null +++ b/lib/device/light.js @@ -0,0 +1,287 @@ +/* jshint esversion: 9, -W014, -W030, node: true */ +"use strict"; +let Characteristic, Service; +const convert = require("color-convert"), + utils = require("./../utils"); +module.exports = class deviceLight { + constructor(platform) { + this.platform = platform; + Service = platform.api.hap.Service; + Characteristic = platform.api.hap.Characteristic; + } + async internalLightbulbUpdate(accessory, value, callback) { + callback(); + try { + let oAccessory, + params = {}, + lightService = accessory.getService(Service.Lightbulb); + switch (accessory.context.switchNumber) { + case "X": + if (accessory.context.eweUIID === 22) { + //*** B1 ***\\ + params.state = value ? "on" : "off"; + } else { + params.switch = value ? "on" : "off"; + } + break; + case "0": + params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = value ? "on" : "off"; + params.switches[1].switch = value ? "on" : "off"; + params.switches[2].switch = value ? "on" : "off"; + params.switches[3].switch = value ? "on" : "off"; + break; + case "1": + case "2": + case "3": + case "4": + params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + for (let i = 1; i <= 4; i++) { + if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + i === parseInt(accessory.context.switchNumber) + ? (params.switches[i - 1].switch = value ? "on" : "off") + : (params.switches[i - 1].switch = oAccessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On).value + ? "on" + : "off"); + } else { + params.switches[i - 1].switch = "off"; + } + } + break; + } + await this.platform.sendDeviceUpdate(accessory, params); + switch (accessory.context.switchNumber) { + case "X": + lightService.updateCharacteristic(Characteristic.On, value); + break; + case "0": + for (let i = 0; i <= 4; i++) { + if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + } + } + break; + case "1": + case "2": + case "3": + case "4": + lightService.updateCharacteristic(Characteristic.On, value); + let masterState = "off"; + for (let i = 1; i <= 4; i++) { + if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + if (oAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + masterState = "on"; + } + } + } + if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { + oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); + oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, masterState === "on"); + } + break; + } + } catch (err) { + this.platform.requestDeviceRefresh(accessory, err); + } + } + async internalBrightnessUpdate(accessory, value, callback) { + callback(); + try { + let params = {}, + lightService = accessory.getService(Service.Lightbulb); + if (value === 0) { + params.switch = "off"; + } else { + if (!lightService.getCharacteristic(Characteristic.On).value) { + params.switch = "on"; + } + switch (accessory.context.eweUIID) { + case 36: //*** KING-M4 ***\\ + params.bright = Math.round((value * 9) / 10 + 10); + break; + case 44: //*** D1 ***\\ + params.brightness = value; + params.mode = 0; + break; + } + } + await utils.sleep(250); + await this.platform.sendDeviceUpdate(accessory, params); + if (value === 0) { + lightService.updateCharacteristic(Characteristic.On, false); + } else { + lightService.updateCharacteristic(Characteristic.Brightness, value); + } + } catch (err) { + this.platform.requestDeviceRefresh(accessory, err); + } + } + async internalHSBUpdate(accessory, type, value, callback) { + callback(); + try { + if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { + throw "it is currently offline"; + } + let newRGB, + params = {}, + lightService = accessory.getService(Service.Lightbulb), + curHue = lightService.getCharacteristic(Characteristic.Hue).value, + curSat = lightService.getCharacteristic(Characteristic.Saturation).value; + switch (type) { + case "hue": + newRGB = convert.hsv.rgb(value, curSat, 100); + switch (accessory.context.eweUIID) { + case 22: //*** B1 ***\\ + params = { + zyx_mode: 2, + type: "middle", + channel0: "0", + channel1: "0", + channel2: newRGB[0].toString(), + channel3: newRGB[1].toString(), + channel4: newRGB[2].toString(), + }; + break; + case 59: //*** L1 ***\\ + params = { + mode: 1, + colorR: newRGB[0], + colorG: newRGB[1], + colorB: newRGB[2], + }; + break; + } + break; + case "bri": + switch (accessory.context.eweUIID) { + case 22: //*** B1 ***\\ + newRGB = convert.hsv.rgb(curHue, curSat, value); + params = { + zyx_mode: 2, + type: "middle", + channel0: "0", + channel1: "0", + channel2: newRGB[0].toString(), + channel3: newRGB[1].toString(), + channel4: newRGB[2].toString(), + }; + break; + case 59: //*** L1 ***\\ + params = { + mode: 1, + bright: value, + }; + break; + } + break; + } + await utils.sleep(250); + await this.platform.sendDeviceUpdate(accessory, params); + switch (type) { + case "hue": + lightService.updateCharacteristic(Characteristic.Hue, value); + break; + case "bri": + lightService.updateCharacteristic(Characteristic.Brightness, value); + break; + } + } catch (err) { + this.platform.requestDeviceRefresh(accessory, err); + } + } + externalSingleLightUpdate(accessory, params) { + try { + let newColour, + mode, + isOn = false, + lightService = accessory.getService(Service.Lightbulb); + if (accessory.context.eweUIID === 22 && params.hasOwnProperty("state")) { + isOn = params.state === "on"; + } else if (accessory.context.eweUIID !== 22 && params.hasOwnProperty("switch")) { + isOn = params.switch === "on"; + } else { + isOn = lightService.getCharacteristic(Characteristic.On).value; + } + if (isOn) { + lightService.updateCharacteristic(Characteristic.On, true); + switch (accessory.context.eweUIID) { + case 36: // KING-M4 + if (params.hasOwnProperty("bright")) { + let nb = Math.round(((params.bright - 10) * 10) / 9); // eWeLink scale is 10-100 and HomeKit scale is 0-100. + lightService.updateCharacteristic(Characteristic.Brightness, nb); + } + break; + case 44: // D1 + if (params.hasOwnProperty("brightness")) { + lightService.updateCharacteristic(Characteristic.Brightness, params.brightness); + } + break; + case 22: // B1 + if (params.hasOwnProperty("zyx_mode")) { + mode = parseInt(params.zyx_mode); + } else if (params.hasOwnProperty("channel0") && parseInt(params.channel0) + parseInt(params.channel1) > 0) { + mode = 1; + } else { + mode = 2; + } + if (mode === 2) { + lightService.updateCharacteristic(Characteristic.On, true); + newColour = convert.rgb.hsv( + parseInt(params.channel2), + parseInt(params.channel3), + parseInt(params.channel4) + ); + lightService + .updateCharacteristic(Characteristic.Hue, newColour[0]) + .updateCharacteristic(Characteristic.Saturation, 100) + .updateCharacteristic(Characteristic.Brightness, 100); + } else if (mode === 1) { + throw "has been set to white mode which is not supported"; + } + break; + case 59: // L1 + if (params.hasOwnProperty("bright")) { + lightService.updateCharacteristic(Characteristic.Brightness, params.bright); + } + if (params.hasOwnProperty("colorR")) { + newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB); + lightService + .updateCharacteristic(Characteristic.Hue, newColour[0]) + .updateCharacteristic(Characteristic.Saturation, newColour[1]); + } + break; + default: + return; + } + } else { + lightService.updateCharacteristic(Characteristic.On, false); + } + } catch (err) { + this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } + externalMultiLightUpdate(accessory, params) { + try { + let idToCheck = accessory.context.hbDeviceId.slice(0, -1), + primaryState = false; + for (let i = 1; i <= accessory.context.channelCount; i++) { + if (this.platform.devicesInHB.has(idToCheck + i)) { + let oAccessory = this.platform.devicesInHB.get(idToCheck + i); + oAccessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); + if (params.switches[i - 1].switch === "on") { + primaryState = true; + } + } + } + if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, primaryState); + } + } catch (err) { + this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } +}; diff --git a/lib/device/lock.js b/lib/device/lock.js new file mode 100644 index 00000000..ac74af5e --- /dev/null +++ b/lib/device/lock.js @@ -0,0 +1,67 @@ +/* jshint esversion: 9, -W014, -W030, node: true */ +"use strict"; +let Characteristic, Service; +const utils = require("./../utils"); +module.exports = class deviceLock { + constructor(platform) { + this.platform = platform; + Service = platform.api.hap.Service; + Characteristic = platform.api.hap.Characteristic; + } + async internalLockUpdate(accessory, value, callback) { + callback(); + try { + let lockConfig, + params = { + switch: "on", + }, + lmService = accessory.getService(Service.LockMechanism); + if (!(lockConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; + } + if (lockConfig.type !== "lock") { + throw "improper configuration"; + } + accessory.context.inUse = true; + await this.platform.sendDeviceUpdate(accessory, params); + lmService + .updateCharacteristic(Characteristic.LockTargetState, 0) + .updateCharacteristic(Characteristic.LockCurrentState, 0); + await utils.sleep(lockConfig.operationTime * 100); + lmService + .updateCharacteristic(Characteristic.LockTargetState, 1) + .updateCharacteristic(Characteristic.LockCurrentState, 1); + accessory.context.inUse = false; + } catch (err) { + this.platform.requestDeviceRefresh(accessory, err); + } + } + externalLockUpdate(accessory, params) { + try { + let lockConfig, + lmService = accessory.getService(Service.LockMechanism); + if (!(lockConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + throw "group config missing"; + } + if (lockConfig.type !== "lock") { + throw "improper configuration"; + } + if (params.switch === "off" || accessory.context.inUse) { + return; + } + accessory.context.inUse = true; + lmService + .updateCharacteristic(Characteristic.LockCurrentState, 0) + .updateCharacteristic(Characteristic.LockTargetState, 0); + setTimeout(() => { + lmService + .updateCharacteristic(Characteristic.LockCurrentState, 1) + .updateCharacteristic(Characteristic.LockTargetState, 1); + accessory.context.inUse = false; + }, parseInt(lockConfig.operationTime) * 100); + } catch (err) { + accessory.context.inUse = false; + this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } +}; diff --git a/lib/device/outlet.js b/lib/device/outlet.js new file mode 100644 index 00000000..a1d7145b --- /dev/null +++ b/lib/device/outlet.js @@ -0,0 +1,56 @@ +/* jshint esversion: 9, -W014, -W030, node: true */ +"use strict"; +let Characteristic, EveService, Service; +const hbLib = require("homebridge-lib"); +module.exports = class deviceOutlet { + constructor(platform, homebridge) { + this.platform = platform; + Service = platform.api.hap.Service; + Characteristic = platform.api.hap.Characteristic; + EveService = new hbLib.EveHomeKitTypes(platform.api); + } + async internalOutletUpdate(accessory, value, callback) { + callback(); + try { + let params = { + switch: value ? "on" : "off", + }, + outletService = accessory.getService(Service.Outlet); + await this.platform.sendDeviceUpdate(accessory, params); + outletService.updateCharacteristic(Characteristic.On, value); + } catch (err) { + this.platform.requestDeviceRefresh(accessory, err); + } + } + externalOutletUpdate(accessory, params) { + try { + let outletService = accessory.getService(Service.Outlet); + if (params.hasOwnProperty("switch")) { + outletService.updateCharacteristic(Characteristic.On, params.switch === "on"); + if (accessory.context.eweModel === "S26" || this.platform.config.disableEveLogging || false) { + outletService.updateCharacteristic(Characteristic.OutletInUse, params.switch === "on"); + } + } + if (params.hasOwnProperty("power")) { + outletService.updateCharacteristic(EveService.Characteristics.CurrentConsumption, parseFloat(params.power)); + outletService.updateCharacteristic( + Characteristic.OutletInUse, + parseFloat(params.power) > (this.platform.config.inUsePowerThreshold || 0) + ); + let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value; + accessory.eveLogger.addEntry({ + time: Date.now(), + power: isOn ? parseFloat(params.power) : 0, + }); + } + if (params.hasOwnProperty("voltage")) { + outletService.updateCharacteristic(EveService.Characteristics.Voltage, parseFloat(params.voltage)); + } + if (params.hasOwnProperty("current")) { + outletService.updateCharacteristic(EveService.Characteristics.ElectricCurrent, parseFloat(params.current)); + } + } catch (err) { + this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } +}; diff --git a/lib/device/rf-sub.js b/lib/device/rf-sub.js new file mode 100644 index 00000000..59dcfb06 --- /dev/null +++ b/lib/device/rf-sub.js @@ -0,0 +1,122 @@ +/* jshint esversion: 9, -W014, -W030, node: true */ +"use strict"; +let Characteristic, Service; +const utils = require("./../utils"); +module.exports = class deviceRFSub { + constructor(platform) { + this.platform = platform; + Service = platform.api.hap.Service; + Characteristic = platform.api.hap.Characteristic; + } + async internalRFUpdate(accessory, rfChl, service, callback) { + callback(); + try { + let params = { + cmd: "transmit", + rfChl: parseInt(rfChl), + }, + rfService = accessory.getService(service); + await this.platform.sendDeviceUpdate(accessory, params); + rfService.updateCharacteristic(Characteristic.On, true); + await utils.sleep(3000); + rfService.updateCharacteristic(Characteristic.On, false); + } catch (err) { + this.platform.requestDeviceRefresh(accessory, err); + } + } + externalRFUpdate(accessory, params) { + try { + if (!params.hasOwnProperty("updateSource")) return; + let timeNow = new Date(), + oAccessory = false; + if (params.hasOwnProperty("cmd") && params.cmd === "transmit" && params.hasOwnProperty("rfChl")) { + //*** RF Button ***\\ + // the device needed is SW% corresponding to params.rfChl + this.platform.devicesInHB.forEach(acc => { + if ( + acc.context.eweDeviceId === accessory.context.eweDeviceId && + acc.context.buttons.hasOwnProperty(params.rfChl.toString()) + ) { + oAccessory = acc; + } + }); + if (oAccessory) { + oAccessory.getService(oAccessory.context.buttons[params.rfChl]).updateCharacteristic(Characteristic.On, 1); + setTimeout( + () => + oAccessory + .getService(oAccessory.context.buttons[params.rfChl]) + .updateCharacteristic(Characteristic.On, 0), + 3000 + ); + } else { + throw "rf button not found in Homebridge"; + } + } else if (params.hasOwnProperty("cmd") && params.cmd === "trigger") { + //*** RF Sensor ***\\ + Object.keys(params) + .filter(name => /rfTrig/.test(name)) + .forEach(chan => { + this.platform.devicesInHB.forEach(acc => { + if ( + acc.context.eweDeviceId === accessory.context.eweDeviceId && + acc.context.buttons.hasOwnProperty(chan.substr(-1).toString()) + ) { + oAccessory = acc; + } + }); + if (oAccessory) { + let timeOfMotion = new Date(params[chan]), + diff = (timeNow.getTime() - timeOfMotion.getTime()) / 1000, + serv, + char; + if (diff < (this.platform.config.sensorTimeDifference || 120)) { + switch (oAccessory.context.sensorType) { + case "button": + break; + case "water": + serv = Service.LeakSensor; + char = Characteristic.LeakDetected; + break; + case "fire": + case "smoke": + serv = Service.SmokeSensor; + char = Characteristic.LeakDetected; + break; + case "co": + serv = Service.CarbonMonoxideSensor; + char = Characteristic.CarbonMonoxideDetected; + break; + case "co2": + serv = Service.CarbonDioxideSensor; + char = Characteristic.CarbonDioxideDetected; + break; + case "contact": + serv = Service.ContactSensor; + char = Characteristic.ContactSensorState; + break; + case "occupancy": + serv = Service.OccupancySensor; + char = Characteristic.OccupancyDetected; + break; + default: + serv = Service.MotionSensor; + char = Characteristic.MotionDetected; + break; + } + oAccessory.getService(serv).updateCharacteristic(char, 1); + setTimeout(() => { + oAccessory.getService(serv).updateCharacteristic(char, 0); + }, (this.platform.config.sensorTimeLength || 2) * 1000); + if (this.platform.debug) { + this.platform.log("[%s] has detected [%s].", oAccessory.displayName, oAccessory.context.sensorType); + } + } + } + }); + } + } catch (err) { + this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } +}; diff --git a/lib/device/scm.js b/lib/device/scm.js new file mode 100644 index 00000000..e424e8eb --- /dev/null +++ b/lib/device/scm.js @@ -0,0 +1,32 @@ +/* jshint esversion: 9, -W014, -W030, node: true */ +"use strict"; +let Characteristic, Service; +module.exports = class deviceSCM { + constructor(platform) { + this.platform = platform; + Service = platform.api.hap.Service; + Characteristic = platform.api.hap.Characteristic; + } + + async internalSCMUpdate(accessory, value, callback) { + callback(); + try { + let params = { + switches: this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches, + }, + switchService = accessory.getService(Service.Switch); + params.switches[0].switch = value ? "on" : "off"; + await this.platform.sendDeviceUpdate(accessory, params); + switchService.updateCharacteristic(Characteristic.On, value); + } catch (err) { + this.platform.requestDeviceRefresh(accessory, err); + } + } + externalSCMUpdate(accessory, params) { + try { + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); + } catch (err) { + this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } +}; diff --git a/lib/device/sensor.js b/lib/device/sensor.js new file mode 100644 index 00000000..391d7f08 --- /dev/null +++ b/lib/device/sensor.js @@ -0,0 +1,54 @@ +/* jshint esversion: 9, -W014, -W030, node: true */ +"use strict"; +let Characteristic, Service; +module.exports = class deviceSensor { + constructor(platform) { + this.platform = platform; + Service = platform.api.hap.Service; + Characteristic = platform.api.hap.Characteristic; + } + externalSensorUpdate(accessory, params) { + try { + if (params.hasOwnProperty("battery")) { + let batteryService = + accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService), + scaledBattery = Math.round(params.battery * 33.3); + batteryService.updateCharacteristic(Characteristic.BatteryLevel, scaledBattery); + batteryService.updateCharacteristic( + Characteristic.StatusLowBattery, + scaledBattery < (this.platform.config.lowBattThreshold || 25) + ); + } + let newState = params.switch === "on" ? 1 : 0, + oAccessory = false, + contactService = accessory.getService(Service.ContactSensor); + contactService.updateCharacteristic(Characteristic.ContactSensorState, newState); + this.platform.cusG.forEach(group => { + if (group.sensorId === accessory.context.eweDeviceId && group.type === "garage") { + if ((oAccessory = this.platform.devicesInHB.get(group.deviceId + "SWX"))) { + switch (newState) { + case 0: + oAccessory + .getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.TargetDoorState, 1) + .updateCharacteristic(Characteristic.CurrentDoorState, 1); + break; + case 1: + setTimeout(() => { + oAccessory + .getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.TargetDoorState, 0) + .updateCharacteristic(Characteristic.CurrentDoorState, 0); + }, group.operationTime * 100); + break; + default: + throw "unknown sensor status received [" + newState + "]"; + } + } + } + }); + } catch (err) { + this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } +}; diff --git a/lib/device/switch.js b/lib/device/switch.js new file mode 100644 index 00000000..e446492a --- /dev/null +++ b/lib/device/switch.js @@ -0,0 +1,111 @@ +/* jshint esversion: 9, -W014, -W030, node: true */ +"use strict"; +let Characteristic, Service; +module.exports = class deviceSwitch { + constructor(platform) { + this.platform = platform; + Service = platform.api.hap.Service; + Characteristic = platform.api.hap.Characteristic; + } + async internalSwitchUpdate(accessory, value, callback) { + callback(); + try { + let oAccessory, + params = {}, + switchService = accessory.getService(Service.Switch); + switch (accessory.context.switchNumber) { + case "X": + params.switch = value ? "on" : "off"; + break; + case "0": + params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + params.switches[0].switch = value ? "on" : "off"; + params.switches[1].switch = value ? "on" : "off"; + params.switches[2].switch = value ? "on" : "off"; + params.switches[3].switch = value ? "on" : "off"; + break; + case "1": + case "2": + case "3": + case "4": + params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + for (let i = 1; i <= 4; i++) { + if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + i === parseInt(accessory.context.switchNumber) + ? (params.switches[i - 1].switch = value ? "on" : "off") + : (params.switches[i - 1].switch = oAccessory + .getService(Service.Switch) + .getCharacteristic(Characteristic.On).value + ? "on" + : "off"); + } else { + params.switches[i - 1].switch = "off"; + } + } + break; + } + await this.platform.sendDeviceUpdate(accessory, params); + switch (accessory.context.switchNumber) { + case "X": + switchService.updateCharacteristic(Characteristic.On, value); + break; + case "0": + for (let i = 0; i <= 4; i++) { + if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + } + } + break; + case "1": + case "2": + case "3": + case "4": + switchService.updateCharacteristic(Characteristic.On, value); + let masterState = "off"; + for (let i = 1; i <= 4; i++) { + if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + if (oAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value) { + masterState = "on"; + } + } + } + if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { + oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); + oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, masterState === "on"); + } + break; + } + } catch (err) { + this.platform.requestDeviceRefresh(accessory, err); + } + } + externalSingleSwitchUpdate(accessory, params) { + try { + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switch === "on"); + } catch (err) { + this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } + externalMultiSwitchUpdate(accessory, params) { + try { + let idToCheck = accessory.context.hbDeviceId.slice(0, -1), + primaryState = false; + for (let i = 1; i <= accessory.context.channelCount; i++) { + if (this.platform.devicesInHB.has(idToCheck + i)) { + let oAccessory = this.platform.devicesInHB.get(idToCheck + i); + oAccessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); + if (params.switches[i - 1].switch === "on") { + primaryState = true; + } + } + } + if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState); + } + } catch (err) { + this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } +}; diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js new file mode 100644 index 00000000..dfc0baec --- /dev/null +++ b/lib/device/thermostat.js @@ -0,0 +1,58 @@ +/* jshint esversion: 9, -W014, -W030, node: true */ +"use strict"; +let Characteristic, Service; +module.exports = class deviceThermostat { + constructor(platform, homebridge) { + this.platform = platform; + } + async internalThermostatUpdate(accessory, value, callback) { + callback(); + try { + let params = { + switch: value ? "on" : "off", + mainSwitch: value ? "on" : "off", + }, + switchService = accessory.getService(Service.Switch); + await this.platform.sendDeviceUpdate(accessory, params); + switchService.updateCharacteristic(Characteristic.On, value); + } catch (err) { + this.platform.requestDeviceRefresh(accessory, err); + } + } + externalThermostatUpdate(accessory, params) { + try { + if ( + !this.platform.config.hideTHSwitch && + (params.hasOwnProperty("switch") || params.hasOwnProperty("mainSwitch")) + ) { + let newState = params.hasOwnProperty("switch") ? params.switch === "on" : params.mainSwitch === "on", + switchService = accessory.getService(Service.Switch); + switchService.updateCharacteristic(Characteristic.On, newState); + } + if (!(this.platform.config.disableEveLogging || false)) { + let eveLog = { + time: Date.now(), + }; + if (params.hasOwnProperty("currentTemperature") && accessory.getService(Service.TemperatureSensor)) { + let currentTemp = params.currentTemperature !== "unavailable" ? params.currentTemperature : 0; + accessory + .getService(Service.TemperatureSensor) + .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); + eveLog.temp = parseFloat(currentTemp); + } + if (params.hasOwnProperty("currentHumidity") && accessory.getService(Service.HumiditySensor)) { + let currentHumi = params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; + accessory + .getService(Service.HumiditySensor) + .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); + eveLog.humidity = parseFloat(currentHumi); + } + if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { + accessory.eveLogger.addEntry(eveLog); + } + } + } catch (err) { + this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } +}; diff --git a/lib/device/usb.js b/lib/device/usb.js new file mode 100644 index 00000000..7d6e244f --- /dev/null +++ b/lib/device/usb.js @@ -0,0 +1,31 @@ +/* jshint esversion: 9, -W014, -W030, node: true */ +"use strict"; +let Characteristic, Service; +module.exports = class deviceUSB { + constructor(platform) { + this.platform = platform; + Service = platform.api.hap.Service; + Characteristic = platform.api.hap.Characteristic; + } + async internalUSBUpdate(accessory, value, callback) { + callback(); + try { + let params = { + switches: this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches, + }, + outletService = accessory.getService(Service.Outlet); + params.switches[0].switch = value ? "on" : "off"; + await this.platform.sendDeviceUpdate(accessory, params); + outletService.updateCharacteristic(Characteristic.On, value); + } catch (err) { + this.platform.requestDeviceRefresh(accessory, err); + } + } + externalUSBUpdate(accessory, params) { + try { + accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); + } catch (err) { + this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } +}; diff --git a/lib/device/valve.js b/lib/device/valve.js new file mode 100644 index 00000000..6336871d --- /dev/null +++ b/lib/device/valve.js @@ -0,0 +1,71 @@ +/* jshint esversion: 9, -W014, -W030, node: true */ +"use strict"; +let Characteristic, Service; +module.exports = class deviceValve { + constructor(platform) { + this.platform = platform; + Service = platform.api.hap.Service; + Characteristic = platform.api.hap.Characteristic; + } + async internalValveUpdate(accessory, valve, value, callback) { + callback(); + try { + let params = {}, + serviceValve = accessory.getService(valve); + params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + switch (valve) { + case "Valve A": + params.switches[0].switch = value ? "on" : "off"; + params.switches[1].switch = accessory.getService("Valve B").getCharacteristic(Characteristic.Active).value + ? "on" + : "off"; + break; + case "Valve B": + params.switches[0].switch = accessory.getService("Valve A").getCharacteristic(Characteristic.Active).value + ? "on" + : "off"; + params.switches[1].switch = value ? "on" : "off"; + break; + } + params.switches[2].switch = "off"; + params.switches[3].switch = "off"; + await this.platform.sendDeviceUpdate(accessory, params); + serviceValve.updateCharacteristic(Characteristic.Active, value).updateCharacteristic(Characteristic.InUse, value); + switch (value) { + case 0: + serviceValve.updateCharacteristic(Characteristic.RemainingDuration, 0); + clearTimeout(accessory.getService(valve).timer); + break; + case 1: + let timer = serviceValve.getCharacteristic(Characteristic.SetDuration).value; + serviceValve.updateCharacteristic(Characteristic.RemainingDuration, timer); + serviceValve.timer = setTimeout(() => serviceValve.setCharacteristic(Characteristic.Active, 0), timer * 1000); + break; + } + } catch (err) { + this.platform.requestDeviceRefresh(accessory, err); + } + } + externalValveUpdate(accessory, params) { + try { + ["A", "B"].forEach((v, k) => { + let valveService = accessory.getService("Valve " + v); + valveService + .updateCharacteristic(Characteristic.Active, params.switches[k].switch === "on") + .updateCharacteristic(Characteristic.InUse, params.switches[k].switch === "on"); + if (params.switches[k].switch === "on") { + let timer = valveService.getCharacteristic(Characteristic.SetDuration).value; + valveService.updateCharacteristic(Characteristic.RemainingDuration, timer); + valveService.timer = setTimeout(() => { + valveService.setCharacteristic(Characteristic.Active, 0); + }, timer * 1000); + } else { + valveService.updateCharacteristic(Characteristic.RemainingDuration, 0); + clearTimeout(valveService.timer); + } + }); + } catch (err) { + this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } +}; diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js new file mode 100644 index 00000000..07e64a8f --- /dev/null +++ b/lib/device/zb-dev.js @@ -0,0 +1,82 @@ +/* jshint esversion: 9, -W014, -W030, node: true */ +"use strict"; +let Characteristic, Service; +module.exports = class deviceZBDev { + constructor(platform) { + this.platform = platform; + Service = platform.api.hap.Service; + Characteristic = platform.api.hap.Characteristic; + } + externalZBUpdate(accessory, params) { + try { + //*** credit @tasict ***\\ + if (params.hasOwnProperty("battery")) { + if (accessory.context.eweUIID === 3026 && (this.platform.config.ZBDWBatt || false)) { + params.battery *= 10; + } + let batteryService = + accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); + batteryService.updateCharacteristic(Characteristic.BatteryLevel, params.battery); + batteryService.updateCharacteristic( + Characteristic.StatusLowBattery, + params.battery < (this.platform.config.lowBattThreshold || 25) + ); + } + switch (accessory.context.eweUIID) { + case 1000: + if (params.hasOwnProperty("key") && [0, 1, 2].includes(params.key)) { + accessory + .getService(Service.StatelessProgrammableSwitch) + .updateCharacteristic(Characteristic.ProgrammableSwitchEvent, params.key); + } + break; + case 1770: + let eveLog = { + time: Date.now(), + }; + if (params.hasOwnProperty("temperature")) { + let currentTemp = parseInt(params.temperature) / 100; + accessory + .getService(Service.TemperatureSensor) + .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); + eveLog.temp = parseFloat(currentTemp); + } + if (params.hasOwnProperty("humidity")) { + let currentHumi = parseInt(params.humidity) / 100; + accessory + .getService(Service.HumiditySensor) + .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); + eveLog.humidity = parseFloat(currentHumi); + } + if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { + accessory.eveLogger.addEntry(eveLog); + } + break; + case 2026: + if (params.hasOwnProperty("motion") && params.hasOwnProperty("trigTime")) { + let timeNow = new Date(), + diff = (timeNow.getTime() - params.trigTime) / 1000; + accessory + .getService(Service.MotionSensor) + .updateCharacteristic( + Characteristic.MotionDetected, + params.hasOwnProperty("updateSource") && + params.motion === 1 && + diff < (this.platform.config.sensorTimeDifference || 120) + ); + break; + } + break; + case 3026: + if (params.hasOwnProperty("lock") && [0, 1].includes(params.lock)) { + accessory + .getService(Service.ContactSensor) + .updateCharacteristic(Characteristic.ContactSensorState, params.lock); + } + break; + } + } catch (err) { + this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + } + } +}; diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 53bc6241..f5ca8134 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -2,8 +2,22 @@ "use strict"; let Accessory, Characteristic, EveService, EveHistoryService, Service; const cns = require("./constants"), - convert = require("color-convert"), corrInterval = require("correcting-interval"), + deviceCurtain = require("./device/curtain"), + deviceBlind = require("./device/blind"), + deviceGarage = require("./device/garage"), + deviceLock = require("./device/lock"), + deviceValve = require("./device/valve"), + deviceSensor = require("./device/sensor"), + deviceFan = require("./device/fan"), + deviceThermostat = require("./device/thermostat"), + deviceOutlet = require("./device/outlet"), + deviceUSB = require("./device/usb"), + deviceSCM = require("./device/scm"), + deviceLight = require("./device/light"), + deviceSwitch = require("./device/switch"), + deviceRFSub = require("./device/rf-sub"), + deviceZBDev = require("./device/zb-dev"), eWeLinkHTTP = require("./eWeLinkHTTP"), eWeLinkWS = require("./eWeLinkWS"), eWeLinkLAN = require("./eWeLinkLAN"), @@ -169,9 +183,9 @@ class eWeLink { } //*** SINGLE LOCKS ***\\ else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "lock") { - let lockConfig = (accessory = this.devicesInHB.has(device.deviceid + "SWX") + accessory = this.devicesInHB.has(device.deviceid + "SWX") ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "lock")); + : this.addAccessory(device, device.deviceid + "SWX", "lock"); } //*** SENSORS (DW2) ***\\ else if (cns.devicesSensor.includes(device.extra.uiid)) { @@ -504,35 +518,8 @@ class eWeLink { accessory.context.reachableWAN = true; accessory.context.reachableLAN = true; switch (accessory.context.type) { - case "valve": - ["A", "B"].forEach(v => { - let valveService; - if (!(valveService = accessory.getService("Valve " + v))) { - accessory - .addService(Service.Valve, "Valve " + v, "valve" + v.toLowerCase()) - .setCharacteristic(Characteristic.Active, 0) - .setCharacteristic(Characteristic.InUse, 0) - .setCharacteristic(Characteristic.ValveType, 1) - .setCharacteristic(Characteristic.SetDuration, this.config.valveTimeLength || 120) - .addCharacteristic(Characteristic.RemainingDuration); - valveService = accessory.getService("Valve " + v); - } - valveService - .getCharacteristic(Characteristic.Active) - .on("set", (value, callback) => this.internalValveUpdate(accessory, "Valve " + v, value, callback)); - valveService.getCharacteristic(Characteristic.SetDuration).on("set", (value, callback) => { - if (valveService.getCharacteristic(Characteristic.InUse).value) { - valveService.updateCharacteristic(Characteristic.RemainingDuration, value); - clearTimeout(valveService.timer); - valveService.timer = setTimeout(() => { - valveService.setCharacteristic(Characteristic.Active, 0); - }, value * 1000); - } - callback(); - }); - }); - break; case "curtain": + accessory.control = new deviceCurtain(this); let cService; if (!(cService = accessory.getService(Service.WindowCovering))) { accessory @@ -544,9 +531,10 @@ class eWeLink { } cService .getCharacteristic(Characteristic.TargetPosition) - .on("set", (value, callback) => this.internalCurtainUpdate(accessory, value, callback)); + .on("set", (value, callback) => accessory.control.internalCurtainUpdate(accessory, value, callback)); break; case "blind": + accessory.control = new deviceBlind(this); let wcService; if (!(wcService = accessory.getService(Service.WindowCovering))) { accessory @@ -558,9 +546,10 @@ class eWeLink { } wcService .getCharacteristic(Characteristic.TargetPosition) - .on("set", (value, callback) => this.internalBlindUpdate(accessory, value, callback)); + .on("set", (value, callback) => accessory.control.internalBlindUpdate(accessory, value, callback)); break; case "garage": + accessory.control = new deviceGarage(this); let gdService; if (!(gdService = accessory.getService(Service.GarageDoorOpener))) { accessory @@ -572,35 +561,70 @@ class eWeLink { } gdService .getCharacteristic(Characteristic.TargetDoorState) - .on("set", (value, callback) => this.internalGarageUpdate(accessory, value, callback)); + .on("set", (value, callback) => accessory.control.internalGarageUpdate(accessory, value, callback)); break; case "lock": + accessory.control = new deviceLock(this); let lmService = accessory.getService(Service.LockMechanism) || accessory.addService(Service.LockMechanism); lmService .getCharacteristic(Characteristic.LockTargetState) - .on("set", (value, callback) => this.internalLockUpdate(accessory, value, callback)); + .on("set", (value, callback) => accessory.control.internalLockUpdate(accessory, value, callback)); + break; + case "valve": + accessory.control = new deviceValve(this); + ["A", "B"].forEach(v => { + let valveService; + if (!(valveService = accessory.getService("Valve " + v))) { + accessory + .addService(Service.Valve, "Valve " + v, "valve" + v.toLowerCase()) + .setCharacteristic(Characteristic.Active, 0) + .setCharacteristic(Characteristic.InUse, 0) + .setCharacteristic(Characteristic.ValveType, 1) + .setCharacteristic(Characteristic.SetDuration, this.config.valveTimeLength || 120) + .addCharacteristic(Characteristic.RemainingDuration); + valveService = accessory.getService("Valve " + v); + } + valveService + .getCharacteristic(Characteristic.Active) + .on("set", (value, callback) => + accessory.control.internalValveUpdate(accessory, "Valve " + v, value, callback) + ); + valveService.getCharacteristic(Characteristic.SetDuration).on("set", (value, callback) => { + if (valveService.getCharacteristic(Characteristic.InUse).value) { + valveService.updateCharacteristic(Characteristic.RemainingDuration, value); + clearTimeout(valveService.timer); + valveService.timer = setTimeout(() => { + valveService.setCharacteristic(Characteristic.Active, 0); + }, value * 1000); + } + callback(); + }); + }); break; case "sensor": + accessory.control = new deviceSensor(this); accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor); accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); break; case "fan": + accessory.control = new deviceFan(this); let fanService = accessory.getService(Service.Fanv2) || accessory.addService(Service.Fanv2), fanLightService = accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb); fanService .getCharacteristic(Characteristic.Active) - .on("set", (value, callback) => this.internalFanUpdate(accessory, "power", value, callback)); + .on("set", (value, callback) => accessory.control.internalFanUpdate(accessory, "power", value, callback)); fanService .getCharacteristic(Characteristic.RotationSpeed) - .on("set", (value, callback) => this.internalFanUpdate(accessory, "speed", value, callback)) + .on("set", (value, callback) => accessory.control.internalFanUpdate(accessory, "speed", value, callback)) .setProps({ minStep: 33, }); fanLightService .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalFanUpdate(accessory, "light", value, callback)); + .on("set", (value, callback) => accessory.control.internalFanUpdate(accessory, "light", value, callback)); break; case "thermostat": + accessory.control = new deviceThermostat(this); let tempService = accessory.getService(Service.TemperatureSensor) || accessory.addService(Service.TemperatureSensor), humiService = false; @@ -615,7 +639,7 @@ class eWeLink { let switchService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch); switchService .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalThermostatUpdate(accessory, value, callback)); + .on("set", (value, callback) => accessory.control.internalThermostatUpdate(accessory, value, callback)); } if (!(this.config.disableEveLogging || false)) { accessory.log = this.log; @@ -637,6 +661,7 @@ class eWeLink { } break; case "outlet": + accessory.control = new deviceOutlet(this); let outletService; if (!(outletService = accessory.getService(Service.Outlet))) { accessory.addService(Service.Outlet); @@ -660,7 +685,7 @@ class eWeLink { } outletService .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalOutletUpdate(accessory, value, callback)); + .on("set", (value, callback) => accessory.control.internalOutletUpdate(accessory, value, callback)); if (accessory.context.eweModel !== "S26" && !(this.config.disableEveLogging || false)) { accessory.log = this.log; accessory.eveLogger = new EveHistoryService("energy", accessory, { @@ -729,61 +754,66 @@ class eWeLink { } break; case "usb": + accessory.control = new deviceUSB(this); let usbService = accessory.getService(Service.Outlet) || accessory.addService(Service.Outlet); usbService .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalUSBUpdate(accessory, value, callback)); + .on("set", (value, callback) => accessory.control.internalUSBUpdate(accessory, value, callback)); break; case "scm": + accessory.control = new deviceSCM(this); let scmService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch); scmService .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalSCMUpdate(accessory, value, callback)); + .on("set", (value, callback) => accessory.control.internalSCMUpdate(accessory, value, callback)); break; case "light": + accessory.control = new deviceLight(this); let lightService = accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb); lightService .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalLightbulbUpdate(accessory, value, callback)); + .on("set", (value, callback) => accessory.control.internalLightbulbUpdate(accessory, value, callback)); if (cns.devicesBrightable.includes(accessory.context.eweUIID)) { lightService.getCharacteristic(Characteristic.Brightness).on("set", (value, callback) => { if (value > 0) { if (!lightService.getCharacteristic(Characteristic.On).value) { - this.internalLightbulbUpdate(accessory, true, function () { + accessory.control.internalLightbulbUpdate(accessory, true, function () { return; }); } - this.internalBrightnessUpdate(accessory, value, callback); + accessory.control.internalBrightnessUpdate(accessory, value, callback); } else { - this.internalLightbulbUpdate(accessory, false, callback); + accessory.control.internalLightbulbUpdate(accessory, false, callback); } }); } else if (cns.devicesColourable.includes(accessory.context.eweUIID)) { lightService.getCharacteristic(Characteristic.Brightness).on("set", (value, callback) => { if (value > 0) { if (!lightService.getCharacteristic(Characteristic.On).value) { - this.internalLightbulbUpdate(accessory, true, function () { + accessory.control.internalLightbulbUpdate(accessory, true, function () { return; }); } - this.internalHSBUpdate(accessory, "bri", value, callback); + accessory.control.internalHSBUpdate(accessory, "bri", value, callback); } else { - this.internalLightbulbUpdate(accessory, false, callback); + accessory.control.internalLightbulbUpdate(accessory, false, callback); } }); lightService .getCharacteristic(Characteristic.Hue) - .on("set", (value, callback) => this.internalHSBUpdate(accessory, "hue", value, callback)); + .on("set", (value, callback) => accessory.control.internalHSBUpdate(accessory, "hue", value, callback)); lightService.getCharacteristic(Characteristic.Saturation).on("set", (value, callback) => callback()); } break; case "switch": + accessory.control = new deviceSwitch(this); let switchService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch); switchService .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => this.internalSwitchUpdate(accessory, value, callback)); + .on("set", (value, callback) => accessory.control.internalSwitchUpdate(accessory, value, callback)); break; case "rf_sub": + accessory.control = new deviceRFSub(this); switch (accessory.context.subType) { case "water": accessory.getService(Service.LeakSensor) || accessory.addService(Service.LeakSensor); @@ -815,13 +845,14 @@ class eWeLink { .getService(name) .getCharacteristic(Characteristic.On) .on("set", (value, callback) => { - value ? this.internalRFUpdate(accessory, chan, name, callback) : callback(); + value ? accessory.control.internalRFUpdate(accessory, chan, name, callback) : callback(); }); }); break; } break; case "zb_dev": //*** credit @tasict ***\\ + accessory.control = new deviceZBDev(this); accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); switch (accessory.context.eweUIID) { case 1000: @@ -872,60 +903,57 @@ class eWeLink { switch (accessory.context.type) { case "valve": if (Object.keys(newParams).some(v => cns.devicesValveParams.includes(v)) && Array.isArray(newParams.switches)) { - this.externalValveUpdate(accessory, newParams); + accessory.control.externalValveUpdate(accessory, newParams); } return true; case "curtain": if (Object.keys(newParams).some(v => cns.devicesCurtainParams.includes(v))) { - this.externalCurtainUpdate(accessory, newParams); + accessory.control.externalCurtainUpdate(accessory, newParams); } return true; case "blind": - if (Object.keys(newParams).some(v => cns.devicesBlindParams.includes(v)) && Array.isArray(newParams.switches)) { - this.externalBlindUpdate(accessory, newParams); - } return true; case "garage": if ( Object.keys(newParams).some(v => cns.devicesGarageParams.includes(v)) && Array.isArray(newParams.switches) ) { - this.externalGarageUpdate(accessory, newParams); + accessory.control.externalGarageUpdate(accessory, newParams); } return true; case "lock": if (Object.keys(newParams).some(v => cns.devicesLockParams.includes(v))) { - this.externalLockUpdate(accessory, newParams); + accessory.control.externalLockUpdate(accessory, newParams); } return true; case "sensor": if (Object.keys(newParams).some(v => cns.devicesSensorParams.includes(v))) { - this.externalSensorUpdate(accessory, newParams); + accessory.control.externalSensorUpdate(accessory, newParams); } return true; case "fan": if (Object.keys(newParams).some(v => cns.devicesFanParams.includes(v))) { - this.externalFanUpdate(accessory, newParams); + accessory.control.externalFanUpdate(accessory, newParams); } return true; case "thermostat": if (Object.keys(newParams).some(v => cns.devicesThermostatParams.includes(v))) { - this.externalThermostatUpdate(accessory, newParams); + accessory.control.externalThermostatUpdate(accessory, newParams); } return true; case "outlet": if (Object.keys(newParams).some(v => cns.devicesOutletParams.includes(v))) { - this.externalOutletUpdate(accessory, newParams); + accessory.control.externalOutletUpdate(accessory, newParams); } return true; case "usb": if (Object.keys(newParams).some(v => cns.devicesUSBParams.includes(v)) && Array.isArray(newParams.switches)) { - this.externalUSBUpdate(accessory, newParams); + accessory.control.externalUSBUpdate(accessory, newParams); } return true; case "scm": if (Object.keys(newParams).some(v => cns.devicesSCMParams.includes(v)) && Array.isArray(newParams.switches)) { - this.externalSCMUpdate(accessory, newParams); + accessory.control.externalSCMUpdate(accessory, newParams); } return true; case "light": @@ -934,7 +962,7 @@ class eWeLink { cns.devicesSingleSwitchLight.includes(accessory.context.eweModel) ) { if (Object.keys(newParams).some(v => cns.devicesSingleSwitchLightParams.includes(v))) { - this.externalSingleLightUpdate(accessory, newParams); + accessory.control.externalSingleLightUpdate(accessory, newParams); } } else if ( cns.devicesMultiSwitch.includes(accessory.context.eweUIID) && @@ -944,34 +972,34 @@ class eWeLink { Object.keys(newParams).some(v => cns.devicesMultiSwitchLightParams.includes(v)) && Array.isArray(newParams.switches) ) { - this.externalMultiLightUpdate(accessory, newParams); + accessory.control.externalMultiLightUpdate(accessory, newParams); } } return true; case "switch": if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID)) { if (Object.keys(newParams).some(v => cns.devicesSingleSwitchParams.includes(v))) { - this.externalSingleSwitchUpdate(accessory, newParams); + accessory.control.externalSingleSwitchUpdate(accessory, newParams); } } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID)) { if ( Object.keys(newParams).some(v => cns.devicesMultiSwitchParams.includes(v)) && Array.isArray(newParams.switches) ) { - this.externalMultiSwitchUpdate(accessory, newParams); + accessory.control.externalMultiSwitchUpdate(accessory, newParams); } } return true; case "rf_pri": if (Object.keys(newParams).some(v => cns.devicesRFBridgeParams.includes(v))) { - this.externalRFUpdate(accessory, newParams); + accessory.control.externalRFUpdate(accessory, newParams); } return true; case "rf_sub": return true; case "zb_dev": if (Object.keys(newParams).some(v => cns.devicesZBBridgeParams.includes(v))) { - this.externalZBUpdate(accessory, newParams); + accessory.control.externalZBUpdate(accessory, newParams); } return true; default: @@ -1100,1163 +1128,6 @@ class eWeLink { this.log.warn("[%s] Homebridge state will be synced once the device comes back online.", accessory.displayName); } } - async internalValveUpdate(accessory, valve, value, callback) { - callback(); - try { - let params = {}, - serviceValve = accessory.getService(valve); - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; - switch (valve) { - case "Valve A": - params.switches[0].switch = value ? "on" : "off"; - params.switches[1].switch = accessory.getService("Valve B").getCharacteristic(Characteristic.Active).value - ? "on" - : "off"; - break; - case "Valve B": - params.switches[0].switch = accessory.getService("Valve A").getCharacteristic(Characteristic.Active).value - ? "on" - : "off"; - params.switches[1].switch = value ? "on" : "off"; - break; - } - params.switches[2].switch = "off"; - params.switches[3].switch = "off"; - await this.sendDeviceUpdate(accessory, params); - serviceValve.updateCharacteristic(Characteristic.Active, value).updateCharacteristic(Characteristic.InUse, value); - switch (value) { - case 0: - serviceValve.updateCharacteristic(Characteristic.RemainingDuration, 0); - clearTimeout(accessory.getService(valve).timer); - break; - case 1: - let timer = serviceValve.getCharacteristic(Characteristic.SetDuration).value; - serviceValve.updateCharacteristic(Characteristic.RemainingDuration, timer); - serviceValve.timer = setTimeout(() => serviceValve.setCharacteristic(Characteristic.Active, 0), timer * 1000); - break; - } - } catch (err) { - this.requestDeviceRefresh(accessory, err); - } - } - externalValveUpdate(accessory, params) { - try { - ["A", "B"].forEach((v, k) => { - let valveService = accessory.getService("Valve " + v); - valveService - .updateCharacteristic(Characteristic.Active, params.switches[k].switch === "on") - .updateCharacteristic(Characteristic.InUse, params.switches[k].switch === "on"); - if (params.switches[k].switch === "on") { - let timer = valveService.getCharacteristic(Characteristic.SetDuration).value; - valveService.updateCharacteristic(Characteristic.RemainingDuration, timer); - valveService.timer = setTimeout(() => { - valveService.setCharacteristic(Characteristic.Active, 0); - }, timer * 1000); - } else { - valveService.updateCharacteristic(Characteristic.RemainingDuration, 0); - clearTimeout(valveService.timer); - } - }); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - async internalCurtainUpdate(accessory, value, callback) { - callback(); - try { - let params, - cService = accessory.getService(Service.WindowCovering), - prevPos = accessory.context.cacheCurrentPosition, - newPos = value; - if (newPos === prevPos) return; - if (newPos === 0 || newPos === 100) { - params = { - switch: newPos === 100 ? "on" : "off", - }; - } else { - params = { - setclose: Math.abs(100 - newPos), - }; - } - await this.sendDeviceUpdate(accessory, params); - cService - .updateCharacteristic(Characteristic.TargetPosition, newPos) - .updateCharacteristic(Characteristic.PositionState, newPos > prevPos ? 1 : 0); - accessory.context.cacheCurrentPosition = newPos; - } catch (err) { - this.requestDeviceRefresh(accessory, err); - } - } - externalCurtainUpdate(accessory, params) { - try { - let cService = accessory.getService(Service.WindowCovering); - if (params.hasOwnProperty("switch") && params.hasOwnProperty("setclose")) { - let newPos = Math.abs(100 - parseInt(params.setclose)); - cService - .updateCharacteristic(Characteristic.TargetPosition, newPos) - .updateCharacteristic(Characteristic.CurrentPosition, newPos) - .updateCharacteristic(Characteristic.PositionState, 2); - accessory.context.cacheCurrentPosition = newPos; - return; - } - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - async internalBlindUpdate(accessory, value, callback) { - callback(); - try { - let blindConfig, - params = {}, - wcService = accessory.getService(Service.WindowCovering), - prevState = accessory.context.cachePositionState, - prevPosition = accessory.context.cacheCurrentPosition, - newTarget = value, - updateKey = Math.random().toString(36).substr(2, 8); - if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; - } - if (blindConfig.type !== "blind" || blindConfig.setup !== "twoSwitch") { - throw "improper configuration"; - } - if (newTarget === prevPosition) return; - params.switches = cns.defaultMultiSwitchOff; - accessory.context.updateKey = updateKey; - let percentStepPerDecisecond = blindConfig.operationTime / 100; - if (prevState !== 2) { - await this.sendDeviceUpdate(accessory, params); - let positionPercentChange = Math.round( - Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime * percentStepPerDecisecond - ); - if ((prevState === 0 && newTarget > prevPosition) || (prevState === 1 && newTarget < prevPosition)) { - prevPosition += positionPercentChange; - } else { - prevPosition -= positionPercentChange; - } - wcService.updateCharacteristic(Characteristic.CurrentPosition, prevPosition); - accessory.context.cacheCurrentPosition = prevPosition; - } - let diffPosition = newTarget - prevPosition; - let setToMoveUp = diffPosition > 0; - let decisecondsToMove = Math.round(Math.abs(diffPosition) * percentStepPerDecisecond); - params.switches[0].switch = setToMoveUp ? "on" : "off"; - params.switches[1].switch = setToMoveUp ? "off" : "on"; - await this.sendDeviceUpdate(accessory, params); - wcService - .updateCharacteristic(Characteristic.TargetPosition, newTarget) - .updateCharacteristic(Characteristic.PositionState, setToMoveUp); - accessory.context.cacheTargetPosition = newTarget; - accessory.context.cachePositionState = setToMoveUp; - accessory.context.cacheLastStartTime = Math.floor(Date.now() / 100); - this.log.warn(decisecondsToMove + " movement time in deciseconds"); - await utils.sleep(decisecondsToMove * 100); - if (accessory.context.updateKey === updateKey) { - params.switches[0].switch = "off"; - params.switches[1].switch = "off"; - await this.sendDeviceUpdate(accessory, params); - wcService.updateCharacteristic(Characteristic.PositionState, 2); - wcService.updateCharacteristic(Characteristic.CurrentPosition, newTarget); - accessory.context.cachePositionState = 2; - accessory.context.cacheCurrentPosition = newTarget; - } - } catch (err) { - this.requestDeviceRefresh(accessory, err); - } - } - externalBlindUpdate(accessory, params) { - try { - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - async internalGarageUpdate(accessory, value, callback) { - callback(); - try { - let garageConfig; - if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; - } - if (garageConfig.type !== "garage" || !["oneSwitch", "twoSwitch"].includes(garageConfig.setup)) { - throw "improper configuration"; - } - let sensorDefinition = garageConfig.sensorId || false, - sAccessory = false, - prevState, - newPos = value, - params = {}, - delay = 0, - gdService = accessory.getService(Service.GarageDoorOpener); - if (sensorDefinition && !(sAccessory = this.devicesInHB.get(garageConfig.sensorId + "SWX"))) { - throw "defined DW2 sensor doesn't exist"; - } - if (sensorDefinition && sAccessory.context.type !== "sensor") { - throw "defined DW2 sensor isn't a sensor"; - } - prevState = sAccessory - ? sAccessory.getService(Service.ContactSensor).getCharacteristic(Characteristic.ContactSensorState).value === 0 - ? 1 - : 0 - : accessory.context.cacheCurrentDoorState; - if (newPos === prevState % 2) return; - accessory.context.inUse = true; - accessory.context.state = value; - if (garageConfig.setup === "oneSwitch" && [2, 3].includes(prevState)) { - gdService.updateCharacteristic(Characteristic.CurrentDoorState, ((prevState * 2) % 3) + 2); - accessory.context.cacheCurrentDoorState = ((prevState * 2) % 3) + 2; - delay = 1500; - } - if (accessory.context.state !== newPos) return; - await utils.sleep(delay); - gdService - .updateCharacteristic(Characteristic.TargetDoorState, newPos) - .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2); - accessory.context.cacheTargetDoorState = newPos; - accessory.context.cacheCurrentDoorState = newPos + 2; - switch (garageConfig.setup) { - case "oneSwitch": - params.switch = "on"; - break; - case "twoSwitch": - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = newPos === 0 ? "on" : "off"; - params.switches[1].switch = newPos === 1 ? "on" : "off"; - break; - } - await this.sendDeviceUpdate(accessory, params); - await utils.sleep(garageConfig.operationTime * 100); - if (!sAccessory) { - gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos); - accessory.context.cacheCurrentDoorState = newPos; - } - accessory.context.inUse = false; - } catch (err) { - this.requestDeviceRefresh(accessory, err); - } - } - externalGarageUpdate(accessory, params) { - try { - let garageConfig, - gcService = accessory.getService(Service.GarageDoorOpener), - prevState = accessory.context.cacheCurrentDoorState, - newPos = [0, 2].includes(prevState) ? 3 : 2; - if (!(garageConfig = this.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; - } - if (garageConfig.type !== "garage" || !["oneSwitch", "twoSwitch"].includes(garageConfig.setup)) { - throw "improper configuration"; - } - if (accessory.context.inUse || garageConfig.sensorId) { - return; - } - switch (garageConfig.setup) { - case "oneSwitch": - if (params.switch === "off") { - return; - } - break; - case "twoSwitch": - if ( - params.switches[0].switch === params.switches[1].switch || - params.switches[prevState % 2].switch === "on" - ) { - return; - } - break; - } - accessory.context.inUse = true; - if (!garageConfig.sensorId) { - gcService - .updateCharacteristic(Characteristic.CurrentDoorState, newPos) - .updateCharacteristic(Characteristic.TargetDoorState, newPos - 2); - accessory.context.cacheCurrentDoorState = newPos; - accessory.context.cacheTargetDoorState = newPos - 2; - setTimeout(() => { - gcService.updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2); - accessory.context.cacheCurrentDoorState = newPos - 2; - }, parseInt(garageConfig.operationTime) * 100); - } - setTimeout(() => { - accessory.context.inUse = false; - }, parseInt(garageConfig.operationTime) * 100); - } catch (err) { - accessory.context.inUse = false; - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - async internalLockUpdate(accessory, value, callback) { - callback(); - try { - let lockConfig, - params = { - switch: "on", - }, - lmService = accessory.getService(Service.LockMechanism); - if (!(lockConfig = this.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; - } - if (lockConfig.type !== "lock") { - throw "improper configuration"; - } - accessory.context.inUse = true; - await this.sendDeviceUpdate(accessory, params); - lmService - .updateCharacteristic(Characteristic.LockTargetState, 0) - .updateCharacteristic(Characteristic.LockCurrentState, 0); - await utils.sleep(lockConfig.operationTime * 100); - lmService - .updateCharacteristic(Characteristic.LockTargetState, 1) - .updateCharacteristic(Characteristic.LockCurrentState, 1); - accessory.context.inUse = false; - } catch (err) { - this.requestDeviceRefresh(accessory, err); - } - } - externalLockUpdate(accessory, params) { - try { - let lockConfig, - lmService = accessory.getService(Service.LockMechanism); - if (!(lockConfig = this.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; - } - if (lockConfig.type !== "lock") { - throw "improper configuration"; - } - if (params.switch === "off" || accessory.context.inUse) { - return; - } - accessory.context.inUse = true; - lmService - .updateCharacteristic(Characteristic.LockCurrentState, 0) - .updateCharacteristic(Characteristic.LockTargetState, 0); - setTimeout(() => { - lmService - .updateCharacteristic(Characteristic.LockCurrentState, 1) - .updateCharacteristic(Characteristic.LockTargetState, 1); - accessory.context.inUse = false; - }, parseInt(lockConfig.operationTime) * 100); - } catch (err) { - accessory.context.inUse = false; - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalSensorUpdate(accessory, params) { - try { - if (params.hasOwnProperty("battery")) { - let batteryService = - accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService), - scaledBattery = Math.round(params.battery * 33.3); - batteryService.updateCharacteristic(Characteristic.BatteryLevel, scaledBattery); - batteryService.updateCharacteristic( - Characteristic.StatusLowBattery, - scaledBattery < (this.config.lowBattThreshold || 25) - ); - } - let newState = params.switch === "on" ? 1 : 0, - oAccessory = false, - contactService = accessory.getService(Service.ContactSensor); - contactService.updateCharacteristic(Characteristic.ContactSensorState, newState); - this.cusG.forEach(group => { - if (group.sensorId === accessory.context.eweDeviceId && group.type === "garage") { - if ((oAccessory = this.devicesInHB.get(group.deviceId + "SWX"))) { - switch (newState) { - case 0: - oAccessory - .getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.TargetDoorState, 1) - .updateCharacteristic(Characteristic.CurrentDoorState, 1); - break; - case 1: - setTimeout(() => { - oAccessory - .getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.TargetDoorState, 0) - .updateCharacteristic(Characteristic.CurrentDoorState, 0); - }, group.operationTime * 100); - break; - default: - throw "unknown sensor status received [" + newState + "]"; - } - } - } - }); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - async internalFanUpdate(accessory, type, value, callback) { - callback(); - try { - let newPower, - newSpeed, - newLight, - lightService = accessory.getService(Service.Lightbulb), - fanService = accessory.getService(Service.Fanv2); - switch (type) { - case "power": - newPower = value; - newSpeed = value ? 33 : 0; - newLight = lightService.getCharacteristic(Characteristic.On).value; - break; - case "speed": - newPower = value >= 33 ? 1 : 0; - newSpeed = value; - newLight = lightService.getCharacteristic(Characteristic.On).value; - break; - case "light": - newPower = fanService.getCharacteristic(Characteristic.Active).value; - newSpeed = fanService.getCharacteristic(Characteristic.RotationSpeed).value; - newLight = value; - break; - } - let params = { - switches: this.devicesInEW.get(accessory.context.eweDeviceId).params.switches, - }; - params.switches[0].switch = newLight ? "on" : "off"; - params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? "on" : "off"; - params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? "on" : "off"; - params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? "on" : "off"; - await this.sendDeviceUpdate(accessory, params); - lightService.updateCharacteristic(Characteristic.On, newLight); - fanService - .updateCharacteristic(Characteristic.Active, newPower) - .updateCharacteristic(Characteristic.RotationSpeed, newSpeed); - } catch (err) { - this.requestDeviceRefresh(accessory, err); - } - } - externalFanUpdate(accessory, params) { - try { - let light, - status, - speed, - lightService = accessory.getService(Service.Lightbulb), - fanService = accessory.getService(Service.Fanv2); - if (Array.isArray(params.switches)) { - light = params.switches[0].switch === "on"; - switch (params.switches[1].switch + params.switches[2].switch + params.switches[3].switch) { - default: - status = 0; - speed = 0; - break; - case "onoffoff": - status = 1; - speed = 33; - break; - case "ononoff": - status = 1; - speed = 66; - break; - case "onoffon": - status = 1; - speed = 99; - } - } else if (params.hasOwnProperty("light") && params.hasOwnProperty("fan") && params.hasOwnProperty("speed")) { - light = params.light === "on"; - status = params.fan === "on" ? 1 : 0; - speed = params.speed * 33 * status; - } else { - throw "unknown parameters received"; - } - lightService.updateCharacteristic(Characteristic.On, light); - fanService - .updateCharacteristic(Characteristic.Active, status) - .updateCharacteristic(Characteristic.RotationSpeed, speed); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - async internalThermostatUpdate(accessory, value, callback) { - callback(); - try { - let params = { - switch: value ? "on" : "off", - mainSwitch: value ? "on" : "off", - }, - switchService = accessory.getService(Service.Switch); - await this.sendDeviceUpdate(accessory, params); - switchService.updateCharacteristic(Characteristic.On, value); - } catch (err) { - this.requestDeviceRefresh(accessory, err); - } - } - externalThermostatUpdate(accessory, params) { - try { - if (!this.config.hideTHSwitch && (params.hasOwnProperty("switch") || params.hasOwnProperty("mainSwitch"))) { - let newState = params.hasOwnProperty("switch") ? params.switch === "on" : params.mainSwitch === "on", - switchService = accessory.getService(Service.Switch); - switchService.updateCharacteristic(Characteristic.On, newState); - } - if (!(this.config.disableEveLogging || false)) { - let eveLog = { - time: Date.now(), - }; - if (params.hasOwnProperty("currentTemperature") && accessory.getService(Service.TemperatureSensor)) { - let currentTemp = params.currentTemperature !== "unavailable" ? params.currentTemperature : 0; - accessory - .getService(Service.TemperatureSensor) - .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); - eveLog.temp = parseFloat(currentTemp); - } - if (params.hasOwnProperty("currentHumidity") && accessory.getService(Service.HumiditySensor)) { - let currentHumi = params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; - accessory - .getService(Service.HumiditySensor) - .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); - eveLog.humidity = parseFloat(currentHumi); - } - if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { - accessory.eveLogger.addEntry(eveLog); - } - } - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - async internalOutletUpdate(accessory, value, callback) { - callback(); - try { - let params = { - switch: value ? "on" : "off", - }, - outletService = accessory.getService(Service.Outlet); - await this.sendDeviceUpdate(accessory, params); - outletService.updateCharacteristic(Characteristic.On, value); - } catch (err) { - this.requestDeviceRefresh(accessory, err); - } - } - externalOutletUpdate(accessory, params) { - try { - let outletService = accessory.getService(Service.Outlet); - if (params.hasOwnProperty("switch")) { - outletService.updateCharacteristic(Characteristic.On, params.switch === "on"); - if (accessory.context.eweModel === "S26" || this.config.disableEveLogging || false) { - outletService.updateCharacteristic(Characteristic.OutletInUse, params.switch === "on"); - } - } - if (params.hasOwnProperty("power")) { - outletService.updateCharacteristic(EveService.Characteristics.CurrentConsumption, parseFloat(params.power)); - outletService.updateCharacteristic( - Characteristic.OutletInUse, - parseFloat(params.power) > (this.config.inUsePowerThreshold || 0) - ); - let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value; - accessory.eveLogger.addEntry({ - time: Date.now(), - power: isOn ? parseFloat(params.power) : 0, - }); - } - if (params.hasOwnProperty("voltage")) { - outletService.updateCharacteristic(EveService.Characteristics.Voltage, parseFloat(params.voltage)); - } - if (params.hasOwnProperty("current")) { - outletService.updateCharacteristic(EveService.Characteristics.ElectricCurrent, parseFloat(params.current)); - } - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - async internalUSBUpdate(accessory, value, callback) { - callback(); - try { - let params = { - switches: this.devicesInEW.get(accessory.context.eweDeviceId).params.switches, - }, - outletService = accessory.getService(Service.Outlet); - params.switches[0].switch = value ? "on" : "off"; - await this.sendDeviceUpdate(accessory, params); - outletService.updateCharacteristic(Characteristic.On, value); - } catch (err) { - this.requestDeviceRefresh(accessory, err); - } - } - externalUSBUpdate(accessory, params) { - try { - accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - async internalSCMUpdate(accessory, value, callback) { - callback(); - try { - let params = { - switches: this.devicesInEW.get(accessory.context.eweDeviceId).params.switches, - }, - switchService = accessory.getService(Service.Switch); - params.switches[0].switch = value ? "on" : "off"; - await this.sendDeviceUpdate(accessory, params); - switchService.updateCharacteristic(Characteristic.On, value); - } catch (err) { - this.requestDeviceRefresh(accessory, err); - } - } - externalSCMUpdate(accessory, params) { - try { - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - async internalLightbulbUpdate(accessory, value, callback) { - callback(); - try { - let oAccessory, - params = {}, - lightService = accessory.getService(Service.Lightbulb); - switch (accessory.context.switchNumber) { - case "X": - if (accessory.context.eweUIID === 22) { - //*** B1 ***\\ - params.state = value ? "on" : "off"; - } else { - params.switch = value ? "on" : "off"; - } - break; - case "0": - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = value ? "on" : "off"; - params.switches[1].switch = value ? "on" : "off"; - params.switches[2].switch = value ? "on" : "off"; - params.switches[3].switch = value ? "on" : "off"; - break; - case "1": - case "2": - case "3": - case "4": - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; - for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - i === parseInt(accessory.context.switchNumber) - ? (params.switches[i - 1].switch = value ? "on" : "off") - : (params.switches[i - 1].switch = oAccessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.On).value - ? "on" - : "off"); - } else { - params.switches[i - 1].switch = "off"; - } - } - break; - } - await this.sendDeviceUpdate(accessory, params); - switch (accessory.context.switchNumber) { - case "X": - lightService.updateCharacteristic(Characteristic.On, value); - break; - case "0": - for (let i = 0; i <= 4; i++) { - if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); - } - } - break; - case "1": - case "2": - case "3": - case "4": - lightService.updateCharacteristic(Characteristic.On, value); - let masterState = "off"; - for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - if (oAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { - masterState = "on"; - } - } - } - if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, masterState === "on"); - } - break; - } - } catch (err) { - this.requestDeviceRefresh(accessory, err); - } - } - async internalBrightnessUpdate(accessory, value, callback) { - callback(); - try { - let params = {}, - lightService = accessory.getService(Service.Lightbulb); - if (value === 0) { - params.switch = "off"; - } else { - if (!lightService.getCharacteristic(Characteristic.On).value) { - params.switch = "on"; - } - switch (accessory.context.eweUIID) { - case 36: //*** KING-M4 ***\\ - params.bright = Math.round((value * 9) / 10 + 10); - break; - case 44: //*** D1 ***\\ - params.brightness = value; - params.mode = 0; - break; - } - } - await utils.sleep(250); - await this.sendDeviceUpdate(accessory, params); - if (value === 0) { - lightService.updateCharacteristic(Characteristic.On, false); - } else { - lightService.updateCharacteristic(Characteristic.Brightness, value); - } - } catch (err) { - this.requestDeviceRefresh(accessory, err); - } - } - async internalHSBUpdate(accessory, type, value, callback) { - callback(); - try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } - let newRGB, - params = {}, - lightService = accessory.getService(Service.Lightbulb), - curHue = lightService.getCharacteristic(Characteristic.Hue).value, - curSat = lightService.getCharacteristic(Characteristic.Saturation).value; - switch (type) { - case "hue": - newRGB = convert.hsv.rgb(value, curSat, 100); - switch (accessory.context.eweUIID) { - case 22: //*** B1 ***\\ - params = { - zyx_mode: 2, - type: "middle", - channel0: "0", - channel1: "0", - channel2: newRGB[0].toString(), - channel3: newRGB[1].toString(), - channel4: newRGB[2].toString(), - }; - break; - case 59: //*** L1 ***\\ - params = { - mode: 1, - colorR: newRGB[0], - colorG: newRGB[1], - colorB: newRGB[2], - }; - break; - } - break; - case "bri": - switch (accessory.context.eweUIID) { - case 22: //*** B1 ***\\ - newRGB = convert.hsv.rgb(curHue, curSat, value); - params = { - zyx_mode: 2, - type: "middle", - channel0: "0", - channel1: "0", - channel2: newRGB[0].toString(), - channel3: newRGB[1].toString(), - channel4: newRGB[2].toString(), - }; - break; - case 59: //*** L1 ***\\ - params = { - mode: 1, - bright: value, - }; - break; - } - break; - } - await utils.sleep(250); - await this.sendDeviceUpdate(accessory, params); - switch (type) { - case "hue": - lightService.updateCharacteristic(Characteristic.Hue, value); - break; - case "bri": - lightService.updateCharacteristic(Characteristic.Brightness, value); - break; - } - } catch (err) { - this.requestDeviceRefresh(accessory, err); - } - } - externalSingleLightUpdate(accessory, params) { - try { - let newColour, - mode, - isOn = false, - lightService = accessory.getService(Service.Lightbulb); - if (accessory.context.eweUIID === 22 && params.hasOwnProperty("state")) { - isOn = params.state === "on"; - } else if (accessory.context.eweUIID !== 22 && params.hasOwnProperty("switch")) { - isOn = params.switch === "on"; - } else { - isOn = lightService.getCharacteristic(Characteristic.On).value; - } - if (isOn) { - lightService.updateCharacteristic(Characteristic.On, true); - switch (accessory.context.eweUIID) { - case 36: // KING-M4 - if (params.hasOwnProperty("bright")) { - let nb = Math.round(((params.bright - 10) * 10) / 9); // eWeLink scale is 10-100 and HomeKit scale is 0-100. - lightService.updateCharacteristic(Characteristic.Brightness, nb); - } - break; - case 44: // D1 - if (params.hasOwnProperty("brightness")) { - lightService.updateCharacteristic(Characteristic.Brightness, params.brightness); - } - break; - case 22: // B1 - if (params.hasOwnProperty("zyx_mode")) { - mode = parseInt(params.zyx_mode); - } else if (params.hasOwnProperty("channel0") && parseInt(params.channel0) + parseInt(params.channel1) > 0) { - mode = 1; - } else { - mode = 2; - } - if (mode === 2) { - lightService.updateCharacteristic(Characteristic.On, true); - newColour = convert.rgb.hsv( - parseInt(params.channel2), - parseInt(params.channel3), - parseInt(params.channel4) - ); - lightService - .updateCharacteristic(Characteristic.Hue, newColour[0]) - .updateCharacteristic(Characteristic.Saturation, 100) - .updateCharacteristic(Characteristic.Brightness, 100); - } else if (mode === 1) { - throw "has been set to white mode which is not supported"; - } - break; - case 59: // L1 - if (params.hasOwnProperty("bright")) { - lightService.updateCharacteristic(Characteristic.Brightness, params.bright); - } - if (params.hasOwnProperty("colorR")) { - newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB); - lightService - .updateCharacteristic(Characteristic.Hue, newColour[0]) - .updateCharacteristic(Characteristic.Saturation, newColour[1]); - } - break; - default: - return; - } - } else { - lightService.updateCharacteristic(Characteristic.On, false); - } - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalMultiLightUpdate(accessory, params) { - try { - let idToCheck = accessory.context.hbDeviceId.slice(0, -1), - primaryState = false; - for (let i = 1; i <= accessory.context.channelCount; i++) { - if (this.devicesInHB.has(idToCheck + i)) { - let oAccessory = this.devicesInHB.get(idToCheck + i); - oAccessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); - if (params.switches[i - 1].switch === "on") { - primaryState = true; - } - } - } - if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, primaryState); - } - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - async internalSwitchUpdate(accessory, value, callback) { - callback(); - try { - let oAccessory, - params = {}, - switchService = accessory.getService(Service.Switch); - switch (accessory.context.switchNumber) { - case "X": - params.switch = value ? "on" : "off"; - break; - case "0": - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = value ? "on" : "off"; - params.switches[1].switch = value ? "on" : "off"; - params.switches[2].switch = value ? "on" : "off"; - params.switches[3].switch = value ? "on" : "off"; - break; - case "1": - case "2": - case "3": - case "4": - params.switches = this.devicesInEW.get(accessory.context.eweDeviceId).params.switches; - for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - i === parseInt(accessory.context.switchNumber) - ? (params.switches[i - 1].switch = value ? "on" : "off") - : (params.switches[i - 1].switch = oAccessory - .getService(Service.Switch) - .getCharacteristic(Characteristic.On).value - ? "on" - : "off"); - } else { - params.switches[i - 1].switch = "off"; - } - } - break; - } - await this.sendDeviceUpdate(accessory, params); - switch (accessory.context.switchNumber) { - case "X": - switchService.updateCharacteristic(Characteristic.On, value); - break; - case "0": - for (let i = 0; i <= 4; i++) { - if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); - } - } - break; - case "1": - case "2": - case "3": - case "4": - switchService.updateCharacteristic(Characteristic.On, value); - let masterState = "off"; - for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - if (oAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value) { - masterState = "on"; - } - } - } - if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { - oAccessory = this.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, masterState === "on"); - } - break; - } - } catch (err) { - this.requestDeviceRefresh(accessory, err); - } - } - externalSingleSwitchUpdate(accessory, params) { - try { - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switch === "on"); - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalMultiSwitchUpdate(accessory, params) { - try { - let idToCheck = accessory.context.hbDeviceId.slice(0, -1), - primaryState = false; - for (let i = 1; i <= accessory.context.channelCount; i++) { - if (this.devicesInHB.has(idToCheck + i)) { - let oAccessory = this.devicesInHB.get(idToCheck + i); - oAccessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); - if (params.switches[i - 1].switch === "on") { - primaryState = true; - } - } - } - if (!this.hiddenMasters.includes(accessory.context.eweDeviceId)) { - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState); - } - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - async internalRFUpdate(accessory, rfChl, service, callback) { - callback(); - try { - let params = { - cmd: "transmit", - rfChl: parseInt(rfChl), - }, - rfService = accessory.getService(service); - await this.sendDeviceUpdate(accessory, params); - rfService.updateCharacteristic(Characteristic.On, true); - await utils.sleep(3000); - rfService.updateCharacteristic(Characteristic.On, false); - } catch (err) { - this.requestDeviceRefresh(accessory, err); - } - } - externalRFUpdate(accessory, params) { - try { - if (!params.hasOwnProperty("updateSource")) return; - let timeNow = new Date(), - oAccessory = false; - if (params.hasOwnProperty("cmd") && params.cmd === "transmit" && params.hasOwnProperty("rfChl")) { - //*** RF Button ***\\ - // the device needed is SW% corresponding to params.rfChl - this.devicesInHB.forEach(acc => { - if ( - acc.context.eweDeviceId === accessory.context.eweDeviceId && - acc.context.buttons.hasOwnProperty(params.rfChl.toString()) - ) { - oAccessory = acc; - } - }); - if (oAccessory) { - oAccessory.getService(oAccessory.context.buttons[params.rfChl]).updateCharacteristic(Characteristic.On, 1); - setTimeout( - () => - oAccessory - .getService(oAccessory.context.buttons[params.rfChl]) - .updateCharacteristic(Characteristic.On, 0), - 3000 - ); - } else { - throw "rf button not found in Homebridge"; - } - } else if (params.hasOwnProperty("cmd") && params.cmd === "trigger") { - //*** RF Sensor ***\\ - Object.keys(params) - .filter(name => /rfTrig/.test(name)) - .forEach(chan => { - this.devicesInHB.forEach(acc => { - if ( - acc.context.eweDeviceId === accessory.context.eweDeviceId && - acc.context.buttons.hasOwnProperty(chan.substr(-1).toString()) - ) { - oAccessory = acc; - } - }); - if (oAccessory) { - let timeOfMotion = new Date(params[chan]), - diff = (timeNow.getTime() - timeOfMotion.getTime()) / 1000, - serv, - char; - if (diff < (this.config.sensorTimeDifference || 120)) { - switch (oAccessory.context.sensorType) { - case "button": - break; - case "water": - serv = Service.LeakSensor; - char = Characteristic.LeakDetected; - break; - case "fire": - case "smoke": - serv = Service.SmokeSensor; - char = Characteristic.LeakDetected; - break; - case "co": - serv = Service.CarbonMonoxideSensor; - char = Characteristic.CarbonMonoxideDetected; - break; - case "co2": - serv = Service.CarbonDioxideSensor; - char = Characteristic.CarbonDioxideDetected; - break; - case "contact": - serv = Service.ContactSensor; - char = Characteristic.ContactSensorState; - break; - case "occupancy": - serv = Service.OccupancySensor; - char = Characteristic.OccupancyDetected; - break; - default: - serv = Service.MotionSensor; - char = Characteristic.MotionDetected; - break; - } - oAccessory.getService(serv).updateCharacteristic(char, 1); - setTimeout(() => { - oAccessory.getService(serv).updateCharacteristic(char, 0); - }, (this.config.sensorTimeLength || 2) * 1000); - if (this.debug) { - this.log("[%s] has detected [%s].", oAccessory.displayName, oAccessory.context.sensorType); - } - } - } - }); - } - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } - externalZBUpdate(accessory, params) { - try { - //*** credit @tasict ***\\ - if (params.hasOwnProperty("battery")) { - if (accessory.context.eweUIID === 3026 && (this.config.ZBDWBatt || false)) { - params.battery *= 10; - } - let batteryService = - accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); - batteryService.updateCharacteristic(Characteristic.BatteryLevel, params.battery); - batteryService.updateCharacteristic( - Characteristic.StatusLowBattery, - params.battery < (this.config.lowBattThreshold || 25) - ); - } - switch (accessory.context.eweUIID) { - case 1000: - if (params.hasOwnProperty("key") && [0, 1, 2].includes(params.key)) { - accessory - .getService(Service.StatelessProgrammableSwitch) - .updateCharacteristic(Characteristic.ProgrammableSwitchEvent, params.key); - } - break; - case 1770: - let eveLog = { - time: Date.now(), - }; - if (params.hasOwnProperty("temperature")) { - let currentTemp = parseInt(params.temperature) / 100; - accessory - .getService(Service.TemperatureSensor) - .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); - eveLog.temp = parseFloat(currentTemp); - } - if (params.hasOwnProperty("humidity")) { - let currentHumi = parseInt(params.humidity) / 100; - accessory - .getService(Service.HumiditySensor) - .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); - eveLog.humidity = parseFloat(currentHumi); - } - if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { - accessory.eveLogger.addEntry(eveLog); - } - break; - case 2026: - if (params.hasOwnProperty("motion") && params.hasOwnProperty("trigTime")) { - let timeNow = new Date(), - diff = (timeNow.getTime() - params.trigTime) / 1000; - accessory - .getService(Service.MotionSensor) - .updateCharacteristic( - Characteristic.MotionDetected, - params.hasOwnProperty("updateSource") && - params.motion === 1 && - diff < (this.config.sensorTimeDifference || 120) - ); - break; - } - break; - case 3026: - if (params.hasOwnProperty("lock") && [0, 1].includes(params.lock)) { - accessory - .getService(Service.ContactSensor) - .updateCharacteristic(Characteristic.ContactSensorState, params.lock); - } - break; - } - } catch (err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); - } - } } module.exports = function (homebridge) { Accessory = homebridge.platformAccessory; From 7e33edf6faeaa3bccc1148526823dda000bcb171 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 26 Sep 2020 22:19:23 +0100 Subject: [PATCH 0225/3183] blinds --- lib/device/blind.js | 87 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 13 deletions(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index 8057a852..bb9b5725 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -18,9 +18,12 @@ module.exports = class deviceBlind { wcService = accessory.getService(Service.WindowCovering), prevState = accessory.context.cachePositionState, prevPosition = accessory.context.cacheCurrentPosition, + prevFixedPosition = accessory.context.cacheLastFixedPosition, newTarget = value, updateKey = Math.random().toString(36).substr(2, 8); - if (!(blindConfig = this.cusG.get(accessory.context.hbDeviceId))) { + if ( + !(blindConfig = this.platform.cusG.get(accessory.context.hbDeviceId)) + ) { throw "group config missing"; } if (blindConfig.type !== "blind" || blindConfig.setup !== "twoSwitch") { @@ -30,41 +33,99 @@ module.exports = class deviceBlind { params.switches = cns.defaultMultiSwitchOff; accessory.context.updateKey = updateKey; let percentStepPerDecisecond = blindConfig.operationTime / 100; + + // + // + + this.platform.log("============================"); + this.platform.log("============================"); + this.platform.log("Starting main calculation..."); + this.platform.log("Moving from [%s%] to [%s%].", prevPosition, newTarget); + + // + // + if (prevState !== 2) { - await this.platform.sendDeviceUpdate(accessory, params); + // await this.platform.sendDeviceUpdate(accessory, params); let positionPercentChange = Math.round( - Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime * percentStepPerDecisecond + (Math.floor(Date.now() / 100) - + accessory.context.cacheLastStartTime) * + percentStepPerDecisecond ); - if ((prevState === 0 && newTarget > prevPosition) || (prevState === 1 && newTarget < prevPosition)) { - prevPosition += positionPercentChange; + if ( + (prevState === 0 && newTarget < prevPosition) || + (prevState === 1 && newTarget > prevPosition) + ) { + prevPosition = Math.abs(prevPosition - positionPercentChange); } else { - prevPosition -= positionPercentChange; + prevPosition = Math.abs(prevPosition + positionPercentChange); } - wcService.updateCharacteristic(Characteristic.CurrentPosition, prevPosition); + wcService.updateCharacteristic( + Characteristic.CurrentPosition, + prevPosition + ); + this.platform.log.warn("But..."); + this.platform.log.warn( + "Blind was already moving %s when it was changed and was probably around %s%", + prevState === 1 ? "up" : "down", + prevPosition + ); + this.platform.log.warn( + "Blind was already moving from time %s when it was changed at %s time", + accessory.context.cacheLastStartTime, + Math.floor(Date.now() / 100) + ); + this.platform.log.warn( + "Giving a difference of %s seconds", + (Math.floor(Date.now() / 100) - + accessory.context.cacheLastStartTime) / + 10 + ); + this.platform.log.warn( + "This works out as a position change of %s%", + positionPercentChange + ); + accessory.context.cacheCurrentPosition = prevPosition; } + let diffPosition = newTarget - prevPosition; let setToMoveUp = diffPosition > 0; - let decisecondsToMove = Math.round(Math.abs(diffPosition) * percentStepPerDecisecond); + let decisecondsToMove = Math.round( + Math.abs(diffPosition) * percentStepPerDecisecond + ); + this.platform.log( + "So we need to move %s from the previous state of %s for about %s seconds", + setToMoveUp ? "up" : "down", + prevState === 0 + ? "moving down" + : prevState === 1 + ? "moving up" + : "stopped", + decisecondsToMove / 10 + ); params.switches[0].switch = setToMoveUp ? "on" : "off"; params.switches[1].switch = setToMoveUp ? "off" : "on"; - await this.platform.sendDeviceUpdate(accessory, params); + // await this.platform.sendDeviceUpdate(accessory, params); wcService .updateCharacteristic(Characteristic.TargetPosition, newTarget) .updateCharacteristic(Characteristic.PositionState, setToMoveUp); accessory.context.cacheTargetPosition = newTarget; - accessory.context.cachePositionState = setToMoveUp; + accessory.context.cachePositionState = setToMoveUp ? 1 : 0; accessory.context.cacheLastStartTime = Math.floor(Date.now() / 100); - this.platform.log.warn(decisecondsToMove + " movement time in deciseconds"); await utils.sleep(decisecondsToMove * 100); if (accessory.context.updateKey === updateKey) { params.switches[0].switch = "off"; params.switches[1].switch = "off"; - await this.platform.sendDeviceUpdate(accessory, params); + // await this.platform.sendDeviceUpdate(accessory, params); wcService.updateCharacteristic(Characteristic.PositionState, 2); - wcService.updateCharacteristic(Characteristic.CurrentPosition, newTarget); + wcService.updateCharacteristic( + Characteristic.CurrentPosition, + newTarget + ); accessory.context.cachePositionState = 2; accessory.context.cacheCurrentPosition = newTarget; + accessory.context.cacheLastFixedPosition = newTarget; } } catch (err) { this.platform.requestDeviceRefresh(accessory, err); From a322e981c076fefff52296283324cef28f3013e3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 26 Sep 2020 22:20:01 +0100 Subject: [PATCH 0226/3183] formatting --- lib/device/blind.js | 42 +++++++++--------------------------------- 1 file changed, 9 insertions(+), 33 deletions(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index bb9b5725..73615c4e 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -21,9 +21,7 @@ module.exports = class deviceBlind { prevFixedPosition = accessory.context.cacheLastFixedPosition, newTarget = value, updateKey = Math.random().toString(36).substr(2, 8); - if ( - !(blindConfig = this.platform.cusG.get(accessory.context.hbDeviceId)) - ) { + if (!(blindConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw "group config missing"; } if (blindConfig.type !== "blind" || blindConfig.setup !== "twoSwitch") { @@ -48,22 +46,14 @@ module.exports = class deviceBlind { if (prevState !== 2) { // await this.platform.sendDeviceUpdate(accessory, params); let positionPercentChange = Math.round( - (Math.floor(Date.now() / 100) - - accessory.context.cacheLastStartTime) * - percentStepPerDecisecond + (Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime) * percentStepPerDecisecond ); - if ( - (prevState === 0 && newTarget < prevPosition) || - (prevState === 1 && newTarget > prevPosition) - ) { + if ((prevState === 0 && newTarget < prevPosition) || (prevState === 1 && newTarget > prevPosition)) { prevPosition = Math.abs(prevPosition - positionPercentChange); } else { prevPosition = Math.abs(prevPosition + positionPercentChange); } - wcService.updateCharacteristic( - Characteristic.CurrentPosition, - prevPosition - ); + wcService.updateCharacteristic(Characteristic.CurrentPosition, prevPosition); this.platform.log.warn("But..."); this.platform.log.warn( "Blind was already moving %s when it was changed and was probably around %s%", @@ -77,31 +67,20 @@ module.exports = class deviceBlind { ); this.platform.log.warn( "Giving a difference of %s seconds", - (Math.floor(Date.now() / 100) - - accessory.context.cacheLastStartTime) / - 10 - ); - this.platform.log.warn( - "This works out as a position change of %s%", - positionPercentChange + (Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime) / 10 ); + this.platform.log.warn("This works out as a position change of %s%", positionPercentChange); accessory.context.cacheCurrentPosition = prevPosition; } let diffPosition = newTarget - prevPosition; let setToMoveUp = diffPosition > 0; - let decisecondsToMove = Math.round( - Math.abs(diffPosition) * percentStepPerDecisecond - ); + let decisecondsToMove = Math.round(Math.abs(diffPosition) * percentStepPerDecisecond); this.platform.log( "So we need to move %s from the previous state of %s for about %s seconds", setToMoveUp ? "up" : "down", - prevState === 0 - ? "moving down" - : prevState === 1 - ? "moving up" - : "stopped", + prevState === 0 ? "moving down" : prevState === 1 ? "moving up" : "stopped", decisecondsToMove / 10 ); params.switches[0].switch = setToMoveUp ? "on" : "off"; @@ -119,10 +98,7 @@ module.exports = class deviceBlind { params.switches[1].switch = "off"; // await this.platform.sendDeviceUpdate(accessory, params); wcService.updateCharacteristic(Characteristic.PositionState, 2); - wcService.updateCharacteristic( - Characteristic.CurrentPosition, - newTarget - ); + wcService.updateCharacteristic(Characteristic.CurrentPosition, newTarget); accessory.context.cachePositionState = 2; accessory.context.cacheCurrentPosition = newTarget; accessory.context.cacheLastFixedPosition = newTarget; From fc49a009ea9ce229050cb192cbafbbb486cd54c6 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 26 Sep 2020 22:20:43 +0100 Subject: [PATCH 0227/3183] 3.0.3-2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index cf967598..4325215d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.3-1", + "version": "3.0.3-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a50beb2b..71511ffd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.3-1", + "version": "3.0.3-2", "author": "bwp91", "contributors": [ "gbro115", From aff2c9e5626a9b7d6f66dfc70494e665e2d83bf5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 26 Sep 2020 22:30:00 +0100 Subject: [PATCH 0228/3183] Update blind.js --- lib/device/blind.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index 73615c4e..9d36d708 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -44,7 +44,7 @@ module.exports = class deviceBlind { // if (prevState !== 2) { - // await this.platform.sendDeviceUpdate(accessory, params); + await this.platform.sendDeviceUpdate(accessory, params); let positionPercentChange = Math.round( (Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime) * percentStepPerDecisecond ); @@ -85,7 +85,7 @@ module.exports = class deviceBlind { ); params.switches[0].switch = setToMoveUp ? "on" : "off"; params.switches[1].switch = setToMoveUp ? "off" : "on"; - // await this.platform.sendDeviceUpdate(accessory, params); + await this.platform.sendDeviceUpdate(accessory, params); wcService .updateCharacteristic(Characteristic.TargetPosition, newTarget) .updateCharacteristic(Characteristic.PositionState, setToMoveUp); @@ -96,7 +96,7 @@ module.exports = class deviceBlind { if (accessory.context.updateKey === updateKey) { params.switches[0].switch = "off"; params.switches[1].switch = "off"; - // await this.platform.sendDeviceUpdate(accessory, params); + await this.platform.sendDeviceUpdate(accessory, params); wcService.updateCharacteristic(Characteristic.PositionState, 2); wcService.updateCharacteristic(Characteristic.CurrentPosition, newTarget); accessory.context.cachePositionState = 2; From 22833940e95044673193ad94de8c8820f2e500fa Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 26 Sep 2020 22:31:28 +0100 Subject: [PATCH 0229/3183] 3.0.3-3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4325215d..8937010e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.3-2", + "version": "3.0.3-3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 71511ffd..2b7e84c0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.3-2", + "version": "3.0.3-3", "author": "bwp91", "contributors": [ "gbro115", From 55172e1f222e12ef9f4916c7c10bf573724628b6 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 00:13:38 +0100 Subject: [PATCH 0230/3183] Update blind.js --- lib/device/blind.js | 57 +++++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 35 deletions(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index 9d36d708..4e205161 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -9,7 +9,6 @@ module.exports = class deviceBlind { Service = platform.api.hap.Service; Characteristic = platform.api.hap.Characteristic; } - async internalBlindUpdate(accessory, value, callback) { callback(); try { @@ -18,7 +17,6 @@ module.exports = class deviceBlind { wcService = accessory.getService(Service.WindowCovering), prevState = accessory.context.cachePositionState, prevPosition = accessory.context.cacheCurrentPosition, - prevFixedPosition = accessory.context.cacheLastFixedPosition, newTarget = value, updateKey = Math.random().toString(36).substr(2, 8); if (!(blindConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { @@ -31,49 +29,39 @@ module.exports = class deviceBlind { params.switches = cns.defaultMultiSwitchOff; accessory.context.updateKey = updateKey; let percentStepPerDecisecond = blindConfig.operationTime / 100; - // // - this.platform.log("============================"); this.platform.log("============================"); this.platform.log("Starting main calculation..."); - this.platform.log("Moving from [%s%] to [%s%].", prevPosition, newTarget); - // // - if (prevState !== 2) { await this.platform.sendDeviceUpdate(accessory, params); - let positionPercentChange = Math.round( - (Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime) * percentStepPerDecisecond - ); - if ((prevState === 0 && newTarget < prevPosition) || (prevState === 1 && newTarget > prevPosition)) { - prevPosition = Math.abs(prevPosition - positionPercentChange); + let positionPercentChange = Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime; + positionPercentChange = Math.floor(percentStepPerDecisecond * positionPercentChange); + if (prevState === 0) { + // moving down + prevPosition -= positionPercentChange; } else { - prevPosition = Math.abs(prevPosition + positionPercentChange); + prevPosition += positionPercentChange; } wcService.updateCharacteristic(Characteristic.CurrentPosition, prevPosition); - this.platform.log.warn("But..."); + accessory.context.cacheCurrentPosition = prevPosition; + this.platform.log.warn("Moving from [%s%] to [%s]", prevPosition, newTarget); this.platform.log.warn( "Blind was already moving %s when it was changed and was probably around %s%", prevState === 1 ? "up" : "down", prevPosition ); this.platform.log.warn( - "Blind was already moving from time %s when it was changed at %s time", - accessory.context.cacheLastStartTime, - Math.floor(Date.now() / 100) - ); - this.platform.log.warn( - "Giving a difference of %s seconds", - (Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime) / 10 + "Giving a difference of %s seconds - a position change of %s%", + (Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime) / 10, + positionPercentChange ); - this.platform.log.warn("This works out as a position change of %s%", positionPercentChange); - - accessory.context.cacheCurrentPosition = prevPosition; + } else { + this.platform.log("Moving from [%s%] to [%s%].", prevPosition, newTarget); } - let diffPosition = newTarget - prevPosition; let setToMoveUp = diffPosition > 0; let decisecondsToMove = Math.round(Math.abs(diffPosition) * percentStepPerDecisecond); @@ -92,17 +80,16 @@ module.exports = class deviceBlind { accessory.context.cacheTargetPosition = newTarget; accessory.context.cachePositionState = setToMoveUp ? 1 : 0; accessory.context.cacheLastStartTime = Math.floor(Date.now() / 100); + if (accessory.context.updateKey !== updateKey) return; await utils.sleep(decisecondsToMove * 100); - if (accessory.context.updateKey === updateKey) { - params.switches[0].switch = "off"; - params.switches[1].switch = "off"; - await this.platform.sendDeviceUpdate(accessory, params); - wcService.updateCharacteristic(Characteristic.PositionState, 2); - wcService.updateCharacteristic(Characteristic.CurrentPosition, newTarget); - accessory.context.cachePositionState = 2; - accessory.context.cacheCurrentPosition = newTarget; - accessory.context.cacheLastFixedPosition = newTarget; - } + if (accessory.context.updateKey !== updateKey) return; + params.switches[0].switch = "off"; + params.switches[1].switch = "off"; + await this.platform.sendDeviceUpdate(accessory, params); + wcService.updateCharacteristic(Characteristic.PositionState, 2); + wcService.updateCharacteristic(Characteristic.CurrentPosition, newTarget); + accessory.context.cachePositionState = 2; + accessory.context.cacheCurrentPosition = newTarget; } catch (err) { this.platform.requestDeviceRefresh(accessory, err); } From 996850df5f75fa4a585e3c14b98ada50de64b0f7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 00:14:08 +0100 Subject: [PATCH 0231/3183] Update blind.js --- lib/device/blind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index 4e205161..377fb763 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -48,7 +48,7 @@ module.exports = class deviceBlind { } wcService.updateCharacteristic(Characteristic.CurrentPosition, prevPosition); accessory.context.cacheCurrentPosition = prevPosition; - this.platform.log.warn("Moving from [%s%] to [%s]", prevPosition, newTarget); + this.platform.log.warn("Moving from [%s%] to [%s%]", prevPosition, newTarget); this.platform.log.warn( "Blind was already moving %s when it was changed and was probably around %s%", prevState === 1 ? "up" : "down", From 5879e1b7a61a42691c3931988618c3b1afca09ee Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 00:14:51 +0100 Subject: [PATCH 0232/3183] 3.0.3-4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8937010e..a05cbda3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.3-3", + "version": "3.0.3-4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 2b7e84c0..81643c16 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.3-3", + "version": "3.0.3-4", "author": "bwp91", "contributors": [ "gbro115", From cba99517e8c2d66a27602cdc767116bf9261ef12 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 02:20:59 +0100 Subject: [PATCH 0233/3183] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 79d92ff6..d8a98c3f 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) [![Discord](https://img.shields.io/discord/432663330281226270?color=728ED5&logo=discord&label=discord)](https://discord.com/channels/432663330281226270/742733745743855627) - [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) + [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/latest?label=release)](https://www.npmjs.com/package/homebridge-ewelink) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://www.npmjs.com/package/homebridge-ewelink) [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) From 9da0ed7433bf951a59a9ca80bdbd2fe6e6ce2437 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 02:24:39 +0100 Subject: [PATCH 0234/3183] standard js --- .prettier.ignore | 5 - .prettierrc.json | 4 - config.schema.json | 62 +- index.js | 9 +- lib/constants.js | 137 ++--- lib/eWeLink.js | 1456 ++++++++++++++++++++++---------------------- lib/eWeLinkHTTP.js | 460 +++++++------- lib/eWeLinkLAN.js | 287 ++++----- lib/eWeLinkWS.js | 492 ++++++++------- lib/utils.js | 9 +- package-lock.json | 6 - package.json | 3 - 12 files changed, 1462 insertions(+), 1468 deletions(-) delete mode 100644 .prettier.ignore delete mode 100644 .prettierrc.json diff --git a/.prettier.ignore b/.prettier.ignore deleted file mode 100644 index 45fb205e..00000000 --- a/.prettier.ignore +++ /dev/null @@ -1,5 +0,0 @@ -.DS_Store -.nova -.github -.npm -node_modules/ \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json deleted file mode 100644 index 163a0a7e..00000000 --- a/.prettierrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "arrowParens": "avoid", - "printWidth": 120 -} diff --git a/config.schema.json b/config.schema.json index f1e23146..037b6c42 100644 --- a/config.schema.json +++ b/config.schema.json @@ -136,15 +136,21 @@ "oneOf": [ { "title": "Blind", - "enum": ["blind"] + "enum": [ + "blind" + ] }, { "title": "Garage Door", - "enum": ["garage"] + "enum": [ + "garage" + ] }, { "title": "Lock", - "enum": ["lock"] + "enum": [ + "lock" + ] } ] }, @@ -156,11 +162,15 @@ "oneOf": [ { "title": "One Switch - for up and down", - "enum": ["oneSwitch"] + "enum": [ + "oneSwitch" + ] }, { "title": "Two Switches - one for up and one for down", - "enum": ["twoSwitch"] + "enum": [ + "twoSwitch" + ] } ] }, @@ -205,31 +215,45 @@ "oneOf": [ { "title": "Motion", - "enum": ["motion"] + "enum": [ + "motion" + ] }, { "title": "Smoke/Fire", - "enum": ["smoke"] + "enum": [ + "smoke" + ] }, { "title": "Water/Leak", - "enum": ["water"] + "enum": [ + "water" + ] }, { "title": "Carbon Monoxide", - "enum": ["co"] + "enum": [ + "co" + ] }, { "title": "Carbon Dioxide", - "enum": ["co2"] + "enum": [ + "co2" + ] }, { "title": "Occupancy", - "enum": ["occupancy"] + "enum": [ + "occupancy" + ] }, { "title": "Contact", - "enum": ["contact"] + "enum": [ + "contact" + ] } ] } @@ -237,14 +261,22 @@ } } }, - "required": ["countryCode", "username", "password"] + "required": [ + "countryCode", + "username", + "password" + ] }, "layout": [ { "type": "fieldset", "title": "Required Settings", "description": "These are the basic settings that are required for this plugin to work.", - "items": ["countryCode", "username", "password"] + "items": [ + "countryCode", + "username", + "password" + ] }, { "type": "fieldset", @@ -312,4 +344,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/index.js b/index.js index 01e13ba7..bff9ae59 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,5 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; +'use strict' module.exports = function (homebridge) { - const eWeLink = require("./lib/eWeLink.js")(homebridge); - homebridge.registerPlatform("homebridge-ewelink", "eWeLink", eWeLink, true); -}; + const eWeLink = require('./lib/eWeLink.js')(homebridge) + homebridge.registerPlatform('homebridge-ewelink', 'eWeLink', eWeLink, true) +} diff --git a/lib/constants.js b/lib/constants.js index 803a3423..1ec671bc 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -1,110 +1,61 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; +'use strict' module.exports = { - // appId: "Uw83EKZFxdif7XFXEsrpduz5YyjP7nTl", - appId: "oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq", - // appSecret: "mXLOjea0woSMvK9gw7Fjsy7YlFO4iSu6", - appSecret: "6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM", - devicesHideable: ["switch", "light"], + appId: 'oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq', + appSecret: '6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM', + devicesHideable: ['switch', 'light'], devicesNonLAN: [22, 28, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], - devicesSingleSwitchParams: ["switch"], - devicesSingleSwitchOutlet: ["Sonoff Pow", "S26"], + devicesSingleSwitchParams: ['switch'], + devicesSingleSwitchOutlet: ['Sonoff Pow', 'S26'], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], - devicesMultiSwitchParams: ["switches"], - devicesSingleSwitchLight: ["T1 1C", "L1", "B1", "B1_R2", "TX1C", "D1", "D1R1", "KING-M4", "Slampher", "GTTA59"], - devicesSingleSwitchLightParams: [ - "switch", - "state", - "bright", - "colorR", - "brightness", - "channel0", - "channel2", - "xyz_mode", - ], - devicesMultiSwitchLight: ["T1 2C", "T1 3C", "TX2C", "TX3C"], - devicesMultiSwitchLightParams: ["switches"], + devicesMultiSwitchParams: ['switches'], + devicesSingleSwitchLight: ['T1 1C', 'L1', 'B1', 'B1_R2', 'TX1C', 'D1', 'D1R1', 'KING-M4', 'Slampher', 'GTTA59'], + devicesSingleSwitchLightParams: ['switch', 'state', 'bright', 'colorR', 'brightness', 'channel0', 'channel2', 'xyz_mode'], + devicesMultiSwitchLight: ['T1 2C', 'T1 3C', 'TX2C', 'TX3C'], + devicesMultiSwitchLightParams: ['switches'], devicesBrightable: [36, 44], devicesColourable: [22, 59], devicesCurtain: [11], - devicesCurtainParams: ["switch", "setclose"], + devicesCurtainParams: ['switch', 'setclose'], devicesSensor: [102], - devicesSensorParams: ["switch", "battery"], + devicesSensorParams: ['switch', 'battery'], devicesThermostat: [15], - devicesThermostatParams: ["currentTemperature", "currentHumidity", "switch", "masterSwitch"], + devicesThermostatParams: ['currentTemperature', 'currentHumidity', 'switch', 'masterSwitch'], devicesFan: [34], - devicesFanParams: ["switches", "light", "fan", "speed"], + devicesFanParams: ['switches', 'light', 'fan', 'speed'], devicesOutlet: [32], - devicesOutletParams: ["switch", "power", "voltage", "current"], + devicesOutletParams: ['switch', 'power', 'voltage', 'current'], devicesCamera: [87], devicesUSB: [77], - devicesUSBParams: ["switches"], + devicesUSBParams: ['switches'], devicesSCM: [78], - devicesSCMParams: ["switches"], + devicesSCMParams: ['switches'], devicesRFBridge: [28], - devicesRFBridgeParams: ["cmd"], + devicesRFBridgeParams: ['cmd'], devicesZBBridge: [66], - devicesZBBridgeParams: ["key", "temperature", "humidity", "motion", "lock", "trigTime", "battery"], + devicesZBBridgeParams: ['key', 'temperature', 'humidity', 'motion', 'lock', 'trigTime', 'battery'], devicesZB: [1000, 1770, 2026, 3026], - devicesValveParams: ["switches"], - devicesGarageParams: ["switch", "switches"], - devicesLockParams: ["switch"], - allowedGroups: ["blind", "garage", "lock"], - paramsToKeep: [ - "battery", - "bright", - "brightness", - "channel", - "cmd", - "colorB", - "colorG", - "colorR", - "current", - "currentHumidity", - "currentTemperature", - "fan", - "humidity", - "key", - "light", - "lock", - "mainSwitch", - "mode", - "motion", - "online", - "power", - "rfChl", - "rfList", - "rfTrig", - "sensorType", - "setclose", - "speed", - "state", - "switch", - "switches", - "temperature", - "trigTime", - "type", - "voltage", - "zyx_mode", - ], - defaultMultiSwitchOff: [ - { - switch: "off", - outlet: 0, - }, - { - switch: "off", - outlet: 1, - }, - { - switch: "off", - outlet: 2, - }, - { - switch: "off", - outlet: 3, - }, + devicesValveParams: ['switches'], + devicesGarageParams: ['switch', 'switches'], + devicesLockParams: ['switch'], + allowedGroups: ['blind', 'garage', 'lock'], + paramsToKeep: ['battery', 'bright', 'brightness', 'channel', 'cmd', 'colorB', 'colorG', 'colorR', 'current', 'currentHumidity', 'currentTemperature', 'fan', 'humidity', 'key', 'light', 'lock', 'mainSwitch', 'mode', 'motion', 'online', 'power', 'rfChl', 'rfList', 'rfTrig', 'sensorType', 'setclose', 'speed', 'state', 'switch', 'switches', 'temperature', 'trigTime', 'type', 'voltage', 'zyx_mode'], + defaultMultiSwitchOff: [{ + switch: 'off', + outlet: 0 + }, + { + switch: 'off', + outlet: 1 + }, + { + switch: 'off', + outlet: 2 + }, + { + switch: 'off', + outlet: 3 + } ], chansFromUiid: { 1: 1, // "SOCKET" \\ 20, MINI, BASIC, S26 @@ -200,6 +151,6 @@ module.exports = { 3026: 1, // "ZIGBEE_DOOR_AND_WINDOW_SENSOR" \\ 3256: 3, // "ZIGBEE_SWITCH_3" \\ 4026: 1, // "ZIGBEE_WATER_SENSOR" \\ - 4256: 4, // "ZIGBEE_SWITCH_4" \\ - }, -}; + 4256: 4 // "ZIGBEE_SWITCH_4" \\ + } +} diff --git a/lib/eWeLink.js b/lib/eWeLink.js index f5ca8134..7ea7569b 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1,492 +1,453 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -let Accessory, Characteristic, EveService, EveHistoryService, Service; -const cns = require("./constants"), - corrInterval = require("correcting-interval"), - deviceCurtain = require("./device/curtain"), - deviceBlind = require("./device/blind"), - deviceGarage = require("./device/garage"), - deviceLock = require("./device/lock"), - deviceValve = require("./device/valve"), - deviceSensor = require("./device/sensor"), - deviceFan = require("./device/fan"), - deviceThermostat = require("./device/thermostat"), - deviceOutlet = require("./device/outlet"), - deviceUSB = require("./device/usb"), - deviceSCM = require("./device/scm"), - deviceLight = require("./device/light"), - deviceSwitch = require("./device/switch"), - deviceRFSub = require("./device/rf-sub"), - deviceZBDev = require("./device/zb-dev"), - eWeLinkHTTP = require("./eWeLinkHTTP"), - eWeLinkWS = require("./eWeLinkWS"), - eWeLinkLAN = require("./eWeLinkLAN"), - fakegato = require("fakegato-history"), - hbLib = require("homebridge-lib"), - promInterval = require("interval-promise"), - utils = require("./utils"); +'use strict' +let Accessory, Characteristic, EveService, EveHistoryService, Service +const cns = require('./constants') +const corrInterval = require('correcting-interval') +const DeviceCurtain = require('./device/curtain') +const DeviceBlind = require('./device/blind') +const DeviceGarage = require('./device/garage') +const DeviceLock = require('./device/lock') +const DeviceValve = require('./device/valve') +const DeviceSensor = require('./device/sensor') +const DeviceFan = require('./device/fan') +const DeviceThermostat = require('./device/thermostat') +const DeviceOutlet = require('./device/outlet') +const DeviceUSB = require('./device/usb') +const DeviceSCM = require('./device/scm') +const DeviceLight = require('./device/light') +const DeviceSwitch = require('./device/switch') +const DeviceRFSub = require('./device/rf-sub') +const DeviceZBDev = require('./device/zb-dev') +const EWeLinkHTTP = require('./eWeLinkHTTP') +const EWeLinkWS = require('./eWeLinkWS') +const EWeLinkLAN = require('./eWeLinkLAN') +const fakegato = require('fakegato-history') +const hbLib = require('homebridge-lib') +const promInterval = require('interval-promise') +const utils = require('./utils') class eWeLink { - constructor(log, config, api) { - if (!log || !api || !config) return; + constructor (log, config, api) { + if (!log || !api || !config) return if (!config.username || !config.password || !config.countryCode) { - log.error("*********** Cannot load homebridge-ewelink ***********"); - log.error("eWeLink credentials missing from the Homebridge config."); - log.error("*******************************************************"); - return; + log.error('*********** Cannot load homebridge-ewelink ***********') + log.error('eWeLink credentials missing from the Homebridge config.') + log.error('*******************************************************') + return } - this.log = log; - this.config = config; - this.api = api; - this.debug = this.config.debug || false; - this.devicesInHB = new Map(); - this.devicesInEW = new Map(); - this.cusG = new Map(); - this.cusS = new Map(); - this.hiddenMasters = []; - this.eveLogPath = this.api.user.storagePath() + "/homebridge-ewelink/"; - this.wsRefreshFlag = true; + this.log = log + this.config = config + this.api = api + this.debug = this.config.debug || false + this.devicesInHB = new Map() + this.devicesInEW = new Map() + this.cusG = new Map() + this.cusS = new Map() + this.hiddenMasters = [] + this.eveLogPath = this.api.user.storagePath() + '/homebridge-ewelink/' + this.wsRefreshFlag = true this.api - .on("didFinishLaunching", () => this.eWeLinkSync()) - .on("shutdown", () => { - if (this.lanClient) this.lanClient.closeConnection(); - if (this.wsClient) this.wsClient.closeConnection(); - this.wsRefreshFlag = false; - }); + .on('didFinishLaunching', () => this.eWeLinkSync()) + .on('shutdown', () => { + if (this.lanClient) this.lanClient.closeConnection() + if (this.wsClient) this.wsClient.closeConnection() + this.wsRefreshFlag = false + }) } - async eWeLinkSync() { + + async eWeLinkSync () { try { - this.log("Plugin has finished initialising. Synching with eWeLink."); - this.httpClient = new eWeLinkHTTP(this.config, this.log); - await this.httpClient.getHost(); - this.authData = await this.httpClient.login(); - let deviceList = await this.httpClient.getDevices(); - deviceList.forEach(device => this.devicesInEW.set(device.deviceid, device)); - this.wsClient = new eWeLinkWS(this.config, this.log, this.authData); - this.lanClient = new eWeLinkLAN(this.config, this.log, deviceList); - await this.wsClient.getHost(); - this.wsClient.login(); - this.lanDevices = await this.lanClient.getHosts(); + this.log('Plugin has finished initialising. Synching with eWeLink.') + this.httpClient = new EWeLinkHTTP(this.config, this.log) + await this.httpClient.getHost() + this.authData = await this.httpClient.login() + const deviceList = await this.httpClient.getDevices() + deviceList.forEach(device => this.devicesInEW.set(device.deviceid, device)) + this.wsClient = new EWeLinkWS(this.config, this.log, this.authData) + this.lanClient = new EWeLinkLAN(this.config, this.log, deviceList) + await this.wsClient.getHost() + this.wsClient.login() + this.lanDevices = await this.lanClient.getHosts() await this.lanClient.startMonitor(); (() => { - //*** Make a map of custom groups from Homebridge config ***\\ + //* ** Make a map of custom groups from Homebridge config ***\\ if (Object.keys(this.config.groups || []).length > 0) { this.config.groups - .filter(g => g.hasOwnProperty("type") && cns.allowedGroups.includes(g.type)) - .filter(g => g.hasOwnProperty("deviceId") && this.devicesInEW.has(g.deviceId)) - .forEach(g => this.cusG.set(g.deviceId + "SWX", g)); + .filter(g => Object.prototype.hasOwnProperty.call(g, 'type') && cns.allowedGroups.includes(g.type)) + .filter(g => Object.prototype.hasOwnProperty.call(g, 'deviceId') && this.devicesInEW.has(g.deviceId)) + .forEach(g => this.cusG.set(g.deviceId + 'SWX', g)) } - //*** Make a map of RF Bridge custom sensors from Homebridge config ***\\ + //* ** Make a map of RF Bridge custom sensors from Homebridge config ***\\ if (Object.keys(this.config.bridgeSensors || []).length > 0) { this.config.bridgeSensors - .filter(s => s.hasOwnProperty("deviceId") && this.devicesInEW.has(s.deviceId)) - .forEach(s => this.cusS.set(s.fullDeviceId, s)); + .filter(s => Object.prototype.hasOwnProperty.call(s, 'deviceId') && this.devicesInEW.has(s.deviceId)) + .forEach(s => this.cusS.set(s.fullDeviceId, s)) } - //*** Logging always helps to see if everything is okay so far ***\\ - this.log("[%s] eWeLink devices loaded from the Homebridge cache.", this.devicesInHB.size); - this.log("[%s] primary devices loaded from your eWeLink account.", this.devicesInEW.size); - //*** Remove Homebridge accessories that don't appear in eWeLink ***\\ + //* ** Logging always helps to see if everything is okay so far ***\\ + this.log('[%s] eWeLink devices loaded from the Homebridge cache.', this.devicesInHB.size) + this.log('[%s] primary devices loaded from your eWeLink account.', this.devicesInEW.size) + //* ** Remove Homebridge accessories that don't appear in eWeLink ***\\ this.devicesInHB.forEach(a => { if (!this.devicesInEW.has(a.context.eweDeviceId)) { - this.removeAccessory(a); + this.removeAccessory(a) } - }); - //*** Synchronise devices between eWeLink and Homebridge and set up ws/lan listeners ***\\ - this.devicesInEW.forEach(d => this.initialiseDevice(d)); - this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); - this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)); + }) + //* ** Synchronise devices between eWeLink and Homebridge and set up ws/lan listeners ***\\ + this.devicesInEW.forEach(d => this.initialiseDevice(d)) + this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)) + this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)) this.wsRefresh = promInterval( async () => { if (this.wsRefreshFlag) { try { if (this.wsClient) { - await this.wsClient.getHost(); - await this.wsClient.closeConnection(); - await utils.sleep(250); - await this.wsClient.login(); + await this.wsClient.getHost() + await this.wsClient.closeConnection() + await utils.sleep(250) + await this.wsClient.login() } } catch (err) { - this.log.warn(err); + this.log.warn(err) } } }, - 1800000, - { - stopOnError: false, + 1800000, { + stopOnError: false } - ); - this.log("eWeLink sync complete. Don't forget to ⭐ī¸ this plugin on GitHub!"); + ) + this.log("eWeLink sync complete. Don't forget to ⭐ī¸ this plugin on GitHub!") if (this.config.debugReqRes || false) { - this.log.warn("Note: 'Request & Response Logging' is not advised for long-term use."); + this.log.warn("Note: 'Request & Response Logging' is not advised for long-term use.") } - })(); + })() } catch (err) { - this.log.error("************** Cannot load homebridge-ewelink **************"); - this.log.error(err); - this.log.error("************************************************************"); - if (this.lanClient) this.lanClient.closeConnection(); - if (this.wsClient) this.wsClient.closeConnection(); - this.wsRefreshFlag = false; + this.log.error('************** Cannot load homebridge-ewelink **************') + this.log.error(err) + this.log.error('************************************************************') + if (this.lanClient) this.lanClient.closeConnection() + if (this.wsClient) this.wsClient.closeConnection() + this.wsRefreshFlag = false } } - initialiseDevice(device) { - let accessory; - //*** CURTAINS ***\\ + initialiseDevice (device) { + let accessory + //* ** CURTAINS ***\\ if (cns.devicesCurtain.includes(device.extra.uiid)) { - accessory = this.devicesInHB.has(device.deviceid + "SWX") - ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "curtain", false, { - cacheCurrentPosition: 0, - }); - //*** @UPGRADE from v2 -> v3 23.09.2020 ***\\ - if (accessory.context.hasOwnProperty("prevPos")) { - accessory.context.cacheCurrentPosition = accessory.context.prevPos; - delete accessory.context.prevPos; - //*** @ENDUPGRADE ***\\ + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', 'curtain', false, { + cacheCurrentPosition: 0 + }) + //* ** @UPGRADE from v2 -> v3 23.09.2020 ***\\ + if (Object.prototype.hasOwnProperty.call(accessory.context, 'prevPos')) { + accessory.context.cacheCurrentPosition = accessory.context.prevPos + delete accessory.context.prevPos + //* ** @ENDUPGRADE ***\\ } - if (!accessory.context.hasOwnProperty("cacheCurrentPosition")) { - accessory.context.cacheCurrentPosition = 0; - //*** @ENDUPGRADE ***\\ + if (!Object.prototype.hasOwnProperty.call(accessory.context, 'cacheCurrentPosition')) { + accessory.context.cacheCurrentPosition = 0 + //* ** @ENDUPGRADE ***\\ } - } - //*** WINDOW BLINDS ***\\ - else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "blind") { - accessory = this.devicesInHB.has(device.deviceid + "SWX") - ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "blind", false, { - cacheCurrentPosition: 0, - cachePositionState: 2, - cacheTargetPosition: 0, - }); - //*** @UPGRADE from v2 -> v3 23.09.2020 ***\\ - if (!accessory.context.hasOwnProperty("cacheCurrentPosition")) { - accessory.context.cacheCurrentPosition = 0; - accessory.context.cachePositionState = 2; - accessory.context.cacheTargetPosition = 0; + } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'blind') { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', 'blind', false, { + cacheCurrentPosition: 0, + cachePositionState: 2, + cacheTargetPosition: 0 + }) + //* ** @UPGRADE from v2 -> v3 23.09.2020 ***\\ + if (!Object.prototype.hasOwnProperty.call(accessory.context, 'cacheCurrentPosition')) { + accessory.context.cacheCurrentPosition = 0 + accessory.context.cachePositionState = 2 + accessory.context.cacheTargetPosition = 0 } - //*** @ENDUPGRADE ***\\ - } - //*** GARAGE DOORS ***\\ - else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "garage") { - accessory = this.devicesInHB.has(device.deviceid + "SWX") - ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "garage", false, { - cacheCurrentDoorState: 1, - cacheTargetDoorState: 1, - }); - //*** @UPGRADE from v2 -> v3 23.09.2020 ***\\ - if (!accessory.context.hasOwnProperty("cacheCurrentDoorState")) { - accessory.context.cacheCurrentDoorState = 1; - accessory.context.cacheTargetDoorState = 1; + //* ** @ENDUPGRADE ***\\ + } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage') { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', 'garage', false, { + cacheCurrentDoorState: 1, + cacheTargetDoorState: 1 + }) + //* ** @UPGRADE from v2 -> v3 23.09.2020 ***\\ + if (!Object.prototype.hasOwnProperty.call(accessory.context, 'cacheCurrentDoorState')) { + accessory.context.cacheCurrentDoorState = 1 + accessory.context.cacheTargetDoorState = 1 } - //*** @ENDUPGRADE ***\\ - } - //*** SINGLE LOCKS ***\\ - else if (this.cusG.has(device.deviceid + "SWX") && this.cusG.get(device.deviceid + "SWX").type === "lock") { - accessory = this.devicesInHB.has(device.deviceid + "SWX") - ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "lock"); - } - //*** SENSORS (DW2) ***\\ - else if (cns.devicesSensor.includes(device.extra.uiid)) { - accessory = this.devicesInHB.has(device.deviceid + "SWX") - ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "sensor"); - } - //*** IRRIGATION VALVES ***\\ - else if (device.extra.uiid === 2 && device.brandName === "coolkit" && device.productModel === "0285") { - accessory = this.devicesInHB.has(device.deviceid + "SWX") - ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "valve"); - } - //*** FANS ***\\ - else if (cns.devicesFan.includes(device.extra.uiid)) { - accessory = this.devicesInHB.has(device.deviceid + "SWX") - ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "fan"); - } - //*** THERMOSTATS ***\\ - else if (cns.devicesThermostat.includes(device.extra.uiid)) { - accessory = this.devicesInHB.has(device.deviceid + "SWX") - ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "thermostat", false, { - sensorType: device.params.sensorType, - }); - //*** @UPGRADE from v2 -> v3 23.09.2020 ***\\ - if (!accessory.context.hasOwnProperty("sensorType")) { - accessory.context.sensorType = device.params.sensorType; + //* ** @ENDUPGRADE ***\\ + } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'lock') { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', 'lock') + } else if (cns.devicesSensor.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', 'sensor') + } else if (device.extra.uiid === 2 && device.brandName === 'coolkit' && device.productModel === '0285') { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', 'valve') + } else if (cns.devicesFan.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', 'fan') + } else if (cns.devicesThermostat.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', 'thermostat', false, { + sensorType: device.params.sensorType + }) + //* ** @UPGRADE from v2 -> v3 23.09.2020 ***\\ + if (!Object.prototype.hasOwnProperty.call(accessory.context, 'sensorType')) { + accessory.context.sensorType = device.params.sensorType } - //*** @ENDUPGRADE ***\\ + //* ** @ENDUPGRADE ***\\ if (accessory.context.sensorType !== device.params.sensorType) { - accessory.context.sensorType = device.params.sensorType; - this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + accessory.context.sensorType = device.params.sensorType + this.devicesInHB.set(accessory.context.hbDeviceId, accessory) } - } - //*** OUTLETS ***\\ - else if ( + } else if ( cns.devicesOutlet.includes(device.extra.uiid) || (cns.devicesSingleSwitch.includes(device.extra.uiid) && cns.devicesSingleSwitchOutlet.includes(device.productModel)) ) { - accessory = this.devicesInHB.has(device.deviceid + "SWX") - ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "outlet"); - } - //*** USB OUTLETS ***\\ - else if (cns.devicesUSB.includes(device.extra.uiid)) { - accessory = this.devicesInHB.has(device.deviceid + "SWX") - ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "usb"); - } - //*** SINGLE CHANNEL [MULTI CHANNEL HARDWARE] ***\\ - else if (cns.devicesSCM.includes(device.extra.uiid)) { - accessory = this.devicesInHB.has(device.deviceid + "SWX") - ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "scm"); - } - //*** SINGLE CHANNEL LIGHTS ***\\ - else if ( + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', 'outlet') + } else if (cns.devicesUSB.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', 'usb') + } else if (cns.devicesSCM.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', 'scm') + } else if ( cns.devicesSingleSwitch.includes(device.extra.uiid) && cns.devicesSingleSwitchLight.includes(device.productModel) ) { - accessory = this.devicesInHB.has(device.deviceid + "SWX") - ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "light"); - } - //*** MULTI CHANNEL LIGHTS ***\\ - else if ( + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', 'light') + } else if ( cns.devicesMultiSwitch.includes(device.extra.uiid) && cns.devicesMultiSwitchLight.includes(device.productModel) ) { if (this.config.hideMasters) { - if (this.devicesInHB.has(device.deviceid + "SW0")) { - this.removeAccessory(this.devicesInHB.get(device.deviceid + "SW0")); + if (this.devicesInHB.has(device.deviceid + 'SW0')) { + this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) } - this.hiddenMasters.push(device.deviceid); - accessory = this.addAccessory(device, device.deviceid + "SW0", "light", true); + this.hiddenMasters.push(device.deviceid) + accessory = this.addAccessory(device, device.deviceid + 'SW0', 'light', true) } else { - accessory = this.devicesInHB.has(device.deviceid + "SW0") - ? this.devicesInHB.get(device.deviceid + "SW0") - : this.addAccessory(device, device.deviceid + "SW0", "light"); + accessory = this.devicesInHB.has(device.deviceid + 'SW0') + ? this.devicesInHB.get(device.deviceid + 'SW0') + : this.addAccessory(device, device.deviceid + 'SW0', 'light') } for (let i = 1; i <= cns.chansFromUiid[device.extra.uiid]; i++) { - if ((this.config.hideFromHB || "").includes(device.deviceid + "SW" + i)) { - if (this.devicesInHB.has(device.deviceid + "SW" + i)) { - this.removeAccessory(this.devicesInHB.get(device.deviceid + "SW" + i)); + if ((this.config.hideFromHB || '').includes(device.deviceid + 'SW' + i)) { + if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { + this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + i)) } } else { - let oAccessory = this.devicesInHB.has(device.deviceid + "SW" + i) - ? this.devicesInHB.get(device.deviceid + "SW" + i) - : this.addAccessory(device, device.deviceid + "SW" + i, "light"); + const oAccessory = this.devicesInHB.has(device.deviceid + 'SW' + i) + ? this.devicesInHB.get(device.deviceid + 'SW' + i) + : this.addAccessory(device, device.deviceid + 'SW' + i, 'light') oAccessory .getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); - oAccessory.context.reachableWAN = device.online; - oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; - this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) + oAccessory.context.reachableWAN = device.online + oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) } } - } - //*** SINGLE CHANNEL SWITCHES ***\\ - else if (cns.devicesSingleSwitch.includes(device.extra.uiid)) { - accessory = this.devicesInHB.has(device.deviceid + "SWX") - ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "switch"); - } - //*** MULTI CHANNEL SWITCHES ***\\ - else if (cns.devicesMultiSwitch.includes(device.extra.uiid)) { + } else if (cns.devicesSingleSwitch.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', 'switch') + } else if (cns.devicesMultiSwitch.includes(device.extra.uiid)) { if (this.config.hideMasters) { - if (this.devicesInHB.has(device.deviceid + "SW0")) { - this.removeAccessory(this.devicesInHB.get(device.deviceid + "SW0")); + if (this.devicesInHB.has(device.deviceid + 'SW0')) { + this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) } - this.hiddenMasters.push(device.deviceid); - accessory = this.addAccessory(device, device.deviceid + "SW0", "switch", true); + this.hiddenMasters.push(device.deviceid) + accessory = this.addAccessory(device, device.deviceid + 'SW0', 'switch', true) } else { - accessory = this.devicesInHB.has(device.deviceid + "SW0") - ? this.devicesInHB.get(device.deviceid + "SW0") - : this.addAccessory(device, device.deviceid + "SW0", "switch"); + accessory = this.devicesInHB.has(device.deviceid + 'SW0') + ? this.devicesInHB.get(device.deviceid + 'SW0') + : this.addAccessory(device, device.deviceid + 'SW0', 'switch') } for (let i = 1; i <= cns.chansFromUiid[device.extra.uiid]; i++) { - if ((this.config.hideFromHB || "").includes(device.deviceid + "SW" + i)) { - if (this.devicesInHB.has(device.deviceid + "SW" + i)) { - this.removeAccessory(this.devicesInHB.get(device.deviceid + "SW" + i)); + if ((this.config.hideFromHB || '').includes(device.deviceid + 'SW' + i)) { + if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { + this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + i)) } } else { - let oAccessory = this.devicesInHB.has(device.deviceid + "SW" + i) - ? this.devicesInHB.get(device.deviceid + "SW" + i) - : this.addAccessory(device, device.deviceid + "SW" + i, "switch"); + const oAccessory = this.devicesInHB.has(device.deviceid + 'SW' + i) + ? this.devicesInHB.get(device.deviceid + 'SW' + i) + : this.addAccessory(device, device.deviceid + 'SW' + i, 'switch') oAccessory .getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); - oAccessory.context.reachableWAN = device.online; - oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false; - this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) + oAccessory.context.reachableWAN = device.online + oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) } } - } - //*** RF BRIDGES ***\\ - else if (cns.devicesRFBridge.includes(device.extra.uiid)) { - let accessory, - rfChlCounter = 0, - rfMap = []; - if (device.hasOwnProperty("tags") && device.tags.hasOwnProperty("zyx_info")) { + } else if (cns.devicesRFBridge.includes(device.extra.uiid)) { + let rfChlCounter = 0 + const rfMap = [] + if (Object.prototype.hasOwnProperty.call(device, 'tags') && Object.prototype.hasOwnProperty.call(device.tags, 'zyx_info')) { device.tags.zyx_info.forEach(remote => rfMap.push({ name: remote.name, type: remote.remote_type, - buttons: Object.assign({}, ...remote.buttonName), + buttons: Object.assign({}, ...remote.buttonName) }) - ); + ) } - accessory = this.devicesInHB.has(device.deviceid + "SW0") - ? this.devicesInHB.get(device.deviceid + "SW0") - : this.addAccessory(device, device.deviceid + "SW0", "rf_pri", true, { - rfMap, - }); - this.log.error(JSON.stringify(accessory.context, null, 2)); + const accessory = this.devicesInHB.has(device.deviceid + 'SW0') + ? this.devicesInHB.get(device.deviceid + 'SW0') + : this.addAccessory(device, device.deviceid + 'SW0', 'rf_pri', true, { + rfMap + }) + this.log.error(JSON.stringify(accessory.context, null, 2)) rfMap.forEach(subDevice => { - let swNumber = rfChlCounter + 1, - subAccessory, - subType, - subExtraContext = {}; + const swNumber = rfChlCounter + 1 + let subAccessory + let subType + let subExtraContext = {} switch (subDevice.type) { - case "1": - case "2": - case "3": - case "4": - subType = "button"; - break; - case "6": - subType = this.cusS.has(device.deviceid + "SW" + swNumber) - ? this.cusS.get(device.deviceid + "SW" + swNumber).type - : "motion"; - break; + case '1': + case '2': + case '3': + case '4': + subType = 'button' + break + case '6': + subType = this.cusS.has(device.deviceid + 'SW' + swNumber) + ? this.cusS.get(device.deviceid + 'SW' + swNumber).type + : 'motion' + break default: - return; + return } subExtraContext = { buttons: subDevice.buttons, subType, - swNumber, - }; - if ((subAccessory = this.devicesInHB.get(device.deviceid + "SW" + swNumber))) { + swNumber + } + if ((subAccessory = this.devicesInHB.get(device.deviceid + 'SW' + swNumber))) { if (subAccessory.context.subType !== subType || subAccessory.context.swNumber !== swNumber) { - this.removeAccessory(subAccessory); + this.removeAccessory(subAccessory) } } - subAccessory = this.devicesInHB.has(device.deviceid + "SW" + swNumber) - ? this.devicesInHB.get(device.deviceid + "SW" + swNumber) - : this.addAccessory(device, device.deviceid + "SW" + swNumber, "rf_sub", false, subExtraContext); + subAccessory = this.devicesInHB.has(device.deviceid + 'SW' + swNumber) + ? this.devicesInHB.get(device.deviceid + 'SW' + swNumber) + : this.addAccessory(device, device.deviceid + 'SW' + swNumber, 'rf_sub', false, subExtraContext) subAccessory .getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); - subAccessory.context.reachableWAN = device.online; - subAccessory.context.reachableLAN = false; - this.devicesInHB.set(subAccessory.context.hbDeviceId, subAccessory); - this.log.warn(JSON.stringify(subAccessory.context, null, 2)); - rfChlCounter += Object.keys(subDevice.buttons || {}).length; - }); - accessory.context.channelCount = rfChlCounter; - this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - } - //*** ZIGBEE BRIDGES ***\\ - else if (cns.devicesZBBridge.includes(device.extra.uiid)) { + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) + subAccessory.context.reachableWAN = device.online + subAccessory.context.reachableLAN = false + this.devicesInHB.set(subAccessory.context.hbDeviceId, subAccessory) + this.log.warn(JSON.stringify(subAccessory.context, null, 2)) + rfChlCounter += Object.keys(subDevice.buttons || {}).length + }) + accessory.context.channelCount = rfChlCounter + this.devicesInHB.set(accessory.context.hbDeviceId, accessory) + } else if (cns.devicesZBBridge.includes(device.extra.uiid)) { // Nothing to do here but needed to avoid the below not supported error - //*** @UPGRADE from v2 -> v3 23.09.2020 ***\\ - if ((accessory = this.devicesInHB.get(device.deviceid + "SWX"))) { - this.removeAccessory(accessory); + //* ** @UPGRADE from v2 -> v3 23.09.2020 ***\\ + if ((accessory = this.devicesInHB.get(device.deviceid + 'SWX'))) { + this.removeAccessory(accessory) } - //*** @ENDUPGRADE ***\\ - } - //*** ZIGBEE DEVICES ***\\ - else if (cns.devicesZB.includes(device.extra.uiid)) { - accessory = this.devicesInHB.has(device.deviceid + "SWX") - ? this.devicesInHB.get(device.deviceid + "SWX") - : this.addAccessory(device, device.deviceid + "SWX", "zb_dev"); - //*** @UPGRADE from v2 -> v3 23.09.2020 ***\\ - if (accessory.context.type === "zb_sub") { - accessory.context.type = "zb_dev"; + //* ** @ENDUPGRADE ***\\ + } else if (cns.devicesZB.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', 'zb_dev') + //* ** @UPGRADE from v2 -> v3 23.09.2020 ***\\ + if (accessory.context.type === 'zb_sub') { + accessory.context.type = 'zb_dev' } - //*** @ENDUPGRADE ***\\ - } - //*** SONOFF CAMERAS ***\\ - else if (cns.devicesCamera.includes(device.extra.uiid)) { + //* ** @ENDUPGRADE ***\\ + } else if (cns.devicesCamera.includes(device.extra.uiid)) { this.log.warn( ' → [%s] please see "https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-Sonoff-Camera".', device.name - ); - return; - } - //*** ALL OTHER = UNSUPPORTED ***\\ - else { + ) + return + } else { this.log.warn( - " → [%s] cannot be added as it is not supported by this plugin. Please make a GitHub issue request.", + ' → [%s] cannot be added as it is not supported by this plugin. Please make a GitHub issue request.', device.name - ); - return; + ) + return } - if (!accessory) return; + if (!accessory) return if (!this.hiddenMasters.includes(device.deviceid)) { accessory .getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion); + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) } - accessory.context.reachableWAN = device.online; + accessory.context.reachableWAN = device.online accessory.context.reachableLAN = this.lanDevices.has(device.deviceid) ? this.lanDevices.get(device.deviceid).online - : false; - accessory.context.inUse = false; + : false + accessory.context.inUse = false let str = accessory.context.reachableLAN - ? "and found locally with IP [" + this.lanDevices.get(device.deviceid).ip + "]" - : "but LAN mode unavailable as device "; + ? 'and found locally with IP [' + this.lanDevices.get(device.deviceid).ip + ']' + : 'but LAN mode unavailable as device ' if (!accessory.context.reachableLAN) { if (cns.devicesNonLAN.includes(device.extra.uiid)) { - str += "doesn't support it"; - } else if (device.hasOwnProperty("sharedBy") && device.sharedBy.hasOwnProperty("email")) { - str += "is shared (" + device.sharedBy.email + ")"; + str += "doesn't support it" + } else if (Object.prototype.hasOwnProperty.call(device, 'sharedBy') && Object.prototype.hasOwnProperty.call(device.sharedBy, 'email')) { + str += 'is shared (' + device.sharedBy.email + ')' } else { - str += "is unreachable"; + str += 'is unreachable' } } - this.log(" → [%s] initialised %s.", device.name, str); - this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + this.log(' → [%s] initialised %s.', device.name, str) + this.devicesInHB.set(accessory.context.hbDeviceId, accessory) if (!(this.config.disableHTTPRefresh || false)) { if (!this.refreshAccessory(accessory, device.params)) { this.log.warn( - "[%s] could not be initialised. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.) [debug:%s:%s].", + '[%s] could not be initialised. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.) [debug:%s:%s].', accessory.displayName, accessory.context.type, accessory.context.channelCount - ); + ) this.log.warn( 'If you are unsure how to do this, please see "https://github.com/bwp91/homebridge-ewelink/wiki/How-to-remove-an-accessory-from-the-cache' - ); + ) } } } - addAccessory(device, hbDeviceId, type, hidden = false, extraContext = {}) { - let switchNumber = hbDeviceId.substr(-1).toString(), - newDeviceName = type === "rf_sub" ? device.tags.zyx_info[switchNumber - 1].name : device.name, - channelCount = - type === "rf_pri" - ? Object.keys((device.tags && device.tags.zyx_info) || []).length - : cns.chansFromUiid[device.extra.uiid]; - if (["1", "2", "3", "4"].includes(switchNumber) && type !== "rf_sub") { - newDeviceName += " SW" + switchNumber; + + addAccessory (device, hbDeviceId, type, hidden = false, extraContext = {}) { + const switchNumber = hbDeviceId.substr(-1).toString() + let newDeviceName = type === 'rf_sub' ? device.tags.zyx_info[switchNumber - 1].name : device.name + const channelCount = + type === 'rf_pri' + ? Object.keys((device.tags && device.tags.zyx_info) || []).length + : cns.chansFromUiid[device.extra.uiid] + if (['1', '2', '3', '4'].includes(switchNumber) && type !== 'rf_sub') { + newDeviceName += ' SW' + switchNumber } - if ((this.config.nameOverride || {}).hasOwnProperty(hbDeviceId)) { - newDeviceName = this.config.nameOverride[hbDeviceId]; + if (Object.prototype.hasOwnProperty.call(this.config.nameOverride || {}, hbDeviceId)) { + newDeviceName = this.config.nameOverride[hbDeviceId] } try { - const accessory = new Accessory(newDeviceName, this.api.hap.uuid.generate(hbDeviceId).toString()); + const accessory = new Accessory(newDeviceName, this.api.hap.uuid.generate(hbDeviceId).toString()) if (!hidden) { accessory .getService(Service.AccessoryInformation) .setCharacteristic(Characteristic.SerialNumber, hbDeviceId) .setCharacteristic(Characteristic.Manufacturer, device.brandName) - .setCharacteristic(Characteristic.Model, device.productModel + " (" + device.extra.model + ")") + .setCharacteristic(Characteristic.Model, device.productModel + ' (' + device.extra.model + ')') .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) - .setCharacteristic(Characteristic.Identify, false); + .setCharacteristic(Characteristic.Identify, false) } accessory.context = { ...{ @@ -497,472 +458,487 @@ class eWeLink { eweApiKey: device.apikey, switchNumber, channelCount, - type, + type }, - ...extraContext, - }; + ...extraContext + } if (!hidden) { - this.api.registerPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); - this.configureAccessory(accessory); - this.log(" → [%s] has been added to Homebridge.", newDeviceName); + this.api.registerPlatformAccessories('homebridge-ewelink', 'eWeLink', [accessory]) + this.configureAccessory(accessory) + this.log(' → [%s] has been added to Homebridge.', newDeviceName) } - return accessory; + return accessory } catch (err) { - this.log.warn(" → [%s] could not be added as %s.", newDeviceName, err); - return false; + this.log.warn(' → [%s] could not be added as %s.', newDeviceName, err) + return false } } - configureAccessory(accessory) { - if (!this.log) return; + + configureAccessory (accessory) { + if (!this.log) return try { - accessory.context.reachableWAN = true; - accessory.context.reachableLAN = true; + accessory.context.reachableWAN = true + accessory.context.reachableLAN = true switch (accessory.context.type) { - case "curtain": - accessory.control = new deviceCurtain(this); - let cService; + case 'curtain': { + accessory.control = new DeviceCurtain(this) + let cService if (!(cService = accessory.getService(Service.WindowCovering))) { accessory .addService(Service.WindowCovering) .setCharacteristic(Characteristic.CurrentPosition, 0) .setCharacteristic(Characteristic.TargetPosition, 0) - .setCharacteristic(Characteristic.PositionState, 2); - cService = accessory.getService(Service.WindowCovering); + .setCharacteristic(Characteristic.PositionState, 2) + cService = accessory.getService(Service.WindowCovering) } cService .getCharacteristic(Characteristic.TargetPosition) - .on("set", (value, callback) => accessory.control.internalCurtainUpdate(accessory, value, callback)); - break; - case "blind": - accessory.control = new deviceBlind(this); - let wcService; + .on('set', (value, callback) => accessory.control.internalCurtainUpdate(accessory, value, callback)) + break + } + case 'blind': { + accessory.control = new DeviceBlind(this) + let wcService if (!(wcService = accessory.getService(Service.WindowCovering))) { accessory .addService(Service.WindowCovering) .setCharacteristic(Characteristic.CurrentPosition, 0) .setCharacteristic(Characteristic.TargetPosition, 0) - .setCharacteristic(Characteristic.PositionState, 2); - wcService = accessory.getService(Service.WindowCovering); + .setCharacteristic(Characteristic.PositionState, 2) + wcService = accessory.getService(Service.WindowCovering) } wcService .getCharacteristic(Characteristic.TargetPosition) - .on("set", (value, callback) => accessory.control.internalBlindUpdate(accessory, value, callback)); - break; - case "garage": - accessory.control = new deviceGarage(this); - let gdService; + .on('set', (value, callback) => accessory.control.internalBlindUpdate(accessory, value, callback)) + break + } + case 'garage': { + accessory.control = new DeviceGarage(this) + let gdService if (!(gdService = accessory.getService(Service.GarageDoorOpener))) { accessory .addService(Service.GarageDoorOpener) .setCharacteristic(Characteristic.CurrentDoorState, 1) .setCharacteristic(Characteristic.TargetDoorState, 1) - .setCharacteristic(Characteristic.ObstructionDetected, false); - gdService = accessory.getService(Service.GarageDoorOpener); + .setCharacteristic(Characteristic.ObstructionDetected, false) + gdService = accessory.getService(Service.GarageDoorOpener) } gdService .getCharacteristic(Characteristic.TargetDoorState) - .on("set", (value, callback) => accessory.control.internalGarageUpdate(accessory, value, callback)); - break; - case "lock": - accessory.control = new deviceLock(this); - let lmService = accessory.getService(Service.LockMechanism) || accessory.addService(Service.LockMechanism); + .on('set', (value, callback) => accessory.control.internalGarageUpdate(accessory, value, callback)) + break + } + case 'lock': { + accessory.control = new DeviceLock(this) + const lmService = accessory.getService(Service.LockMechanism) || accessory.addService(Service.LockMechanism) lmService .getCharacteristic(Characteristic.LockTargetState) - .on("set", (value, callback) => accessory.control.internalLockUpdate(accessory, value, callback)); - break; - case "valve": - accessory.control = new deviceValve(this); - ["A", "B"].forEach(v => { - let valveService; - if (!(valveService = accessory.getService("Valve " + v))) { + .on('set', (value, callback) => accessory.control.internalLockUpdate(accessory, value, callback)) + break + } + case 'valve': { + accessory.control = new DeviceValve(this); + ['A', 'B'].forEach(v => { + let valveService + if (!(valveService = accessory.getService('Valve ' + v))) { accessory - .addService(Service.Valve, "Valve " + v, "valve" + v.toLowerCase()) + .addService(Service.Valve, 'Valve ' + v, 'valve' + v.toLowerCase()) .setCharacteristic(Characteristic.Active, 0) .setCharacteristic(Characteristic.InUse, 0) .setCharacteristic(Characteristic.ValveType, 1) .setCharacteristic(Characteristic.SetDuration, this.config.valveTimeLength || 120) - .addCharacteristic(Characteristic.RemainingDuration); - valveService = accessory.getService("Valve " + v); + .addCharacteristic(Characteristic.RemainingDuration) + valveService = accessory.getService('Valve ' + v) } valveService .getCharacteristic(Characteristic.Active) - .on("set", (value, callback) => - accessory.control.internalValveUpdate(accessory, "Valve " + v, value, callback) - ); - valveService.getCharacteristic(Characteristic.SetDuration).on("set", (value, callback) => { + .on('set', (value, callback) => + accessory.control.internalValveUpdate(accessory, 'Valve ' + v, value, callback) + ) + valveService.getCharacteristic(Characteristic.SetDuration).on('set', (value, callback) => { if (valveService.getCharacteristic(Characteristic.InUse).value) { - valveService.updateCharacteristic(Characteristic.RemainingDuration, value); - clearTimeout(valveService.timer); + valveService.updateCharacteristic(Characteristic.RemainingDuration, value) + clearTimeout(valveService.timer) valveService.timer = setTimeout(() => { - valveService.setCharacteristic(Characteristic.Active, 0); - }, value * 1000); + valveService.setCharacteristic(Characteristic.Active, 0) + }, value * 1000) } - callback(); - }); - }); - break; - case "sensor": - accessory.control = new deviceSensor(this); - accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor); - accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); - break; - case "fan": - accessory.control = new deviceFan(this); - let fanService = accessory.getService(Service.Fanv2) || accessory.addService(Service.Fanv2), - fanLightService = accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb); + callback() + }) + }) + break + } + case 'sensor': { + accessory.control = new DeviceSensor(this) + accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor) + accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService) + break + } + case 'fan': { + accessory.control = new DeviceFan(this) + const fanService = accessory.getService(Service.Fanv2) || accessory.addService(Service.Fanv2) + const fanLightService = accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb) fanService .getCharacteristic(Characteristic.Active) - .on("set", (value, callback) => accessory.control.internalFanUpdate(accessory, "power", value, callback)); + .on('set', (value, callback) => accessory.control.internalFanUpdate(accessory, 'power', value, callback)) fanService .getCharacteristic(Characteristic.RotationSpeed) - .on("set", (value, callback) => accessory.control.internalFanUpdate(accessory, "speed", value, callback)) + .on('set', (value, callback) => accessory.control.internalFanUpdate(accessory, 'speed', value, callback)) .setProps({ - minStep: 33, - }); + minStep: 33 + }) fanLightService .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => accessory.control.internalFanUpdate(accessory, "light", value, callback)); - break; - case "thermostat": - accessory.control = new deviceThermostat(this); - let tempService = - accessory.getService(Service.TemperatureSensor) || accessory.addService(Service.TemperatureSensor), - humiService = false; - if (accessory.context.sensorType !== "DS18B20") { - humiService = accessory.getService(Service.HumiditySensor) || accessory.addService(Service.HumiditySensor); + .on('set', (value, callback) => accessory.control.internalFanUpdate(accessory, 'light', value, callback)) + break + } + case 'thermostat': { + accessory.control = new DeviceThermostat(this) + const tempService = + accessory.getService(Service.TemperatureSensor) || accessory.addService(Service.TemperatureSensor) + let humiService = false + if (accessory.context.sensorType !== 'DS18B20') { + humiService = accessory.getService(Service.HumiditySensor) || accessory.addService(Service.HumiditySensor) } else { if (accessory.getService(Service.HumiditySensor)) { - accessory.removeService(Service.HumiditySensor); + accessory.removeService(Service.HumiditySensor) } } if (!this.config.hideTHSwitch) { - let switchService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch); + const switchService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch) switchService .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => accessory.control.internalThermostatUpdate(accessory, value, callback)); + .on('set', (value, callback) => accessory.control.internalThermostatUpdate(accessory, value, callback)) } if (!(this.config.disableEveLogging || false)) { - accessory.log = this.log; - accessory.eveLogger = new EveHistoryService("weather", accessory, { - storage: "fs", + accessory.log = this.log + accessory.eveLogger = new EveHistoryService('weather', accessory, { + storage: 'fs', minutes: 5, - path: this.eveLogPath, - }); + path: this.eveLogPath + }) corrInterval.setCorrectingInterval(() => { - let dataToAdd = { + const dataToAdd = { time: Date.now(), - temp: tempService.getCharacteristic(Characteristic.CurrentTemperature).value, - }; + temp: tempService.getCharacteristic(Characteristic.CurrentTemperature).value + } if (humiService) { - humiService.getCharacteristic(Characteristic.CurrentRelativeHumidity).value; + dataToAdd.humidity = humiService.getCharacteristic(Characteristic.CurrentRelativeHumidity).value } - accessory.eveLogger.addEntry(dataToAdd); - }, 300000); + accessory.eveLogger.addEntry(dataToAdd) + }, 300000) } - break; - case "outlet": - accessory.control = new deviceOutlet(this); - let outletService; + break + } + case 'outlet': { + accessory.control = new DeviceOutlet(this) + let outletService if (!(outletService = accessory.getService(Service.Outlet))) { - accessory.addService(Service.Outlet); - outletService = accessory.getService(Service.Outlet); - if (accessory.context.eweModel !== "S26" && !(this.config.disableEveLogging || false)) { - outletService.addCharacteristic(EveService.Characteristics.Voltage); - outletService.addCharacteristic(EveService.Characteristics.CurrentConsumption); - outletService.addCharacteristic(EveService.Characteristics.ElectricCurrent); - outletService.addCharacteristic(EveService.Characteristics.TotalConsumption); - outletService.addCharacteristic(EveService.Characteristics.ResetTotal); + accessory.addService(Service.Outlet) + outletService = accessory.getService(Service.Outlet) + if (accessory.context.eweModel !== 'S26' && !(this.config.disableEveLogging || false)) { + outletService.addCharacteristic(EveService.Characteristics.Voltage) + outletService.addCharacteristic(EveService.Characteristics.CurrentConsumption) + outletService.addCharacteristic(EveService.Characteristics.ElectricCurrent) + outletService.addCharacteristic(EveService.Characteristics.TotalConsumption) + outletService.addCharacteristic(EveService.Characteristics.ResetTotal) accessory.context = { ...accessory.context, ...{ extraPersistedData: {}, lastReset: 0, totalEnergy: 0, - totalEnergyTemp: 0, - }, - }; + totalEnergyTemp: 0 + } + } } } outletService .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => accessory.control.internalOutletUpdate(accessory, value, callback)); - if (accessory.context.eweModel !== "S26" && !(this.config.disableEveLogging || false)) { - accessory.log = this.log; - accessory.eveLogger = new EveHistoryService("energy", accessory, { - storage: "fs", + .on('set', (value, callback) => accessory.control.internalOutletUpdate(accessory, value, callback)) + if (accessory.context.eweModel !== 'S26' && !(this.config.disableEveLogging || false)) { + accessory.log = this.log + accessory.eveLogger = new EveHistoryService('energy', accessory, { + storage: 'fs', minutes: 5, - path: this.eveLogPath, - }); + path: this.eveLogPath + }) corrInterval.setCorrectingInterval(() => { - let isOn = outletService.getCharacteristic(Characteristic.On).value, - currentWatt = isOn - ? outletService.getCharacteristic(EveService.Characteristics.CurrentConsumption).value - : 0; + const isOn = outletService.getCharacteristic(Characteristic.On).value + const currentWatt = isOn + ? outletService.getCharacteristic(EveService.Characteristics.CurrentConsumption).value + : 0 if (accessory.eveLogger.isHistoryLoaded()) { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() if (accessory.context.extraPersistedData !== undefined) { accessory.context.totalEnergy = accessory.context.extraPersistedData.totalenergy + accessory.context.totalEnergyTemp + - (currentWatt * 10) / 3600 / 1000; + (currentWatt * 10) / 3600 / 1000 accessory.eveLogger.setExtraPersistedData({ totalenergy: accessory.context.totalEnergy, - lastReset: accessory.context.extraPersistedData.lastReset, - }); + lastReset: accessory.context.extraPersistedData.lastReset + }) } else { - accessory.context.totalEnergy = accessory.context.totalEnergyTemp + (currentWatt * 10) / 3600 / 1000; + accessory.context.totalEnergy = accessory.context.totalEnergyTemp + (currentWatt * 10) / 3600 / 1000 accessory.eveLogger.setExtraPersistedData({ totalenergy: accessory.context.totalEnergy, - lastReset: 0, - }); + lastReset: 0 + }) } - accessory.context.totalEnergytemp = 0; + accessory.context.totalEnergytemp = 0 } else { - accessory.context.totalEnergyTemp += (currentWatt * 10) / 3600 / 1000; - accessory.context.totalEnergy = accessory.context.totalEnergyTemp; + accessory.context.totalEnergyTemp += (currentWatt * 10) / 3600 / 1000 + accessory.context.totalEnergy = accessory.context.totalEnergyTemp } accessory.eveLogger.addEntry({ time: Date.now(), - power: currentWatt, - }); - }, 300000); - outletService.getCharacteristic(EveService.Characteristics.TotalConsumption).on("get", callback => { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); + power: currentWatt + }) + }, 300000) + outletService.getCharacteristic(EveService.Characteristics.TotalConsumption).on('get', callback => { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower; + accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower } - callback(null, accessory.context.totalEnergy); - }); + callback(null, accessory.context.totalEnergy) + }) outletService .getCharacteristic(EveService.Characteristics.ResetTotal) - .on("set", (value, callback) => { - accessory.context.totalEnergy = 0; - accessory.context.lastReset = value; + .on('set', (value, callback) => { + accessory.context.totalEnergy = 0 + accessory.context.lastReset = value accessory.eveLogger.setExtraPersistedData({ totalPower: 0, - lastReset: value, - }); - callback(); + lastReset: value + }) + callback() }) - .on("get", callback => { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData(); + .on('get', callback => { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() if (accessory.context.extraPersistedData !== undefined) { - accessory.context.lastReset = accessory.context.extraPersistedData.lastReset; + accessory.context.lastReset = accessory.context.extraPersistedData.lastReset } - callback(null, accessory.context.lastReset); - }); + callback(null, accessory.context.lastReset) + }) } - break; - case "usb": - accessory.control = new deviceUSB(this); - let usbService = accessory.getService(Service.Outlet) || accessory.addService(Service.Outlet); + break + } + case 'usb': { + accessory.control = new DeviceUSB(this) + const usbService = accessory.getService(Service.Outlet) || accessory.addService(Service.Outlet) usbService .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => accessory.control.internalUSBUpdate(accessory, value, callback)); - break; - case "scm": - accessory.control = new deviceSCM(this); - let scmService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch); + .on('set', (value, callback) => accessory.control.internalUSBUpdate(accessory, value, callback)) + break + } + case 'scm': { + accessory.control = new DeviceSCM(this) + const scmService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch) scmService .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => accessory.control.internalSCMUpdate(accessory, value, callback)); - break; - case "light": - accessory.control = new deviceLight(this); - let lightService = accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb); + .on('set', (value, callback) => accessory.control.internalSCMUpdate(accessory, value, callback)) + break + } + case 'light': { + accessory.control = new DeviceLight(this) + const lightService = accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb) lightService .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => accessory.control.internalLightbulbUpdate(accessory, value, callback)); + .on('set', (value, callback) => accessory.control.internalLightbulbUpdate(accessory, value, callback)) if (cns.devicesBrightable.includes(accessory.context.eweUIID)) { - lightService.getCharacteristic(Characteristic.Brightness).on("set", (value, callback) => { + lightService.getCharacteristic(Characteristic.Brightness).on('set', (value, callback) => { if (value > 0) { if (!lightService.getCharacteristic(Characteristic.On).value) { - accessory.control.internalLightbulbUpdate(accessory, true, function () { - return; - }); + accessory.control.internalLightbulbUpdate(accessory, true, function () {}) } - accessory.control.internalBrightnessUpdate(accessory, value, callback); + accessory.control.internalBrightnessUpdate(accessory, value, callback) } else { - accessory.control.internalLightbulbUpdate(accessory, false, callback); + accessory.control.internalLightbulbUpdate(accessory, false, callback) } - }); + }) } else if (cns.devicesColourable.includes(accessory.context.eweUIID)) { - lightService.getCharacteristic(Characteristic.Brightness).on("set", (value, callback) => { + lightService.getCharacteristic(Characteristic.Brightness).on('set', (value, callback) => { if (value > 0) { if (!lightService.getCharacteristic(Characteristic.On).value) { - accessory.control.internalLightbulbUpdate(accessory, true, function () { - return; - }); + accessory.control.internalLightbulbUpdate(accessory, true, function () {}) } - accessory.control.internalHSBUpdate(accessory, "bri", value, callback); + accessory.control.internalHSBUpdate(accessory, 'bri', value, callback) } else { - accessory.control.internalLightbulbUpdate(accessory, false, callback); + accessory.control.internalLightbulbUpdate(accessory, false, callback) } - }); + }) lightService .getCharacteristic(Characteristic.Hue) - .on("set", (value, callback) => accessory.control.internalHSBUpdate(accessory, "hue", value, callback)); - lightService.getCharacteristic(Characteristic.Saturation).on("set", (value, callback) => callback()); + .on('set', (value, callback) => accessory.control.internalHSBUpdate(accessory, 'hue', value, callback)) + lightService.getCharacteristic(Characteristic.Saturation).on('set', (value, callback) => callback()) } - break; - case "switch": - accessory.control = new deviceSwitch(this); - let switchService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch); + break + } + case 'switch': { + accessory.control = new DeviceSwitch(this) + const switchService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch) switchService .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => accessory.control.internalSwitchUpdate(accessory, value, callback)); - break; - case "rf_sub": - accessory.control = new deviceRFSub(this); + .on('set', (value, callback) => accessory.control.internalSwitchUpdate(accessory, value, callback)) + break + } + case 'rf_sub': { + accessory.control = new DeviceRFSub(this) switch (accessory.context.subType) { - case "water": - accessory.getService(Service.LeakSensor) || accessory.addService(Service.LeakSensor); - break; - case "fire": - case "smoke": - accessory.getService(Service.SmokeSensor) || accessory.addService(Service.SmokeSensor); - break; - case "co": - accessory.getService(Service.CarbonMonoxideSensor) || accessory.addService(Service.CarbonMonoxideSensor); - break; - case "co2": - accessory.getService(Service.CarbonDioxideSensor) || accessory.addService(Service.CarbonDioxideSensor); - break; - case "contact": - accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor); - break; - case "occupancy": - accessory.getService(Service.OccupancySensor) || accessory.addService(Service.OccupancySensor); - break; + case 'water': + accessory.getService(Service.LeakSensor) || accessory.addService(Service.LeakSensor) + break + case 'fire': + case 'smoke': + accessory.getService(Service.SmokeSensor) || accessory.addService(Service.SmokeSensor) + break + case 'co': + accessory.getService(Service.CarbonMonoxideSensor) || accessory.addService(Service.CarbonMonoxideSensor) + break + case 'co2': + accessory.getService(Service.CarbonDioxideSensor) || accessory.addService(Service.CarbonDioxideSensor) + break + case 'contact': + accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor) + break + case 'occupancy': + accessory.getService(Service.OccupancySensor) || accessory.addService(Service.OccupancySensor) + break default: - accessory.getService(Service.MotionSensor) || accessory.addService(Service.MotionSensor); - break; - case "button": + accessory.getService(Service.MotionSensor) || accessory.addService(Service.MotionSensor) + break + case 'button': Object.entries(accessory.context.buttons).forEach(([chan, name]) => { - accessory.getService(name) || accessory.addService(Service.Switch, name, "switch" + chan); - accessory.getService(name).updateCharacteristic(Characteristic.On, false); + accessory.getService(name) || accessory.addService(Service.Switch, name, 'switch' + chan) + accessory.getService(name).updateCharacteristic(Characteristic.On, false) accessory .getService(name) .getCharacteristic(Characteristic.On) - .on("set", (value, callback) => { - value ? accessory.control.internalRFUpdate(accessory, chan, name, callback) : callback(); - }); - }); - break; + .on('set', (value, callback) => { + value ? accessory.control.internalRFUpdate(accessory, chan, name, callback) : callback() + }) + }) + break } - break; - case "zb_dev": //*** credit @tasict ***\\ - accessory.control = new deviceZBDev(this); - accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); + break + } + case 'zb_dev': { //* ** credit @tasict ***\\ + accessory.control = new DeviceZBDev(this) + accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService) switch (accessory.context.eweUIID) { - case 1000: - let zbspsService = + case 1000: { + const zbspsService = accessory.getService(Service.StatelessProgrammableSwitch) || - accessory.addService(Service.StatelessProgrammableSwitch); + accessory.addService(Service.StatelessProgrammableSwitch) if (this.config.hideZBLDPress) { zbspsService.getCharacteristic(Characteristic.ProgrammableSwitchEvent).setProps({ - validValues: [0], - }); + validValues: [0] + }) } - break; - case 1770: - let zbTempService = - accessory.getService(Service.TemperatureSensor) || accessory.addService(Service.TemperatureSensor); - let zbHumiService = - accessory.getService(Service.HumiditySensor) || accessory.addService(Service.HumiditySensor); - accessory.log = this.log; - accessory.eveLogger = new EveHistoryService("weather", accessory, { - storage: "fs", + break + } + case 1770: { + const zbTempService = + accessory.getService(Service.TemperatureSensor) || accessory.addService(Service.TemperatureSensor) + const zbHumiService = + accessory.getService(Service.HumiditySensor) || accessory.addService(Service.HumiditySensor) + accessory.log = this.log + accessory.eveLogger = new EveHistoryService('weather', accessory, { + storage: 'fs', minutes: 5, - path: this.eveLogPath, - }); + path: this.eveLogPath + }) corrInterval.setCorrectingInterval(() => { - let dataToAdd = { + const dataToAdd = { time: Date.now(), temp: zbTempService.getCharacteristic(Characteristic.CurrentTemperature).value, - humidity: zbHumiService.getCharacteristic(Characteristic.CurrentRelativeHumidity).value, - }; - accessory.eveLogger.addEntry(dataToAdd); - }, 300000); - break; + humidity: zbHumiService.getCharacteristic(Characteristic.CurrentRelativeHumidity).value + } + accessory.eveLogger.addEntry(dataToAdd) + }, 300000) + break + } case 2026: - accessory.getService(Service.MotionSensor) || accessory.addService(Service.MotionSensor); - break; + accessory.getService(Service.MotionSensor) || accessory.addService(Service.MotionSensor) + break case 3026: - accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor); - break; + accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor) + break } - break; + break + } } - this.devicesInHB.set(accessory.context.hbDeviceId, accessory); + this.devicesInHB.set(accessory.context.hbDeviceId, accessory) } catch (err) { - this.log.warn("[%s] could not be refreshed as %s.", accessory.displayName, err); + this.log.warn('[%s] could not be refreshed as %s.', accessory.displayName, err) } } - refreshAccessory(accessory, newParams) { + + refreshAccessory (accessory, newParams) { switch (accessory.context.type) { - case "valve": + case 'valve': if (Object.keys(newParams).some(v => cns.devicesValveParams.includes(v)) && Array.isArray(newParams.switches)) { - accessory.control.externalValveUpdate(accessory, newParams); + accessory.control.externalValveUpdate(accessory, newParams) } - return true; - case "curtain": + return true + case 'curtain': if (Object.keys(newParams).some(v => cns.devicesCurtainParams.includes(v))) { - accessory.control.externalCurtainUpdate(accessory, newParams); + accessory.control.externalCurtainUpdate(accessory, newParams) } - return true; - case "blind": - return true; - case "garage": + return true + case 'blind': + return true + case 'garage': if ( Object.keys(newParams).some(v => cns.devicesGarageParams.includes(v)) && Array.isArray(newParams.switches) ) { - accessory.control.externalGarageUpdate(accessory, newParams); + accessory.control.externalGarageUpdate(accessory, newParams) } - return true; - case "lock": + return true + case 'lock': if (Object.keys(newParams).some(v => cns.devicesLockParams.includes(v))) { - accessory.control.externalLockUpdate(accessory, newParams); + accessory.control.externalLockUpdate(accessory, newParams) } - return true; - case "sensor": + return true + case 'sensor': if (Object.keys(newParams).some(v => cns.devicesSensorParams.includes(v))) { - accessory.control.externalSensorUpdate(accessory, newParams); + accessory.control.externalSensorUpdate(accessory, newParams) } - return true; - case "fan": + return true + case 'fan': if (Object.keys(newParams).some(v => cns.devicesFanParams.includes(v))) { - accessory.control.externalFanUpdate(accessory, newParams); + accessory.control.externalFanUpdate(accessory, newParams) } - return true; - case "thermostat": + return true + case 'thermostat': if (Object.keys(newParams).some(v => cns.devicesThermostatParams.includes(v))) { - accessory.control.externalThermostatUpdate(accessory, newParams); + accessory.control.externalThermostatUpdate(accessory, newParams) } - return true; - case "outlet": + return true + case 'outlet': if (Object.keys(newParams).some(v => cns.devicesOutletParams.includes(v))) { - accessory.control.externalOutletUpdate(accessory, newParams); + accessory.control.externalOutletUpdate(accessory, newParams) } - return true; - case "usb": + return true + case 'usb': if (Object.keys(newParams).some(v => cns.devicesUSBParams.includes(v)) && Array.isArray(newParams.switches)) { - accessory.control.externalUSBUpdate(accessory, newParams); + accessory.control.externalUSBUpdate(accessory, newParams) } - return true; - case "scm": + return true + case 'scm': if (Object.keys(newParams).some(v => cns.devicesSCMParams.includes(v)) && Array.isArray(newParams.switches)) { - accessory.control.externalSCMUpdate(accessory, newParams); + accessory.control.externalSCMUpdate(accessory, newParams) } - return true; - case "light": + return true + case 'light': if ( cns.devicesSingleSwitch.includes(accessory.context.eweUIID) && cns.devicesSingleSwitchLight.includes(accessory.context.eweModel) ) { if (Object.keys(newParams).some(v => cns.devicesSingleSwitchLightParams.includes(v))) { - accessory.control.externalSingleLightUpdate(accessory, newParams); + accessory.control.externalSingleLightUpdate(accessory, newParams) } } else if ( cns.devicesMultiSwitch.includes(accessory.context.eweUIID) && @@ -972,168 +948,170 @@ class eWeLink { Object.keys(newParams).some(v => cns.devicesMultiSwitchLightParams.includes(v)) && Array.isArray(newParams.switches) ) { - accessory.control.externalMultiLightUpdate(accessory, newParams); + accessory.control.externalMultiLightUpdate(accessory, newParams) } } - return true; - case "switch": + return true + case 'switch': if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID)) { if (Object.keys(newParams).some(v => cns.devicesSingleSwitchParams.includes(v))) { - accessory.control.externalSingleSwitchUpdate(accessory, newParams); + accessory.control.externalSingleSwitchUpdate(accessory, newParams) } } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID)) { if ( Object.keys(newParams).some(v => cns.devicesMultiSwitchParams.includes(v)) && Array.isArray(newParams.switches) ) { - accessory.control.externalMultiSwitchUpdate(accessory, newParams); + accessory.control.externalMultiSwitchUpdate(accessory, newParams) } } - return true; - case "rf_pri": + return true + case 'rf_pri': if (Object.keys(newParams).some(v => cns.devicesRFBridgeParams.includes(v))) { - accessory.control.externalRFUpdate(accessory, newParams); + accessory.control.externalRFUpdate(accessory, newParams) } - return true; - case "rf_sub": - return true; - case "zb_dev": + return true + case 'rf_sub': + return true + case 'zb_dev': if (Object.keys(newParams).some(v => cns.devicesZBBridgeParams.includes(v))) { - accessory.control.externalZBUpdate(accessory, newParams); + accessory.control.externalZBUpdate(accessory, newParams) } - return true; + return true default: - return false; + return false } } - removeAccessory(accessory) { + + removeAccessory (accessory) { try { - this.api.unregisterPlatformAccessories("homebridge-ewelink", "eWeLink", [accessory]); - this.devicesInHB.delete(accessory.context.hbDeviceId); - this.log(" → [%s] was removed from Homebridge.", accessory.displayName); + this.api.unregisterPlatformAccessories('homebridge-ewelink', 'eWeLink', [accessory]) + this.devicesInHB.delete(accessory.context.hbDeviceId) + this.log(' → [%s] was removed from Homebridge.', accessory.displayName) } catch (err) { - this.log.warn(" → [%s] wasn't removed as %s.", accessory.displayName, err); + this.log.warn(" → [%s] wasn't removed as %s.", accessory.displayName, err) } } - sendDeviceUpdate(accessory, params) { - return new Promise(async (resolve, reject) => { - let payload = { - apikey: accessory.context.eweApiKey, - deviceid: accessory.context.eweDeviceId, - params, - }; - try { - await utils.sleep(Math.random() * 100 + 200); - await this.lanClient.sendUpdate(payload); - resolve(); - } catch (err) { - if (accessory.context.reachableWAN) { - if (this.debug) { - this.log.warn("[%s] Reverting to web socket as %s.", accessory.displayName, err); - } - try { - await this.wsClient.sendUpdate(payload); - resolve(); - } catch (err) { - reject(err); - } - } else { - reject("it is unreachable. I's status will be corrected once it is reachable"); + + async sendDeviceUpdate (accessory, params) { + const payload = { + apikey: accessory.context.eweApiKey, + deviceid: accessory.context.eweDeviceId, + params + } + try { + await utils.sleep(Math.random() * 100 + 200) + await this.lanClient.sendUpdate(payload) + return + } catch (err) { + if (accessory.context.reachableWAN) { + if (this.debug) { + this.log.warn('[%s] Reverting to web socket as %s.', accessory.displayName, err) } + try { + await this.wsClient.sendUpdate(payload) + return + } catch (err) { + throw new Error(err) + } + } else { + throw new Error("it is unreachable. I's status will be corrected once it is reachable") } - }); + } } - async receiveDeviceUpdate(device) { - let accessory, - deviceId = device.deviceid, - reachableChange = false; - if ((accessory = this.devicesInHB.get(deviceId + "SWX") || this.devicesInHB.get(deviceId + "SW0"))) { - let isX = accessory.context.hbDeviceId.substr(-1) === "X"; - if (device.params.updateSource === "WS") { - if (device.params.online != accessory.context.reachableWAN) { - accessory.context.reachableWAN = device.params.online; - this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - if (accessory.context.reachableWAN) this.wsClient.requestUpdate(accessory).catch(() => {}); - reachableChange = true; + + async receiveDeviceUpdate (device) { + let accessory + const deviceId = device.deviceid + let reachableChange = false + if ((accessory = this.devicesInHB.get(deviceId + 'SWX') || this.devicesInHB.get(deviceId + 'SW0'))) { + const isX = accessory.context.hbDeviceId.substr(-1) === 'X' + if (device.params.updateSource === 'WS') { + if (device.params.online !== accessory.context.reachableWAN) { + accessory.context.reachableWAN = device.params.online + this.devicesInHB.set(accessory.context.hbDeviceId, accessory) + if (accessory.context.reachableWAN) this.wsClient.requestUpdate(accessory).catch(() => {}) + reachableChange = true this.log.warn( - "[%s] has been reported [%s] via [WS].", + '[%s] has been reported [%s] via [WS].', accessory.displayName, - accessory.context.reachableWAN ? "online" : "offline" - ); + accessory.context.reachableWAN ? 'online' : 'offline' + ) } } - if (device.params.updateSource === "LAN" && !accessory.context.reachableLAN) { - accessory.context.reachableLAN = true; - this.devicesInHB.set(accessory.context.hbDeviceId, accessory); - this.wsClient.requestUpdate(accessory).catch(() => {}); - reachableChange = true; - this.log.warn("[%s] has been reported [online] via [LAN].", accessory.displayName); + if (device.params.updateSource === 'LAN' && !accessory.context.reachableLAN) { + accessory.context.reachableLAN = true + this.devicesInHB.set(accessory.context.hbDeviceId, accessory) + this.wsClient.requestUpdate(accessory).catch(() => {}) + reachableChange = true + this.log.warn('[%s] has been reported [online] via [LAN].', accessory.displayName) } if (reachableChange && !isX) { for (let i = 1; i <= accessory.context.channelCount; i++) { - if (this.devicesInHB.has(deviceId + "SW" + i)) { - let oAccessory = this.devicesInHB.get(deviceId + "SW" + i); - oAccessory.context.reachableWAN = device.params.online; - if (device.params.updateSource === "LAN") { - oAccessory.context.reachableLAN = true; + if (this.devicesInHB.has(deviceId + 'SW' + i)) { + const oAccessory = this.devicesInHB.get(deviceId + 'SW' + i) + oAccessory.context.reachableWAN = device.params.online + if (device.params.updateSource === 'LAN') { + oAccessory.context.reachableLAN = true } - this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory); + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) } } } if (this.debug) { this.log( - "[%s] externally updated from above %s message and will be refreshed.", + '[%s] externally updated from above %s message and will be refreshed.', accessory.displayName, device.params.updateSource - ); + ) } if (!this.refreshAccessory(accessory, device.params)) { this.log.warn( - "[%s] cannot be refreshed. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.). [debug:%s:%s]", + '[%s] cannot be refreshed. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.). [debug:%s:%s]', accessory.displayName, accessory.context.type, accessory.context.channelCount - ); + ) this.log.warn( 'If you are unsure how to do this, please see "https://github.com/bwp91/homebridge-ewelink/wiki/How-to-remove-an-accessory-from-the-cache' - ); + ) } } else { - if (!(this.config.hideDevFromHB || "").includes(deviceId)) { + if (!(this.config.hideDevFromHB || '').includes(deviceId)) { this.log.warn( - "[%s] update received via %s does not exist in Homebridge so device will be added.", + '[%s] update received via %s does not exist in Homebridge so device will be added.', deviceId, device.params.updateSource - ); + ) try { - let device = await this.httpClient.getDevice(deviceId); - this.initialiseDevice(device); - this.lanClient.addDeviceToMap(device); + const device = await this.httpClient.getDevice(deviceId) + this.initialiseDevice(device) + this.lanClient.addDeviceToMap(device) } catch (err) { - this.log.error("[%s] error getting info [%s]", deviceId, err); - this.log.error("[%s] Please try restarting Homebridge so this device is added.", deviceId); + this.log.error('[%s] error getting info [%s]', deviceId, err) + this.log.error('[%s] Please try restarting Homebridge so this device is added.', deviceId) } } } } - async requestDeviceRefresh(accessory, err) { - this.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + + async requestDeviceRefresh (accessory, err) { + this.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) if (accessory.context.reachableWAN) { try { - await this.wsClient.requestUpdate(accessory); - this.log.warn("[%s] requesting previous state to revert Homebridge state.", accessory.displayName); + await this.wsClient.requestUpdate(accessory) + this.log.warn('[%s] requesting previous state to revert Homebridge state.', accessory.displayName) } catch (err) {} } else { - this.log.warn("[%s] Homebridge state will be synced once the device comes back online.", accessory.displayName); + this.log.warn('[%s] Homebridge state will be synced once the device comes back online.', accessory.displayName) } } } module.exports = function (homebridge) { - Accessory = homebridge.platformAccessory; - Characteristic = homebridge.hap.Characteristic; - EveService = new hbLib.EveHomeKitTypes(homebridge); - EveHistoryService = fakegato(homebridge); - Service = homebridge.hap.Service; - return eWeLink; -}; + Accessory = homebridge.platformAccessory + Characteristic = homebridge.hap.Characteristic + EveService = new hbLib.EveHomeKitTypes(homebridge) + EveHistoryService = fakegato(homebridge) + Service = homebridge.hap.Service + return eWeLink +} diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 03e24b06..61572545 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -1,243 +1,267 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -const axios = require("axios"), - constants = require("./constants"), - crypto = require("crypto"), - utils = require("./utils"); +'use strict' +const axios = require('axios') +const constants = require('./constants') +const crypto = require('crypto') +const utils = require('./utils') module.exports = class eWeLinkHTTP { - constructor(config, log) { - this.log = log; - this.debug = config.debug || false; - this.debugReqRes = config.debugReqRes || false; - this.username = config.username.toString(); - this.password = config.password.toString(); - this.hideDevFromHB = (config.hideDevFromHB || "").toString(); - this.cCode = "+" + config.countryCode.toString().replace("+", "").replace(" ", ""); + constructor (config, log) { + this.log = log + this.debug = config.debug || false + this.debugReqRes = config.debugReqRes || false + this.username = config.username.toString() + this.password = config.password.toString() + this.hideDevFromHB = (config.hideDevFromHB || '').toString() + this.cCode = + '+' + config.countryCode.toString().replace('+', '').replace(' ', '') } - getHost() { - return new Promise(async (resolve, reject) => { - let params = { - appid: constants.appId, - country_code: this.cCode, - nonce: Math.random().toString(36).substr(2, 8), - ts: Math.floor(new Date().getTime() / 1000), - version: 8, - }, - dataToSign = []; - try { - Object.keys(params).forEach(k => { - dataToSign.push({ - key: k, - value: params.k, - }); - }); - dataToSign.sort((a, b) => (a.key < b.key ? -1 : 1)); - dataToSign = dataToSign.map(k => k.key + "=" + k.value).join("&"); - dataToSign = crypto.createHmac("sha256", constants.appSecret).update(dataToSign).digest("base64"); - if (this.debugReqRes) { - this.log.warn( - "Sending HTTP getHost request. This text is yellow for clarity.\n%s", - JSON.stringify(params, null, 2) - ); - } else if (this.debug) { - this.log("Sending HTTP getHost request."); - } - let res = await axios.get("https://api.coolkit.cc:8080/api/user/region", { + + async getHost () { + const params = { + appid: constants.appId, + country_code: this.cCode, + nonce: Math.random().toString(36).substr(2, 8), + ts: Math.floor(new Date().getTime() / 1000), + version: 8 + } + let dataToSign = [] + try { + Object.keys(params).forEach((k) => { + dataToSign.push({ + key: k, + value: params.k + }) + }) + dataToSign.sort((a, b) => (a.key < b.key ? -1 : 1)) + dataToSign = dataToSign.map((k) => k.key + '=' + k.value).join('&') + dataToSign = crypto + .createHmac('sha256', constants.appSecret) + .update(dataToSign) + .digest('base64') + if (this.debugReqRes) { + this.log.warn( + 'Sending HTTP getHost request. This text is yellow for clarity.\n%s', + JSON.stringify(params, null, 2) + ) + } else if (this.debug) { + this.log('Sending HTTP getHost request.') + } + const res = await axios.get( + 'https://api.coolkit.cc:8080/api/user/region', { headers: { - Authorization: "Sign " + dataToSign, - "Content-Type": "application/json", + Authorization: 'Sign ' + dataToSign, + 'Content-Type': 'application/json' }, - params, - }); - let body = res.data; - if (!body.region) { - throw "Server did not respond with a region.\n" + JSON.stringify(body, null, 2); + params } - switch (body.region) { - case "eu": - case "us": - case "as": - this.httpHost = body.region + "-apia.coolkit.cc"; - break; - case "cn": - this.httpHost = "cn-apia.coolkit.cn"; - break; + ) + const body = res.data + if (!body.region) { + throw new Error( + 'Server did not respond with a region.\n' + + JSON.stringify(body, null, 2) + ) + } + switch (body.region) { + case 'eu': + case 'us': + case 'as': + this.httpHost = body.region + '-apia.coolkit.cc' + break + case 'cn': + this.httpHost = 'cn-apia.coolkit.cn' + break + default: + throw new Error('No valid region received - [' + body.region + '].') + } + if (this.debug) { + this.log('HTTP API host received [%s].', this.httpHost) + } + return this.httpHost + } catch (err) { + if ( + Object.prototype.hasOwnProperty.call(err, 'code') && ['ENOTFOUND', 'ETIMEDOUT', 'EAI_AGAIN'].includes(err.code) + ) { + this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') + await utils.sleep(30000) + return this.getHost() + } else { + throw new Error(err.message || err) + } + } + } + + async login () { + const data = { + countryCode: this.cCode, + password: this.password + } + try { + this.username.includes('@') + ? (data.email = this.username) + : (data.phoneNumber = this.username) + if (this.debugReqRes) { + const msg = JSON.stringify(data, null, 2) + .replace(this.password, '**hidden**') + .replace(this.username, '**hidden**') + this.log.warn( + 'Sending HTTP login request. This text is yellow for clarity.\n%s', + msg + ) + } else if (this.debug) { + this.log('Sending HTTP login request.') + } + const dataToSign = crypto + .createHmac('sha256', constants.appSecret) + .update(JSON.stringify(data)) + .digest('base64') + const res = await axios.post( + 'https://' + this.httpHost + '/v2/user/login', + data, { + headers: { + Authorization: 'Sign ' + dataToSign, + 'Content-Type': 'application/json', + Host: this.httpHost, + 'X-CK-Appid': constants.appId, + 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) + } + } + ) + const body = res.data + if ( + Object.prototype.hasOwnProperty.call(body, 'error') && + body.error === 10004 && + Object.prototype.hasOwnProperty.call(body, 'data') && + Object.prototype.hasOwnProperty.call(body.data, 'region') + ) { + const givenRegion = body.data.region + switch (givenRegion) { + case 'eu': + case 'us': + case 'as': + this.httpHost = givenRegion + '-apia.coolkit.cc' + break + case 'cn': + this.httpHost = 'cn-apia.coolkit.cn' + break default: - throw "No valid region received - [" + body.region + "]."; + throw new Error('No valid region received - [' + givenRegion + '].') } if (this.debug) { - this.log("HTTP API host received [%s].", this.httpHost); + this.log('New HTTP API host received [%s].', this.httpHost) + } + return this.login() + } + if (body.data.at) { + this.aToken = body.data.at + this.apiKey = body.data.user.apikey + return { + aToken: this.aToken, + apiKey: this.apiKey, + httpHost: this.httpHost } - resolve(this.httpHost); - } catch (err) { - if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT", "EAI_AGAIN"].includes(err.code)) { - this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); - await utils.sleep(30000); - resolve(this.getHost()); + } else { + if (body.error === 500) { + this.log.warn( + 'An eWeLink error [500] occured. Retrying in 30 seconds.' + ) + await utils.sleep(30000) + return this.login() } else { - reject(err.message || err); + throw new Error('No auth token received.\n' + JSON.stringify(body, null, 2)) } } - }); + } catch (err) { + throw new Error(err.message || err) + } } - login() { - return new Promise(async (resolve, reject) => { - let data = { - countryCode: this.cCode, - password: this.password, - }; - try { - this.username.includes("@") ? (data.email = this.username) : (data.phoneNumber = this.username); - if (this.debugReqRes) { - let msg = JSON.stringify(data, null, 2) - .replace(this.password, "**hidden**") - .replace(this.username, "**hidden**"); - this.log.warn("Sending HTTP login request. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("Sending HTTP login request."); - } - let dataToSign = crypto.createHmac("sha256", constants.appSecret).update(JSON.stringify(data)).digest("base64"); - let res = await axios.post("https://" + this.httpHost + "/v2/user/login", data, { + + async getDevices () { + try { + const res = await axios.get( + 'https://' + this.httpHost + '/v2/device/thing', { headers: { - Authorization: "Sign " + dataToSign, - "Content-Type": "application/json", + Authorization: 'Bearer ' + this.aToken, + 'Content-Type': 'application/json', Host: this.httpHost, - "X-CK-Appid": constants.appId, - "X-CK-Nonce": Math.random().toString(36).substr(2, 8), - }, - }); - let body = res.data; - if ( - body.hasOwnProperty("error") && - body.error === 10004 && - body.hasOwnProperty("data") && - body.data.hasOwnProperty("region") - ) { - let givenRegion = body.data.region; - switch (givenRegion) { - case "eu": - case "us": - case "as": - this.httpHost = givenRegion + "-apia.coolkit.cc"; - break; - case "cn": - this.httpHost = "cn-apia.coolkit.cn"; - break; - default: - throw "No valid region received - [" + givenRegion + "]."; - } - if (this.debug) { - this.log("New HTTP API host received [%s].", this.httpHost); + 'X-CK-Appid': constants.appId, + 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) } - resolve(this.login()); - return; } - if (body.data.at) { - this.aToken = body.data.at; - this.apiKey = body.data.user.apikey; - resolve({ - aToken: this.aToken, - apiKey: this.apiKey, - httpHost: this.httpHost, - }); - } else { - if (body.error === 500) { - this.log.warn("An eWeLink error [500] occured. Retrying in 30 seconds."); - await utils.sleep(30000); - resolve(this.login()); - } else { - throw "No auth token received.\n" + JSON.stringify(body, null, 2); - } - } - } catch (err) { - reject(err.message || err); + ) + const body = res.data + if ( + !Object.prototype.hasOwnProperty.call(body, 'data') || + !Object.prototype.hasOwnProperty.call(body, 'error') || + (Object.prototype.hasOwnProperty.call(body, 'error') && body.error !== 0) + ) { + throw new Error(JSON.stringify(body, null, 2)) + } + const deviceList = [] + if (body.data.thingList && body.data.thingList.length > 0) { + body.data.thingList.forEach((device) => + deviceList.push(device.itemData) + ) + } + deviceList + .filter( + (d) => Object.prototype.hasOwnProperty.call(d, 'extra') && Object.prototype.hasOwnProperty.call(d.extra, 'uiid') + ) + .filter((d) => !this.hideDevFromHB.includes(d.deviceid)) + return deviceList + } catch (err) { + if ( + Object.prototype.hasOwnProperty.call(err, 'code') && ['ENOTFOUND', 'ETIMEDOUT'].includes(err.code) + ) { + this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') + await utils.sleep(30000) + return this.getDevices() + } else { + throw new Error(err.message || err) } - }); + } } - getDevices() { - return new Promise(async (resolve, reject) => { - try { - let res = await axios.get("https://" + this.httpHost + "/v2/device/thing", { + + async getDevice (deviceId) { + try { + const res = await axios.post( + 'https://' + this.httpHost + '/v2/device/thing', { + thingList: [{ + itemType: 1, + id: deviceId + }] + }, { headers: { - Authorization: "Bearer " + this.aToken, - "Content-Type": "application/json", + Authorization: 'Bearer ' + this.aToken, + 'Content-Type': 'application/json', Host: this.httpHost, - "X-CK-Appid": constants.appId, - "X-CK-Nonce": Math.random().toString(36).substr(2, 8), - }, - }); - let body = res.data; - if ( - !body.hasOwnProperty("data") || - !body.hasOwnProperty("error") || - (body.hasOwnProperty("error") && body.error !== 0) - ) { - throw JSON.stringify(body, null, 2); - } - let deviceList = []; - if (body.data.thingList && body.data.thingList.length > 0) { - body.data.thingList.forEach(device => deviceList.push(device.itemData)); - } - deviceList - .filter(d => d.hasOwnProperty("extra") && d.extra.hasOwnProperty("uiid")) - .filter(d => !this.hideDevFromHB.includes(d.deviceid)); - resolve(deviceList); - } catch (err) { - if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { - this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); - await utils.sleep(30000); - resolve(this.getDevices()); - } else { - reject(err.message || err); - } - } - }); - } - getDevice(deviceId) { - return new Promise(async (resolve, reject) => { - try { - let res = await axios.post( - "https://" + this.httpHost + "/v2/device/thing", - { - thingList: [ - { - itemType: 1, - id: deviceId, - }, - ], - }, - { - headers: { - Authorization: "Bearer " + this.aToken, - "Content-Type": "application/json", - Host: this.httpHost, - "X-CK-Appid": constants.appId, - "X-CK-Nonce": Math.random().toString(36).substr(2, 8), - }, + 'X-CK-Appid': constants.appId, + 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) } - ); - let body = res.data; - if ( - !body.hasOwnProperty("data") || - !body.hasOwnProperty("error") || - (body.hasOwnProperty("error") && body.error !== 0) - ) { - throw JSON.stringify(body, null, 2); - } - if (body.data.thingList && body.data.thingList.length === 1) { - resolve(body.data.thingList[0].itemData); - } else { - throw "device not found in eWeLink"; - } - } catch (err) { - if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { - this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); - await utils.sleep(30000); - resolve(this.getDevice(deviceId)); - } else { - reject(err.message || err); } + ) + const body = res.data + if ( + !Object.prototype.hasOwnProperty.call(body, 'data') || + !Object.prototype.hasOwnProperty.call(body, 'error') || + (Object.prototype.hasOwnProperty.call(body, 'error') && body.error !== 0) + ) { + throw new Error(JSON.stringify(body, null, 2)) + } + if (body.data.thingList && body.data.thingList.length === 1) { + return body.data.thingList[0].itemData + } else { + throw new Error('device not found in eWeLink') + } + } catch (err) { + if ( + Object.prototype.hasOwnProperty.call(err, 'code') && ['ENOTFOUND', 'ETIMEDOUT'].includes(err.code) + ) { + this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') + await utils.sleep(30000) + return this.getDevice(deviceId) + } else { + throw new Error(err.message || err) } - }); + } } -}; +} diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 70d0c13c..a14d8cda 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -1,185 +1,186 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -const axios = require("axios"), - cns = require("./constants"), - crypto = require("crypto"), - dns = require("node-dns-sd"), - eventemitter = require("events"); +'use strict' +const axios = require('axios') +const cns = require('./constants') +const crypto = require('crypto') +const dns = require('node-dns-sd') +const EventEmitter = require('events') module.exports = class eWeLinkLAN { - constructor(config, log, devices) { - this.log = log; - this.devices = devices; - this.ipOverrides = config.ipOverride || {}; - this.deviceMap = new Map(); + constructor (config, log, devices) { + this.log = log + this.devices = devices + this.ipOverrides = config.ipOverride || {} + this.deviceMap = new Map() devices.forEach(device => { this.deviceMap.set(device.deviceid, { apiKey: device.devicekey, - online: this.ipOverrides.hasOwnProperty(device.deviceid) ? true : false, - ip: this.ipOverrides.hasOwnProperty(device.deviceid) ? this.ipOverrides[device.deviceid] : null, - }); - }); - this.debug = config.debug || false; - this.debugReqRes = config.debugReqRes || false; - this.emitter = new eventemitter(); + online: !!Object.prototype.hasOwnProperty.call(this.ipOverrides, device.deviceid), + ip: Object.prototype.hasOwnProperty.call(this.ipOverrides, device.deviceid) ? this.ipOverrides[device.deviceid] : null + }) + }) + this.debug = config.debug || false + this.debugReqRes = config.debugReqRes || false + this.emitter = new EventEmitter() } - getHosts() { - return new Promise(async (resolve, reject) => { - try { - let res = await dns.discover({ - name: "_ewelink._tcp.local", - }); - res.forEach(device => { - let d, - deviceId = device.fqdn.replace("._ewelink._tcp.local", "").replace("eWeLink_", ""); - if ((d = this.deviceMap.get(deviceId))) { - if (!this.ipOverrides.hasOwnProperty(deviceId)) { - this.deviceMap.set(deviceId, { - apiKey: d.apiKey, - online: true, - ip: device.address, - }); - } + + async getHosts () { + try { + const res = await dns.discover({ + name: '_ewelink._tcp.local' + }) + res.forEach(device => { + let d + const deviceId = device.fqdn.replace('._ewelink._tcp.local', '').replace('eWeLink_', '') + if ((d = this.deviceMap.get(deviceId))) { + if (!Object.prototype.hasOwnProperty.call(this.ipOverrides, deviceId)) { + this.deviceMap.set(deviceId, { + apiKey: d.apiKey, + online: true, + ip: device.address + }) } - }); - resolve(this.deviceMap); - } catch (err) { - reject(err); - } - }); + } + }) + return this.deviceMap + } catch (err) { + throw new Error(err) + } } - startMonitor() { + + startMonitor () { dns.ondata = packet => { if (packet.answers) { packet.answers - .filter(value => value.name.includes("_ewelink._tcp.local")) - .filter(value => value.type === "TXT") + .filter(value => value.name.includes('_ewelink._tcp.local')) + .filter(value => value.type === 'TXT') .filter(value => this.deviceMap.has(value.rdata.id)) .forEach(value => { - let rdata = value.rdata, - deviceInfo = this.deviceMap.get(rdata.id), - data = - rdata.data1 + - (rdata.hasOwnProperty("data2") ? rdata.data2 : "") + - (rdata.hasOwnProperty("data3") ? rdata.data3 : "") + - (rdata.hasOwnProperty("data4") ? rdata.data4 : ""), - key = crypto.createHash("md5").update(Buffer.from(deviceInfo.apiKey, "utf8")).digest(), - dText = crypto.createDecipheriv("aes-128-cbc", key, Buffer.from(rdata.iv, "base64")), - pText = Buffer.concat([dText.update(Buffer.from(data, "base64")), dText.final()]).toString("utf8"), - params; - if (packet.address !== deviceInfo.ip && !this.ipOverrides.hasOwnProperty(rdata.id)) { + const rdata = value.rdata + const deviceInfo = this.deviceMap.get(rdata.id) + const data = + rdata.data1 + + (Object.prototype.hasOwnProperty.call(rdata, 'data2') ? rdata.data2 : '') + + (Object.prototype.hasOwnProperty.call(rdata, 'data3') ? rdata.data3 : '') + + (Object.prototype.hasOwnProperty.call(rdata, 'data4') ? rdata.data4 : '') + const key = crypto.createHash('md5').update(Buffer.from(deviceInfo.apiKey, 'utf8')).digest() + const dText = crypto.createDecipheriv('aes-128-cbc', key, Buffer.from(rdata.iv, 'base64')) + const pText = Buffer.concat([dText.update(Buffer.from(data, 'base64')), dText.final()]).toString('utf8') + let params + if (packet.address !== deviceInfo.ip && !Object.prototype.hasOwnProperty.call(this.ipOverrides, rdata.id)) { this.deviceMap.set(rdata.id, { apiKey: deviceInfo.apiKey, online: true, - ip: packet.address, - }); + ip: packet.address + }) if (this.debug) { - this.log.warn("[%s] updating IP address to [%s].", rdata.id, packet.address); + this.log.warn('[%s] updating IP address to [%s].', rdata.id, packet.address) } } try { - params = JSON.parse(pText); + params = JSON.parse(pText) } catch (e) { - this.log.warn("[%s] An error occured reading the LAN message [%s]", rdata.id, e); - return; + this.log.warn('[%s] An error occured reading the LAN message [%s]', rdata.id, e) + return } - for (let param in params) { - if (params.hasOwnProperty(param)) { - if (!cns.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { - delete params[param]; + for (const param in params) { + if (Object.prototype.hasOwnProperty.call(params, param)) { + if (!cns.paramsToKeep.includes(param.replace(/[0-9]/g, ''))) { + delete params[param] } } } if (Object.keys(params).length > 0) { - params.updateSource = "LAN"; - params.online = true; - let returnTemplate = { + params.updateSource = 'LAN' + params.online = true + const returnTemplate = { deviceid: rdata.id, - params, - }; + params + } if (this.debugReqRes) { - let msg = JSON.stringify(returnTemplate, null, 2).replace(rdata.id, "**hidden**"); - this.log("LAN message received.\n%s", msg); + const msg = JSON.stringify(returnTemplate, null, 2).replace(rdata.id, '**hidden**') + this.log('LAN message received.\n%s', msg) } else if (this.debug) { - this.log("LAN message received."); + this.log('LAN message received.') } - this.emitter.emit("update", returnTemplate); + this.emitter.emit('update', returnTemplate) } - }); + }) } - }; - dns.startMonitoring(); + } + dns.startMonitoring() } - sendUpdate(json) { - return new Promise(async (resolve, reject) => { - try { - if (!this.deviceMap.get(json.deviceid).online) { - throw "device isn't reachable via LAN mode"; + + async sendUpdate (json) { + try { + if (!this.deviceMap.get(json.deviceid).online) { + throw new Error("device isn't reachable via LAN mode") + } + let apiKey + let suffix + const params = {} + if (Object.prototype.hasOwnProperty.call(json.params, 'switches')) { + params.switches = json.params.switches + suffix = 'switches' + } else if (Object.prototype.hasOwnProperty.call(json.params, 'switch')) { + params.switch = json.params.switch + suffix = 'switch' + } else { + throw new Error("device isn't reachable via LAN mode") + } + if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { + const key = crypto.createHash('md5').update(Buffer.from(apiKey, 'utf8')).digest() + const iv = crypto.randomBytes(16) + const enc = crypto.createCipheriv('aes-128-cbc', key, iv) + const data = { + data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString('base64'), + deviceid: json.deviceid, + encrypt: true, + iv: iv.toString('base64'), + selfApikey: '123', + sequence: Date.now().toString() } - let apiKey, - suffix, - params = {}; - if (json.params.hasOwnProperty("switches")) { - params.switches = json.params.switches; - suffix = "switches"; - } else if (json.params.hasOwnProperty("switch")) { - params.switch = json.params.switch; - suffix = "switch"; - } else { - throw "device isn't reachable via LAN mode"; + if (this.debugReqRes) { + const msg = JSON.stringify(json, null, 2) + .replace(json.apikey, '**hidden**') + .replace(json.apikey, '**hidden**') + .replace(json.deviceid, '**hidden**') + this.log.warn('LAN message sent. This text is yellow for clarity.\n%s', msg) + } else if (this.debug) { + this.log('LAN message sent.') } - if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { - let key = crypto.createHash("md5").update(Buffer.from(apiKey, "utf8")).digest(), - iv = crypto.randomBytes(16), - enc = crypto.createCipheriv("aes-128-cbc", key, iv), - data = { - data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString("base64"), - deviceid: json.deviceid, - encrypt: true, - iv: iv.toString("base64"), - selfApikey: "123", - sequence: Date.now().toString(), - }; - if (this.debugReqRes) { - let msg = JSON.stringify(json, null, 2) - .replace(json.apikey, "**hidden**") - .replace(json.apikey, "**hidden**") - .replace(json.deviceid, "**hidden**"); - this.log.warn("LAN message sent. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("LAN message sent."); - } - let res = await axios({ - method: "post", - url: "http://" + this.deviceMap.get(json.deviceid).ip + ":8081/zeroconf/" + suffix, - headers: { - Accept: "application/json", - "Content-Type": "application/json", - }, - data, - }); - if (res.data.hasOwnProperty("error") && res.data.error === 0) { - resolve(); - } else { - throw res.data; - } + const res = await axios({ + method: 'post', + url: 'http://' + this.deviceMap.get(json.deviceid).ip + ':8081/zeroconf/' + suffix, + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + }, + data + }) + if (Object.prototype.hasOwnProperty.call(res.data, 'error') && res.data.error === 0) { + return + } else { + throw new Error(res.data) } - } catch (err) { - reject(err); } - }); + } catch (err) { + throw new Error(err) + } } - receiveUpdate(f) { - this.emitter.addListener("update", f); + + receiveUpdate (f) { + this.emitter.addListener('update', f) } - addDeviceToMap(device) { + + addDeviceToMap (device) { this.deviceMap.set(device.deviceid, { apiKey: device.devicekey, - online: this.ipOverrides.hasOwnProperty(device.deviceid) ? true : false, - ip: this.ipOverrides.hasOwnProperty(device.deviceid) ? this.ipOverrides[device.deviceid] : null, - }); + online: !!Object.prototype.hasOwnProperty.call(this.ipOverrides, device.deviceid), + ip: Object.prototype.hasOwnProperty.call(this.ipOverrides, device.deviceid) ? this.ipOverrides[device.deviceid] : null + }) } - closeConnection() { - dns.stopMonitoring(); - this.log("LAN monitoring gracefully stopped."); + + closeConnection () { + dns.stopMonitoring() + this.log('LAN monitoring gracefully stopped.') } -}; +} diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index c3201325..647eb091 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -1,289 +1,317 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -const axios = require("axios"), - cns = require("./constants"), - eventemitter = require("events"), - utils = require("./utils"), - ws = require("ws"), - wsp = require("websocket-as-promised"); +'use strict' +const axios = require('axios') +const cns = require('./constants') +const EventEmitter = require('events') +const utils = require('./utils') +const WS = require('ws') +const WSP = require('websocket-as-promised') module.exports = class eWeLinkWS { - constructor(config, log, res) { - this.config = config; - this.log = log; - this.debug = this.config.debug || false; - this.debugReqRes = this.config.debugReqRes || false; - this.httpHost = res.httpHost; - this.aToken = res.aToken; - this.apiKey = res.apiKey; - this.wsIsOpen = false; - this.emitter = new eventemitter(); - this.delaySend = 0; + constructor (config, log, res) { + this.config = config + this.log = log + this.debug = this.config.debug || false + this.debugReqRes = this.config.debugReqRes || false + this.httpHost = res.httpHost + this.aToken = res.aToken + this.apiKey = res.apiKey + this.wsIsOpen = false + this.emitter = new EventEmitter() + this.delaySend = 0 } - getHost() { - return new Promise(async (resolve, reject) => { - try { - let res = await axios({ - method: "post", - url: "https://" + this.httpHost.replace("-api", "-disp") + "/dispatch/app", - headers: { - Authorization: "Bearer " + this.aToken, - "Content-Type": "application/json", - }, - data: { - appid: cns.appId, - nonce: Math.random().toString(36).substr(2, 8), - ts: Math.floor(new Date().getTime() / 1000), - version: 8, - }, - }); - let body = res.data; - if (!body.domain) { - throw "Server did not respond with a web socket host."; - } - if (this.debug) { - this.log("Web socket host received [%s].", body.domain); - } - this.wsHost = body.domain; - resolve(body.domain); - } catch (err) { - if (err.hasOwnProperty("code") && ["ENOTFOUND", "ETIMEDOUT"].includes(err.code)) { - this.log.warn("Unable to reach eWeLink. Retrying in 30 seconds."); - await utils.sleep(30000); - resolve(this.getDevices()); - } else { - reject(err.message || err); + + async getHost () { + try { + const res = await axios({ + method: 'post', + url: 'https://' + + this.httpHost.replace('-api', '-disp') + + '/dispatch/app', + headers: { + Authorization: 'Bearer ' + this.aToken, + 'Content-Type': 'application/json' + }, + data: { + appid: cns.appId, + nonce: Math.random().toString(36).substr(2, 8), + ts: Math.floor(new Date().getTime() / 1000), + version: 8 } + }) + const body = res.data + if (!body.domain) { + throw new Error('Server did not respond with a web socket host.') } - }); + if (this.debug) { + this.log('Web socket host received [%s].', body.domain) + } + this.wsHost = body.domain + return body.domain + } catch (err) { + if ( + Object.prototype.hasOwnProperty.call(err, 'code') && ['ENOTFOUND', 'ETIMEDOUT'].includes(err.code) + ) { + this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') + await utils.sleep(30000) + return this.getDevices() + } else { + throw new Error(err.message || err) + } + } } - login() { - this.wsp = new wsp("wss://" + this.wsHost + ":8080/api/ws", { - createWebSocket: url => new ws(url), - extractMessageData: event => event, + + login () { + this.wsp = new WSP('wss://' + this.wsHost + ':8080/api/ws', { + createWebSocket: (url) => new WS(url), + extractMessageData: (event) => event, attachRequestId: (data, requestId) => - Object.assign( - { - sequence: requestId, - }, - data + Object.assign({ + sequence: requestId + }, + data ), - extractRequestId: data => data && data.sequence, - packMessage: data => JSON.stringify(data), - unpackMessage: data => { - return data === "pong" ? data : JSON.parse(data); - }, - }); - this.wsp.open(); + extractRequestId: (data) => data && data.sequence, + packMessage: (data) => JSON.stringify(data), + unpackMessage: (data) => { + return data === 'pong' ? data : JSON.parse(data) + } + }) + this.wsp.open() this.wsp.onOpen.addListener(async () => { - this.wsIsOpen = true; - let sequence = Math.floor(new Date()).toString(), - payload = { - action: "userOnline", - apikey: this.apiKey, - appid: cns.appId, - at: this.aToken, - nonce: Math.random().toString(36).substr(2, 8), - sequence, - ts: Math.floor(new Date() / 1000), - userAgent: "app", - version: 8, - }; + this.wsIsOpen = true + const sequence = Math.floor(new Date()).toString() + const payload = { + action: 'userOnline', + apikey: this.apiKey, + appid: cns.appId, + at: this.aToken, + nonce: Math.random().toString(36).substr(2, 8), + sequence, + ts: Math.floor(new Date() / 1000), + userAgent: 'app', + version: 8 + } if (this.debugReqRes) { - let msg = JSON.stringify(payload, null, 2) - .replace(this.aToken, "**hidden**") - .replace(this.apiKey, "**hidden**"); - this.log.warn("Sending WS login request. This text is yellow for clarity.\n%s", msg); + const msg = JSON.stringify(payload, null, 2) + .replace(this.aToken, '**hidden**') + .replace(this.apiKey, '**hidden**') + this.log.warn( + 'Sending WS login request. This text is yellow for clarity.\n%s', + msg + ) } else if (this.debug) { - this.log("Sending WS login request."); + this.log('Sending WS login request.') } try { - let res = await this.wsp.sendRequest(payload, { - requestId: sequence, - }); - if (res.hasOwnProperty("config") && res.config.hb && res.config.hbInterval && !this.hbInterval) { + const res = await this.wsp.sendRequest(payload, { + requestId: sequence + }) + if ( + Object.prototype.hasOwnProperty.call(res, 'config') && + res.config.hb && + res.config.hbInterval && + !this.hbInterval + ) { this.hbInterval = setInterval(() => { - this.wsp.send("ping"); - }, (res.config.hbInterval + 7) * 1000); + this.wsp.send('ping') + }, (res.config.hbInterval + 7) * 1000) } else { - throw "Unknown parameters received"; + throw new Error('Unknown parameters received') } } catch (err) { - this.log.error("WS login failed [%s].", err); + this.log.error('WS login failed [%s].', err) } - }); - this.wsp.onUnpackedMessage.addListener(device => { - if (device === "pong") return; - let onlineStatus = true; - if (!device.hasOwnProperty("params")) device.params = {}; - if (device.hasOwnProperty("deviceid") && device.hasOwnProperty("error")) { - device.action = "update"; - onlineStatus = device.error === 0; + }) + this.wsp.onUnpackedMessage.addListener((device) => { + if (device === 'pong') return + let onlineStatus = true + if (!Object.prototype.hasOwnProperty.call(device, 'params')) device.params = {} + if (Object.prototype.hasOwnProperty.call(device, 'deviceid') && Object.prototype.hasOwnProperty.call(device, 'error')) { + device.action = 'update' + onlineStatus = device.error === 0 } - if (device.hasOwnProperty("action")) { + if (Object.prototype.hasOwnProperty.call(device, 'action')) { switch (device.action) { - case "update": - case "sysmsg": - if (device.action === "sysmsg" && device.params.hasOwnProperty("online")) { - onlineStatus = device.params.online; + case 'update': + case 'sysmsg': + if ( + device.action === 'sysmsg' && + Object.prototype.hasOwnProperty.call(device.params, 'online') + ) { + onlineStatus = device.params.online } - for (let param in device.params) { - if (device.params.hasOwnProperty(param)) { - if (!cns.paramsToKeep.includes(param.replace(/[0-9]/g, ""))) { - delete device.params[param]; + for (const param in device.params) { + if (Object.prototype.hasOwnProperty.call(device.params, param)) { + if (!cns.paramsToKeep.includes(param.replace(/[0-9]/g, ''))) { + delete device.params[param] } } } - device.params.online = onlineStatus; - device.params.updateSource = "WS"; + device.params.online = onlineStatus + device.params.updateSource = 'WS' if (Object.keys(device.params).length > 0) { - let returnTemplate = { + const returnTemplate = { deviceid: device.deviceid, - params: device.params, - }; + params: device.params + } if (this.debugReqRes) { - let msg = JSON.stringify(returnTemplate, null, 2).replace(device.deviceid, "**hidden**"); - this.log("WS message received.\n%s", msg); + const msg = JSON.stringify(returnTemplate, null, 2).replace( + device.deviceid, + '**hidden**' + ) + this.log('WS message received.\n%s', msg) } else if (this.debug) { - this.log("WS message received."); + this.log('WS message received.') } - this.emitter.emit("update", returnTemplate); + this.emitter.emit('update', returnTemplate) } - break; - case "reportSubDevice": - return; + break + case 'reportSubDevice': + return default: - this.log.warn("[%s] WS message has unknown action.\n" + JSON.stringify(device, null, 2), device.deviceid); - return; + this.log.warn( + '[%s] WS message has unknown action.\n' + + JSON.stringify(device, null, 2), + device.deviceid + ) } - } else if (device.hasOwnProperty("error") && device.error === 0) { + } else if (Object.prototype.hasOwnProperty.call(device, 'error') && device.error === 0) { // *** Safe to ignore these messages *** \\ } else { if (this.debug) { - this.log.warn("WS unknown command received.\n" + JSON.stringify(device, null, 2)); + this.log.warn( + 'WS unknown command received.\n' + JSON.stringify(device, null, 2) + ) } } - }); + }) this.wsp.onClose.addListener((e, m) => { - this.wsIsOpen = false; + this.wsIsOpen = false if (e !== 1005) { - this.log.warn("Web socket closed [%s].", e); + this.log.warn('Web socket closed [%s].', e) if (e !== 1000) { - this.log("Web socket will try to reconnect in five seconds."); - setTimeout(() => this.login(), 5000); + this.log('Web socket will try to reconnect in five seconds.') + setTimeout(() => this.login(), 5000) } else { - this.log("Please try restarting Homebridge so that this plugin can work again."); + this.log( + 'Please try restarting Homebridge so that this plugin can work again.' + ) } } if (this.hbInterval) { - clearInterval(this.hbInterval); - this.hbInterval = null; + clearInterval(this.hbInterval) + this.hbInterval = null } - this.wsp.removeAllListeners(); - }); - this.wsp.onError.addListener(e => { - this.log.error("Web socket error - [%s].", e); - if (e.code === "ECONNREFUSED") { - this.log.warn("Web socket will try to reconnect in five seconds then try the command again."); - this.wsp.removeAllListeners(); - setTimeout(() => this.login(), 5000); - } else { - this.log.warn("If this was unexpected then please try restarting Homebridge."); - } - }); - } - sendUpdate(json) { - return new Promise(async (resolve, reject) => { - let sequence = Math.floor(new Date()).toString(), - jsonToSend = { - ...json, - ...{ - action: "update", - sequence, - userAgent: "app", - }, - }; - if (this.wsp && this.wsIsOpen) { - try { - let device = await this.wsp.sendRequest(jsonToSend, { - requestId: sequence, - }); - if (this.debugReqRes) { - let msg = JSON.stringify(json, null, 2) - .replace(json.apikey, "**hidden**") - .replace(json.apiKey, "**hidden**") - .replace(json.deviceid, "**hidden**"); - this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); - } else if (this.debug) { - this.log("WS message sent."); - } - device.error = device.hasOwnProperty("error") ? device.error : 504; // mimic ewelink device offline - switch (device.error) { - case 0: - resolve(); - break; - default: - throw "Unknown response"; - } - } catch (err) { - reject("device update failed [" + err + "]"); - } + this.wsp.removeAllListeners() + }) + this.wsp.onError.addListener((e) => { + this.log.error('Web socket error - [%s].', e) + if (e.code === 'ECONNREFUSED') { + this.log.warn( + 'Web socket will try to reconnect in five seconds then try the command again.' + ) + this.wsp.removeAllListeners() + setTimeout(() => this.login(), 5000) } else { - if (this.debug) { - this.log.warn("Command will be resent when WS is reconnected."); - } - await utils.sleep(30000); - resolve(this.sendUpdate(json)); + this.log.warn( + 'If this was unexpected then please try restarting Homebridge.' + ) } - }); + }) } - requestUpdate(accessory) { - return new Promise(async resolve => { - let sequence = Math.floor(new Date()).toString(), - json = { - action: "query", - apikey: accessory.context.eweApiKey, - deviceid: accessory.context.eweDeviceId, - params: [], - sequence, - ts: 0, - userAgent: "app", - }; - if (this.wsp && this.wsIsOpen) { - this.wsp.send(JSON.stringify(json)); + async sendUpdate (json) { + const sequence = Math.floor(new Date()).toString() + const jsonToSend = { + ...json, + ...{ + action: 'update', + sequence, + userAgent: 'app' + } + } + if (this.wsp && this.wsIsOpen) { + try { + const device = await this.wsp.sendRequest(jsonToSend, { + requestId: sequence + }) if (this.debugReqRes) { - let msg = JSON.stringify(json, null, 2) - .replace(json.apikey, "**hidden**") - .replace(json.apiKey, "**hidden**") - .replace(json.deviceid, "**hidden**"); - this.log.warn("WS message sent. This text is yellow for clarity.\n%s", msg); + const msg = JSON.stringify(json, null, 2) + .replace(json.apikey, '**hidden**') + .replace(json.apiKey, '**hidden**') + .replace(json.deviceid, '**hidden**') + this.log.warn( + 'WS message sent. This text is yellow for clarity.\n%s', + msg + ) } else if (this.debug) { - this.log("WS message sent."); + this.log('WS message sent.') } - } else { - if (this.debug) { - this.log.warn("Command will be resent when WS is reconnected."); + device.error = Object.prototype.hasOwnProperty.call(device, 'error') ? device.error : 504 + switch (device.error) { + case 0: + return + default: + throw new Error('Unknown response') } - await utils.sleep(30000); - resolve(this.requestUpdate(accessory)); + } catch (err) { + throw new Error('device update failed [' + err + ']') } - }); + } else { + if (this.debug) { + this.log.warn('Command will be resent when WS is reconnected.') + } + await utils.sleep(30000) + return this.sendUpdate(json) + } } - receiveUpdate(f) { - this.emitter.addListener("update", f); + + async requestUpdate (accessory) { + const sequence = Math.floor(new Date()).toString() + const json = { + action: 'query', + apikey: accessory.context.eweApiKey, + deviceid: accessory.context.eweDeviceId, + params: [], + sequence, + ts: 0, + userAgent: 'app' + } + if (this.wsp && this.wsIsOpen) { + this.wsp.send(JSON.stringify(json)) + if (this.debugReqRes) { + const msg = JSON.stringify(json, null, 2) + .replace(json.apikey, '**hidden**') + .replace(json.apiKey, '**hidden**') + .replace(json.deviceid, '**hidden**') + this.log.warn( + 'WS message sent. This text is yellow for clarity.\n%s', + msg + ) + } else if (this.debug) { + this.log('WS message sent.') + } + } else { + if (this.debug) { + this.log.warn('Command will be resent when WS is reconnected.') + } + await utils.sleep(30000) + return this.requestUpdate(accessory) + } } - closeConnection() { - return new Promise(async (resolve, reject) => { - if (this.wsp && this.wsIsOpen) { - try { - await this.wsp.close(); - this.log("Web socket gracefully closed."); - resolve(); - } catch (err) { - reject(err); - } + + receiveUpdate (f) { + this.emitter.addListener('update', f) + } + + async closeConnection () { + if (this.wsp && this.wsIsOpen) { + try { + await this.wsp.close() + this.log('Web socket gracefully closed.') + return + } catch (err) { + throw new Error(err) } - resolve(); - }); + } } -}; +} diff --git a/lib/utils.js b/lib/utils.js index 5cb638ad..bf3698e8 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,7 +1,6 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; +'use strict' module.exports = { sleep: ms => { - return new Promise(resolve => setTimeout(resolve, ms)); - }, -}; + return new Promise(resolve => setTimeout(resolve, ms)) + } +} diff --git a/package-lock.json b/package-lock.json index a05cbda3..d667effe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -560,12 +560,6 @@ "object-keys": "^1.0.11" } }, - "prettier": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz", - "integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==", - "dev": true - }, "promise-controller": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/promise-controller/-/promise-controller-1.0.0.tgz", diff --git a/package.json b/package.json index 81643c16..c27caff6 100644 --- a/package.json +++ b/package.json @@ -67,8 +67,5 @@ "node-dns-sd": "0.4.1", "websocket-as-promised": "1.0.1", "ws": "7.3.1" - }, - "devDependencies": { - "prettier": "2.1.2" } } From 007a70d42653ba9fb89854c0d1340489d4fa8b8a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 08:32:16 +0100 Subject: [PATCH 0235/3183] standard code style --- lib/device/blind.js | 136 ++++++++-------- lib/device/curtain.js | 63 +++---- lib/device/fan.js | 141 ++++++++-------- lib/device/garage.js | 164 +++++++++---------- lib/device/light.js | 344 ++++++++++++++++++++------------------- lib/device/lock.js | 83 +++++----- lib/device/outlet.js | 73 +++++---- lib/device/rf-sub.js | 157 +++++++++--------- lib/device/scm.js | 42 ++--- lib/device/sensor.js | 58 +++---- lib/device/switch.js | 139 ++++++++-------- lib/device/thermostat.js | 71 ++++---- lib/device/usb.js | 43 ++--- lib/device/valve.js | 105 ++++++------ lib/device/zb-dev.js | 91 ++++++----- 15 files changed, 862 insertions(+), 848 deletions(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index 377fb763..13ea726e 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -1,97 +1,97 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -let Characteristic, Service; -const cns = require("./../constants"), - utils = require("./../utils"); +'use strict' +let Characteristic, Service +const cns = require('./../constants') +const utils = require('./../utils') module.exports = class deviceBlind { - constructor(platform) { - this.platform = platform; - Service = platform.api.hap.Service; - Characteristic = platform.api.hap.Characteristic; + constructor (platform) { + this.platform = platform + Service = platform.api.hap.Service + Characteristic = platform.api.hap.Characteristic } - async internalBlindUpdate(accessory, value, callback) { - callback(); + + async internalBlindUpdate (accessory, value, callback) { + callback() try { - let blindConfig, - params = {}, - wcService = accessory.getService(Service.WindowCovering), - prevState = accessory.context.cachePositionState, - prevPosition = accessory.context.cacheCurrentPosition, - newTarget = value, - updateKey = Math.random().toString(36).substr(2, 8); + let blindConfig + const params = {} + const wcService = accessory.getService(Service.WindowCovering) + const prevState = accessory.context.cachePositionState + let prevPosition = accessory.context.cacheCurrentPosition + const newTarget = value + const updateKey = Math.random().toString(36).substr(2, 8) if (!(blindConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; + throw new Error('group config missing') } - if (blindConfig.type !== "blind" || blindConfig.setup !== "twoSwitch") { - throw "improper configuration"; + if (blindConfig.type !== 'blind' || blindConfig.setup !== 'twoSwitch') { + throw new Error('improper configuration') } - if (newTarget === prevPosition) return; - params.switches = cns.defaultMultiSwitchOff; - accessory.context.updateKey = updateKey; - let percentStepPerDecisecond = blindConfig.operationTime / 100; + if (newTarget === prevPosition) return + params.switches = cns.defaultMultiSwitchOff + accessory.context.updateKey = updateKey + const percentStepPerDecisecond = blindConfig.operationTime / 100 // // - this.platform.log("============================"); - this.platform.log("============================"); - this.platform.log("Starting main calculation..."); + this.platform.log('============================') + this.platform.log('============================') + this.platform.log('Starting main calculation...') // // if (prevState !== 2) { - await this.platform.sendDeviceUpdate(accessory, params); - let positionPercentChange = Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime; - positionPercentChange = Math.floor(percentStepPerDecisecond * positionPercentChange); + await this.platform.sendDeviceUpdate(accessory, params) + let positionPercentChange = Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime + positionPercentChange = Math.floor(percentStepPerDecisecond * positionPercentChange) if (prevState === 0) { // moving down - prevPosition -= positionPercentChange; + prevPosition -= positionPercentChange } else { - prevPosition += positionPercentChange; + prevPosition += positionPercentChange } - wcService.updateCharacteristic(Characteristic.CurrentPosition, prevPosition); - accessory.context.cacheCurrentPosition = prevPosition; - this.platform.log.warn("Moving from [%s%] to [%s%]", prevPosition, newTarget); + wcService.updateCharacteristic(Characteristic.CurrentPosition, prevPosition) + accessory.context.cacheCurrentPosition = prevPosition + this.platform.log.warn('Moving from [%s%] to [%s%]', prevPosition, newTarget) this.platform.log.warn( - "Blind was already moving %s when it was changed and was probably around %s%", - prevState === 1 ? "up" : "down", + 'Blind was already moving %s when it was changed and was probably around %s%', + prevState === 1 ? 'up' : 'down', prevPosition - ); + ) this.platform.log.warn( - "Giving a difference of %s seconds - a position change of %s%", + 'Giving a difference of %s seconds - a position change of %s%', (Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime) / 10, positionPercentChange - ); + ) } else { - this.platform.log("Moving from [%s%] to [%s%].", prevPosition, newTarget); + this.platform.log('Moving from [%s%] to [%s%].', prevPosition, newTarget) } - let diffPosition = newTarget - prevPosition; - let setToMoveUp = diffPosition > 0; - let decisecondsToMove = Math.round(Math.abs(diffPosition) * percentStepPerDecisecond); + const diffPosition = newTarget - prevPosition + const setToMoveUp = diffPosition > 0 + const decisecondsToMove = Math.round(Math.abs(diffPosition) * percentStepPerDecisecond) this.platform.log( - "So we need to move %s from the previous state of %s for about %s seconds", - setToMoveUp ? "up" : "down", - prevState === 0 ? "moving down" : prevState === 1 ? "moving up" : "stopped", + 'So we need to move %s from the previous state of %s for about %s seconds', + setToMoveUp ? 'up' : 'down', + prevState === 0 ? 'moving down' : prevState === 1 ? 'moving up' : 'stopped', decisecondsToMove / 10 - ); - params.switches[0].switch = setToMoveUp ? "on" : "off"; - params.switches[1].switch = setToMoveUp ? "off" : "on"; - await this.platform.sendDeviceUpdate(accessory, params); + ) + params.switches[0].switch = setToMoveUp ? 'on' : 'off' + params.switches[1].switch = setToMoveUp ? 'off' : 'on' + await this.platform.sendDeviceUpdate(accessory, params) wcService .updateCharacteristic(Characteristic.TargetPosition, newTarget) - .updateCharacteristic(Characteristic.PositionState, setToMoveUp); - accessory.context.cacheTargetPosition = newTarget; - accessory.context.cachePositionState = setToMoveUp ? 1 : 0; - accessory.context.cacheLastStartTime = Math.floor(Date.now() / 100); - if (accessory.context.updateKey !== updateKey) return; - await utils.sleep(decisecondsToMove * 100); - if (accessory.context.updateKey !== updateKey) return; - params.switches[0].switch = "off"; - params.switches[1].switch = "off"; - await this.platform.sendDeviceUpdate(accessory, params); - wcService.updateCharacteristic(Characteristic.PositionState, 2); - wcService.updateCharacteristic(Characteristic.CurrentPosition, newTarget); - accessory.context.cachePositionState = 2; - accessory.context.cacheCurrentPosition = newTarget; + .updateCharacteristic(Characteristic.PositionState, setToMoveUp) + accessory.context.cacheTargetPosition = newTarget + accessory.context.cachePositionState = setToMoveUp ? 1 : 0 + accessory.context.cacheLastStartTime = Math.floor(Date.now() / 100) + if (accessory.context.updateKey !== updateKey) return + await utils.sleep(decisecondsToMove * 100) + if (accessory.context.updateKey !== updateKey) return + params.switches[0].switch = 'off' + params.switches[1].switch = 'off' + await this.platform.sendDeviceUpdate(accessory, params) + wcService.updateCharacteristic(Characteristic.PositionState, 2) + wcService.updateCharacteristic(Characteristic.CurrentPosition, newTarget) + accessory.context.cachePositionState = 2 + accessory.context.cacheCurrentPosition = newTarget } catch (err) { - this.platform.requestDeviceRefresh(accessory, err); + this.platform.requestDeviceRefresh(accessory, err) } } -}; +} diff --git a/lib/device/curtain.js b/lib/device/curtain.js index d7a8cf8a..95ab6086 100644 --- a/lib/device/curtain.js +++ b/lib/device/curtain.js @@ -1,52 +1,53 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -let Characteristic, Service; +'use strict' +let Characteristic, Service module.exports = class deviceCurtain { - constructor(platform) { - this.platform = platform; - Service = platform.api.hap.Service; - Characteristic = platform.api.hap.Characteristic; + constructor (platform) { + this.platform = platform + Service = platform.api.hap.Service + Characteristic = platform.api.hap.Characteristic } - async internalCurtainUpdate(accessory, value, callback) { - callback(); + + async internalCurtainUpdate (accessory, value, callback) { + callback() try { - let params, - cService = accessory.getService(Service.WindowCovering), - prevPos = accessory.context.cacheCurrentPosition, - newPos = value; - if (newPos === prevPos) return; + let params + const cService = accessory.getService(Service.WindowCovering) + const prevPos = accessory.context.cacheCurrentPosition + const newPos = value + if (newPos === prevPos) return if (newPos === 0 || newPos === 100) { params = { - switch: newPos === 100 ? "on" : "off", - }; + switch: newPos === 100 ? 'on' : 'off' + } } else { params = { - setclose: Math.abs(100 - newPos), - }; + setclose: Math.abs(100 - newPos) + } } - await this.platform.sendDeviceUpdate(accessory, params); + await this.platform.sendDeviceUpdate(accessory, params) cService .updateCharacteristic(Characteristic.TargetPosition, newPos) - .updateCharacteristic(Characteristic.PositionState, newPos > prevPos ? 1 : 0); - accessory.context.cacheCurrentPosition = newPos; + .updateCharacteristic(Characteristic.PositionState, newPos > prevPos ? 1 : 0) + accessory.context.cacheCurrentPosition = newPos } catch (err) { - this.platform.requestDeviceRefresh(accessory, err); + this.platform.requestDeviceRefresh(accessory, err) } } - externalCurtainUpdate(accessory, params) { + + externalCurtainUpdate (accessory, params) { try { - let cService = accessory.getService(Service.WindowCovering); - if (params.hasOwnProperty("switch") && params.hasOwnProperty("setclose")) { - let newPos = Math.abs(100 - parseInt(params.setclose)); + const cService = accessory.getService(Service.WindowCovering) + if (Object.prototype.hasOwnProperty.call(params, 'switch') && Object.prototype.hasOwnProperty.call(params, 'setclose')) { + const newPos = Math.abs(100 - parseInt(params.setclose)) cService .updateCharacteristic(Characteristic.TargetPosition, newPos) .updateCharacteristic(Characteristic.CurrentPosition, newPos) - .updateCharacteristic(Characteristic.PositionState, 2); - accessory.context.cacheCurrentPosition = newPos; - return; + .updateCharacteristic(Characteristic.PositionState, 2) + accessory.context.cacheCurrentPosition = newPos + return } } catch (err) { - this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) } } -}; +} diff --git a/lib/device/fan.js b/lib/device/fan.js index 2c12a5e7..09323633 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -1,92 +1,93 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -let Characteristic, Service; +'use strict' +let Characteristic, Service module.exports = class deviceFan { - constructor(platform) { - this.platform = platform; - Service = platform.api.hap.Service; - Characteristic = platform.api.hap.Characteristic; + constructor (platform) { + this.platform = platform + Service = platform.api.hap.Service + Characteristic = platform.api.hap.Characteristic } - async internalFanUpdate(accessory, type, value, callback) { - callback(); + + async internalFanUpdate (accessory, type, value, callback) { + callback() try { - let newPower, - newSpeed, - newLight, - lightService = accessory.getService(Service.Lightbulb), - fanService = accessory.getService(Service.Fanv2); + let newPower + let newSpeed + let newLight + const lightService = accessory.getService(Service.Lightbulb) + const fanService = accessory.getService(Service.Fanv2) switch (type) { - case "power": - newPower = value; - newSpeed = value ? 33 : 0; - newLight = lightService.getCharacteristic(Characteristic.On).value; - break; - case "speed": - newPower = value >= 33 ? 1 : 0; - newSpeed = value; - newLight = lightService.getCharacteristic(Characteristic.On).value; - break; - case "light": - newPower = fanService.getCharacteristic(Characteristic.Active).value; - newSpeed = fanService.getCharacteristic(Characteristic.RotationSpeed).value; - newLight = value; - break; + case 'power': + newPower = value + newSpeed = value ? 33 : 0 + newLight = lightService.getCharacteristic(Characteristic.On).value + break + case 'speed': + newPower = value >= 33 ? 1 : 0 + newSpeed = value + newLight = lightService.getCharacteristic(Characteristic.On).value + break + case 'light': + newPower = fanService.getCharacteristic(Characteristic.Active).value + newSpeed = fanService.getCharacteristic(Characteristic.RotationSpeed).value + newLight = value + break } - let params = { - switches: this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches, - }; - params.switches[0].switch = newLight ? "on" : "off"; - params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? "on" : "off"; - params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? "on" : "off"; - params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? "on" : "off"; - await this.platform.sendDeviceUpdate(accessory, params); - lightService.updateCharacteristic(Characteristic.On, newLight); + const params = { + switches: this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches + } + params.switches[0].switch = newLight ? 'on' : 'off' + params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? 'on' : 'off' + params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? 'on' : 'off' + params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? 'on' : 'off' + await this.platform.sendDeviceUpdate(accessory, params) + lightService.updateCharacteristic(Characteristic.On, newLight) fanService .updateCharacteristic(Characteristic.Active, newPower) - .updateCharacteristic(Characteristic.RotationSpeed, newSpeed); + .updateCharacteristic(Characteristic.RotationSpeed, newSpeed) } catch (err) { - this.platform.requestDeviceRefresh(accessory, err); + this.platform.requestDeviceRefresh(accessory, err) } } - externalFanUpdate(accessory, params) { + + externalFanUpdate (accessory, params) { try { - let light, - status, - speed, - lightService = accessory.getService(Service.Lightbulb), - fanService = accessory.getService(Service.Fanv2); + let light + let status + let speed + const lightService = accessory.getService(Service.Lightbulb) + const fanService = accessory.getService(Service.Fanv2) if (Array.isArray(params.switches)) { - light = params.switches[0].switch === "on"; + light = params.switches[0].switch === 'on' switch (params.switches[1].switch + params.switches[2].switch + params.switches[3].switch) { default: - status = 0; - speed = 0; - break; - case "onoffoff": - status = 1; - speed = 33; - break; - case "ononoff": - status = 1; - speed = 66; - break; - case "onoffon": - status = 1; - speed = 99; + status = 0 + speed = 0 + break + case 'onoffoff': + status = 1 + speed = 33 + break + case 'ononoff': + status = 1 + speed = 66 + break + case 'onoffon': + status = 1 + speed = 99 } - } else if (params.hasOwnProperty("light") && params.hasOwnProperty("fan") && params.hasOwnProperty("speed")) { - light = params.light === "on"; - status = params.fan === "on" ? 1 : 0; - speed = params.speed * 33 * status; + } else if (Object.prototype.hasOwnProperty.call(params, 'light') && Object.prototype.hasOwnProperty.call(params, 'fan') && Object.prototype.hasOwnProperty.call(params, 'speed')) { + light = params.light === 'on' + status = params.fan === 'on' ? 1 : 0 + speed = params.speed * 33 * status } else { - throw "unknown parameters received"; + throw new Error('unknown parameters received') } - lightService.updateCharacteristic(Characteristic.On, light); + lightService.updateCharacteristic(Characteristic.On, light) fanService .updateCharacteristic(Characteristic.Active, status) - .updateCharacteristic(Characteristic.RotationSpeed, speed); + .updateCharacteristic(Characteristic.RotationSpeed, speed) } catch (err) { - this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) } } -}; +} diff --git a/lib/device/garage.js b/lib/device/garage.js index e888c551..30ec61ec 100644 --- a/lib/device/garage.js +++ b/lib/device/garage.js @@ -1,125 +1,125 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -let Characteristic, Service; -const utils = require("./../utils"); +'use strict' +let Characteristic, Service +const utils = require('./../utils') module.exports = class deviceGarage { - constructor(platform) { - this.platform = platform; - Service = platform.api.hap.Service; - Characteristic = platform.api.hap.Characteristic; + constructor (platform) { + this.platform = platform + Service = platform.api.hap.Service + Characteristic = platform.api.hap.Characteristic } - async internalGarageUpdate(accessory, value, callback) { - callback(); + + async internalGarageUpdate (accessory, value, callback) { + callback() try { - let garageConfig; + let garageConfig if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; + throw new Error('group config missing') } - if (garageConfig.type !== "garage" || !["oneSwitch", "twoSwitch"].includes(garageConfig.setup)) { - throw "improper configuration"; + if (garageConfig.type !== 'garage' || !['oneSwitch', 'twoSwitch'].includes(garageConfig.setup)) { + throw new Error('improper configuration') } - let sensorDefinition = garageConfig.sensorId || false, - sAccessory = false, - prevState, - newPos = value, - params = {}, - delay = 0, - gdService = accessory.getService(Service.GarageDoorOpener); - if (sensorDefinition && !(sAccessory = this.platform.devicesInHB.get(garageConfig.sensorId + "SWX"))) { - throw "defined DW2 sensor doesn't exist"; + const sensorDefinition = garageConfig.sensorId || false + let sAccessory = false + const newPos = value + const params = {} + let delay = 0 + const gdService = accessory.getService(Service.GarageDoorOpener) + if (sensorDefinition && !(sAccessory = this.platform.devicesInHB.get(garageConfig.sensorId + 'SWX'))) { + throw new Error("defined DW2 sensor doesn't exist") } - if (sensorDefinition && sAccessory.context.type !== "sensor") { - throw "defined DW2 sensor isn't a sensor"; + if (sensorDefinition && sAccessory.context.type !== 'sensor') { + throw new Error("defined DW2 sensor isn't a sensor") } - prevState = sAccessory + const prevState = sAccessory ? sAccessory.getService(Service.ContactSensor).getCharacteristic(Characteristic.ContactSensorState).value === 0 ? 1 : 0 - : accessory.context.cacheCurrentDoorState; - if (newPos === prevState % 2) return; - accessory.context.inUse = true; - accessory.context.state = value; - if (garageConfig.setup === "oneSwitch" && [2, 3].includes(prevState)) { - gdService.updateCharacteristic(Characteristic.CurrentDoorState, ((prevState * 2) % 3) + 2); - accessory.context.cacheCurrentDoorState = ((prevState * 2) % 3) + 2; - delay = 1500; + : accessory.context.cacheCurrentDoorState + if (newPos === prevState % 2) return + accessory.context.inUse = true + accessory.context.state = value + if (garageConfig.setup === 'oneSwitch' && [2, 3].includes(prevState)) { + gdService.updateCharacteristic(Characteristic.CurrentDoorState, ((prevState * 2) % 3) + 2) + accessory.context.cacheCurrentDoorState = ((prevState * 2) % 3) + 2 + delay = 1500 } - if (accessory.context.state !== newPos) return; - await utils.sleep(delay); + if (accessory.context.state !== newPos) return + await utils.sleep(delay) gdService .updateCharacteristic(Characteristic.TargetDoorState, newPos) - .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2); - accessory.context.cacheTargetDoorState = newPos; - accessory.context.cacheCurrentDoorState = newPos + 2; + .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2) + accessory.context.cacheTargetDoorState = newPos + accessory.context.cacheCurrentDoorState = newPos + 2 switch (garageConfig.setup) { - case "oneSwitch": - params.switch = "on"; - break; - case "twoSwitch": - params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = newPos === 0 ? "on" : "off"; - params.switches[1].switch = newPos === 1 ? "on" : "off"; - break; + case 'oneSwitch': + params.switch = 'on' + break + case 'twoSwitch': + params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches + params.switches[0].switch = newPos === 0 ? 'on' : 'off' + params.switches[1].switch = newPos === 1 ? 'on' : 'off' + break } - await this.platform.sendDeviceUpdate(accessory, params); - await utils.sleep(garageConfig.operationTime * 100); + await this.platform.sendDeviceUpdate(accessory, params) + await utils.sleep(garageConfig.operationTime * 100) if (!sAccessory) { - gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos); - accessory.context.cacheCurrentDoorState = newPos; + gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos) + accessory.context.cacheCurrentDoorState = newPos } - accessory.context.inUse = false; + accessory.context.inUse = false } catch (err) { - this.platform.requestDeviceRefresh(accessory, err); + this.platform.requestDeviceRefresh(accessory, err) } } - externalGarageUpdate(accessory, params) { + + externalGarageUpdate (accessory, params) { try { - let garageConfig, - gcService = accessory.getService(Service.GarageDoorOpener), - prevState = accessory.context.cacheCurrentDoorState, - newPos = [0, 2].includes(prevState) ? 3 : 2; + let garageConfig + const gcService = accessory.getService(Service.GarageDoorOpener) + const prevState = accessory.context.cacheCurrentDoorState + const newPos = [0, 2].includes(prevState) ? 3 : 2 if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; + throw new Error('group config missing') } - if (garageConfig.type !== "garage" || !["oneSwitch", "twoSwitch"].includes(garageConfig.setup)) { - throw "improper configuration"; + if (garageConfig.type !== 'garage' || !['oneSwitch', 'twoSwitch'].includes(garageConfig.setup)) { + throw new Error('improper configuration') } if (accessory.context.inUse || garageConfig.sensorId) { - return; + return } switch (garageConfig.setup) { - case "oneSwitch": - if (params.switch === "off") { - return; + case 'oneSwitch': + if (params.switch === 'off') { + return } - break; - case "twoSwitch": + break + case 'twoSwitch': if ( params.switches[0].switch === params.switches[1].switch || - params.switches[prevState % 2].switch === "on" + params.switches[prevState % 2].switch === 'on' ) { - return; + return } - break; + break } - accessory.context.inUse = true; + accessory.context.inUse = true if (!garageConfig.sensorId) { gcService .updateCharacteristic(Characteristic.CurrentDoorState, newPos) - .updateCharacteristic(Characteristic.TargetDoorState, newPos - 2); - accessory.context.cacheCurrentDoorState = newPos; - accessory.context.cacheTargetDoorState = newPos - 2; + .updateCharacteristic(Characteristic.TargetDoorState, newPos - 2) + accessory.context.cacheCurrentDoorState = newPos + accessory.context.cacheTargetDoorState = newPos - 2 setTimeout(() => { - gcService.updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2); - accessory.context.cacheCurrentDoorState = newPos - 2; - }, parseInt(garageConfig.operationTime) * 100); + gcService.updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2) + accessory.context.cacheCurrentDoorState = newPos - 2 + }, parseInt(garageConfig.operationTime) * 100) } setTimeout(() => { - accessory.context.inUse = false; - }, parseInt(garageConfig.operationTime) * 100); + accessory.context.inUse = false + }, parseInt(garageConfig.operationTime) * 100) } catch (err) { - accessory.context.inUse = false; - this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + accessory.context.inUse = false + this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) } } -}; +} diff --git a/lib/device/light.js b/lib/device/light.js index ac838310..42006e45 100644 --- a/lib/device/light.js +++ b/lib/device/light.js @@ -1,287 +1,289 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -let Characteristic, Service; -const convert = require("color-convert"), - utils = require("./../utils"); +'use strict' +let Characteristic, Service +const convert = require('color-convert') +const utils = require('./../utils') module.exports = class deviceLight { - constructor(platform) { - this.platform = platform; - Service = platform.api.hap.Service; - Characteristic = platform.api.hap.Characteristic; + constructor (platform) { + this.platform = platform + Service = platform.api.hap.Service + Characteristic = platform.api.hap.Characteristic } - async internalLightbulbUpdate(accessory, value, callback) { - callback(); + + async internalLightbulbUpdate (accessory, value, callback) { + callback() try { - let oAccessory, - params = {}, - lightService = accessory.getService(Service.Lightbulb); + let oAccessory + const params = {} + const lightService = accessory.getService(Service.Lightbulb) switch (accessory.context.switchNumber) { - case "X": + case 'X': if (accessory.context.eweUIID === 22) { - //*** B1 ***\\ - params.state = value ? "on" : "off"; + //* ** B1 ***\\ + params.state = value ? 'on' : 'off' } else { - params.switch = value ? "on" : "off"; + params.switch = value ? 'on' : 'off' } - break; - case "0": - params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = value ? "on" : "off"; - params.switches[1].switch = value ? "on" : "off"; - params.switches[2].switch = value ? "on" : "off"; - params.switches[3].switch = value ? "on" : "off"; - break; - case "1": - case "2": - case "3": - case "4": - params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + break + case '0': + params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches + params.switches[0].switch = value ? 'on' : 'off' + params.switches[1].switch = value ? 'on' : 'off' + params.switches[2].switch = value ? 'on' : 'off' + params.switches[3].switch = value ? 'on' : 'off' + break + case '1': + case '2': + case '3': + case '4': + params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { i === parseInt(accessory.context.switchNumber) - ? (params.switches[i - 1].switch = value ? "on" : "off") + ? (params.switches[i - 1].switch = value ? 'on' : 'off') : (params.switches[i - 1].switch = oAccessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.On).value - ? "on" - : "off"); + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On).value + ? 'on' + : 'off') } else { - params.switches[i - 1].switch = "off"; + params.switches[i - 1].switch = 'off' } } - break; + break } - await this.platform.sendDeviceUpdate(accessory, params); + await this.platform.sendDeviceUpdate(accessory, params) switch (accessory.context.switchNumber) { - case "X": - lightService.updateCharacteristic(Characteristic.On, value); - break; - case "0": + case 'X': + lightService.updateCharacteristic(Characteristic.On, value) + break + case '0': for (let i = 0; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value); + if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { + oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value) } } - break; - case "1": - case "2": - case "3": - case "4": - lightService.updateCharacteristic(Characteristic.On, value); - let masterState = "off"; + break + case '1': + case '2': + case '3': + case '4': { + lightService.updateCharacteristic(Characteristic.On, value) + let masterState = 'off' for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { if (oAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { - masterState = "on"; + masterState = 'on' } } } if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { - oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, masterState === "on"); + oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW0') + oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, masterState === 'on') } - break; + break + } } } catch (err) { - this.platform.requestDeviceRefresh(accessory, err); + this.platform.requestDeviceRefresh(accessory, err) } } - async internalBrightnessUpdate(accessory, value, callback) { - callback(); + + async internalBrightnessUpdate (accessory, value, callback) { + callback() try { - let params = {}, - lightService = accessory.getService(Service.Lightbulb); + const params = {} + const lightService = accessory.getService(Service.Lightbulb) if (value === 0) { - params.switch = "off"; + params.switch = 'off' } else { if (!lightService.getCharacteristic(Characteristic.On).value) { - params.switch = "on"; + params.switch = 'on' } switch (accessory.context.eweUIID) { - case 36: //*** KING-M4 ***\\ - params.bright = Math.round((value * 9) / 10 + 10); - break; - case 44: //*** D1 ***\\ - params.brightness = value; - params.mode = 0; - break; + case 36: //* ** KING-M4 ***\\ + params.bright = Math.round((value * 9) / 10 + 10) + break + case 44: //* ** D1 ***\\ + params.brightness = value + params.mode = 0 + break } } - await utils.sleep(250); - await this.platform.sendDeviceUpdate(accessory, params); + await utils.sleep(250) + await this.platform.sendDeviceUpdate(accessory, params) if (value === 0) { - lightService.updateCharacteristic(Characteristic.On, false); + lightService.updateCharacteristic(Characteristic.On, false) } else { - lightService.updateCharacteristic(Characteristic.Brightness, value); + lightService.updateCharacteristic(Characteristic.Brightness, value) } } catch (err) { - this.platform.requestDeviceRefresh(accessory, err); + this.platform.requestDeviceRefresh(accessory, err) } } - async internalHSBUpdate(accessory, type, value, callback) { - callback(); + + async internalHSBUpdate (accessory, type, value, callback) { + callback() try { - if (!accessory.context.reachableWAN && !accessory.context.reachableLAN) { - throw "it is currently offline"; - } - let newRGB, - params = {}, - lightService = accessory.getService(Service.Lightbulb), - curHue = lightService.getCharacteristic(Characteristic.Hue).value, - curSat = lightService.getCharacteristic(Characteristic.Saturation).value; + let newRGB + let params = {} + const lightService = accessory.getService(Service.Lightbulb) + const curHue = lightService.getCharacteristic(Characteristic.Hue).value + const curSat = lightService.getCharacteristic(Characteristic.Saturation).value switch (type) { - case "hue": - newRGB = convert.hsv.rgb(value, curSat, 100); + case 'hue': + newRGB = convert.hsv.rgb(value, curSat, 100) switch (accessory.context.eweUIID) { - case 22: //*** B1 ***\\ + case 22: //* ** B1 ***\\ params = { zyx_mode: 2, - type: "middle", - channel0: "0", - channel1: "0", + type: 'middle', + channel0: '0', + channel1: '0', channel2: newRGB[0].toString(), channel3: newRGB[1].toString(), - channel4: newRGB[2].toString(), - }; - break; - case 59: //*** L1 ***\\ + channel4: newRGB[2].toString() + } + break + case 59: //* ** L1 ***\\ params = { mode: 1, colorR: newRGB[0], colorG: newRGB[1], - colorB: newRGB[2], - }; - break; + colorB: newRGB[2] + } + break } - break; - case "bri": + break + case 'bri': switch (accessory.context.eweUIID) { - case 22: //*** B1 ***\\ - newRGB = convert.hsv.rgb(curHue, curSat, value); + case 22: //* ** B1 ***\\ + newRGB = convert.hsv.rgb(curHue, curSat, value) params = { zyx_mode: 2, - type: "middle", - channel0: "0", - channel1: "0", + type: 'middle', + channel0: '0', + channel1: '0', channel2: newRGB[0].toString(), channel3: newRGB[1].toString(), - channel4: newRGB[2].toString(), - }; - break; - case 59: //*** L1 ***\\ + channel4: newRGB[2].toString() + } + break + case 59: //* ** L1 ***\\ params = { mode: 1, - bright: value, - }; - break; + bright: value + } + break } - break; + break } - await utils.sleep(250); - await this.platform.sendDeviceUpdate(accessory, params); + await utils.sleep(250) + await this.platform.sendDeviceUpdate(accessory, params) switch (type) { - case "hue": - lightService.updateCharacteristic(Characteristic.Hue, value); - break; - case "bri": - lightService.updateCharacteristic(Characteristic.Brightness, value); - break; + case 'hue': + lightService.updateCharacteristic(Characteristic.Hue, value) + break + case 'bri': + lightService.updateCharacteristic(Characteristic.Brightness, value) + break } } catch (err) { - this.platform.requestDeviceRefresh(accessory, err); + this.platform.requestDeviceRefresh(accessory, err) } } - externalSingleLightUpdate(accessory, params) { + + externalSingleLightUpdate (accessory, params) { try { - let newColour, - mode, - isOn = false, - lightService = accessory.getService(Service.Lightbulb); - if (accessory.context.eweUIID === 22 && params.hasOwnProperty("state")) { - isOn = params.state === "on"; - } else if (accessory.context.eweUIID !== 22 && params.hasOwnProperty("switch")) { - isOn = params.switch === "on"; + let newColour + let mode + let isOn = false + const lightService = accessory.getService(Service.Lightbulb) + if (accessory.context.eweUIID === 22 && Object.prototype.hasOwnProperty.call(params, 'state')) { + isOn = params.state === 'on' + } else if (accessory.context.eweUIID !== 22 && Object.prototype.hasOwnProperty.call(params, 'switch')) { + isOn = params.switch === 'on' } else { - isOn = lightService.getCharacteristic(Characteristic.On).value; + isOn = lightService.getCharacteristic(Characteristic.On).value } if (isOn) { - lightService.updateCharacteristic(Characteristic.On, true); + lightService.updateCharacteristic(Characteristic.On, true) switch (accessory.context.eweUIID) { case 36: // KING-M4 - if (params.hasOwnProperty("bright")) { - let nb = Math.round(((params.bright - 10) * 10) / 9); // eWeLink scale is 10-100 and HomeKit scale is 0-100. - lightService.updateCharacteristic(Characteristic.Brightness, nb); + if (Object.prototype.hasOwnProperty.call(params, 'bright')) { + const nb = Math.round(((params.bright - 10) * 10) / 9) // eWeLink scale is 10-100 and HomeKit scale is 0-100. + lightService.updateCharacteristic(Characteristic.Brightness, nb) } - break; + break case 44: // D1 - if (params.hasOwnProperty("brightness")) { - lightService.updateCharacteristic(Characteristic.Brightness, params.brightness); + if (Object.prototype.hasOwnProperty.call(params, 'brightness')) { + lightService.updateCharacteristic(Characteristic.Brightness, params.brightness) } - break; + break case 22: // B1 - if (params.hasOwnProperty("zyx_mode")) { - mode = parseInt(params.zyx_mode); - } else if (params.hasOwnProperty("channel0") && parseInt(params.channel0) + parseInt(params.channel1) > 0) { - mode = 1; + if (Object.prototype.hasOwnProperty.call(params, 'zyx_mode')) { + mode = parseInt(params.zyx_mode) + } else if (Object.prototype.hasOwnProperty.call(params, 'channel0') && parseInt(params.channel0) + parseInt(params.channel1) > 0) { + mode = 1 } else { - mode = 2; + mode = 2 } if (mode === 2) { - lightService.updateCharacteristic(Characteristic.On, true); + lightService.updateCharacteristic(Characteristic.On, true) newColour = convert.rgb.hsv( parseInt(params.channel2), parseInt(params.channel3), parseInt(params.channel4) - ); + ) lightService .updateCharacteristic(Characteristic.Hue, newColour[0]) .updateCharacteristic(Characteristic.Saturation, 100) - .updateCharacteristic(Characteristic.Brightness, 100); + .updateCharacteristic(Characteristic.Brightness, 100) } else if (mode === 1) { - throw "has been set to white mode which is not supported"; + throw new Error('has been set to white mode which is not supported') } - break; + break case 59: // L1 - if (params.hasOwnProperty("bright")) { - lightService.updateCharacteristic(Characteristic.Brightness, params.bright); + if (Object.prototype.hasOwnProperty.call(params, 'bright')) { + lightService.updateCharacteristic(Characteristic.Brightness, params.bright) } - if (params.hasOwnProperty("colorR")) { - newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB); + if (Object.prototype.hasOwnProperty.call(params, 'colorR')) { + newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB) lightService .updateCharacteristic(Characteristic.Hue, newColour[0]) - .updateCharacteristic(Characteristic.Saturation, newColour[1]); + .updateCharacteristic(Characteristic.Saturation, newColour[1]) } - break; + break default: - return; + return } } else { - lightService.updateCharacteristic(Characteristic.On, false); + lightService.updateCharacteristic(Characteristic.On, false) } } catch (err) { - this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) } } - externalMultiLightUpdate(accessory, params) { + + externalMultiLightUpdate (accessory, params) { try { - let idToCheck = accessory.context.hbDeviceId.slice(0, -1), - primaryState = false; + const idToCheck = accessory.context.hbDeviceId.slice(0, -1) + let primaryState = false for (let i = 1; i <= accessory.context.channelCount; i++) { if (this.platform.devicesInHB.has(idToCheck + i)) { - let oAccessory = this.platform.devicesInHB.get(idToCheck + i); + const oAccessory = this.platform.devicesInHB.get(idToCheck + i) oAccessory .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); - if (params.switches[i - 1].switch === "on") { - primaryState = true; + .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === 'on') + if (params.switches[i - 1].switch === 'on') { + primaryState = true } } } if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, primaryState); + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, primaryState) } } catch (err) { - this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) } } -}; +} diff --git a/lib/device/lock.js b/lib/device/lock.js index ac74af5e..93278892 100644 --- a/lib/device/lock.js +++ b/lib/device/lock.js @@ -1,67 +1,68 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -let Characteristic, Service; -const utils = require("./../utils"); +'use strict' +let Characteristic, Service +const utils = require('./../utils') module.exports = class deviceLock { - constructor(platform) { - this.platform = platform; - Service = platform.api.hap.Service; - Characteristic = platform.api.hap.Characteristic; + constructor (platform) { + this.platform = platform + Service = platform.api.hap.Service + Characteristic = platform.api.hap.Characteristic } - async internalLockUpdate(accessory, value, callback) { - callback(); + + async internalLockUpdate (accessory, value, callback) { + callback() try { - let lockConfig, - params = { - switch: "on", - }, - lmService = accessory.getService(Service.LockMechanism); + let lockConfig + const params = { + switch: 'on' + } + const lmService = accessory.getService(Service.LockMechanism) if (!(lockConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; + throw new Error('group config missing') } - if (lockConfig.type !== "lock") { - throw "improper configuration"; + if (lockConfig.type !== 'lock') { + throw new Error('improper configuration') } - accessory.context.inUse = true; - await this.platform.sendDeviceUpdate(accessory, params); + accessory.context.inUse = true + await this.platform.sendDeviceUpdate(accessory, params) lmService .updateCharacteristic(Characteristic.LockTargetState, 0) - .updateCharacteristic(Characteristic.LockCurrentState, 0); - await utils.sleep(lockConfig.operationTime * 100); + .updateCharacteristic(Characteristic.LockCurrentState, 0) + await utils.sleep(lockConfig.operationTime * 100) lmService .updateCharacteristic(Characteristic.LockTargetState, 1) - .updateCharacteristic(Characteristic.LockCurrentState, 1); - accessory.context.inUse = false; + .updateCharacteristic(Characteristic.LockCurrentState, 1) + accessory.context.inUse = false } catch (err) { - this.platform.requestDeviceRefresh(accessory, err); + this.platform.requestDeviceRefresh(accessory, err) } } - externalLockUpdate(accessory, params) { + + externalLockUpdate (accessory, params) { try { - let lockConfig, - lmService = accessory.getService(Service.LockMechanism); + let lockConfig + const lmService = accessory.getService(Service.LockMechanism) if (!(lockConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { - throw "group config missing"; + throw new Error('group config missing') } - if (lockConfig.type !== "lock") { - throw "improper configuration"; + if (lockConfig.type !== 'lock') { + throw new Error('improper configuration') } - if (params.switch === "off" || accessory.context.inUse) { - return; + if (params.switch === 'off' || accessory.context.inUse) { + return } - accessory.context.inUse = true; + accessory.context.inUse = true lmService .updateCharacteristic(Characteristic.LockCurrentState, 0) - .updateCharacteristic(Characteristic.LockTargetState, 0); + .updateCharacteristic(Characteristic.LockTargetState, 0) setTimeout(() => { lmService .updateCharacteristic(Characteristic.LockCurrentState, 1) - .updateCharacteristic(Characteristic.LockTargetState, 1); - accessory.context.inUse = false; - }, parseInt(lockConfig.operationTime) * 100); + .updateCharacteristic(Characteristic.LockTargetState, 1) + accessory.context.inUse = false + }, parseInt(lockConfig.operationTime) * 100) } catch (err) { - accessory.context.inUse = false; - this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + accessory.context.inUse = false + this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) } } -}; +} diff --git a/lib/device/outlet.js b/lib/device/outlet.js index a1d7145b..8696dc36 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -1,56 +1,57 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -let Characteristic, EveService, Service; -const hbLib = require("homebridge-lib"); +'use strict' +let Characteristic, EveService, Service +const hbLib = require('homebridge-lib') module.exports = class deviceOutlet { - constructor(platform, homebridge) { - this.platform = platform; - Service = platform.api.hap.Service; - Characteristic = platform.api.hap.Characteristic; - EveService = new hbLib.EveHomeKitTypes(platform.api); + constructor (platform, homebridge) { + this.platform = platform + Service = platform.api.hap.Service + Characteristic = platform.api.hap.Characteristic + EveService = new hbLib.EveHomeKitTypes(platform.api) } - async internalOutletUpdate(accessory, value, callback) { - callback(); + + async internalOutletUpdate (accessory, value, callback) { + callback() try { - let params = { - switch: value ? "on" : "off", - }, - outletService = accessory.getService(Service.Outlet); - await this.platform.sendDeviceUpdate(accessory, params); - outletService.updateCharacteristic(Characteristic.On, value); + const params = { + switch: value ? 'on' : 'off' + } + const outletService = accessory.getService(Service.Outlet) + await this.platform.sendDeviceUpdate(accessory, params) + outletService.updateCharacteristic(Characteristic.On, value) } catch (err) { - this.platform.requestDeviceRefresh(accessory, err); + this.platform.requestDeviceRefresh(accessory, err) } } - externalOutletUpdate(accessory, params) { + + externalOutletUpdate (accessory, params) { try { - let outletService = accessory.getService(Service.Outlet); - if (params.hasOwnProperty("switch")) { - outletService.updateCharacteristic(Characteristic.On, params.switch === "on"); - if (accessory.context.eweModel === "S26" || this.platform.config.disableEveLogging || false) { - outletService.updateCharacteristic(Characteristic.OutletInUse, params.switch === "on"); + const outletService = accessory.getService(Service.Outlet) + if (Object.prototype.hasOwnProperty.call(params, 'switch')) { + outletService.updateCharacteristic(Characteristic.On, params.switch === 'on') + if (accessory.context.eweModel === 'S26' || this.platform.config.disableEveLogging || false) { + outletService.updateCharacteristic(Characteristic.OutletInUse, params.switch === 'on') } } - if (params.hasOwnProperty("power")) { - outletService.updateCharacteristic(EveService.Characteristics.CurrentConsumption, parseFloat(params.power)); + if (Object.prototype.hasOwnProperty.call(params, 'power')) { + outletService.updateCharacteristic(EveService.Characteristics.CurrentConsumption, parseFloat(params.power)) outletService.updateCharacteristic( Characteristic.OutletInUse, parseFloat(params.power) > (this.platform.config.inUsePowerThreshold || 0) - ); - let isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value; + ) + const isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value accessory.eveLogger.addEntry({ time: Date.now(), - power: isOn ? parseFloat(params.power) : 0, - }); + power: isOn ? parseFloat(params.power) : 0 + }) } - if (params.hasOwnProperty("voltage")) { - outletService.updateCharacteristic(EveService.Characteristics.Voltage, parseFloat(params.voltage)); + if (Object.prototype.hasOwnProperty.call(params, 'voltage')) { + outletService.updateCharacteristic(EveService.Characteristics.Voltage, parseFloat(params.voltage)) } - if (params.hasOwnProperty("current")) { - outletService.updateCharacteristic(EveService.Characteristics.ElectricCurrent, parseFloat(params.current)); + if (Object.prototype.hasOwnProperty.call(params, 'current')) { + outletService.updateCharacteristic(EveService.Characteristics.ElectricCurrent, parseFloat(params.current)) } } catch (err) { - this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) } } -}; +} diff --git a/lib/device/rf-sub.js b/lib/device/rf-sub.js index 59dcfb06..3bf3320c 100644 --- a/lib/device/rf-sub.js +++ b/lib/device/rf-sub.js @@ -1,122 +1,123 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -let Characteristic, Service; -const utils = require("./../utils"); +'use strict' +let Characteristic, Service +const utils = require('./../utils') module.exports = class deviceRFSub { - constructor(platform) { - this.platform = platform; - Service = platform.api.hap.Service; - Characteristic = platform.api.hap.Characteristic; + constructor (platform) { + this.platform = platform + Service = platform.api.hap.Service + Characteristic = platform.api.hap.Characteristic } - async internalRFUpdate(accessory, rfChl, service, callback) { - callback(); + + async internalRFUpdate (accessory, rfChl, service, callback) { + callback() try { - let params = { - cmd: "transmit", - rfChl: parseInt(rfChl), - }, - rfService = accessory.getService(service); - await this.platform.sendDeviceUpdate(accessory, params); - rfService.updateCharacteristic(Characteristic.On, true); - await utils.sleep(3000); - rfService.updateCharacteristic(Characteristic.On, false); + const params = { + cmd: 'transmit', + rfChl: parseInt(rfChl) + } + const rfService = accessory.getService(service) + await this.platform.sendDeviceUpdate(accessory, params) + rfService.updateCharacteristic(Characteristic.On, true) + await utils.sleep(3000) + rfService.updateCharacteristic(Characteristic.On, false) } catch (err) { - this.platform.requestDeviceRefresh(accessory, err); + this.platform.requestDeviceRefresh(accessory, err) } } - externalRFUpdate(accessory, params) { + + externalRFUpdate (accessory, params) { try { - if (!params.hasOwnProperty("updateSource")) return; - let timeNow = new Date(), - oAccessory = false; - if (params.hasOwnProperty("cmd") && params.cmd === "transmit" && params.hasOwnProperty("rfChl")) { - //*** RF Button ***\\ + if (!Object.prototype.hasOwnProperty.call(params, 'updateSource')) return + const timeNow = new Date() + let oAccessory = false + if (Object.prototype.hasOwnProperty.call(params, 'cmd') && params.cmd === 'transmit' && Object.prototype.hasOwnProperty.call(params, 'rfChl')) { + //* ** RF Button ***\\ // the device needed is SW% corresponding to params.rfChl this.platform.devicesInHB.forEach(acc => { if ( acc.context.eweDeviceId === accessory.context.eweDeviceId && - acc.context.buttons.hasOwnProperty(params.rfChl.toString()) + Object.prototype.hasOwnProperty.call(acc.context.buttons, params.rfChl.toString()) ) { - oAccessory = acc; + oAccessory = acc } - }); + }) if (oAccessory) { - oAccessory.getService(oAccessory.context.buttons[params.rfChl]).updateCharacteristic(Characteristic.On, 1); + oAccessory.getService(oAccessory.context.buttons[params.rfChl]).updateCharacteristic(Characteristic.On, 1) setTimeout( () => oAccessory .getService(oAccessory.context.buttons[params.rfChl]) .updateCharacteristic(Characteristic.On, 0), 3000 - ); + ) } else { - throw "rf button not found in Homebridge"; + throw new Error('rf button not found in Homebridge') } - } else if (params.hasOwnProperty("cmd") && params.cmd === "trigger") { - //*** RF Sensor ***\\ + } else if (Object.prototype.hasOwnProperty.call(params, 'cmd') && params.cmd === 'trigger') { + //* ** RF Sensor ***\\ Object.keys(params) .filter(name => /rfTrig/.test(name)) .forEach(chan => { this.platform.devicesInHB.forEach(acc => { if ( acc.context.eweDeviceId === accessory.context.eweDeviceId && - acc.context.buttons.hasOwnProperty(chan.substr(-1).toString()) + Object.prototype.hasOwnProperty.call(acc.context.buttons, chan.substr(-1).toString()) ) { - oAccessory = acc; + oAccessory = acc } - }); + }) if (oAccessory) { - let timeOfMotion = new Date(params[chan]), - diff = (timeNow.getTime() - timeOfMotion.getTime()) / 1000, - serv, - char; + const timeOfMotion = new Date(params[chan]) + const diff = (timeNow.getTime() - timeOfMotion.getTime()) / 1000 + let serv + let char if (diff < (this.platform.config.sensorTimeDifference || 120)) { switch (oAccessory.context.sensorType) { - case "button": - break; - case "water": - serv = Service.LeakSensor; - char = Characteristic.LeakDetected; - break; - case "fire": - case "smoke": - serv = Service.SmokeSensor; - char = Characteristic.LeakDetected; - break; - case "co": - serv = Service.CarbonMonoxideSensor; - char = Characteristic.CarbonMonoxideDetected; - break; - case "co2": - serv = Service.CarbonDioxideSensor; - char = Characteristic.CarbonDioxideDetected; - break; - case "contact": - serv = Service.ContactSensor; - char = Characteristic.ContactSensorState; - break; - case "occupancy": - serv = Service.OccupancySensor; - char = Characteristic.OccupancyDetected; - break; + case 'button': + break + case 'water': + serv = Service.LeakSensor + char = Characteristic.LeakDetected + break + case 'fire': + case 'smoke': + serv = Service.SmokeSensor + char = Characteristic.LeakDetected + break + case 'co': + serv = Service.CarbonMonoxideSensor + char = Characteristic.CarbonMonoxideDetected + break + case 'co2': + serv = Service.CarbonDioxideSensor + char = Characteristic.CarbonDioxideDetected + break + case 'contact': + serv = Service.ContactSensor + char = Characteristic.ContactSensorState + break + case 'occupancy': + serv = Service.OccupancySensor + char = Characteristic.OccupancyDetected + break default: - serv = Service.MotionSensor; - char = Characteristic.MotionDetected; - break; + serv = Service.MotionSensor + char = Characteristic.MotionDetected + break } - oAccessory.getService(serv).updateCharacteristic(char, 1); + oAccessory.getService(serv).updateCharacteristic(char, 1) setTimeout(() => { - oAccessory.getService(serv).updateCharacteristic(char, 0); - }, (this.platform.config.sensorTimeLength || 2) * 1000); + oAccessory.getService(serv).updateCharacteristic(char, 0) + }, (this.platform.config.sensorTimeLength || 2) * 1000) if (this.platform.debug) { - this.platform.log("[%s] has detected [%s].", oAccessory.displayName, oAccessory.context.sensorType); + this.platform.log('[%s] has detected [%s].', oAccessory.displayName, oAccessory.context.sensorType) } } } - }); + }) } } catch (err) { - this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) } } -}; +} diff --git a/lib/device/scm.js b/lib/device/scm.js index e424e8eb..276c385f 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -1,32 +1,32 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -let Characteristic, Service; +'use strict' +let Characteristic, Service module.exports = class deviceSCM { - constructor(platform) { - this.platform = platform; - Service = platform.api.hap.Service; - Characteristic = platform.api.hap.Characteristic; + constructor (platform) { + this.platform = platform + Service = platform.api.hap.Service + Characteristic = platform.api.hap.Characteristic } - async internalSCMUpdate(accessory, value, callback) { - callback(); + async internalSCMUpdate (accessory, value, callback) { + callback() try { - let params = { - switches: this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches, - }, - switchService = accessory.getService(Service.Switch); - params.switches[0].switch = value ? "on" : "off"; - await this.platform.sendDeviceUpdate(accessory, params); - switchService.updateCharacteristic(Characteristic.On, value); + const params = { + switches: this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches + } + const switchService = accessory.getService(Service.Switch) + params.switches[0].switch = value ? 'on' : 'off' + await this.platform.sendDeviceUpdate(accessory, params) + switchService.updateCharacteristic(Characteristic.On, value) } catch (err) { - this.platform.requestDeviceRefresh(accessory, err); + this.platform.requestDeviceRefresh(accessory, err) } } - externalSCMUpdate(accessory, params) { + + externalSCMUpdate (accessory, params) { try { - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switches[0].switch === 'on') } catch (err) { - this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) } } -}; +} diff --git a/lib/device/sensor.js b/lib/device/sensor.js index 391d7f08..b16f3a5c 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -1,54 +1,54 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -let Characteristic, Service; +'use strict' +let Characteristic, Service module.exports = class deviceSensor { - constructor(platform) { - this.platform = platform; - Service = platform.api.hap.Service; - Characteristic = platform.api.hap.Characteristic; + constructor (platform) { + this.platform = platform + Service = platform.api.hap.Service + Characteristic = platform.api.hap.Characteristic } - externalSensorUpdate(accessory, params) { + + externalSensorUpdate (accessory, params) { try { - if (params.hasOwnProperty("battery")) { - let batteryService = - accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService), - scaledBattery = Math.round(params.battery * 33.3); - batteryService.updateCharacteristic(Characteristic.BatteryLevel, scaledBattery); + if (Object.prototype.hasOwnProperty.call(params, 'battery')) { + const batteryService = + accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService) + const scaledBattery = Math.round(params.battery * 33.3) + batteryService.updateCharacteristic(Characteristic.BatteryLevel, scaledBattery) batteryService.updateCharacteristic( Characteristic.StatusLowBattery, scaledBattery < (this.platform.config.lowBattThreshold || 25) - ); + ) } - let newState = params.switch === "on" ? 1 : 0, - oAccessory = false, - contactService = accessory.getService(Service.ContactSensor); - contactService.updateCharacteristic(Characteristic.ContactSensorState, newState); + const newState = params.switch === 'on' ? 1 : 0 + let oAccessory = false + const contactService = accessory.getService(Service.ContactSensor) + contactService.updateCharacteristic(Characteristic.ContactSensorState, newState) this.platform.cusG.forEach(group => { - if (group.sensorId === accessory.context.eweDeviceId && group.type === "garage") { - if ((oAccessory = this.platform.devicesInHB.get(group.deviceId + "SWX"))) { + if (group.sensorId === accessory.context.eweDeviceId && group.type === 'garage') { + if ((oAccessory = this.platform.devicesInHB.get(group.deviceId + 'SWX'))) { switch (newState) { case 0: oAccessory .getService(Service.GarageDoorOpener) .updateCharacteristic(Characteristic.TargetDoorState, 1) - .updateCharacteristic(Characteristic.CurrentDoorState, 1); - break; + .updateCharacteristic(Characteristic.CurrentDoorState, 1) + break case 1: setTimeout(() => { oAccessory .getService(Service.GarageDoorOpener) .updateCharacteristic(Characteristic.TargetDoorState, 0) - .updateCharacteristic(Characteristic.CurrentDoorState, 0); - }, group.operationTime * 100); - break; + .updateCharacteristic(Characteristic.CurrentDoorState, 0) + }, group.operationTime * 100) + break default: - throw "unknown sensor status received [" + newState + "]"; + throw new Error('unknown sensor status received [' + newState + ']') } } } - }); + }) } catch (err) { - this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) } } -}; +} diff --git a/lib/device/switch.js b/lib/device/switch.js index e446492a..0f49f802 100644 --- a/lib/device/switch.js +++ b/lib/device/switch.js @@ -1,111 +1,114 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -let Characteristic, Service; +'use strict' +let Characteristic, Service module.exports = class deviceSwitch { - constructor(platform) { - this.platform = platform; - Service = platform.api.hap.Service; - Characteristic = platform.api.hap.Characteristic; + constructor (platform) { + this.platform = platform + Service = platform.api.hap.Service + Characteristic = platform.api.hap.Characteristic } - async internalSwitchUpdate(accessory, value, callback) { - callback(); + + async internalSwitchUpdate (accessory, value, callback) { + callback() try { - let oAccessory, - params = {}, - switchService = accessory.getService(Service.Switch); + let oAccessory + const params = {} + const switchService = accessory.getService(Service.Switch) switch (accessory.context.switchNumber) { - case "X": - params.switch = value ? "on" : "off"; - break; - case "0": - params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches; - params.switches[0].switch = value ? "on" : "off"; - params.switches[1].switch = value ? "on" : "off"; - params.switches[2].switch = value ? "on" : "off"; - params.switches[3].switch = value ? "on" : "off"; - break; - case "1": - case "2": - case "3": - case "4": - params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + case 'X': + params.switch = value ? 'on' : 'off' + break + case '0': + params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches + params.switches[0].switch = value ? 'on' : 'off' + params.switches[1].switch = value ? 'on' : 'off' + params.switches[2].switch = value ? 'on' : 'off' + params.switches[3].switch = value ? 'on' : 'off' + break + case '1': + case '2': + case '3': + case '4': + params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { i === parseInt(accessory.context.switchNumber) - ? (params.switches[i - 1].switch = value ? "on" : "off") + ? (params.switches[i - 1].switch = value ? 'on' : 'off') : (params.switches[i - 1].switch = oAccessory - .getService(Service.Switch) - .getCharacteristic(Characteristic.On).value - ? "on" - : "off"); + .getService(Service.Switch) + .getCharacteristic(Characteristic.On).value + ? 'on' + : 'off') } else { - params.switches[i - 1].switch = "off"; + params.switches[i - 1].switch = 'off' } } - break; + break } - await this.platform.sendDeviceUpdate(accessory, params); + await this.platform.sendDeviceUpdate(accessory, params) switch (accessory.context.switchNumber) { - case "X": - switchService.updateCharacteristic(Characteristic.On, value); - break; - case "0": + case 'X': + switchService.updateCharacteristic(Characteristic.On, value) + break + case '0': for (let i = 0; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { - oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value); + if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { + oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value) } } - break; - case "1": - case "2": - case "3": - case "4": - switchService.updateCharacteristic(Characteristic.On, value); - let masterState = "off"; + break + case '1': + case '2': + case '3': + case '4': { + switchService.updateCharacteristic(Characteristic.On, value) + let masterState = 'off' for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + "SW" + i))) { + if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { if (oAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value) { - masterState = "on"; + masterState = 'on' } } } if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { - oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + "SW0"); - oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, masterState === "on"); + oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW0') + oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, masterState === 'on') } - break; + break + } } } catch (err) { - this.platform.requestDeviceRefresh(accessory, err); + this.platform.requestDeviceRefresh(accessory, err) } } - externalSingleSwitchUpdate(accessory, params) { + + externalSingleSwitchUpdate (accessory, params) { try { - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switch === "on"); + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switch === 'on') } catch (err) { - this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) } } - externalMultiSwitchUpdate(accessory, params) { + + externalMultiSwitchUpdate (accessory, params) { try { - let idToCheck = accessory.context.hbDeviceId.slice(0, -1), - primaryState = false; + const idToCheck = accessory.context.hbDeviceId.slice(0, -1) + let primaryState = false for (let i = 1; i <= accessory.context.channelCount; i++) { if (this.platform.devicesInHB.has(idToCheck + i)) { - let oAccessory = this.platform.devicesInHB.get(idToCheck + i); + const oAccessory = this.platform.devicesInHB.get(idToCheck + i) oAccessory .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === "on"); - if (params.switches[i - 1].switch === "on") { - primaryState = true; + .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === 'on') + if (params.switches[i - 1].switch === 'on') { + primaryState = true } } } if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState); + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState) } } catch (err) { - this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) } } -}; +} diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index dfc0baec..fe076368 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -1,58 +1,59 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -let Characteristic, Service; +'use strict' +let Characteristic, Service module.exports = class deviceThermostat { - constructor(platform, homebridge) { - this.platform = platform; + constructor (platform, homebridge) { + this.platform = platform } - async internalThermostatUpdate(accessory, value, callback) { - callback(); + + async internalThermostatUpdate (accessory, value, callback) { + callback() try { - let params = { - switch: value ? "on" : "off", - mainSwitch: value ? "on" : "off", - }, - switchService = accessory.getService(Service.Switch); - await this.platform.sendDeviceUpdate(accessory, params); - switchService.updateCharacteristic(Characteristic.On, value); + const params = { + switch: value ? 'on' : 'off', + mainSwitch: value ? 'on' : 'off' + } + const switchService = accessory.getService(Service.Switch) + await this.platform.sendDeviceUpdate(accessory, params) + switchService.updateCharacteristic(Characteristic.On, value) } catch (err) { - this.platform.requestDeviceRefresh(accessory, err); + this.platform.requestDeviceRefresh(accessory, err) } } - externalThermostatUpdate(accessory, params) { + + externalThermostatUpdate (accessory, params) { try { if ( !this.platform.config.hideTHSwitch && - (params.hasOwnProperty("switch") || params.hasOwnProperty("mainSwitch")) + (Object.prototype.hasOwnProperty.call(params, 'switch') || Object.prototype.hasOwnProperty.call(params, 'mainSwitch')) ) { - let newState = params.hasOwnProperty("switch") ? params.switch === "on" : params.mainSwitch === "on", - switchService = accessory.getService(Service.Switch); - switchService.updateCharacteristic(Characteristic.On, newState); + const newState = Object.prototype.hasOwnProperty.call(params, 'switch') ? params.switch === 'on' : params.mainSwitch === 'on' + const switchService = accessory.getService(Service.Switch) + switchService.updateCharacteristic(Characteristic.On, newState) } if (!(this.platform.config.disableEveLogging || false)) { - let eveLog = { - time: Date.now(), - }; - if (params.hasOwnProperty("currentTemperature") && accessory.getService(Service.TemperatureSensor)) { - let currentTemp = params.currentTemperature !== "unavailable" ? params.currentTemperature : 0; + const eveLog = { + time: Date.now() + } + if (Object.prototype.hasOwnProperty.call(params, 'currentTemperature') && accessory.getService(Service.TemperatureSensor)) { + const currentTemp = params.currentTemperature !== 'unavailable' ? params.currentTemperature : 0 accessory .getService(Service.TemperatureSensor) - .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); - eveLog.temp = parseFloat(currentTemp); + .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp) + eveLog.temp = parseFloat(currentTemp) } - if (params.hasOwnProperty("currentHumidity") && accessory.getService(Service.HumiditySensor)) { - let currentHumi = params.currentHumidity !== "unavailable" ? params.currentHumidity : 0; + if (Object.prototype.hasOwnProperty.call(params, 'currentHumidity') && accessory.getService(Service.HumiditySensor)) { + const currentHumi = params.currentHumidity !== 'unavailable' ? params.currentHumidity : 0 accessory .getService(Service.HumiditySensor) - .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); - eveLog.humidity = parseFloat(currentHumi); + .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi) + eveLog.humidity = parseFloat(currentHumi) } - if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { - accessory.eveLogger.addEntry(eveLog); + if (Object.prototype.hasOwnProperty.call(eveLog, 'temp') || Object.prototype.hasOwnProperty.call(eveLog, 'humidity')) { + accessory.eveLogger.addEntry(eveLog) } } } catch (err) { - this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) } } -}; +} diff --git a/lib/device/usb.js b/lib/device/usb.js index 7d6e244f..d78cf020 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -1,31 +1,32 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -let Characteristic, Service; +'use strict' +let Characteristic, Service module.exports = class deviceUSB { - constructor(platform) { - this.platform = platform; - Service = platform.api.hap.Service; - Characteristic = platform.api.hap.Characteristic; + constructor (platform) { + this.platform = platform + Service = platform.api.hap.Service + Characteristic = platform.api.hap.Characteristic } - async internalUSBUpdate(accessory, value, callback) { - callback(); + + async internalUSBUpdate (accessory, value, callback) { + callback() try { - let params = { - switches: this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches, - }, - outletService = accessory.getService(Service.Outlet); - params.switches[0].switch = value ? "on" : "off"; - await this.platform.sendDeviceUpdate(accessory, params); - outletService.updateCharacteristic(Characteristic.On, value); + const params = { + switches: this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches + } + const outletService = accessory.getService(Service.Outlet) + params.switches[0].switch = value ? 'on' : 'off' + await this.platform.sendDeviceUpdate(accessory, params) + outletService.updateCharacteristic(Characteristic.On, value) } catch (err) { - this.platform.requestDeviceRefresh(accessory, err); + this.platform.requestDeviceRefresh(accessory, err) } } - externalUSBUpdate(accessory, params) { + + externalUSBUpdate (accessory, params) { try { - accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switches[0].switch === "on"); + accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switches[0].switch === 'on') } catch (err) { - this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) } } -}; +} diff --git a/lib/device/valve.js b/lib/device/valve.js index 6336871d..121f139e 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -1,71 +1,72 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -let Characteristic, Service; +'use strict' +let Characteristic module.exports = class deviceValve { - constructor(platform) { - this.platform = platform; - Service = platform.api.hap.Service; - Characteristic = platform.api.hap.Characteristic; + constructor (platform) { + this.platform = platform + Characteristic = platform.api.hap.Characteristic } - async internalValveUpdate(accessory, valve, value, callback) { - callback(); + + async internalValveUpdate (accessory, valve, value, callback) { + callback() try { - let params = {}, - serviceValve = accessory.getService(valve); - params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches; + const params = {} + const serviceValve = accessory.getService(valve) + params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches switch (valve) { - case "Valve A": - params.switches[0].switch = value ? "on" : "off"; - params.switches[1].switch = accessory.getService("Valve B").getCharacteristic(Characteristic.Active).value - ? "on" - : "off"; - break; - case "Valve B": - params.switches[0].switch = accessory.getService("Valve A").getCharacteristic(Characteristic.Active).value - ? "on" - : "off"; - params.switches[1].switch = value ? "on" : "off"; - break; + case 'Valve A': + params.switches[0].switch = value ? 'on' : 'off' + params.switches[1].switch = accessory.getService('Valve B').getCharacteristic(Characteristic.Active).value + ? 'on' + : 'off' + break + case 'Valve B': + params.switches[0].switch = accessory.getService('Valve A').getCharacteristic(Characteristic.Active).value + ? 'on' + : 'off' + params.switches[1].switch = value ? 'on' : 'off' + break } - params.switches[2].switch = "off"; - params.switches[3].switch = "off"; - await this.platform.sendDeviceUpdate(accessory, params); - serviceValve.updateCharacteristic(Characteristic.Active, value).updateCharacteristic(Characteristic.InUse, value); + params.switches[2].switch = 'off' + params.switches[3].switch = 'off' + await this.platform.sendDeviceUpdate(accessory, params) + serviceValve.updateCharacteristic(Characteristic.Active, value).updateCharacteristic(Characteristic.InUse, value) switch (value) { case 0: - serviceValve.updateCharacteristic(Characteristic.RemainingDuration, 0); - clearTimeout(accessory.getService(valve).timer); - break; - case 1: - let timer = serviceValve.getCharacteristic(Characteristic.SetDuration).value; - serviceValve.updateCharacteristic(Characteristic.RemainingDuration, timer); - serviceValve.timer = setTimeout(() => serviceValve.setCharacteristic(Characteristic.Active, 0), timer * 1000); - break; + serviceValve.updateCharacteristic(Characteristic.RemainingDuration, 0) + clearTimeout(accessory.getService(valve).timer) + break + case 1: { + const timer = serviceValve.getCharacteristic(Characteristic.SetDuration).value + serviceValve.updateCharacteristic(Characteristic.RemainingDuration, timer) + serviceValve.timer = setTimeout(() => serviceValve.setCharacteristic(Characteristic.Active, 0), timer * 1000) + break + } } } catch (err) { - this.platform.requestDeviceRefresh(accessory, err); + this.platform.requestDeviceRefresh(accessory, err) } } - externalValveUpdate(accessory, params) { + + externalValveUpdate (accessory, params) { try { - ["A", "B"].forEach((v, k) => { - let valveService = accessory.getService("Valve " + v); + ['A', 'B'].forEach((v, k) => { + const valveService = accessory.getService('Valve ' + v) valveService - .updateCharacteristic(Characteristic.Active, params.switches[k].switch === "on") - .updateCharacteristic(Characteristic.InUse, params.switches[k].switch === "on"); - if (params.switches[k].switch === "on") { - let timer = valveService.getCharacteristic(Characteristic.SetDuration).value; - valveService.updateCharacteristic(Characteristic.RemainingDuration, timer); + .updateCharacteristic(Characteristic.Active, params.switches[k].switch === 'on') + .updateCharacteristic(Characteristic.InUse, params.switches[k].switch === 'on') + if (params.switches[k].switch === 'on') { + const timer = valveService.getCharacteristic(Characteristic.SetDuration).value + valveService.updateCharacteristic(Characteristic.RemainingDuration, timer) valveService.timer = setTimeout(() => { - valveService.setCharacteristic(Characteristic.Active, 0); - }, timer * 1000); + valveService.setCharacteristic(Characteristic.Active, 0) + }, timer * 1000) } else { - valveService.updateCharacteristic(Characteristic.RemainingDuration, 0); - clearTimeout(valveService.timer); + valveService.updateCharacteristic(Characteristic.RemainingDuration, 0) + clearTimeout(valveService.timer) } - }); + }) } catch (err) { - this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) } } -}; +} diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index 07e64a8f..d4b2f58e 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -1,82 +1,83 @@ -/* jshint esversion: 9, -W014, -W030, node: true */ -"use strict"; -let Characteristic, Service; +'use strict' +let Characteristic, Service module.exports = class deviceZBDev { - constructor(platform) { - this.platform = platform; - Service = platform.api.hap.Service; - Characteristic = platform.api.hap.Characteristic; + constructor (platform) { + this.platform = platform + Service = platform.api.hap.Service + Characteristic = platform.api.hap.Characteristic } - externalZBUpdate(accessory, params) { + + externalZBUpdate (accessory, params) { try { - //*** credit @tasict ***\\ - if (params.hasOwnProperty("battery")) { + //* ** credit @tasict ***\\ + if (Object.prototype.hasOwnProperty.call(params, 'battery')) { if (accessory.context.eweUIID === 3026 && (this.platform.config.ZBDWBatt || false)) { - params.battery *= 10; + params.battery *= 10 } - let batteryService = - accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService); - batteryService.updateCharacteristic(Characteristic.BatteryLevel, params.battery); + const batteryService = + accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService) + batteryService.updateCharacteristic(Characteristic.BatteryLevel, params.battery) batteryService.updateCharacteristic( Characteristic.StatusLowBattery, params.battery < (this.platform.config.lowBattThreshold || 25) - ); + ) } switch (accessory.context.eweUIID) { case 1000: - if (params.hasOwnProperty("key") && [0, 1, 2].includes(params.key)) { + if (Object.prototype.hasOwnProperty.call(params, 'key') && [0, 1, 2].includes(params.key)) { accessory .getService(Service.StatelessProgrammableSwitch) - .updateCharacteristic(Characteristic.ProgrammableSwitchEvent, params.key); + .updateCharacteristic(Characteristic.ProgrammableSwitchEvent, params.key) } - break; - case 1770: - let eveLog = { - time: Date.now(), - }; - if (params.hasOwnProperty("temperature")) { - let currentTemp = parseInt(params.temperature) / 100; + break + case 1770: { + const eveLog = { + time: Date.now() + } + if (Object.prototype.hasOwnProperty.call(params, 'temperature')) { + const currentTemp = parseInt(params.temperature) / 100 accessory .getService(Service.TemperatureSensor) - .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp); - eveLog.temp = parseFloat(currentTemp); + .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp) + eveLog.temp = parseFloat(currentTemp) } - if (params.hasOwnProperty("humidity")) { - let currentHumi = parseInt(params.humidity) / 100; + if (Object.prototype.hasOwnProperty.call(params, 'humidity')) { + const currentHumi = parseInt(params.humidity) / 100 accessory .getService(Service.HumiditySensor) - .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi); - eveLog.humidity = parseFloat(currentHumi); + .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi) + eveLog.humidity = parseFloat(currentHumi) } - if (eveLog.hasOwnProperty("temp") || eveLog.hasOwnProperty("humidity")) { - accessory.eveLogger.addEntry(eveLog); + if (Object.prototype.hasOwnProperty.call(eveLog, 'temp') || Object.prototype.hasOwnProperty.call(eveLog, 'humidity')) { + accessory.eveLogger.addEntry(eveLog) } - break; + break + } case 2026: - if (params.hasOwnProperty("motion") && params.hasOwnProperty("trigTime")) { - let timeNow = new Date(), - diff = (timeNow.getTime() - params.trigTime) / 1000; + if (Object.prototype.hasOwnProperty.call(params, 'motion') && Object.prototype.hasOwnProperty.call(params, 'trigTime')) { + const timeNow = new Date() + const diff = (timeNow.getTime() - params.trigTime) / 1000 accessory .getService(Service.MotionSensor) .updateCharacteristic( Characteristic.MotionDetected, - params.hasOwnProperty("updateSource") && + Object.prototype.hasOwnProperty.call(params, 'updateSource') && params.motion === 1 && diff < (this.platform.config.sensorTimeDifference || 120) - ); - break; + ) + break } - break; + break case 3026: - if (params.hasOwnProperty("lock") && [0, 1].includes(params.lock)) { + if (Object.prototype.hasOwnProperty.call(params, 'lock') && [0, 1].includes(params.lock)) { accessory .getService(Service.ContactSensor) - .updateCharacteristic(Characteristic.ContactSensorState, params.lock); + .updateCharacteristic(Characteristic.ContactSensorState, params.lock) } - break; + break } } catch (err) { - this.platform.log.warn("[%s] could not be updated as %s.", accessory.displayName, err); + this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) } } -}; +} From ab86a1f6df73a4d87593e48db8fd80b32e22be55 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 09:38:46 +0100 Subject: [PATCH 0236/3183] irrigation to custom group --- config.schema.json | 20 +++++++++----------- lib/constants.js | 2 +- lib/device/valve.js | 14 ++++++++++++++ lib/eWeLink.js | 7 ++++--- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/config.schema.json b/config.schema.json index 037b6c42..5e99588c 100644 --- a/config.schema.json +++ b/config.schema.json @@ -88,14 +88,6 @@ "minimum": 10, "maximum": 300 }, - "valveTimeLength": { - "type": "integer", - "title": "Valve Duration", - "description": "The default number of seconds that irrigation valves will run for.", - "default": 20, - "minimum": 10, - "maximum": 1800 - }, "inUsePowerThreshold": { "type": "integer", "title": "Outlet 'In Use' Threshold", @@ -151,6 +143,12 @@ "enum": [ "lock" ] + }, + { + "title": "Irrigation", + "enum": [ + "valve" + ] } ] }, @@ -158,7 +156,7 @@ "type": "string", "title": "Device Setup", "default": "null", - "description": "The device setup. Blinds must be set up with two switches. Please ignore this setting for locks.", + "description": "The device setup. Blinds must be set up with two switches. Please ignore this setting for locks and irrigation.", "oneOf": [ { "title": "One Switch - for up and down", @@ -176,8 +174,8 @@ }, "operationTime": { "type": "integer", - "title": "Operation Time", - "description": "For blinds and garage doors this is the total time in deciseconds to fully open/close the device. For locks this is the time to show the Home app tile as unlocked. Count the time in seconds and multiply by 10, for example 100 for 10 seconds or 75 for 7.5 seconds.", + "title": "Operation Time (Deciseconds)", + "description": "Blinds/garage doors: the time to fully open/close the device. Locks: the time to show as unlocked. Irrigation: the time the valves will open for. This setting is in deciseconds - count the time in seconds and multiply by 10, for example 100 for 10 seconds or 75 for 7.5 seconds.", "default": 100, "minimum": 10, "maximum": 600 diff --git a/lib/constants.js b/lib/constants.js index 1ec671bc..72090079 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -2,6 +2,7 @@ module.exports = { appId: 'oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq', appSecret: '6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM', + allowedGroups: ['blind', 'garage', 'lock', 'valve'], devicesHideable: ['switch', 'light'], devicesNonLAN: [22, 28, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], @@ -38,7 +39,6 @@ module.exports = { devicesValveParams: ['switches'], devicesGarageParams: ['switch', 'switches'], devicesLockParams: ['switch'], - allowedGroups: ['blind', 'garage', 'lock'], paramsToKeep: ['battery', 'bright', 'brightness', 'channel', 'cmd', 'colorB', 'colorG', 'colorR', 'current', 'currentHumidity', 'currentTemperature', 'fan', 'humidity', 'key', 'light', 'lock', 'mainSwitch', 'mode', 'motion', 'online', 'power', 'rfChl', 'rfList', 'rfTrig', 'sensorType', 'setclose', 'speed', 'state', 'switch', 'switches', 'temperature', 'trigTime', 'type', 'voltage', 'zyx_mode'], defaultMultiSwitchOff: [{ switch: 'off', diff --git a/lib/device/valve.js b/lib/device/valve.js index 121f139e..84129895 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -9,7 +9,14 @@ module.exports = class deviceValve { async internalValveUpdate (accessory, valve, value, callback) { callback() try { + let valveConfig const params = {} + if (!(valveConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + throw new Error('group config missing') + } + if (valveConfig.type !== 'valve') { + throw new Error('improper configuration') + } const serviceValve = accessory.getService(valve) params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches switch (valve) { @@ -49,6 +56,13 @@ module.exports = class deviceValve { externalValveUpdate (accessory, params) { try { + let valveConfig + if (!(valveConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + throw new Error('group config missing') + } + if (valveConfig.type !== 'valve') { + throw new Error('improper configuration') + } ['A', 'B'].forEach((v, k) => { const valveService = accessory.getService('Valve ' + v) valveService diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 7ea7569b..30a78aed 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -28,7 +28,7 @@ class eWeLink { constructor (log, config, api) { if (!log || !api || !config) return if (!config.username || !config.password || !config.countryCode) { - log.error('*********** Cannot load homebridge-ewelink ***********') + log.error('*********** Cannot load homebridge-ewelink ************') log.error('eWeLink credentials missing from the Homebridge config.') log.error('*******************************************************') return @@ -183,7 +183,7 @@ class eWeLink { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX', 'sensor') - } else if (device.extra.uiid === 2 && device.brandName === 'coolkit' && device.productModel === '0285') { + } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'valve') { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX', 'valve') @@ -538,6 +538,7 @@ class eWeLink { } case 'valve': { accessory.control = new DeviceValve(this); + let valveConfig = this.platform.cusG.get(accessory.context.hbDeviceId) ['A', 'B'].forEach(v => { let valveService if (!(valveService = accessory.getService('Valve ' + v))) { @@ -546,7 +547,7 @@ class eWeLink { .setCharacteristic(Characteristic.Active, 0) .setCharacteristic(Characteristic.InUse, 0) .setCharacteristic(Characteristic.ValveType, 1) - .setCharacteristic(Characteristic.SetDuration, this.config.valveTimeLength || 120) + .setCharacteristic(Characteristic.SetDuration, Math.round(valveConfig.operationTime / 10) || 120) .addCharacteristic(Characteristic.RemainingDuration) valveService = accessory.getService('Valve ' + v) } From af7271c7785e6cb278d8c0c9ceb5a99bbf18072c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 10:18:02 +0100 Subject: [PATCH 0237/3183] irrigation valve bug --- lib/device/valve.js | 3 ++- lib/eWeLink.js | 17 +++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/device/valve.js b/lib/device/valve.js index 84129895..9feff0c4 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -63,7 +63,8 @@ module.exports = class deviceValve { if (valveConfig.type !== 'valve') { throw new Error('improper configuration') } - ['A', 'B'].forEach((v, k) => { + const arr = ['A', 'B'] + arr.forEach((v, k) => { const valveService = accessory.getService('Valve ' + v) valveService .updateCharacteristic(Characteristic.Active, params.switches[k].switch === 'on') diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 30a78aed..8281a2d7 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -179,14 +179,14 @@ class eWeLink { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX', 'lock') - } else if (cns.devicesSensor.includes(device.extra.uiid)) { - accessory = this.devicesInHB.has(device.deviceid + 'SWX') - ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', 'sensor') } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'valve') { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX', 'valve') + } else if (cns.devicesSensor.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', 'sensor') } else if (cns.devicesFan.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') @@ -537,9 +537,10 @@ class eWeLink { break } case 'valve': { - accessory.control = new DeviceValve(this); - let valveConfig = this.platform.cusG.get(accessory.context.hbDeviceId) - ['A', 'B'].forEach(v => { + accessory.control = new DeviceValve(this) + const valveConfig = this.cusG.get(accessory.context.hbDeviceId) + const arr = ['A', 'B'] + arr.forEach(v => { let valveService if (!(valveService = accessory.getService('Valve ' + v))) { accessory @@ -872,7 +873,7 @@ class eWeLink { } this.devicesInHB.set(accessory.context.hbDeviceId, accessory) } catch (err) { - this.log.warn('[%s] could not be refreshed as %s.', accessory.displayName, err) + this.log.warn('[%s] could not be configured as %s.', accessory.displayName, err) } } From dfcfb64257ebb21c973b0f65b2e4c8ac4337f2d8 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 10:41:27 +0100 Subject: [PATCH 0238/3183] 3.1.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index d667effe..2dcb3e8d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.3-4", + "version": "3.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index c27caff6..1554d21e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.0.3-4", + "version": "3.1.0", "author": "bwp91", "contributors": [ "gbro115", From 12066e1ca040b36cfee424be2c787076cf3578e9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 12:18:13 +0100 Subject: [PATCH 0239/3183] Update eWeLink.js --- lib/eWeLink.js | 97 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 32 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 8281a2d7..4e1fbdbf 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -90,7 +90,7 @@ class eWeLink { this.removeAccessory(a) } }) - //* ** Synchronise devices between eWeLink and Homebridge and set up ws/lan listeners ***\\ + //* ** Synchronise devices between eWeLink and Homebridge and set up WS/LAN listeners ***\\ this.devicesInEW.forEach(d => this.initialiseDevice(d)) this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)) this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)) @@ -596,8 +596,7 @@ class eWeLink { } case 'thermostat': { accessory.control = new DeviceThermostat(this) - const tempService = - accessory.getService(Service.TemperatureSensor) || accessory.addService(Service.TemperatureSensor) + const tempService = accessory.getService(Service.TemperatureSensor) || accessory.addService(Service.TemperatureSensor) let humiService = false if (accessory.context.sensorType !== 'DS18B20') { humiService = accessory.getService(Service.HumiditySensor) || accessory.addService(Service.HumiditySensor) @@ -698,13 +697,15 @@ class eWeLink { power: currentWatt }) }, 300000) - outletService.getCharacteristic(EveService.Characteristics.TotalConsumption).on('get', callback => { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower - } - callback(null, accessory.context.totalEnergy) - }) + outletService + .getCharacteristic(EveService.Characteristics.TotalConsumption) + .on('get', callback => { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower + } + callback(null, accessory.context.totalEnergy) + }) outletService .getCharacteristic(EveService.Characteristics.ResetTotal) .on('set', (value, callback) => { @@ -880,12 +881,16 @@ class eWeLink { refreshAccessory (accessory, newParams) { switch (accessory.context.type) { case 'valve': - if (Object.keys(newParams).some(v => cns.devicesValveParams.includes(v)) && Array.isArray(newParams.switches)) { + if (Object.keys(newParams).some(v => { + cns.devicesValveParams.includes(v) + }) && Array.isArray(newParams.switches)) { accessory.control.externalValveUpdate(accessory, newParams) } return true case 'curtain': - if (Object.keys(newParams).some(v => cns.devicesCurtainParams.includes(v))) { + if (Object.keys(newParams).some(v => { + cns.devicesCurtainParams.includes(v) + })) { accessory.control.externalCurtainUpdate(accessory, newParams) } return true @@ -893,62 +898,82 @@ class eWeLink { return true case 'garage': if ( - Object.keys(newParams).some(v => cns.devicesGarageParams.includes(v)) && - Array.isArray(newParams.switches) + Object.keys(newParams).some(v => { + cns.devicesGarageParams.includes(v) + }) && + Array.isArray(newParams.switches) ) { accessory.control.externalGarageUpdate(accessory, newParams) } return true case 'lock': - if (Object.keys(newParams).some(v => cns.devicesLockParams.includes(v))) { + if (Object.keys(newParams).some(v => { + cns.devicesLockParams.includes(v) + })) { accessory.control.externalLockUpdate(accessory, newParams) } return true case 'sensor': - if (Object.keys(newParams).some(v => cns.devicesSensorParams.includes(v))) { + if (Object.keys(newParams).some(v => { + cns.devicesSensorParams.includes(v) + })) { accessory.control.externalSensorUpdate(accessory, newParams) } return true case 'fan': - if (Object.keys(newParams).some(v => cns.devicesFanParams.includes(v))) { + if (Object.keys(newParams).some(v => { + cns.devicesFanParams.includes(v) + })) { accessory.control.externalFanUpdate(accessory, newParams) } return true case 'thermostat': - if (Object.keys(newParams).some(v => cns.devicesThermostatParams.includes(v))) { + if (Object.keys(newParams).some(v => { + cns.devicesThermostatParams.includes(v) + })) { accessory.control.externalThermostatUpdate(accessory, newParams) } return true case 'outlet': - if (Object.keys(newParams).some(v => cns.devicesOutletParams.includes(v))) { + if (Object.keys(newParams).some(v => { + cns.devicesOutletParams.includes(v) + })) { accessory.control.externalOutletUpdate(accessory, newParams) } return true case 'usb': - if (Object.keys(newParams).some(v => cns.devicesUSBParams.includes(v)) && Array.isArray(newParams.switches)) { + if (Object.keys(newParams).some(v => { + cns.devicesUSBParams.includes(v) + }) && Array.isArray(newParams.switches)) { accessory.control.externalUSBUpdate(accessory, newParams) } return true case 'scm': - if (Object.keys(newParams).some(v => cns.devicesSCMParams.includes(v)) && Array.isArray(newParams.switches)) { + if (Object.keys(newParams).some(v => { + cns.devicesSCMParams.includes(v) + }) && Array.isArray(newParams.switches)) { accessory.control.externalSCMUpdate(accessory, newParams) } return true case 'light': if ( cns.devicesSingleSwitch.includes(accessory.context.eweUIID) && - cns.devicesSingleSwitchLight.includes(accessory.context.eweModel) + cns.devicesSingleSwitchLight.includes(accessory.context.eweModel) ) { - if (Object.keys(newParams).some(v => cns.devicesSingleSwitchLightParams.includes(v))) { + if (Object.keys(newParams).some(v => { + cns.devicesSingleSwitchLightParams.includes(v) + })) { accessory.control.externalSingleLightUpdate(accessory, newParams) } } else if ( cns.devicesMultiSwitch.includes(accessory.context.eweUIID) && - cns.devicesMultiSwitchLight.includes(accessory.context.eweModel) + cns.devicesMultiSwitchLight.includes(accessory.context.eweModel) ) { if ( - Object.keys(newParams).some(v => cns.devicesMultiSwitchLightParams.includes(v)) && - Array.isArray(newParams.switches) + Object.keys(newParams).some(v => { + cns.devicesMultiSwitchLightParams.includes(v) + }) && + Array.isArray(newParams.switches) ) { accessory.control.externalMultiLightUpdate(accessory, newParams) } @@ -956,27 +981,35 @@ class eWeLink { return true case 'switch': if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID)) { - if (Object.keys(newParams).some(v => cns.devicesSingleSwitchParams.includes(v))) { + if (Object.keys(newParams).some(v => { + cns.devicesSingleSwitchParams.includes(v) + })) { accessory.control.externalSingleSwitchUpdate(accessory, newParams) } } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID)) { if ( - Object.keys(newParams).some(v => cns.devicesMultiSwitchParams.includes(v)) && - Array.isArray(newParams.switches) + Object.keys(newParams).some(v => { + cns.devicesMultiSwitchParams.includes(v) + }) && + Array.isArray(newParams.switches) ) { accessory.control.externalMultiSwitchUpdate(accessory, newParams) } } return true case 'rf_pri': - if (Object.keys(newParams).some(v => cns.devicesRFBridgeParams.includes(v))) { + if (Object.keys(newParams).some(v => { + cns.devicesRFBridgeParams.includes(v) + })) { accessory.control.externalRFUpdate(accessory, newParams) } return true case 'rf_sub': return true case 'zb_dev': - if (Object.keys(newParams).some(v => cns.devicesZBBridgeParams.includes(v))) { + if (Object.keys(newParams).some(v => { + cns.devicesZBBridgeParams.includes(v) + })) { accessory.control.externalZBUpdate(accessory, newParams) } return true @@ -1017,7 +1050,7 @@ class eWeLink { throw new Error(err) } } else { - throw new Error("it is unreachable. I's status will be corrected once it is reachable") + throw new Error("it is unreachable. It's status will be corrected once it is reachable") } } } From febc689ac8b34b6a390db38a98b258bf16fd87e3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 12:22:10 +0100 Subject: [PATCH 0240/3183] Update eWeLink.js --- lib/eWeLink.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 4e1fbdbf..b4f5e8a8 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -900,8 +900,7 @@ class eWeLink { if ( Object.keys(newParams).some(v => { cns.devicesGarageParams.includes(v) - }) && - Array.isArray(newParams.switches) + }) && Array.isArray(newParams.switches) ) { accessory.control.externalGarageUpdate(accessory, newParams) } @@ -958,7 +957,7 @@ class eWeLink { case 'light': if ( cns.devicesSingleSwitch.includes(accessory.context.eweUIID) && - cns.devicesSingleSwitchLight.includes(accessory.context.eweModel) + cns.devicesSingleSwitchLight.includes(accessory.context.eweModel) ) { if (Object.keys(newParams).some(v => { cns.devicesSingleSwitchLightParams.includes(v) @@ -967,13 +966,12 @@ class eWeLink { } } else if ( cns.devicesMultiSwitch.includes(accessory.context.eweUIID) && - cns.devicesMultiSwitchLight.includes(accessory.context.eweModel) + cns.devicesMultiSwitchLight.includes(accessory.context.eweModel) ) { if ( Object.keys(newParams).some(v => { cns.devicesMultiSwitchLightParams.includes(v) - }) && - Array.isArray(newParams.switches) + }) && Array.isArray(newParams.switches) ) { accessory.control.externalMultiLightUpdate(accessory, newParams) } @@ -990,8 +988,7 @@ class eWeLink { if ( Object.keys(newParams).some(v => { cns.devicesMultiSwitchParams.includes(v) - }) && - Array.isArray(newParams.switches) + }) && Array.isArray(newParams.switches) ) { accessory.control.externalMultiSwitchUpdate(accessory, newParams) } From 575fcd7c36cc25ca746aa78bf8b0bbdfe8885c9e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 12:23:33 +0100 Subject: [PATCH 0241/3183] 3.1.1-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2dcb3e8d..1152196f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.0", + "version": "3.1.1-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1554d21e..7e30e8f7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.0", + "version": "3.1.1-0", "author": "bwp91", "contributors": [ "gbro115", From 6034b461a24d43950a086cb7854c7c796a320fea Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 15:43:09 +0100 Subject: [PATCH 0242/3183] catch lan stop error --- lib/eWeLinkLAN.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index a14d8cda..d0982e59 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -180,7 +180,9 @@ module.exports = class eWeLinkLAN { } closeConnection () { - dns.stopMonitoring() + dns.stopMonitoring().catch(err) => { + if (this.debug) this.log.warn(err); + }) this.log('LAN monitoring gracefully stopped.') } } From 33bbc5dc34b6b8878f96c1cff90a6bc874c76d05 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 15:44:55 +0100 Subject: [PATCH 0243/3183] 3.1.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1152196f..e5221ca0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.1-0", + "version": "3.1.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 7e30e8f7..3b696966 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.1-0", + "version": "3.1.1", "author": "bwp91", "contributors": [ "gbro115", From f4f2330e8a338ad47cdaa43a614701db7f35938b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 15:53:03 +0100 Subject: [PATCH 0244/3183] Update eWeLinkLAN.js --- lib/eWeLinkLAN.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index d0982e59..f2f49e1f 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -180,7 +180,7 @@ module.exports = class eWeLinkLAN { } closeConnection () { - dns.stopMonitoring().catch(err) => { + dns.stopMonitoring().catch(err => { if (this.debug) this.log.warn(err); }) this.log('LAN monitoring gracefully stopped.') From c9e1f5aa77f8642c79c4ad3e779887bae801dc70 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 15:53:38 +0100 Subject: [PATCH 0245/3183] 3.1.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index e5221ca0..0b9fccd4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.1", + "version": "3.1.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 3b696966..f7d967f0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.1", + "version": "3.1.2", "author": "bwp91", "contributors": [ "gbro115", From 2962a8f8f4731f10e6c8d7c445171358213066f7 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 16:42:44 +0100 Subject: [PATCH 0246/3183] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d8a98c3f..1c683be2 100644 --- a/README.md +++ b/README.md @@ -35,3 +35,5 @@ * [Support Request](https://github.com/bwp91/homebridge-ewelink/issues/new/choose) * [Roadmap](https://github.com/bwp91/homebridge-ewelink/wiki/Roadmap) * [Credits](https://github.com/bwp91/homebridge-ewelink/wiki/Credits) +### Disclaimer +I am in no way affiliated with eWeLink nor any of the device brands (like Sonoff) and this plugin is a personal project that I maintain in my free time. From 3c4e603b0785f9f5fb5d77ace0a396d919422f66 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 21:46:02 +0100 Subject: [PATCH 0247/3183] random fixes --- lib/device/thermostat.js | 40 +++++++------- lib/eWeLink.js | 111 +++++++-------------------------------- lib/eWeLinkHTTP.js | 8 +-- lib/eWeLinkLAN.js | 16 +++--- lib/eWeLinkWS.js | 4 +- 5 files changed, 56 insertions(+), 123 deletions(-) diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index fe076368..a5d5f2b0 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -1,8 +1,10 @@ 'use strict' let Characteristic, Service module.exports = class deviceThermostat { - constructor (platform, homebridge) { + constructor (platform) { this.platform = platform + Service = platform.api.hap.Service + Characteristic = platform.api.hap.Characteristic } async internalThermostatUpdate (accessory, value, callback) { @@ -30,24 +32,24 @@ module.exports = class deviceThermostat { const switchService = accessory.getService(Service.Switch) switchService.updateCharacteristic(Characteristic.On, newState) } - if (!(this.platform.config.disableEveLogging || false)) { - const eveLog = { - time: Date.now() - } - if (Object.prototype.hasOwnProperty.call(params, 'currentTemperature') && accessory.getService(Service.TemperatureSensor)) { - const currentTemp = params.currentTemperature !== 'unavailable' ? params.currentTemperature : 0 - accessory - .getService(Service.TemperatureSensor) - .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp) - eveLog.temp = parseFloat(currentTemp) - } - if (Object.prototype.hasOwnProperty.call(params, 'currentHumidity') && accessory.getService(Service.HumiditySensor)) { - const currentHumi = params.currentHumidity !== 'unavailable' ? params.currentHumidity : 0 - accessory - .getService(Service.HumiditySensor) - .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi) - eveLog.humidity = parseFloat(currentHumi) - } + const eveLog = { + time: Date.now() + } + if (Object.prototype.hasOwnProperty.call(params, 'currentTemperature') && accessory.getService(Service.TemperatureSensor)) { + const currentTemp = parseFloat(params.currentTemperature !== 'unavailable' ? params.currentTemperature : 0) + accessory + .getService(Service.TemperatureSensor) + .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp) + eveLog.temp = currentTemp + } + if (Object.prototype.hasOwnProperty.call(params, 'currentHumidity') && accessory.getService(Service.HumiditySensor)) { + const currentHumi = parseFloat(params.currentHumidity !== 'unavailable' ? params.currentHumidity : 0) + accessory + .getService(Service.HumiditySensor) + .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi) + eveLog.humidity = currentHumi + } + if (!this.platform.config.disableEveLogging) { if (Object.prototype.hasOwnProperty.call(eveLog, 'temp') || Object.prototype.hasOwnProperty.call(eveLog, 'humidity')) { accessory.eveLogger.addEntry(eveLog) } diff --git a/lib/eWeLink.js b/lib/eWeLink.js index b4f5e8a8..fa08826e 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -311,7 +311,7 @@ class eWeLink { : this.addAccessory(device, device.deviceid + 'SW0', 'rf_pri', true, { rfMap }) - this.log.error(JSON.stringify(accessory.context, null, 2)) + // this.log.error(JSON.stringify(accessory.context, null, 2)) rfMap.forEach(subDevice => { const swNumber = rfChlCounter + 1 let subAccessory @@ -351,7 +351,7 @@ class eWeLink { subAccessory.context.reachableWAN = device.online subAccessory.context.reachableLAN = false this.devicesInHB.set(subAccessory.context.hbDeviceId, subAccessory) - this.log.warn(JSON.stringify(subAccessory.context, null, 2)) + // this.log.warn(JSON.stringify(subAccessory.context, null, 2)) rfChlCounter += Object.keys(subDevice.buttons || {}).length }) accessory.context.channelCount = rfChlCounter @@ -410,7 +410,7 @@ class eWeLink { } this.log(' → [%s] initialised %s.', device.name, str) this.devicesInHB.set(accessory.context.hbDeviceId, accessory) - if (!(this.config.disableHTTPRefresh || false)) { + if (!this.config.disableHTTPRefresh && !(accessory.context.switchNumber === '0' && this.hiddenMasters.includes(device.deviceid))) { if (!this.refreshAccessory(accessory, device.params)) { this.log.warn( '[%s] could not be initialised. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.) [debug:%s:%s].', @@ -881,134 +881,64 @@ class eWeLink { refreshAccessory (accessory, newParams) { switch (accessory.context.type) { case 'valve': - if (Object.keys(newParams).some(v => { - cns.devicesValveParams.includes(v) - }) && Array.isArray(newParams.switches)) { - accessory.control.externalValveUpdate(accessory, newParams) - } + accessory.control.externalValveUpdate(accessory, newParams) return true case 'curtain': - if (Object.keys(newParams).some(v => { - cns.devicesCurtainParams.includes(v) - })) { - accessory.control.externalCurtainUpdate(accessory, newParams) - } + accessory.control.externalCurtainUpdate(accessory, newParams) return true case 'blind': return true case 'garage': - if ( - Object.keys(newParams).some(v => { - cns.devicesGarageParams.includes(v) - }) && Array.isArray(newParams.switches) - ) { - accessory.control.externalGarageUpdate(accessory, newParams) - } + accessory.control.externalGarageUpdate(accessory, newParams) return true case 'lock': - if (Object.keys(newParams).some(v => { - cns.devicesLockParams.includes(v) - })) { - accessory.control.externalLockUpdate(accessory, newParams) - } + accessory.control.externalLockUpdate(accessory, newParams) return true case 'sensor': - if (Object.keys(newParams).some(v => { - cns.devicesSensorParams.includes(v) - })) { - accessory.control.externalSensorUpdate(accessory, newParams) - } + accessory.control.externalSensorUpdate(accessory, newParams) return true case 'fan': - if (Object.keys(newParams).some(v => { - cns.devicesFanParams.includes(v) - })) { - accessory.control.externalFanUpdate(accessory, newParams) - } + accessory.control.externalFanUpdate(accessory, newParams) return true case 'thermostat': - if (Object.keys(newParams).some(v => { - cns.devicesThermostatParams.includes(v) - })) { - accessory.control.externalThermostatUpdate(accessory, newParams) - } + accessory.control.externalThermostatUpdate(accessory, newParams) return true case 'outlet': - if (Object.keys(newParams).some(v => { - cns.devicesOutletParams.includes(v) - })) { - accessory.control.externalOutletUpdate(accessory, newParams) - } + accessory.control.externalOutletUpdate(accessory, newParams) return true case 'usb': - if (Object.keys(newParams).some(v => { - cns.devicesUSBParams.includes(v) - }) && Array.isArray(newParams.switches)) { - accessory.control.externalUSBUpdate(accessory, newParams) - } + accessory.control.externalUSBUpdate(accessory, newParams) return true case 'scm': - if (Object.keys(newParams).some(v => { - cns.devicesSCMParams.includes(v) - }) && Array.isArray(newParams.switches)) { - accessory.control.externalSCMUpdate(accessory, newParams) - } + accessory.control.externalSCMUpdate(accessory, newParams) return true case 'light': if ( cns.devicesSingleSwitch.includes(accessory.context.eweUIID) && cns.devicesSingleSwitchLight.includes(accessory.context.eweModel) ) { - if (Object.keys(newParams).some(v => { - cns.devicesSingleSwitchLightParams.includes(v) - })) { - accessory.control.externalSingleLightUpdate(accessory, newParams) - } + accessory.control.externalSingleLightUpdate(accessory, newParams) } else if ( cns.devicesMultiSwitch.includes(accessory.context.eweUIID) && cns.devicesMultiSwitchLight.includes(accessory.context.eweModel) ) { - if ( - Object.keys(newParams).some(v => { - cns.devicesMultiSwitchLightParams.includes(v) - }) && Array.isArray(newParams.switches) - ) { - accessory.control.externalMultiLightUpdate(accessory, newParams) - } + accessory.control.externalMultiLightUpdate(accessory, newParams) } return true case 'switch': if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID)) { - if (Object.keys(newParams).some(v => { - cns.devicesSingleSwitchParams.includes(v) - })) { - accessory.control.externalSingleSwitchUpdate(accessory, newParams) - } + accessory.control.externalSingleSwitchUpdate(accessory, newParams) } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID)) { - if ( - Object.keys(newParams).some(v => { - cns.devicesMultiSwitchParams.includes(v) - }) && Array.isArray(newParams.switches) - ) { - accessory.control.externalMultiSwitchUpdate(accessory, newParams) - } + accessory.control.externalMultiSwitchUpdate(accessory, newParams) } return true case 'rf_pri': - if (Object.keys(newParams).some(v => { - cns.devicesRFBridgeParams.includes(v) - })) { - accessory.control.externalRFUpdate(accessory, newParams) - } + accessory.control.externalRFUpdate(accessory, newParams) return true case 'rf_sub': return true case 'zb_dev': - if (Object.keys(newParams).some(v => { - cns.devicesZBBridgeParams.includes(v) - })) { - accessory.control.externalZBUpdate(accessory, newParams) - } + accessory.control.externalZBUpdate(accessory, newParams) return true default: return false @@ -1034,11 +964,10 @@ class eWeLink { try { await utils.sleep(Math.random() * 100 + 200) await this.lanClient.sendUpdate(payload) - return } catch (err) { if (accessory.context.reachableWAN) { if (this.debug) { - this.log.warn('[%s] Reverting to web socket as %s.', accessory.displayName, err) + this.log.warn('[%s] Reverting to web socket as %s.', accessory.displayName, err.message) } try { await this.wsClient.sendUpdate(payload) diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 61572545..292de844 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -85,7 +85,7 @@ module.exports = class eWeLinkHTTP { await utils.sleep(30000) return this.getHost() } else { - throw new Error(err.message || err) + throw err } } } @@ -171,7 +171,7 @@ module.exports = class eWeLinkHTTP { } } } catch (err) { - throw new Error(err.message || err) + throw err } } @@ -216,7 +216,7 @@ module.exports = class eWeLinkHTTP { await utils.sleep(30000) return this.getDevices() } else { - throw new Error(err.message || err) + throw err } } } @@ -260,7 +260,7 @@ module.exports = class eWeLinkHTTP { await utils.sleep(30000) return this.getDevice(deviceId) } else { - throw new Error(err.message || err) + throw err } } } diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index f2f49e1f..5a121315 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -42,7 +42,7 @@ module.exports = class eWeLinkLAN { }) return this.deviceMap } catch (err) { - throw new Error(err) + throw err } } @@ -163,7 +163,7 @@ module.exports = class eWeLinkLAN { } } } catch (err) { - throw new Error(err) + throw err } } @@ -179,10 +179,12 @@ module.exports = class eWeLinkLAN { }) } - closeConnection () { - dns.stopMonitoring().catch(err => { - if (this.debug) this.log.warn(err); - }) - this.log('LAN monitoring gracefully stopped.') + async closeConnection () { + try { + await dns.stopMonitoring() + this.log('LAN monitoring gracefully stopped.') + } catch (err) { + throw err + } } } diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 647eb091..9478517b 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -54,7 +54,7 @@ module.exports = class eWeLinkWS { await utils.sleep(30000) return this.getDevices() } else { - throw new Error(err.message || err) + throw err } } } @@ -310,7 +310,7 @@ module.exports = class eWeLinkWS { this.log('Web socket gracefully closed.') return } catch (err) { - throw new Error(err) + throw err } } } From 66909899291bc842a6b66e1b112f78ad3e63b225 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 21:46:42 +0100 Subject: [PATCH 0248/3183] 3.1.3-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0b9fccd4..95960a98 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.2", + "version": "3.1.3-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f7d967f0..0b048b64 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.2", + "version": "3.1.3-0", "author": "bwp91", "contributors": [ "gbro115", From c0173c8edf0575114268c9cda9b8c2ad0aa7b2a0 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 22:09:22 +0100 Subject: [PATCH 0249/3183] Update eWeLink.js --- lib/eWeLink.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index fa08826e..1e818b4e 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -201,6 +201,11 @@ class eWeLink { if (!Object.prototype.hasOwnProperty.call(accessory.context, 'sensorType')) { accessory.context.sensorType = device.params.sensorType } + if (accessory.context.sensorType === 'DS18B20') { + if (accessory.getService(Service.HumiditySensor)) { + accessory.removeService(Service.HumiditySensor) + } + } //* ** @ENDUPGRADE ***\\ if (accessory.context.sensorType !== device.params.sensorType) { accessory.context.sensorType = device.params.sensorType @@ -600,10 +605,6 @@ class eWeLink { let humiService = false if (accessory.context.sensorType !== 'DS18B20') { humiService = accessory.getService(Service.HumiditySensor) || accessory.addService(Service.HumiditySensor) - } else { - if (accessory.getService(Service.HumiditySensor)) { - accessory.removeService(Service.HumiditySensor) - } } if (!this.config.hideTHSwitch) { const switchService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch) @@ -611,7 +612,7 @@ class eWeLink { .getCharacteristic(Characteristic.On) .on('set', (value, callback) => accessory.control.internalThermostatUpdate(accessory, value, callback)) } - if (!(this.config.disableEveLogging || false)) { + if (!this.config.disableEveLogging) { accessory.log = this.log accessory.eveLogger = new EveHistoryService('weather', accessory, { storage: 'fs', From ab59289c483ab6a0c14042aba2bb9e9ce2195121 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 22:10:07 +0100 Subject: [PATCH 0250/3183] 3.1.3-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 95960a98..b79c5a20 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.3-0", + "version": "3.1.3-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 0b048b64..1700b110 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.3-0", + "version": "3.1.3-1", "author": "bwp91", "contributors": [ "gbro115", From 48d97100d0d90c2d2ed3d108e320380c1dd4c7cf Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 22:22:13 +0100 Subject: [PATCH 0251/3183] no-useless-catch --- lib/eWeLinkHTTP.js | 140 ++++++++++++++++++++++----------------------- lib/eWeLinkLAN.js | 140 ++++++++++++++++++++------------------------- lib/eWeLinkWS.js | 9 +-- 3 files changed, 133 insertions(+), 156 deletions(-) diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 292de844..10df3508 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -95,83 +95,79 @@ module.exports = class eWeLinkHTTP { countryCode: this.cCode, password: this.password } - try { - this.username.includes('@') - ? (data.email = this.username) - : (data.phoneNumber = this.username) - if (this.debugReqRes) { - const msg = JSON.stringify(data, null, 2) - .replace(this.password, '**hidden**') - .replace(this.username, '**hidden**') - this.log.warn( - 'Sending HTTP login request. This text is yellow for clarity.\n%s', - msg - ) - } else if (this.debug) { - this.log('Sending HTTP login request.') - } - const dataToSign = crypto - .createHmac('sha256', constants.appSecret) - .update(JSON.stringify(data)) - .digest('base64') - const res = await axios.post( - 'https://' + this.httpHost + '/v2/user/login', - data, { - headers: { - Authorization: 'Sign ' + dataToSign, - 'Content-Type': 'application/json', - Host: this.httpHost, - 'X-CK-Appid': constants.appId, - 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) - } - } + this.username.includes('@') + ? (data.email = this.username) + : (data.phoneNumber = this.username) + if (this.debugReqRes) { + const msg = JSON.stringify(data, null, 2) + .replace(this.password, '**hidden**') + .replace(this.username, '**hidden**') + this.log.warn( + 'Sending HTTP login request. This text is yellow for clarity.\n%s', + msg ) - const body = res.data - if ( - Object.prototype.hasOwnProperty.call(body, 'error') && - body.error === 10004 && - Object.prototype.hasOwnProperty.call(body, 'data') && - Object.prototype.hasOwnProperty.call(body.data, 'region') - ) { - const givenRegion = body.data.region - switch (givenRegion) { - case 'eu': - case 'us': - case 'as': - this.httpHost = givenRegion + '-apia.coolkit.cc' - break - case 'cn': - this.httpHost = 'cn-apia.coolkit.cn' - break - default: - throw new Error('No valid region received - [' + givenRegion + '].') - } - if (this.debug) { - this.log('New HTTP API host received [%s].', this.httpHost) + } else if (this.debug) { + this.log('Sending HTTP login request.') + } + const dataToSign = crypto + .createHmac('sha256', constants.appSecret) + .update(JSON.stringify(data)) + .digest('base64') + const res = await axios.post( + 'https://' + this.httpHost + '/v2/user/login', + data, { + headers: { + Authorization: 'Sign ' + dataToSign, + 'Content-Type': 'application/json', + Host: this.httpHost, + 'X-CK-Appid': constants.appId, + 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) } - return this.login() } - if (body.data.at) { - this.aToken = body.data.at - this.apiKey = body.data.user.apikey - return { - aToken: this.aToken, - apiKey: this.apiKey, - httpHost: this.httpHost - } + ) + const body = res.data + if ( + Object.prototype.hasOwnProperty.call(body, 'error') && + body.error === 10004 && + Object.prototype.hasOwnProperty.call(body, 'data') && + Object.prototype.hasOwnProperty.call(body.data, 'region') + ) { + const givenRegion = body.data.region + switch (givenRegion) { + case 'eu': + case 'us': + case 'as': + this.httpHost = givenRegion + '-apia.coolkit.cc' + break + case 'cn': + this.httpHost = 'cn-apia.coolkit.cn' + break + default: + throw new Error('No valid region received - [' + givenRegion + '].') + } + if (this.debug) { + this.log('New HTTP API host received [%s].', this.httpHost) + } + return this.login() + } + if (body.data.at) { + this.aToken = body.data.at + this.apiKey = body.data.user.apikey + return { + aToken: this.aToken, + apiKey: this.apiKey, + httpHost: this.httpHost + } + } else { + if (body.error === 500) { + this.log.warn( + 'An eWeLink error [500] occured. Retrying in 30 seconds.' + ) + await utils.sleep(30000) + return this.login() } else { - if (body.error === 500) { - this.log.warn( - 'An eWeLink error [500] occured. Retrying in 30 seconds.' - ) - await utils.sleep(30000) - return this.login() - } else { - throw new Error('No auth token received.\n' + JSON.stringify(body, null, 2)) - } + throw new Error('No auth token received.\n' + JSON.stringify(body, null, 2)) } - } catch (err) { - throw err } } diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 5a121315..7d4a7226 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -23,27 +23,23 @@ module.exports = class eWeLinkLAN { } async getHosts () { - try { - const res = await dns.discover({ - name: '_ewelink._tcp.local' - }) - res.forEach(device => { - let d - const deviceId = device.fqdn.replace('._ewelink._tcp.local', '').replace('eWeLink_', '') - if ((d = this.deviceMap.get(deviceId))) { - if (!Object.prototype.hasOwnProperty.call(this.ipOverrides, deviceId)) { - this.deviceMap.set(deviceId, { - apiKey: d.apiKey, - online: true, - ip: device.address - }) - } + const res = await dns.discover({ + name: '_ewelink._tcp.local' + }) + res.forEach(device => { + let d + const deviceId = device.fqdn.replace('._ewelink._tcp.local', '').replace('eWeLink_', '') + if ((d = this.deviceMap.get(deviceId))) { + if (!Object.prototype.hasOwnProperty.call(this.ipOverrides, deviceId)) { + this.deviceMap.set(deviceId, { + apiKey: d.apiKey, + online: true, + ip: device.address + }) } - }) - return this.deviceMap - } catch (err) { - throw err - } + } + }) + return this.deviceMap } startMonitor () { @@ -110,60 +106,54 @@ module.exports = class eWeLinkLAN { } async sendUpdate (json) { - try { - if (!this.deviceMap.get(json.deviceid).online) { - throw new Error("device isn't reachable via LAN mode") + if (!this.deviceMap.get(json.deviceid).online) { + throw new Error("device isn't reachable via LAN mode") + } + let apiKey + let suffix + const params = {} + if (Object.prototype.hasOwnProperty.call(json.params, 'switches')) { + params.switches = json.params.switches + suffix = 'switches' + } else if (Object.prototype.hasOwnProperty.call(json.params, 'switch')) { + params.switch = json.params.switch + suffix = 'switch' + } else { + throw new Error("device isn't reachable via LAN mode") + } + if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { + const key = crypto.createHash('md5').update(Buffer.from(apiKey, 'utf8')).digest() + const iv = crypto.randomBytes(16) + const enc = crypto.createCipheriv('aes-128-cbc', key, iv) + const data = { + data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString('base64'), + deviceid: json.deviceid, + encrypt: true, + iv: iv.toString('base64'), + selfApikey: '123', + sequence: Date.now().toString() } - let apiKey - let suffix - const params = {} - if (Object.prototype.hasOwnProperty.call(json.params, 'switches')) { - params.switches = json.params.switches - suffix = 'switches' - } else if (Object.prototype.hasOwnProperty.call(json.params, 'switch')) { - params.switch = json.params.switch - suffix = 'switch' - } else { - throw new Error("device isn't reachable via LAN mode") + if (this.debugReqRes) { + const msg = JSON.stringify(json, null, 2) + .replace(json.apikey, '**hidden**') + .replace(json.apikey, '**hidden**') + .replace(json.deviceid, '**hidden**') + this.log.warn('LAN message sent. This text is yellow for clarity.\n%s', msg) + } else if (this.debug) { + this.log('LAN message sent.') } - if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { - const key = crypto.createHash('md5').update(Buffer.from(apiKey, 'utf8')).digest() - const iv = crypto.randomBytes(16) - const enc = crypto.createCipheriv('aes-128-cbc', key, iv) - const data = { - data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString('base64'), - deviceid: json.deviceid, - encrypt: true, - iv: iv.toString('base64'), - selfApikey: '123', - sequence: Date.now().toString() - } - if (this.debugReqRes) { - const msg = JSON.stringify(json, null, 2) - .replace(json.apikey, '**hidden**') - .replace(json.apikey, '**hidden**') - .replace(json.deviceid, '**hidden**') - this.log.warn('LAN message sent. This text is yellow for clarity.\n%s', msg) - } else if (this.debug) { - this.log('LAN message sent.') - } - const res = await axios({ - method: 'post', - url: 'http://' + this.deviceMap.get(json.deviceid).ip + ':8081/zeroconf/' + suffix, - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json' - }, - data - }) - if (Object.prototype.hasOwnProperty.call(res.data, 'error') && res.data.error === 0) { - return - } else { - throw new Error(res.data) - } + const res = await axios({ + method: 'post', + url: 'http://' + this.deviceMap.get(json.deviceid).ip + ':8081/zeroconf/' + suffix, + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + }, + data + }) + if (!Object.prototype.hasOwnProperty.call(res.data, 'error') || res.data.error !== 0) { + throw new Error(res.data) } - } catch (err) { - throw err } } @@ -180,11 +170,7 @@ module.exports = class eWeLinkLAN { } async closeConnection () { - try { - await dns.stopMonitoring() - this.log('LAN monitoring gracefully stopped.') - } catch (err) { - throw err - } + await dns.stopMonitoring() + this.log('LAN monitoring gracefully stopped.') } } diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 9478517b..137035d2 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -305,13 +305,8 @@ module.exports = class eWeLinkWS { async closeConnection () { if (this.wsp && this.wsIsOpen) { - try { - await this.wsp.close() - this.log('Web socket gracefully closed.') - return - } catch (err) { - throw err - } + await this.wsp.close() + this.log('Web socket gracefully closed.') } } } From 013f1941ad9b73497cc3fa814eedd855415a54ca Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 22:32:31 +0100 Subject: [PATCH 0252/3183] error handling --- lib/eWeLink.js | 7 +------ lib/eWeLinkWS.js | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 1e818b4e..7393124f 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -970,12 +970,7 @@ class eWeLink { if (this.debug) { this.log.warn('[%s] Reverting to web socket as %s.', accessory.displayName, err.message) } - try { - await this.wsClient.sendUpdate(payload) - return - } catch (err) { - throw new Error(err) - } + await this.wsClient.sendUpdate(payload) } else { throw new Error("it is unreachable. It's status will be corrected once it is reachable") } diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 137035d2..a6adfc5b 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -254,7 +254,7 @@ module.exports = class eWeLinkWS { throw new Error('Unknown response') } } catch (err) { - throw new Error('device update failed [' + err + ']') + throw new Error('device update failed [' + err.message + ']') } } else { if (this.debug) { From c186dea4aa99be2f897fe623214c5e69014ad691 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 27 Sep 2020 22:41:49 +0100 Subject: [PATCH 0253/3183] 3.1.3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index b79c5a20..429c84d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.3-1", + "version": "3.1.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1700b110..12f96bd0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.3-1", + "version": "3.1.3", "author": "bwp91", "contributors": [ "gbro115", From a6218f03169b68135f3f831083fd81417c125fea Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 28 Sep 2020 10:20:53 +0100 Subject: [PATCH 0254/3183] cleaning up + improved error --- lib/constants.js | 1 + lib/device/blind.js | 29 +------ lib/device/curtain.js | 19 +++-- lib/device/fan.js | 4 +- lib/device/garage.js | 7 +- lib/device/light.js | 16 ++-- lib/device/lock.js | 5 +- lib/device/outlet.js | 26 +++--- lib/device/rf-sub.js | 9 +- lib/device/scm.js | 8 +- lib/device/sensor.js | 5 +- lib/device/switch.js | 13 +-- lib/device/thermostat.js | 4 +- lib/device/usb.js | 8 +- lib/device/valve.js | 5 +- lib/device/zb-dev.js | 6 +- lib/eWeLink.js | 42 ++++++---- lib/eWeLinkHTTP.js | 172 ++++++++++++++------------------------- lib/eWeLinkLAN.js | 19 +++-- lib/eWeLinkWS.js | 112 ++++++++----------------- 20 files changed, 209 insertions(+), 301 deletions(-) diff --git a/lib/constants.js b/lib/constants.js index 72090079..ba6d44fa 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -2,6 +2,7 @@ module.exports = { appId: 'oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq', appSecret: '6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM', + httpRetryCodes: ['ENOTFOUND', 'ETIMEDOUT', 'EAI_AGAIN'], allowedGroups: ['blind', 'garage', 'lock', 'valve'], devicesHideable: ['switch', 'light'], devicesNonLAN: [22, 28, 59, 102], diff --git a/lib/device/blind.js b/lib/device/blind.js index 13ea726e..9223338a 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -29,48 +29,21 @@ module.exports = class deviceBlind { params.switches = cns.defaultMultiSwitchOff accessory.context.updateKey = updateKey const percentStepPerDecisecond = blindConfig.operationTime / 100 - // - // - this.platform.log('============================') - this.platform.log('============================') - this.platform.log('Starting main calculation...') - // - // if (prevState !== 2) { await this.platform.sendDeviceUpdate(accessory, params) let positionPercentChange = Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime positionPercentChange = Math.floor(percentStepPerDecisecond * positionPercentChange) if (prevState === 0) { - // moving down prevPosition -= positionPercentChange } else { prevPosition += positionPercentChange } wcService.updateCharacteristic(Characteristic.CurrentPosition, prevPosition) accessory.context.cacheCurrentPosition = prevPosition - this.platform.log.warn('Moving from [%s%] to [%s%]', prevPosition, newTarget) - this.platform.log.warn( - 'Blind was already moving %s when it was changed and was probably around %s%', - prevState === 1 ? 'up' : 'down', - prevPosition - ) - this.platform.log.warn( - 'Giving a difference of %s seconds - a position change of %s%', - (Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime) / 10, - positionPercentChange - ) - } else { - this.platform.log('Moving from [%s%] to [%s%].', prevPosition, newTarget) } const diffPosition = newTarget - prevPosition const setToMoveUp = diffPosition > 0 const decisecondsToMove = Math.round(Math.abs(diffPosition) * percentStepPerDecisecond) - this.platform.log( - 'So we need to move %s from the previous state of %s for about %s seconds', - setToMoveUp ? 'up' : 'down', - prevState === 0 ? 'moving down' : prevState === 1 ? 'moving up' : 'stopped', - decisecondsToMove / 10 - ) params.switches[0].switch = setToMoveUp ? 'on' : 'off' params.switches[1].switch = setToMoveUp ? 'off' : 'on' await this.platform.sendDeviceUpdate(accessory, params) @@ -91,7 +64,7 @@ module.exports = class deviceBlind { accessory.context.cachePositionState = 2 accessory.context.cacheCurrentPosition = newTarget } catch (err) { - this.platform.requestDeviceRefresh(accessory, err) + this.platform.deviceUpdateError(accessory, err, true) } } } diff --git a/lib/device/curtain.js b/lib/device/curtain.js index 95ab6086..73e5fc3f 100644 --- a/lib/device/curtain.js +++ b/lib/device/curtain.js @@ -30,24 +30,25 @@ module.exports = class deviceCurtain { .updateCharacteristic(Characteristic.PositionState, newPos > prevPos ? 1 : 0) accessory.context.cacheCurrentPosition = newPos } catch (err) { - this.platform.requestDeviceRefresh(accessory, err) + this.platform.deviceUpdateError(accessory, err, true) } } externalCurtainUpdate (accessory, params) { try { const cService = accessory.getService(Service.WindowCovering) - if (Object.prototype.hasOwnProperty.call(params, 'switch') && Object.prototype.hasOwnProperty.call(params, 'setclose')) { - const newPos = Math.abs(100 - parseInt(params.setclose)) - cService - .updateCharacteristic(Characteristic.TargetPosition, newPos) - .updateCharacteristic(Characteristic.CurrentPosition, newPos) - .updateCharacteristic(Characteristic.PositionState, 2) - accessory.context.cacheCurrentPosition = newPos + if (!Object.prototype.hasOwnProperty.call(params, 'switch') && !Object.prototype.hasOwnProperty.call(params, 'setclose')) { return } + const newPos = Math.abs(100 - parseInt(params.setclose)) + cService + .updateCharacteristic(Characteristic.TargetPosition, newPos) + .updateCharacteristic(Characteristic.CurrentPosition, newPos) + .updateCharacteristic(Characteristic.PositionState, 2) + accessory.context.cacheCurrentPosition = newPos + return } catch (err) { - this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/fan.js b/lib/device/fan.js index 09323633..9e829390 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -45,7 +45,7 @@ module.exports = class deviceFan { .updateCharacteristic(Characteristic.Active, newPower) .updateCharacteristic(Characteristic.RotationSpeed, newSpeed) } catch (err) { - this.platform.requestDeviceRefresh(accessory, err) + this.platform.deviceUpdateError(accessory, err, true) } } @@ -87,7 +87,7 @@ module.exports = class deviceFan { .updateCharacteristic(Characteristic.Active, status) .updateCharacteristic(Characteristic.RotationSpeed, speed) } catch (err) { - this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/garage.js b/lib/device/garage.js index 30ec61ec..5f4cd1dc 100644 --- a/lib/device/garage.js +++ b/lib/device/garage.js @@ -68,12 +68,15 @@ module.exports = class deviceGarage { } accessory.context.inUse = false } catch (err) { - this.platform.requestDeviceRefresh(accessory, err) + this.platform.deviceUpdateError(accessory, err, true) } } externalGarageUpdate (accessory, params) { try { + if (!Object.prototype.hasOwnProperty.call(params, 'switch') && !Object.prototype.hasOwnProperty.call(params, 'switches')) { + return + } let garageConfig const gcService = accessory.getService(Service.GarageDoorOpener) const prevState = accessory.context.cacheCurrentDoorState @@ -119,7 +122,7 @@ module.exports = class deviceGarage { }, parseInt(garageConfig.operationTime) * 100) } catch (err) { accessory.context.inUse = false - this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/light.js b/lib/device/light.js index 42006e45..cd8fe085 100644 --- a/lib/device/light.js +++ b/lib/device/light.js @@ -1,5 +1,6 @@ 'use strict' let Characteristic, Service +const cns = require('./../constants') const convert = require('color-convert') const utils = require('./../utils') module.exports = class deviceLight { @@ -25,7 +26,7 @@ module.exports = class deviceLight { } break case '0': - params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches + params.switches = cns.defaultMultiSwitchOff params.switches[0].switch = value ? 'on' : 'off' params.switches[1].switch = value ? 'on' : 'off' params.switches[2].switch = value ? 'on' : 'off' @@ -35,7 +36,7 @@ module.exports = class deviceLight { case '2': case '3': case '4': - params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches + params.switches = cns.defaultMultiSwitchOff for (let i = 1; i <= 4; i++) { if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { i === parseInt(accessory.context.switchNumber) @@ -84,7 +85,7 @@ module.exports = class deviceLight { } } } catch (err) { - this.platform.requestDeviceRefresh(accessory, err) + this.platform.deviceUpdateError(accessory, err, true) } } @@ -117,7 +118,7 @@ module.exports = class deviceLight { lightService.updateCharacteristic(Characteristic.Brightness, value) } } catch (err) { - this.platform.requestDeviceRefresh(accessory, err) + this.platform.deviceUpdateError(accessory, err, true) } } @@ -188,7 +189,7 @@ module.exports = class deviceLight { break } } catch (err) { - this.platform.requestDeviceRefresh(accessory, err) + this.platform.deviceUpdateError(accessory, err, true) } } @@ -260,12 +261,13 @@ module.exports = class deviceLight { lightService.updateCharacteristic(Characteristic.On, false) } } catch (err) { - this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) + this.platform.deviceUpdateError(accessory, err, false) } } externalMultiLightUpdate (accessory, params) { try { + if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return const idToCheck = accessory.context.hbDeviceId.slice(0, -1) let primaryState = false for (let i = 1; i <= accessory.context.channelCount; i++) { @@ -283,7 +285,7 @@ module.exports = class deviceLight { accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, primaryState) } } catch (err) { - this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/lock.js b/lib/device/lock.js index 93278892..e82e3882 100644 --- a/lib/device/lock.js +++ b/lib/device/lock.js @@ -33,12 +33,13 @@ module.exports = class deviceLock { .updateCharacteristic(Characteristic.LockCurrentState, 1) accessory.context.inUse = false } catch (err) { - this.platform.requestDeviceRefresh(accessory, err) + this.platform.deviceUpdateError(accessory, err, true) } } externalLockUpdate (accessory, params) { try { + if (!Object.prototype.hasOwnProperty.call(params, 'switch')) return let lockConfig const lmService = accessory.getService(Service.LockMechanism) if (!(lockConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { @@ -62,7 +63,7 @@ module.exports = class deviceLock { }, parseInt(lockConfig.operationTime) * 100) } catch (err) { accessory.context.inUse = false - this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/outlet.js b/lib/device/outlet.js index 8696dc36..c244e42f 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -19,7 +19,7 @@ module.exports = class deviceOutlet { await this.platform.sendDeviceUpdate(accessory, params) outletService.updateCharacteristic(Characteristic.On, value) } catch (err) { - this.platform.requestDeviceRefresh(accessory, err) + this.platform.deviceUpdateError(accessory, err, true) } } @@ -28,21 +28,23 @@ module.exports = class deviceOutlet { const outletService = accessory.getService(Service.Outlet) if (Object.prototype.hasOwnProperty.call(params, 'switch')) { outletService.updateCharacteristic(Characteristic.On, params.switch === 'on') - if (accessory.context.eweModel === 'S26' || this.platform.config.disableEveLogging || false) { + if (accessory.context.eweModel === 'S26' || this.platform.config.disableEveLogging) { outletService.updateCharacteristic(Characteristic.OutletInUse, params.switch === 'on') } } if (Object.prototype.hasOwnProperty.call(params, 'power')) { outletService.updateCharacteristic(EveService.Characteristics.CurrentConsumption, parseFloat(params.power)) - outletService.updateCharacteristic( - Characteristic.OutletInUse, - parseFloat(params.power) > (this.platform.config.inUsePowerThreshold || 0) - ) - const isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value - accessory.eveLogger.addEntry({ - time: Date.now(), - power: isOn ? parseFloat(params.power) : 0 - }) + if (accessory.context.eweModel !== 'S26' && !this.platform.config.disableEveLogging) { + outletService.updateCharacteristic( + Characteristic.OutletInUse, + parseFloat(params.power) > (this.platform.config.inUsePowerThreshold || 0) + ) + const isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value + accessory.eveLogger.addEntry({ + time: Date.now(), + power: isOn ? parseFloat(params.power) : 0 + }) + } } if (Object.prototype.hasOwnProperty.call(params, 'voltage')) { outletService.updateCharacteristic(EveService.Characteristics.Voltage, parseFloat(params.voltage)) @@ -51,7 +53,7 @@ module.exports = class deviceOutlet { outletService.updateCharacteristic(EveService.Characteristics.ElectricCurrent, parseFloat(params.current)) } } catch (err) { - this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/rf-sub.js b/lib/device/rf-sub.js index 3bf3320c..e1800637 100644 --- a/lib/device/rf-sub.js +++ b/lib/device/rf-sub.js @@ -21,7 +21,7 @@ module.exports = class deviceRFSub { await utils.sleep(3000) rfService.updateCharacteristic(Characteristic.On, false) } catch (err) { - this.platform.requestDeviceRefresh(accessory, err) + this.platform.deviceUpdateError(accessory, err, true) } } @@ -31,8 +31,6 @@ module.exports = class deviceRFSub { const timeNow = new Date() let oAccessory = false if (Object.prototype.hasOwnProperty.call(params, 'cmd') && params.cmd === 'transmit' && Object.prototype.hasOwnProperty.call(params, 'rfChl')) { - //* ** RF Button ***\\ - // the device needed is SW% corresponding to params.rfChl this.platform.devicesInHB.forEach(acc => { if ( acc.context.eweDeviceId === accessory.context.eweDeviceId && @@ -109,15 +107,12 @@ module.exports = class deviceRFSub { setTimeout(() => { oAccessory.getService(serv).updateCharacteristic(char, 0) }, (this.platform.config.sensorTimeLength || 2) * 1000) - if (this.platform.debug) { - this.platform.log('[%s] has detected [%s].', oAccessory.displayName, oAccessory.context.sensorType) - } } } }) } } catch (err) { - this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/scm.js b/lib/device/scm.js index 276c385f..501bdb29 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -1,5 +1,6 @@ 'use strict' let Characteristic, Service +const cns = require('./../constants') module.exports = class deviceSCM { constructor (platform) { this.platform = platform @@ -11,22 +12,23 @@ module.exports = class deviceSCM { callback() try { const params = { - switches: this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches + switches: cns.defaultMultiSwitchOff } const switchService = accessory.getService(Service.Switch) params.switches[0].switch = value ? 'on' : 'off' await this.platform.sendDeviceUpdate(accessory, params) switchService.updateCharacteristic(Characteristic.On, value) } catch (err) { - this.platform.requestDeviceRefresh(accessory, err) + this.platform.deviceUpdateError(accessory, err, true) } } externalSCMUpdate (accessory, params) { try { + if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switches[0].switch === 'on') } catch (err) { - this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/sensor.js b/lib/device/sensor.js index b16f3a5c..844bca01 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -19,6 +19,7 @@ module.exports = class deviceSensor { scaledBattery < (this.platform.config.lowBattThreshold || 25) ) } + if (!Object.prototype.hasOwnProperty.call(params, 'switch')) return const newState = params.switch === 'on' ? 1 : 0 let oAccessory = false const contactService = accessory.getService(Service.ContactSensor) @@ -41,14 +42,12 @@ module.exports = class deviceSensor { .updateCharacteristic(Characteristic.CurrentDoorState, 0) }, group.operationTime * 100) break - default: - throw new Error('unknown sensor status received [' + newState + ']') } } } }) } catch (err) { - this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/switch.js b/lib/device/switch.js index 0f49f802..9a70c3c1 100644 --- a/lib/device/switch.js +++ b/lib/device/switch.js @@ -1,5 +1,6 @@ 'use strict' let Characteristic, Service +const cns = require('./../constants') module.exports = class deviceSwitch { constructor (platform) { this.platform = platform @@ -18,7 +19,7 @@ module.exports = class deviceSwitch { params.switch = value ? 'on' : 'off' break case '0': - params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches + params.switches = cns.defaultMultiSwitchOff params.switches[0].switch = value ? 'on' : 'off' params.switches[1].switch = value ? 'on' : 'off' params.switches[2].switch = value ? 'on' : 'off' @@ -28,7 +29,7 @@ module.exports = class deviceSwitch { case '2': case '3': case '4': - params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches + params.switches = cns.defaultMultiSwitchOff for (let i = 1; i <= 4; i++) { if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { i === parseInt(accessory.context.switchNumber) @@ -77,20 +78,22 @@ module.exports = class deviceSwitch { } } } catch (err) { - this.platform.requestDeviceRefresh(accessory, err) + this.platform.deviceUpdateError(accessory, err, true) } } externalSingleSwitchUpdate (accessory, params) { try { + if (!Object.prototype.hasOwnProperty.call(params, 'switch')) return accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switch === 'on') } catch (err) { - this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) + this.platform.deviceUpdateError(accessory, err, false) } } externalMultiSwitchUpdate (accessory, params) { try { + if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return const idToCheck = accessory.context.hbDeviceId.slice(0, -1) let primaryState = false for (let i = 1; i <= accessory.context.channelCount; i++) { @@ -108,7 +111,7 @@ module.exports = class deviceSwitch { accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState) } } catch (err) { - this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index a5d5f2b0..ba86d219 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -18,7 +18,7 @@ module.exports = class deviceThermostat { await this.platform.sendDeviceUpdate(accessory, params) switchService.updateCharacteristic(Characteristic.On, value) } catch (err) { - this.platform.requestDeviceRefresh(accessory, err) + this.platform.deviceUpdateError(accessory, err, true) } } @@ -55,7 +55,7 @@ module.exports = class deviceThermostat { } } } catch (err) { - this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/usb.js b/lib/device/usb.js index d78cf020..67a58833 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -1,5 +1,6 @@ 'use strict' let Characteristic, Service +const cns = require('./../constants') module.exports = class deviceUSB { constructor (platform) { this.platform = platform @@ -11,22 +12,23 @@ module.exports = class deviceUSB { callback() try { const params = { - switches: this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches + switches: cns.defaultMultiSwitchOff } const outletService = accessory.getService(Service.Outlet) params.switches[0].switch = value ? 'on' : 'off' await this.platform.sendDeviceUpdate(accessory, params) outletService.updateCharacteristic(Characteristic.On, value) } catch (err) { - this.platform.requestDeviceRefresh(accessory, err) + this.platform.deviceUpdateError(accessory, err, true) } } externalUSBUpdate (accessory, params) { try { + if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switches[0].switch === 'on') } catch (err) { - this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/valve.js b/lib/device/valve.js index 9feff0c4..c7d1dab8 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -50,12 +50,13 @@ module.exports = class deviceValve { } } } catch (err) { - this.platform.requestDeviceRefresh(accessory, err) + this.platform.deviceUpdateError(accessory, err, true) } } externalValveUpdate (accessory, params) { try { + if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return let valveConfig if (!(valveConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') @@ -81,7 +82,7 @@ module.exports = class deviceValve { } }) } catch (err) { - this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index d4b2f58e..365cedb8 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -11,7 +11,7 @@ module.exports = class deviceZBDev { try { //* ** credit @tasict ***\\ if (Object.prototype.hasOwnProperty.call(params, 'battery')) { - if (accessory.context.eweUIID === 3026 && (this.platform.config.ZBDWBatt || false)) { + if (accessory.context.eweUIID === 3026 && this.platform.config.ZBDWBatt) { params.battery *= 10 } const batteryService = @@ -75,9 +75,11 @@ module.exports = class deviceZBDev { .updateCharacteristic(Characteristic.ContactSensorState, params.lock) } break + default: + throw new Error('Zigbee device type not supported [uiid ' + accessory.context.eweUIID + ']') } } catch (err) { - this.platform.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 7393124f..3fd6d668 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -120,7 +120,7 @@ class eWeLink { })() } catch (err) { this.log.error('************** Cannot load homebridge-ewelink **************') - this.log.error(err) + this.log.error(this.debug ? err : err.message) this.log.error('************************************************************') if (this.lanClient) this.lanClient.closeConnection() if (this.wsClient) this.wsClient.closeConnection() @@ -638,7 +638,7 @@ class eWeLink { if (!(outletService = accessory.getService(Service.Outlet))) { accessory.addService(Service.Outlet) outletService = accessory.getService(Service.Outlet) - if (accessory.context.eweModel !== 'S26' && !(this.config.disableEveLogging || false)) { + if (accessory.context.eweModel !== 'S26' && !this.config.disableEveLogging) { outletService.addCharacteristic(EveService.Characteristics.Voltage) outletService.addCharacteristic(EveService.Characteristics.CurrentConsumption) outletService.addCharacteristic(EveService.Characteristics.ElectricCurrent) @@ -658,7 +658,7 @@ class eWeLink { outletService .getCharacteristic(Characteristic.On) .on('set', (value, callback) => accessory.control.internalOutletUpdate(accessory, value, callback)) - if (accessory.context.eweModel !== 'S26' && !(this.config.disableEveLogging || false)) { + if (accessory.context.eweModel !== 'S26' && !this.config.disableEveLogging) { accessory.log = this.log accessory.eveLogger = new EveHistoryService('energy', accessory, { storage: 'fs', @@ -968,7 +968,7 @@ class eWeLink { } catch (err) { if (accessory.context.reachableWAN) { if (this.debug) { - this.log.warn('[%s] Reverting to web socket as %s.', accessory.displayName, err.message) + this.log.warn('[%s] Reverting to web socket as LAN mode warning - %s.', accessory.displayName, this.debug ? err : err.message) } await this.wsClient.sendUpdate(payload) } else { @@ -987,21 +987,31 @@ class eWeLink { if (device.params.online !== accessory.context.reachableWAN) { accessory.context.reachableWAN = device.params.online this.devicesInHB.set(accessory.context.hbDeviceId, accessory) - if (accessory.context.reachableWAN) this.wsClient.requestUpdate(accessory).catch(() => {}) reachableChange = true this.log.warn( '[%s] has been reported [%s] via [WS].', accessory.displayName, accessory.context.reachableWAN ? 'online' : 'offline' ) + if (accessory.context.reachableWAN) { + try { + this.wsClient.requestUpdate(accessory) + } catch (err) { + this.log.warn('[%s] update could not be requested as %s', accessory.displayName, this.debug ? err.message : err) + } + } } } if (device.params.updateSource === 'LAN' && !accessory.context.reachableLAN) { accessory.context.reachableLAN = true this.devicesInHB.set(accessory.context.hbDeviceId, accessory) - this.wsClient.requestUpdate(accessory).catch(() => {}) reachableChange = true this.log.warn('[%s] has been reported [online] via [LAN].', accessory.displayName) + try { + this.wsClient.requestUpdate(accessory) + } catch (err) { + this.log.warn('[%s] update could not be requested as %s', accessory.displayName, this.debug ? err.message : err) + } } if (reachableChange && !isX) { for (let i = 1; i <= accessory.context.channelCount; i++) { @@ -1052,15 +1062,17 @@ class eWeLink { } } - async requestDeviceRefresh (accessory, err) { - this.log.warn('[%s] could not be updated as %s.', accessory.displayName, err) - if (accessory.context.reachableWAN) { - try { - await this.wsClient.requestUpdate(accessory) - this.log.warn('[%s] requesting previous state to revert Homebridge state.', accessory.displayName) - } catch (err) {} - } else { - this.log.warn('[%s] Homebridge state will be synced once the device comes back online.', accessory.displayName) + async deviceUpdateError (accessory, err, requestRefresh) { + this.log.warn('[%s] could not be updated as %s.', accessory.displayName, this.debug ? err : err.message) + if (requestRefresh) { + if (accessory.context.reachableWAN) { + try { + await this.wsClient.requestUpdate(accessory) + this.log.warn('[%s] requesting previous state to revert Homebridge state.', accessory.displayName) + } catch (err) {} + } else { + this.log.warn('[%s] Homebridge state will be synced once the device comes back online.', accessory.displayName) + } } } } diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 10df3508..c3497f4b 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -1,6 +1,6 @@ 'use strict' const axios = require('axios') -const constants = require('./constants') +const cns = require('./constants') const crypto = require('crypto') const utils = require('./utils') module.exports = class eWeLinkHTTP { @@ -11,13 +11,12 @@ module.exports = class eWeLinkHTTP { this.username = config.username.toString() this.password = config.password.toString() this.hideDevFromHB = (config.hideDevFromHB || '').toString() - this.cCode = - '+' + config.countryCode.toString().replace('+', '').replace(' ', '') + this.cCode = '+' + config.countryCode.toString().replace('+', '').replace(' ', '') } async getHost () { const params = { - appid: constants.appId, + appid: cns.appId, country_code: this.cCode, nonce: Math.random().toString(36).substr(2, 8), ts: Math.floor(new Date().getTime() / 1000), @@ -33,33 +32,22 @@ module.exports = class eWeLinkHTTP { }) dataToSign.sort((a, b) => (a.key < b.key ? -1 : 1)) dataToSign = dataToSign.map((k) => k.key + '=' + k.value).join('&') - dataToSign = crypto - .createHmac('sha256', constants.appSecret) - .update(dataToSign) - .digest('base64') + dataToSign = crypto.createHmac('sha256', cns.appSecret).update(dataToSign).digest('base64') if (this.debugReqRes) { - this.log.warn( - 'Sending HTTP getHost request. This text is yellow for clarity.\n%s', - JSON.stringify(params, null, 2) - ) + this.log.warn('Sending HTTP getHost request. This text is yellow for clarity.\n%s', JSON.stringify(params, null, 2)) } else if (this.debug) { this.log('Sending HTTP getHost request.') } - const res = await axios.get( - 'https://api.coolkit.cc:8080/api/user/region', { - headers: { - Authorization: 'Sign ' + dataToSign, - 'Content-Type': 'application/json' - }, - params - } - ) + const res = await axios.get('https://api.coolkit.cc:8080/api/user/region', { + headers: { + Authorization: 'Sign ' + dataToSign, + 'Content-Type': 'application/json' + }, + params + }) const body = res.data if (!body.region) { - throw new Error( - 'Server did not respond with a region.\n' + - JSON.stringify(body, null, 2) - ) + throw new Error('Server did not respond with a region.\n' + JSON.stringify(body, null, 2)) } switch (body.region) { case 'eu': @@ -78,14 +66,12 @@ module.exports = class eWeLinkHTTP { } return this.httpHost } catch (err) { - if ( - Object.prototype.hasOwnProperty.call(err, 'code') && ['ENOTFOUND', 'ETIMEDOUT', 'EAI_AGAIN'].includes(err.code) - ) { + if (Object.prototype.hasOwnProperty.call(err, 'code') && cns.httpRetryCodes.includes(err.code)) { this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') await utils.sleep(30000) return this.getHost() } else { - throw err + return err } } } @@ -95,43 +81,25 @@ module.exports = class eWeLinkHTTP { countryCode: this.cCode, password: this.password } - this.username.includes('@') - ? (data.email = this.username) - : (data.phoneNumber = this.username) + this.username.includes('@') ? (data.email = this.username) : (data.phoneNumber = this.username) if (this.debugReqRes) { - const msg = JSON.stringify(data, null, 2) - .replace(this.password, '**hidden**') - .replace(this.username, '**hidden**') - this.log.warn( - 'Sending HTTP login request. This text is yellow for clarity.\n%s', - msg - ) + const msg = JSON.stringify(data, null, 2).replace(this.password, '**hidden**').replace(this.username, '**hidden**') + this.log.warn('Sending HTTP login request. This text is yellow for clarity.\n%s', msg) } else if (this.debug) { this.log('Sending HTTP login request.') } - const dataToSign = crypto - .createHmac('sha256', constants.appSecret) - .update(JSON.stringify(data)) - .digest('base64') - const res = await axios.post( - 'https://' + this.httpHost + '/v2/user/login', - data, { - headers: { - Authorization: 'Sign ' + dataToSign, - 'Content-Type': 'application/json', - Host: this.httpHost, - 'X-CK-Appid': constants.appId, - 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) - } - } - ) + const dataToSign = crypto.createHmac('sha256', cns.appSecret).update(JSON.stringify(data)).digest('base64') + const res = await axios.post('https://' + this.httpHost + '/v2/user/login', data, { + headers: { + Authorization: 'Sign ' + dataToSign, + 'Content-Type': 'application/json', + Host: this.httpHost, + 'X-CK-Appid': cns.appId, + 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) + } + }) const body = res.data - if ( - Object.prototype.hasOwnProperty.call(body, 'error') && - body.error === 10004 && - Object.prototype.hasOwnProperty.call(body, 'data') && - Object.prototype.hasOwnProperty.call(body.data, 'region') - ) { + if (Object.prototype.hasOwnProperty.call(body, 'error') && body.error === 10004 && Object.prototype.hasOwnProperty.call(body, 'data') && Object.prototype.hasOwnProperty.call(body.data, 'region')) { const givenRegion = body.data.region switch (givenRegion) { case 'eu': @@ -160,9 +128,7 @@ module.exports = class eWeLinkHTTP { } } else { if (body.error === 500) { - this.log.warn( - 'An eWeLink error [500] occured. Retrying in 30 seconds.' - ) + this.log.warn('An eWeLink error [500] occured. Retrying in 30 seconds.') await utils.sleep(30000) return this.login() } else { @@ -173,74 +139,56 @@ module.exports = class eWeLinkHTTP { async getDevices () { try { - const res = await axios.get( - 'https://' + this.httpHost + '/v2/device/thing', { - headers: { - Authorization: 'Bearer ' + this.aToken, - 'Content-Type': 'application/json', - Host: this.httpHost, - 'X-CK-Appid': constants.appId, - 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) - } + const res = await axios.get('https://' + this.httpHost + '/v2/device/thing', { + headers: { + Authorization: 'Bearer ' + this.aToken, + 'Content-Type': 'application/json', + Host: this.httpHost, + 'X-CK-Appid': cns.appId, + 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) } - ) + }) const body = res.data - if ( - !Object.prototype.hasOwnProperty.call(body, 'data') || - !Object.prototype.hasOwnProperty.call(body, 'error') || - (Object.prototype.hasOwnProperty.call(body, 'error') && body.error !== 0) - ) { + if (!Object.prototype.hasOwnProperty.call(body, 'data') || !Object.prototype.hasOwnProperty.call(body, 'error') || (Object.prototype.hasOwnProperty.call(body, 'error') && body.error !== 0)) { throw new Error(JSON.stringify(body, null, 2)) } const deviceList = [] if (body.data.thingList && body.data.thingList.length > 0) { - body.data.thingList.forEach((device) => - deviceList.push(device.itemData) - ) + body.data.thingList.forEach((device) => deviceList.push(device.itemData)) } deviceList - .filter( - (d) => Object.prototype.hasOwnProperty.call(d, 'extra') && Object.prototype.hasOwnProperty.call(d.extra, 'uiid') - ) + .filter((d) => Object.prototype.hasOwnProperty.call(d, 'extra') && Object.prototype.hasOwnProperty.call(d.extra, 'uiid')) .filter((d) => !this.hideDevFromHB.includes(d.deviceid)) return deviceList } catch (err) { - if ( - Object.prototype.hasOwnProperty.call(err, 'code') && ['ENOTFOUND', 'ETIMEDOUT'].includes(err.code) - ) { + if (Object.prototype.hasOwnProperty.call(err, 'code') && cns.httpRetryCodes.includes(err.code)) { this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') await utils.sleep(30000) return this.getDevices() } else { - throw err + return err } } } async getDevice (deviceId) { try { - const res = await axios.post( - 'https://' + this.httpHost + '/v2/device/thing', { - thingList: [{ - itemType: 1, - id: deviceId - }] - }, { - headers: { - Authorization: 'Bearer ' + this.aToken, - 'Content-Type': 'application/json', - Host: this.httpHost, - 'X-CK-Appid': constants.appId, - 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) - } + const res = await axios.post('https://' + this.httpHost + '/v2/device/thing', { + thingList: [{ + itemType: 1, + id: deviceId + }] + }, { + headers: { + Authorization: 'Bearer ' + this.aToken, + 'Content-Type': 'application/json', + Host: this.httpHost, + 'X-CK-Appid': cns.appId, + 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) } - ) + }) const body = res.data - if ( - !Object.prototype.hasOwnProperty.call(body, 'data') || - !Object.prototype.hasOwnProperty.call(body, 'error') || - (Object.prototype.hasOwnProperty.call(body, 'error') && body.error !== 0) - ) { + if (!Object.prototype.hasOwnProperty.call(body, 'data') || !Object.prototype.hasOwnProperty.call(body, 'error') || (Object.prototype.hasOwnProperty.call(body, 'error') && body.error !== 0)) { throw new Error(JSON.stringify(body, null, 2)) } if (body.data.thingList && body.data.thingList.length === 1) { @@ -249,14 +197,12 @@ module.exports = class eWeLinkHTTP { throw new Error('device not found in eWeLink') } } catch (err) { - if ( - Object.prototype.hasOwnProperty.call(err, 'code') && ['ENOTFOUND', 'ETIMEDOUT'].includes(err.code) - ) { + if (Object.prototype.hasOwnProperty.call(err, 'code') && cns.httpRetryCodes.includes(err.code)) { this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') await utils.sleep(30000) return this.getDevice(deviceId) } else { - throw err + return err } } } diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 7d4a7226..73e97cea 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -7,8 +7,12 @@ const EventEmitter = require('events') module.exports = class eWeLinkLAN { constructor (config, log, devices) { this.log = log + this.config = config + this.debug = this.config.debug || false + this.debugReqRes = this.config.debugReqRes || false + this.ipOverrides = this.config.ipOverride || {} + this.emitter = new EventEmitter() this.devices = devices - this.ipOverrides = config.ipOverride || {} this.deviceMap = new Map() devices.forEach(device => { this.deviceMap.set(device.deviceid, { @@ -17,9 +21,6 @@ module.exports = class eWeLinkLAN { ip: Object.prototype.hasOwnProperty.call(this.ipOverrides, device.deviceid) ? this.ipOverrides[device.deviceid] : null }) }) - this.debug = config.debug || false - this.debugReqRes = config.debugReqRes || false - this.emitter = new EventEmitter() } async getHosts () { @@ -42,7 +43,7 @@ module.exports = class eWeLinkLAN { return this.deviceMap } - startMonitor () { + async startMonitor () { dns.ondata = packet => { if (packet.answers) { packet.answers @@ -170,7 +171,11 @@ module.exports = class eWeLinkLAN { } async closeConnection () { - await dns.stopMonitoring() - this.log('LAN monitoring gracefully stopped.') + try { + await dns.stopMonitoring() + this.log('LAN monitoring gracefully stopped.') + } catch (err) { + this.log.warn('LAN monitoring could not be stopped as %s', this.debug ? err : err.message) + } } } diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index a6adfc5b..92f46dab 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -23,9 +23,7 @@ module.exports = class eWeLinkWS { try { const res = await axios({ method: 'post', - url: 'https://' + - this.httpHost.replace('-api', '-disp') + - '/dispatch/app', + url: 'https://' + this.httpHost.replace('-api', '-disp') + '/dispatch/app', headers: { Authorization: 'Bearer ' + this.aToken, 'Content-Type': 'application/json' @@ -47,14 +45,12 @@ module.exports = class eWeLinkWS { this.wsHost = body.domain return body.domain } catch (err) { - if ( - Object.prototype.hasOwnProperty.call(err, 'code') && ['ENOTFOUND', 'ETIMEDOUT'].includes(err.code) - ) { + if (Object.prototype.hasOwnProperty.call(err, 'code') && cns.httpRetryCodes.includes(err.code)) { this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') await utils.sleep(30000) return this.getDevices() } else { - throw err + return err } } } @@ -63,12 +59,9 @@ module.exports = class eWeLinkWS { this.wsp = new WSP('wss://' + this.wsHost + ':8080/api/ws', { createWebSocket: (url) => new WS(url), extractMessageData: (event) => event, - attachRequestId: (data, requestId) => - Object.assign({ - sequence: requestId - }, - data - ), + attachRequestId: (data, requestId) => Object.assign({ + sequence: requestId + }, data), extractRequestId: (data) => data && data.sequence, packMessage: (data) => JSON.stringify(data), unpackMessage: (data) => { @@ -91,13 +84,8 @@ module.exports = class eWeLinkWS { version: 8 } if (this.debugReqRes) { - const msg = JSON.stringify(payload, null, 2) - .replace(this.aToken, '**hidden**') - .replace(this.apiKey, '**hidden**') - this.log.warn( - 'Sending WS login request. This text is yellow for clarity.\n%s', - msg - ) + const msg = JSON.stringify(payload, null, 2).replace(this.aToken, '**hidden**').replace(this.apiKey, '**hidden**') + this.log.warn('Sending WS login request. This text is yellow for clarity.\n%s', msg) } else if (this.debug) { this.log('Sending WS login request.') } @@ -105,12 +93,7 @@ module.exports = class eWeLinkWS { const res = await this.wsp.sendRequest(payload, { requestId: sequence }) - if ( - Object.prototype.hasOwnProperty.call(res, 'config') && - res.config.hb && - res.config.hbInterval && - !this.hbInterval - ) { + if (Object.prototype.hasOwnProperty.call(res, 'config') && res.config.hb && res.config.hbInterval && !this.hbInterval) { this.hbInterval = setInterval(() => { this.wsp.send('ping') }, (res.config.hbInterval + 7) * 1000) @@ -118,7 +101,7 @@ module.exports = class eWeLinkWS { throw new Error('Unknown parameters received') } } catch (err) { - this.log.error('WS login failed [%s].', err) + this.log.error('WS login failed [%s].', this.debug ? err : err.message) } }) this.wsp.onUnpackedMessage.addListener((device) => { @@ -133,10 +116,7 @@ module.exports = class eWeLinkWS { switch (device.action) { case 'update': case 'sysmsg': - if ( - device.action === 'sysmsg' && - Object.prototype.hasOwnProperty.call(device.params, 'online') - ) { + if (device.action === 'sysmsg' && Object.prototype.hasOwnProperty.call(device.params, 'online')) { onlineStatus = device.params.online } for (const param in device.params) { @@ -154,10 +134,7 @@ module.exports = class eWeLinkWS { params: device.params } if (this.debugReqRes) { - const msg = JSON.stringify(returnTemplate, null, 2).replace( - device.deviceid, - '**hidden**' - ) + const msg = JSON.stringify(returnTemplate, null, 2).replace(device.deviceid, '**hidden**') this.log('WS message received.\n%s', msg) } else if (this.debug) { this.log('WS message received.') @@ -168,33 +145,25 @@ module.exports = class eWeLinkWS { case 'reportSubDevice': return default: - this.log.warn( - '[%s] WS message has unknown action.\n' + - JSON.stringify(device, null, 2), - device.deviceid - ) + this.log.warn('[%s] WS message has unknown action.\n' + JSON.stringify(device, null, 2), device.deviceid) } } else if (Object.prototype.hasOwnProperty.call(device, 'error') && device.error === 0) { // *** Safe to ignore these messages *** \\ } else { if (this.debug) { - this.log.warn( - 'WS unknown command received.\n' + JSON.stringify(device, null, 2) - ) + this.log.warn('WS unknown command received.\n' + JSON.stringify(device, null, 2)) } } }) - this.wsp.onClose.addListener((e, m) => { + this.wsp.onClose.addListener(e => { this.wsIsOpen = false - if (e !== 1005) { - this.log.warn('Web socket closed [%s].', e) - if (e !== 1000) { + if (e.code !== 1005) { + this.log.warn('Web socket closed [%s - %s].', e.code, e.reason) + if (e.code !== 1000) { this.log('Web socket will try to reconnect in five seconds.') setTimeout(() => this.login(), 5000) } else { - this.log( - 'Please try restarting Homebridge so that this plugin can work again.' - ) + this.log('Please try restarting Homebridge so that this plugin can work again.') } } if (this.hbInterval) { @@ -203,18 +172,14 @@ module.exports = class eWeLinkWS { } this.wsp.removeAllListeners() }) - this.wsp.onError.addListener((e) => { - this.log.error('Web socket error - [%s].', e) + this.wsp.onError.addListener(e => { + this.log.warn('Web socket error - [%s].', e) if (e.code === 'ECONNREFUSED') { - this.log.warn( - 'Web socket will try to reconnect in five seconds then try the command again.' - ) + this.log.warn('Web socket will try to reconnect in five seconds then try the command again.') this.wsp.removeAllListeners() setTimeout(() => this.login(), 5000) } else { - this.log.warn( - 'If this was unexpected then please try restarting Homebridge.' - ) + this.log.warn('If this was unexpected then please try restarting Homebridge.') } }) } @@ -235,14 +200,8 @@ module.exports = class eWeLinkWS { requestId: sequence }) if (this.debugReqRes) { - const msg = JSON.stringify(json, null, 2) - .replace(json.apikey, '**hidden**') - .replace(json.apiKey, '**hidden**') - .replace(json.deviceid, '**hidden**') - this.log.warn( - 'WS message sent. This text is yellow for clarity.\n%s', - msg - ) + const msg = JSON.stringify(json, null, 2).replace(json.apikey, '**hidden**').replace(json.apiKey, '**hidden**').replace(json.deviceid, '**hidden**') + this.log.warn('WS message sent. This text is yellow for clarity.\n%s', msg) } else if (this.debug) { this.log('WS message sent.') } @@ -254,7 +213,8 @@ module.exports = class eWeLinkWS { throw new Error('Unknown response') } } catch (err) { - throw new Error('device update failed [' + err.message + ']') + const msg = this.debug ? err : err.message + return new Error('device update failed as ' + msg) } } else { if (this.debug) { @@ -279,14 +239,8 @@ module.exports = class eWeLinkWS { if (this.wsp && this.wsIsOpen) { this.wsp.send(JSON.stringify(json)) if (this.debugReqRes) { - const msg = JSON.stringify(json, null, 2) - .replace(json.apikey, '**hidden**') - .replace(json.apiKey, '**hidden**') - .replace(json.deviceid, '**hidden**') - this.log.warn( - 'WS message sent. This text is yellow for clarity.\n%s', - msg - ) + const msg = JSON.stringify(json, null, 2).replace(json.apikey, '**hidden**').replace(json.apiKey, '**hidden**').replace(json.deviceid, '**hidden**') + this.log.warn('WS message sent. This text is yellow for clarity.\n%s', msg) } else if (this.debug) { this.log('WS message sent.') } @@ -305,8 +259,12 @@ module.exports = class eWeLinkWS { async closeConnection () { if (this.wsp && this.wsIsOpen) { - await this.wsp.close() - this.log('Web socket gracefully closed.') + try { + await this.wsp.close() + this.log('Web socket gracefully closed.') + } catch (err) { + this.log.warn('Web socket could not be closed as %s', this.debug ? err : err.message) + } } } } From 4940049ae5caddfd6c385bf9f9f868a72e5dd1ce Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 28 Sep 2020 10:22:43 +0100 Subject: [PATCH 0255/3183] 3.1.4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 429c84d8..da735c95 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.3", + "version": "3.1.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 12f96bd0..e2d5e794 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.3", + "version": "3.1.4", "author": "bwp91", "contributors": [ "gbro115", From 4b444002f28802d5a69f4e2f66b9efa9e009d2a7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 28 Sep 2020 11:17:25 +0100 Subject: [PATCH 0256/3183] setup + shutdown --- lib/eWeLink.js | 30 ++++++++++++++++++++---------- lib/eWeLinkLAN.js | 8 ++------ lib/eWeLinkWS.js | 8 ++------ 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 3fd6d668..5e06b1af 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -45,15 +45,11 @@ class eWeLink { this.eveLogPath = this.api.user.storagePath() + '/homebridge-ewelink/' this.wsRefreshFlag = true this.api - .on('didFinishLaunching', () => this.eWeLinkSync()) - .on('shutdown', () => { - if (this.lanClient) this.lanClient.closeConnection() - if (this.wsClient) this.wsClient.closeConnection() - this.wsRefreshFlag = false - }) + .on('didFinishLaunching', () => this.eWeLinkSetup()) + .on('shutdown', () => this.eWeLinkShutdown()) } - async eWeLinkSync () { + async eWeLinkSetup () { try { this.log('Plugin has finished initialising. Synching with eWeLink.') this.httpClient = new EWeLinkHTTP(this.config, this.log) @@ -105,7 +101,7 @@ class eWeLink { await this.wsClient.login() } } catch (err) { - this.log.warn(err) + this.log.warn(this.debug ? err : err.message) } } }, @@ -122,12 +118,26 @@ class eWeLink { this.log.error('************** Cannot load homebridge-ewelink **************') this.log.error(this.debug ? err : err.message) this.log.error('************************************************************') - if (this.lanClient) this.lanClient.closeConnection() - if (this.wsClient) this.wsClient.closeConnection() + try { + if (this.lanClient) await this.lanClient.closeConnection() + if (this.wsClient) await this.wsClient.closeConnection() + } catch (err) { + this.log.warn(this.debug ? err : err.message) + } this.wsRefreshFlag = false } } + async eWeLinkShutdown () { + try { + if (this.lanClient) await this.lanClient.closeConnection() + if (this.wsClient) await this.wsClient.closeConnection() + } catch (err) { + this.log.warn(this.debug ? err : err.message) + } + this.wsRefreshFlag = false + } + initialiseDevice (device) { let accessory //* ** CURTAINS ***\\ diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 73e97cea..855819fd 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -171,11 +171,7 @@ module.exports = class eWeLinkLAN { } async closeConnection () { - try { - await dns.stopMonitoring() - this.log('LAN monitoring gracefully stopped.') - } catch (err) { - this.log.warn('LAN monitoring could not be stopped as %s', this.debug ? err : err.message) - } + await dns.stopMonitoring() + this.log('LAN monitoring gracefully stopped.') } } diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 92f46dab..086856d3 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -259,12 +259,8 @@ module.exports = class eWeLinkWS { async closeConnection () { if (this.wsp && this.wsIsOpen) { - try { - await this.wsp.close() - this.log('Web socket gracefully closed.') - } catch (err) { - this.log.warn('Web socket could not be closed as %s', this.debug ? err : err.message) - } + await this.wsp.close() + this.log('Web socket gracefully closed.') } } } From f3d340d4060217ae68b10f868d733fe236ac495f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 28 Sep 2020 11:55:39 +0100 Subject: [PATCH 0257/3183] log changes --- lib/eWeLinkLAN.js | 2 +- lib/eWeLinkWS.js | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 855819fd..67bfbae3 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -172,6 +172,6 @@ module.exports = class eWeLinkLAN { async closeConnection () { await dns.stopMonitoring() - this.log('LAN monitoring gracefully stopped.') + if (this.debug) this.log('LAN monitoring gracefully stopped.') } } diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 086856d3..3c305920 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -98,7 +98,7 @@ module.exports = class eWeLinkWS { this.wsp.send('ping') }, (res.config.hbInterval + 7) * 1000) } else { - throw new Error('Unknown parameters received') + throw new Error('Unknown parameters received\n' + res) } } catch (err) { this.log.error('WS login failed [%s].', this.debug ? err : err.message) @@ -157,9 +157,9 @@ module.exports = class eWeLinkWS { }) this.wsp.onClose.addListener(e => { this.wsIsOpen = false - if (e.code !== 1005) { - this.log.warn('Web socket closed [%s - %s].', e.code, e.reason) - if (e.code !== 1000) { + if (e !== 1005) { + this.log.warn('Web socket closed [%s].', e) + if (e !== 1000) { this.log('Web socket will try to reconnect in five seconds.') setTimeout(() => this.login(), 5000) } else { @@ -260,7 +260,7 @@ module.exports = class eWeLinkWS { async closeConnection () { if (this.wsp && this.wsIsOpen) { await this.wsp.close() - this.log('Web socket gracefully closed.') + if (this.debug) this.log('Web socket gracefully closed.') } } } From 283121e81ade308625dfa926937ddba1365a858c Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 28 Sep 2020 20:58:05 +0100 Subject: [PATCH 0258/3183] Update FUNDING.yml --- .github/FUNDING.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 9444c69e..9ccddac1 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,3 +1,4 @@ +github: bwp91 patreon: bwp91 ko_fi: bwp91 -custom: ["https://www.paypal.me/BenPotter"] +custom: https://www.paypal.me/BenPotter From 7d9cd2ed191bcfa26417c1568745a62eb5baf2a6 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 28 Sep 2020 22:27:05 +0100 Subject: [PATCH 0259/3183] Update eWeLink.js --- lib/eWeLink.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 5e06b1af..b07aea8f 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -97,7 +97,7 @@ class eWeLink { if (this.wsClient) { await this.wsClient.getHost() await this.wsClient.closeConnection() - await utils.sleep(250) + await utils.sleep(500) await this.wsClient.login() } } catch (err) { @@ -105,7 +105,7 @@ class eWeLink { } } }, - 1800000, { + 3600000, { stopOnError: false } ) From f9477090c1ece42f8974bc2b0818a44ba9fae557 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 29 Sep 2020 08:54:55 +0100 Subject: [PATCH 0260/3183] hideMasters bug --- lib/eWeLink.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index b07aea8f..e34924a6 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -97,7 +97,7 @@ class eWeLink { if (this.wsClient) { await this.wsClient.getHost() await this.wsClient.closeConnection() - await utils.sleep(500) + await utils.sleep(250) await this.wsClient.login() } } catch (err) { @@ -105,7 +105,7 @@ class eWeLink { } } }, - 3600000, { + 1800000, { stopOnError: false } ) @@ -477,7 +477,10 @@ class eWeLink { }, ...extraContext } - if (!hidden) { + if (hidden) { + if (type === 'light') accessory.control = new DeviceLight(this) + if (type === 'switch') accessory.control = new DeviceSwitch(this) + } else { this.api.registerPlatformAccessories('homebridge-ewelink', 'eWeLink', [accessory]) this.configureAccessory(accessory) this.log(' → [%s] has been added to Homebridge.', newDeviceName) From d24da5c354f79d1950da251783fd6c360efc1f89 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 29 Sep 2020 08:56:55 +0100 Subject: [PATCH 0261/3183] 3.1.5 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index da735c95..745f3ceb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.4", + "version": "3.1.5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index e2d5e794..3f36e1b5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.4", + "version": "3.1.5", "author": "bwp91", "contributors": [ "gbro115", From 88a84f3d2ce4d99c0f61092d47e0d02ba58e30b1 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 29 Sep 2020 15:57:36 +0100 Subject: [PATCH 0262/3183] rf sensor fix --- lib/device/{rf-sub.js => rf-bridge.js} | 3 ++- lib/eWeLink.js | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) rename lib/device/{rf-sub.js => rf-bridge.js} (97%) diff --git a/lib/device/rf-sub.js b/lib/device/rf-bridge.js similarity index 97% rename from lib/device/rf-sub.js rename to lib/device/rf-bridge.js index e1800637..18704edd 100644 --- a/lib/device/rf-sub.js +++ b/lib/device/rf-bridge.js @@ -1,7 +1,7 @@ 'use strict' let Characteristic, Service const utils = require('./../utils') -module.exports = class deviceRFSub { +module.exports = class deviceRFBridge { constructor (platform) { this.platform = platform Service = platform.api.hap.Service @@ -59,6 +59,7 @@ module.exports = class deviceRFSub { this.platform.devicesInHB.forEach(acc => { if ( acc.context.eweDeviceId === accessory.context.eweDeviceId && + Object.prototype.hasOwnProperty.call(acc.context, 'buttons') && Object.prototype.hasOwnProperty.call(acc.context.buttons, chan.substr(-1).toString()) ) { oAccessory = acc diff --git a/lib/eWeLink.js b/lib/eWeLink.js index e34924a6..c7012c01 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -15,7 +15,7 @@ const DeviceUSB = require('./device/usb') const DeviceSCM = require('./device/scm') const DeviceLight = require('./device/light') const DeviceSwitch = require('./device/switch') -const DeviceRFSub = require('./device/rf-sub') +const DeviceRFBridge = require('./device/rf-bridge') const DeviceZBDev = require('./device/zb-dev') const EWeLinkHTTP = require('./eWeLinkHTTP') const EWeLinkWS = require('./eWeLinkWS') @@ -254,6 +254,7 @@ class eWeLink { } this.hiddenMasters.push(device.deviceid) accessory = this.addAccessory(device, device.deviceid + 'SW0', 'light', true) + accessory.control = new DeviceLight(this) } else { accessory = this.devicesInHB.has(device.deviceid + 'SW0') ? this.devicesInHB.get(device.deviceid + 'SW0') @@ -287,6 +288,7 @@ class eWeLink { } this.hiddenMasters.push(device.deviceid) accessory = this.addAccessory(device, device.deviceid + 'SW0', 'switch', true) + accessory.control = new DeviceSwitch(this) } else { accessory = this.devicesInHB.has(device.deviceid + 'SW0') ? this.devicesInHB.get(device.deviceid + 'SW0') @@ -326,6 +328,7 @@ class eWeLink { : this.addAccessory(device, device.deviceid + 'SW0', 'rf_pri', true, { rfMap }) + accessory.control = new DeviceRFBridge(this) // this.log.error(JSON.stringify(accessory.context, null, 2)) rfMap.forEach(subDevice => { const swNumber = rfChlCounter + 1 @@ -477,10 +480,7 @@ class eWeLink { }, ...extraContext } - if (hidden) { - if (type === 'light') accessory.control = new DeviceLight(this) - if (type === 'switch') accessory.control = new DeviceSwitch(this) - } else { + if (!hidden) { this.api.registerPlatformAccessories('homebridge-ewelink', 'eWeLink', [accessory]) this.configureAccessory(accessory) this.log(' → [%s] has been added to Homebridge.', newDeviceName) @@ -801,7 +801,7 @@ class eWeLink { break } case 'rf_sub': { - accessory.control = new DeviceRFSub(this) + accessory.control = new DeviceRFBridge(this) switch (accessory.context.subType) { case 'water': accessory.getService(Service.LeakSensor) || accessory.addService(Service.LeakSensor) From 21ce252e20749ebee659792d6239fc0cab338fb7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 29 Sep 2020 16:10:34 +0100 Subject: [PATCH 0263/3183] subType fix --- lib/device/rf-bridge.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index 18704edd..cb49dd63 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -71,7 +71,7 @@ module.exports = class deviceRFBridge { let serv let char if (diff < (this.platform.config.sensorTimeDifference || 120)) { - switch (oAccessory.context.sensorType) { + switch (oAccessory.context.subType) { case 'button': break case 'water': From 30ae0be2b8566864f362501ac0ab5344c1f456c4 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 29 Sep 2020 16:11:09 +0100 Subject: [PATCH 0264/3183] 3.1.6 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 745f3ceb..b2a0e397 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.5", + "version": "3.1.6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 3f36e1b5..94fe430b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.5", + "version": "3.1.6", "author": "bwp91", "contributors": [ "gbro115", From 1607087dcf431dd21e4e08f2584e17b4c3afd05a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 29 Sep 2020 18:38:49 +0100 Subject: [PATCH 0265/3183] Update package.json --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index 94fe430b..34f1b04d 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,10 @@ { "type": "paypal", "url": "https://www.paypal.me/BenPotter" + }, + { + "type": "github", + "url": "https://github.com/sponsors/bwp91" } ], "dependencies": { From d4e1b057e2d3ea8b0a3fe8d3193a938e73415713 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 30 Sep 2020 01:41:39 +0100 Subject: [PATCH 0266/3183] node-dns-sd dep --- package-lock.json | 5 ++--- package.json | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index b2a0e397..630834c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -516,9 +516,8 @@ "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" }, "node-dns-sd": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/node-dns-sd/-/node-dns-sd-0.4.1.tgz", - "integrity": "sha512-x+WSuMgvDBQv24OCq75YHcZj1SOzvP5fU4Tz+PBUiVvVBsfc+9XAHAuIftaCpf2nPLl+ys71uZoGr/v9fVDa6A==" + "version": "github:bwp91/node-dns-sd#0babcfdd9a9512283df41f184e5f569e63f786fd", + "from": "github:bwp91/node-dns-sd" }, "node-fetch": { "version": "2.6.1", diff --git a/package.json b/package.json index 34f1b04d..e94394e4 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "fakegato-history": "0.5.6", "homebridge-lib": "4.7.15", "interval-promise": "1.4.0", - "node-dns-sd": "0.4.1", + "node-dns-sd": "bwp91/node-dns-sd", "websocket-as-promised": "1.0.1", "ws": "7.3.1" } From 80bb88b2a9dd0dcfa65e12ea65b08c149a5efc06 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 30 Sep 2020 01:48:06 +0100 Subject: [PATCH 0267/3183] return correct devicelist --- lib/eWeLinkHTTP.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index c3497f4b..45e2b6f4 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -153,13 +153,14 @@ module.exports = class eWeLinkHTTP { throw new Error(JSON.stringify(body, null, 2)) } const deviceList = [] + const returnList = [] if (body.data.thingList && body.data.thingList.length > 0) { body.data.thingList.forEach((device) => deviceList.push(device.itemData)) } - deviceList + returnList = deviceList .filter((d) => Object.prototype.hasOwnProperty.call(d, 'extra') && Object.prototype.hasOwnProperty.call(d.extra, 'uiid')) .filter((d) => !this.hideDevFromHB.includes(d.deviceid)) - return deviceList + return returnList } catch (err) { if (Object.prototype.hasOwnProperty.call(err, 'code') && cns.httpRetryCodes.includes(err.code)) { this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') From 3676f41da938f42b0872c6bfba999aa1be39428c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 30 Sep 2020 01:52:35 +0100 Subject: [PATCH 0268/3183] Update eWeLinkHTTP.js --- lib/eWeLinkHTTP.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 45e2b6f4..c5d3bbcf 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -153,14 +153,18 @@ module.exports = class eWeLinkHTTP { throw new Error(JSON.stringify(body, null, 2)) } const deviceList = [] - const returnList = [] if (body.data.thingList && body.data.thingList.length > 0) { - body.data.thingList.forEach((device) => deviceList.push(device.itemData)) + body.data.thingList.forEach(d => { + if ( + Object.prototype.hasOwnProperty.call(d, 'extra') && + Object.prototype.hasOwnProperty.call(d.extra, 'uiid') && + !this.hideDevFromHB.includes(d.deviceid) + ) { + deviceList.push(d.itemData) + } + }) } - returnList = deviceList - .filter((d) => Object.prototype.hasOwnProperty.call(d, 'extra') && Object.prototype.hasOwnProperty.call(d.extra, 'uiid')) - .filter((d) => !this.hideDevFromHB.includes(d.deviceid)) - return returnList + return deviceList } catch (err) { if (Object.prototype.hasOwnProperty.call(err, 'code') && cns.httpRetryCodes.includes(err.code)) { this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') From f18345dbb8200dce2bc49b86651bc366b1394283 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 30 Sep 2020 02:01:56 +0100 Subject: [PATCH 0269/3183] fix deviceList --- lib/eWeLinkHTTP.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index c5d3bbcf..a40122a9 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -156,9 +156,10 @@ module.exports = class eWeLinkHTTP { if (body.data.thingList && body.data.thingList.length > 0) { body.data.thingList.forEach(d => { if ( - Object.prototype.hasOwnProperty.call(d, 'extra') && - Object.prototype.hasOwnProperty.call(d.extra, 'uiid') && - !this.hideDevFromHB.includes(d.deviceid) + Object.prototype.hasOwnProperty.call(d, 'itemData') && + Object.prototype.hasOwnProperty.call(d.itemData, 'extra') && + Object.prototype.hasOwnProperty.call(d.itemData.extra, 'uiid') && + !this.hideDevFromHB.includes(d.itemData.deviceid) ) { deviceList.push(d.itemData) } From b6fe1aafd05dd23bf48737c9595fc34a47000f78 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 30 Sep 2020 06:50:21 +0100 Subject: [PATCH 0270/3183] node-dns-sd dep --- package-lock.json | 5 +++-- package.json | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 630834c2..e81a9949 100644 --- a/package-lock.json +++ b/package-lock.json @@ -516,8 +516,9 @@ "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" }, "node-dns-sd": { - "version": "github:bwp91/node-dns-sd#0babcfdd9a9512283df41f184e5f569e63f786fd", - "from": "github:bwp91/node-dns-sd" + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/node-dns-sd/-/node-dns-sd-0.4.2.tgz", + "integrity": "sha512-fZvDqy19zyaiSXajmRjwue1VWLrJcy8bTV/LJVtAx8DeEFVlXRBMyZknW+q6CEfiW8Y4MQDDKh9x5wF32BHAHQ==" }, "node-fetch": { "version": "2.6.1", diff --git a/package.json b/package.json index e94394e4..96a831d3 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "fakegato-history": "0.5.6", "homebridge-lib": "4.7.15", "interval-promise": "1.4.0", - "node-dns-sd": "bwp91/node-dns-sd", + "node-dns-sd": "0.4.2", "websocket-as-promised": "1.0.1", "ws": "7.3.1" } From 78ee826163b356158633c1e84cf09cc67de66188 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 30 Sep 2020 06:51:51 +0100 Subject: [PATCH 0271/3183] 3.1.7 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index e81a9949..f42e1988 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.6", + "version": "3.1.7", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 96a831d3..256697ec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.6", + "version": "3.1.7", "author": "bwp91", "contributors": [ "gbro115", From 71308867b5f37811269e66f71c7f997839c39460 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Wed, 30 Sep 2020 08:55:41 +0100 Subject: [PATCH 0272/3183] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1c683be2..02449b11 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,12 @@ Homebridge plugin to control eWeLink devices with original firmware. - [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) - [![Discord](https://img.shields.io/discord/432663330281226270?color=728ED5&logo=discord&label=discord)](https://discord.com/channels/432663330281226270/742733745743855627) - [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) + [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/latest?label=release)](https://www.npmjs.com/package/homebridge-ewelink) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://www.npmjs.com/package/homebridge-ewelink) [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) + [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) + [![Discord](https://img.shields.io/discord/432663330281226270?color=728ED5&logo=discord&label=discord)](https://discord.com/channels/432663330281226270/742733745743855627) [![Contribute](https://img.shields.io/badge/contribute-a%20drink-yellow)](https://ko-fi.com/bwp91) From 3f7af86ae8e576db796a7fddb1dc95c223ce6af9 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Wed, 30 Sep 2020 08:55:53 +0100 Subject: [PATCH 0273/3183] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 02449b11..33b6d570 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ [![npm](https://img.shields.io/npm/v/homebridge-ewelink/latest?label=release)](https://www.npmjs.com/package/homebridge-ewelink) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://www.npmjs.com/package/homebridge-ewelink) [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) - [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) + [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Discord](https://img.shields.io/discord/432663330281226270?color=728ED5&logo=discord&label=discord)](https://discord.com/channels/432663330281226270/742733745743855627) [![Contribute](https://img.shields.io/badge/contribute-a%20drink-yellow)](https://ko-fi.com/bwp91) From 1c5e5c6a1edc89e8a2b55d4d34dc96446e530989 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 30 Sep 2020 11:18:16 +0100 Subject: [PATCH 0274/3183] eachen garage door --- config.schema.json | 6 +++++ lib/constants.js | 2 +- lib/device/garage-eachen.js | 52 +++++++++++++++++++++++++++++++++++++ lib/eWeLink.js | 24 +++++++++++++++++ 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 lib/device/garage-eachen.js diff --git a/config.schema.json b/config.schema.json index 5e99588c..e3c794e0 100644 --- a/config.schema.json +++ b/config.schema.json @@ -138,6 +138,12 @@ "garage" ] }, + { + "title": "Garage Door (Eachen)", + "enum": [ + "garage_eachen" + ] + }, { "title": "Lock", "enum": [ diff --git a/lib/constants.js b/lib/constants.js index ba6d44fa..0f618fb6 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -3,7 +3,7 @@ module.exports = { appId: 'oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq', appSecret: '6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM', httpRetryCodes: ['ENOTFOUND', 'ETIMEDOUT', 'EAI_AGAIN'], - allowedGroups: ['blind', 'garage', 'lock', 'valve'], + allowedGroups: ['blind', 'garage', 'garage_eachen', 'lock', 'valve'], devicesHideable: ['switch', 'light'], devicesNonLAN: [22, 28, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js new file mode 100644 index 00000000..22c6c3eb --- /dev/null +++ b/lib/device/garage-eachen.js @@ -0,0 +1,52 @@ +'use strict' +let Characteristic, Service +const utils = require('./../utils') +module.exports = class deviceGarageEachen { + constructor (platform) { + this.platform = platform + Service = platform.api.hap.Service + Characteristic = platform.api.hap.Characteristic + } + + async internalGarageEachenUpdate (accessory, value, callback) { + callback() + try { + let garageConfig + if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + throw new Error('group config missing') + } + const params = {} + const newPos = value + const gdService = accessory.getService(Service.GarageDoorOpener) + const prevState = gdService.getCharacteristic(Characteristic.CurrentDoorState).value + if (newPos === prevState % 2) return + accessory.context.inUse = true + gdService + .updateCharacteristic(Characteristic.TargetDoorState, newPos) + .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2) + // newPos can be 0 TO open and 1 TO CLOSE + // params.switch === 'on' TO open and 'off' TO close + // HK 0 for open 1 for closed + params.switch = value === 0 ? 'on' : 'off' + await this.platform.sendDeviceUpdate(accessory, params) + await utils.sleep(garageConfig.operationTime * 100) + gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos) + accessory.context.inUse = false + } catch (err) { + this.platform.deviceUpdateError(accessory, err, true) + } + } + + externalGarageEachenUpdate (accessory, params) { + try { + if (!Object.prototype.hasOwnProperty.call(params, 'switch') || accessory.context.inUse) { + return + } + const gdService = accessory.getService(Service.GarageDoorOpener) + gdService.updateCharacteristic(Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) + gdService.updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) + } catch (err) { + this.platform.deviceUpdateError(accessory, err, false) + } + } +} diff --git a/lib/eWeLink.js b/lib/eWeLink.js index c7012c01..216a93af 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -5,6 +5,7 @@ const corrInterval = require('correcting-interval') const DeviceCurtain = require('./device/curtain') const DeviceBlind = require('./device/blind') const DeviceGarage = require('./device/garage') +const DeviceGarageEachen = require('./device/garage-eachen') const DeviceLock = require('./device/lock') const DeviceValve = require('./device/valve') const DeviceSensor = require('./device/sensor') @@ -185,6 +186,10 @@ class eWeLink { accessory.context.cacheTargetDoorState = 1 } //* ** @ENDUPGRADE ***\\ + } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage_eachen') { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', 'garage_eachen') } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'lock') { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') @@ -546,6 +551,22 @@ class eWeLink { .on('set', (value, callback) => accessory.control.internalGarageUpdate(accessory, value, callback)) break } + case 'garage_eachen': { + accessory.control = new DeviceGarageEachen(this) + let gdeService + if (!(gdeService = accessory.getService(Service.GarageDoorOpener))) { + accessory + .addService(Service.GarageDoorOpener) + .setCharacteristic(Characteristic.CurrentDoorState, 1) + .setCharacteristic(Characteristic.TargetDoorState, 1) + .setCharacteristic(Characteristic.ObstructionDetected, false) + gdeService = accessory.getService(Service.GarageDoorOpener) + } + gdeService + .getCharacteristic(Characteristic.TargetDoorState) + .on('set', (value, callback) => accessory.control.internalGarageEachenUpdate(accessory, value, callback)) + break + } case 'lock': { accessory.control = new DeviceLock(this) const lmService = accessory.getService(Service.LockMechanism) || accessory.addService(Service.LockMechanism) @@ -905,6 +926,9 @@ class eWeLink { case 'garage': accessory.control.externalGarageUpdate(accessory, newParams) return true + case 'garage_eachen': + accessory.control.externalGarageEachenUpdate(accessory, newParams) + return true case 'lock': accessory.control.externalLockUpdate(accessory, newParams) return true From 76f8549888651267bba5d64e38d21a7f06717e7f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 30 Sep 2020 11:19:24 +0100 Subject: [PATCH 0275/3183] 3.2.0-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f42e1988..9c316094 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.7", + "version": "3.2.0-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 256697ec..5fe27906 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.1.7", + "version": "3.2.0-0", "author": "bwp91", "contributors": [ "gbro115", From 418bd33ecfa61369ad1d9de0e4d16aca2ca5d470 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 30 Sep 2020 12:41:15 +0100 Subject: [PATCH 0276/3183] clean up --- lib/device/garage-eachen.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 22c6c3eb..e3b683a2 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -24,15 +24,13 @@ module.exports = class deviceGarageEachen { gdService .updateCharacteristic(Characteristic.TargetDoorState, newPos) .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2) - // newPos can be 0 TO open and 1 TO CLOSE - // params.switch === 'on' TO open and 'off' TO close - // HK 0 for open 1 for closed params.switch = value === 0 ? 'on' : 'off' await this.platform.sendDeviceUpdate(accessory, params) await utils.sleep(garageConfig.operationTime * 100) gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos) accessory.context.inUse = false } catch (err) { + accessory.context.inUse = false this.platform.deviceUpdateError(accessory, err, true) } } From 1e81de777fe02300fa720e30bcb95fd4568b4379 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 30 Sep 2020 18:12:27 +0100 Subject: [PATCH 0277/3183] improved ui for custom setups --- config.schema.json | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/config.schema.json b/config.schema.json index e3c794e0..24211140 100644 --- a/config.schema.json +++ b/config.schema.json @@ -127,31 +127,31 @@ "description": "The new type for this device.", "oneOf": [ { - "title": "Blind", + "title": "Blind (Generic Setup)", "enum": [ "blind" ] }, { - "title": "Garage Door", + "title": "Garage Door (Generic Setup)", "enum": [ "garage" ] }, { - "title": "Garage Door (Eachen)", + "title": "Garage Door (Eachen GD-DC5)", "enum": [ "garage_eachen" ] }, { - "title": "Lock", + "title": "Lock (Generic Setup)", "enum": [ "lock" ] }, { - "title": "Irrigation", + "title": "Irrigation (Generic Setup)", "enum": [ "valve" ] @@ -162,7 +162,10 @@ "type": "string", "title": "Device Setup", "default": "null", - "description": "The device setup. Blinds must be set up with two switches. Please ignore this setting for locks and irrigation.", + "description": "The setup for your garage doors.", + "condition": { + "functionBody": "return (model.groups[arrayIndices] && model.groups[arrayIndices].type==='garage')" + }, "oneOf": [ { "title": "One Switch - for up and down", @@ -189,7 +192,10 @@ "sensorId": { "type": "string", "title": "Sensor", - "description": "A Sonoff DW2 sensor can optionally be used for garage doors. This is to determine the current open/closed state of the garage door. Please enter the 10 digit device ID (normally in the format 1000ab23cd). Otherwise leave this blank." + "description": "A Sonoff DW2 sensor can optionally be used for garage doors. This is to determine the current open/closed state of the garage door. Please enter the 10 digit device ID (normally in the format 1000ab23cd). Otherwise leave this blank.", + "condition": { + "functionBody": "return (model.groups[arrayIndices] && model.groups[arrayIndices].type==='garage')" + } } } } From 20cbbe6be8220a7cf1defb9f8ceedc4e4df0b8fe Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 09:05:09 +0100 Subject: [PATCH 0278/3183] consistent function names --- lib/device/blind.js | 8 +- lib/device/curtain.js | 4 +- lib/device/fan.js | 4 +- lib/device/garage-eachen.js | 14 +- lib/device/garage.js | 4 +- lib/device/light.js | 406 +++++++++++++++++------------------- lib/device/lock.js | 4 +- lib/device/outlet.js | 4 +- lib/device/rf-bridge.js | 4 +- lib/device/scm.js | 4 +- lib/device/sensor.js | 2 +- lib/device/switch.js | 46 ++-- lib/device/thermostat.js | 4 +- lib/device/usb.js | 4 +- lib/device/valve.js | 4 +- lib/device/zb-dev.js | 2 +- 16 files changed, 256 insertions(+), 262 deletions(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index 9223338a..6584d7b3 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -9,7 +9,7 @@ module.exports = class deviceBlind { Characteristic = platform.api.hap.Characteristic } - async internalBlindUpdate (accessory, value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { let blindConfig @@ -22,7 +22,7 @@ module.exports = class deviceBlind { if (!(blindConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') } - if (blindConfig.type !== 'blind' || blindConfig.setup !== 'twoSwitch') { + if (blindConfig.type !== 'blind') { throw new Error('improper configuration') } if (newTarget === prevPosition) return @@ -67,4 +67,8 @@ module.exports = class deviceBlind { this.platform.deviceUpdateError(accessory, err, true) } } + + externalUpdate (accessory, params) { + return true + } } diff --git a/lib/device/curtain.js b/lib/device/curtain.js index 73e5fc3f..1b5d07cb 100644 --- a/lib/device/curtain.js +++ b/lib/device/curtain.js @@ -7,7 +7,7 @@ module.exports = class deviceCurtain { Characteristic = platform.api.hap.Characteristic } - async internalCurtainUpdate (accessory, value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { let params @@ -34,7 +34,7 @@ module.exports = class deviceCurtain { } } - externalCurtainUpdate (accessory, params) { + externalUpdate (accessory, params) { try { const cService = accessory.getService(Service.WindowCovering) if (!Object.prototype.hasOwnProperty.call(params, 'switch') && !Object.prototype.hasOwnProperty.call(params, 'setclose')) { diff --git a/lib/device/fan.js b/lib/device/fan.js index 9e829390..16221475 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -7,7 +7,7 @@ module.exports = class deviceFan { Characteristic = platform.api.hap.Characteristic } - async internalFanUpdate (accessory, type, value, callback) { + async internalUpdate (accessory, type, value, callback) { callback() try { let newPower @@ -49,7 +49,7 @@ module.exports = class deviceFan { } } - externalFanUpdate (accessory, params) { + externalUpdate (accessory, params) { try { let light let status diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index e3b683a2..dc27d4e6 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -8,13 +8,16 @@ module.exports = class deviceGarageEachen { Characteristic = platform.api.hap.Characteristic } - async internalGarageEachenUpdate (accessory, value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { let garageConfig if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') } + if (garageConfig.type !== 'garage_eachen') { + throw new Error('improper configuration') + } const params = {} const newPos = value const gdService = accessory.getService(Service.GarageDoorOpener) @@ -35,11 +38,18 @@ module.exports = class deviceGarageEachen { } } - externalGarageEachenUpdate (accessory, params) { + externalUpdate (accessory, params) { try { if (!Object.prototype.hasOwnProperty.call(params, 'switch') || accessory.context.inUse) { return } + let garageConfig + if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + throw new Error('group config missing') + } + if (garageConfig.type !== 'garage_eachen') { + throw new Error('improper configuration') + } const gdService = accessory.getService(Service.GarageDoorOpener) gdService.updateCharacteristic(Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) gdService.updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) diff --git a/lib/device/garage.js b/lib/device/garage.js index 5f4cd1dc..4c1270dc 100644 --- a/lib/device/garage.js +++ b/lib/device/garage.js @@ -8,7 +8,7 @@ module.exports = class deviceGarage { Characteristic = platform.api.hap.Characteristic } - async internalGarageUpdate (accessory, value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { let garageConfig @@ -72,7 +72,7 @@ module.exports = class deviceGarage { } } - externalGarageUpdate (accessory, params) { + externalUpdate (accessory, params) { try { if (!Object.prototype.hasOwnProperty.call(params, 'switch') && !Object.prototype.hasOwnProperty.call(params, 'switches')) { return diff --git a/lib/device/light.js b/lib/device/light.js index cd8fe085..3b210f76 100644 --- a/lib/device/light.js +++ b/lib/device/light.js @@ -10,131 +10,117 @@ module.exports = class deviceLight { Characteristic = platform.api.hap.Characteristic } - async internalLightbulbUpdate (accessory, value, callback) { + async internalUpdate (accessory, type, value, callback) { callback() try { let oAccessory - const params = {} + let newRGB + let params = {} const lightService = accessory.getService(Service.Lightbulb) - switch (accessory.context.switchNumber) { - case 'X': - if (accessory.context.eweUIID === 22) { - //* ** B1 ***\\ - params.state = value ? 'on' : 'off' - } else { - params.switch = value ? 'on' : 'off' + switch (type) { + case 'onoff': + switch (accessory.context.switchNumber) { + case 'X': + if (accessory.context.eweUIID === 22) { + //* ** B1 ***\\ + params.state = value ? 'on' : 'off' + } else { + params.switch = value ? 'on' : 'off' + } + break + case '0': + params.switches = cns.defaultMultiSwitchOff + params.switches[0].switch = value ? 'on' : 'off' + params.switches[1].switch = value ? 'on' : 'off' + params.switches[2].switch = value ? 'on' : 'off' + params.switches[3].switch = value ? 'on' : 'off' + break + case '1': + case '2': + case '3': + case '4': + params.switches = cns.defaultMultiSwitchOff + for (let i = 1; i <= 4; i++) { + if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { + i === parseInt(accessory.context.switchNumber) + ? (params.switches[i - 1].switch = value ? 'on' : 'off') + : (params.switches[i - 1].switch = oAccessory + .getService(Service.Lightbulb) + .getCharacteristic(Characteristic.On).value + ? 'on' + : 'off') + } else { + params.switches[i - 1].switch = 'off' + } + } + break } - break - case '0': - params.switches = cns.defaultMultiSwitchOff - params.switches[0].switch = value ? 'on' : 'off' - params.switches[1].switch = value ? 'on' : 'off' - params.switches[2].switch = value ? 'on' : 'off' - params.switches[3].switch = value ? 'on' : 'off' - break - case '1': - case '2': - case '3': - case '4': - params.switches = cns.defaultMultiSwitchOff - for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { - i === parseInt(accessory.context.switchNumber) - ? (params.switches[i - 1].switch = value ? 'on' : 'off') - : (params.switches[i - 1].switch = oAccessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.On).value - ? 'on' - : 'off') - } else { - params.switches[i - 1].switch = 'off' + await this.platform.sendDeviceUpdate(accessory, params) + switch (accessory.context.switchNumber) { + case 'X': + lightService.updateCharacteristic(Characteristic.On, value) + break + case '0': + for (let i = 0; i <= 4; i++) { + if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { + oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value) + } + } + break + case '1': + case '2': + case '3': + case '4': { + lightService.updateCharacteristic(Characteristic.On, value) + let masterState = 'off' + for (let i = 1; i <= 4; i++) { + if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { + if (oAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + masterState = 'on' + } + } + } + if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { + oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW0') + oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, masterState === 'on') + } + break } } break - } - await this.platform.sendDeviceUpdate(accessory, params) - switch (accessory.context.switchNumber) { - case 'X': - lightService.updateCharacteristic(Characteristic.On, value) - break - case '0': - for (let i = 0; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { - oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value) + case 'brightness': + if (value === 0) { + params.switch = 'off' + } else { + if (!lightService.getCharacteristic(Characteristic.On).value) { + params.switch = 'on' } - } - break - case '1': - case '2': - case '3': - case '4': { - lightService.updateCharacteristic(Characteristic.On, value) - let masterState = 'off' - for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { - if (oAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { - masterState = 'on' - } + switch (accessory.context.eweUIID) { + case 36: //* ** KING-M4 ***\\ + params.bright = Math.round((value * 9) / 10 + 10) + break + case 44: //* ** D1 ***\\ + params.brightness = value + params.mode = 0 + break } } - if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { - oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW0') - oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, masterState === 'on') + await utils.sleep(250) + await this.platform.sendDeviceUpdate(accessory, params) + if (value === 0) { + lightService.updateCharacteristic(Characteristic.On, false) + } else { + lightService.updateCharacteristic(Characteristic.Brightness, value) } break - } - } - } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) - } - } - - async internalBrightnessUpdate (accessory, value, callback) { - callback() - try { - const params = {} - const lightService = accessory.getService(Service.Lightbulb) - if (value === 0) { - params.switch = 'off' - } else { - if (!lightService.getCharacteristic(Characteristic.On).value) { - params.switch = 'on' - } - switch (accessory.context.eweUIID) { - case 36: //* ** KING-M4 ***\\ - params.bright = Math.round((value * 9) / 10 + 10) - break - case 44: //* ** D1 ***\\ - params.brightness = value - params.mode = 0 - break - } - } - await utils.sleep(250) - await this.platform.sendDeviceUpdate(accessory, params) - if (value === 0) { - lightService.updateCharacteristic(Characteristic.On, false) - } else { - lightService.updateCharacteristic(Characteristic.Brightness, value) - } - } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) - } - } - - async internalHSBUpdate (accessory, type, value, callback) { - callback() - try { - let newRGB - let params = {} - const lightService = accessory.getService(Service.Lightbulb) - const curHue = lightService.getCharacteristic(Characteristic.Hue).value - const curSat = lightService.getCharacteristic(Characteristic.Saturation).value - switch (type) { - case 'hue': - newRGB = convert.hsv.rgb(value, curSat, 100) + case 'c_brightness': switch (accessory.context.eweUIID) { case 22: //* ** B1 ***\\ + newRGB = convert.hsv.rgb( + lightService.getCharacteristic(Characteristic.Hue).value, + lightService.getCharacteristic(Characteristic.Saturation).value, + value + ) params = { zyx_mode: 2, type: 'middle', @@ -148,17 +134,18 @@ module.exports = class deviceLight { case 59: //* ** L1 ***\\ params = { mode: 1, - colorR: newRGB[0], - colorG: newRGB[1], - colorB: newRGB[2] + bright: value } break } + await utils.sleep(250) + await this.platform.sendDeviceUpdate(accessory, params) + lightService.updateCharacteristic(Characteristic.Brightness, value) break - case 'bri': + case 'c_hue': + newRGB = convert.hsv.rgb(value, lightService.getCharacteristic(Characteristic.Saturation).value, 100) switch (accessory.context.eweUIID) { case 22: //* ** B1 ***\\ - newRGB = convert.hsv.rgb(curHue, curSat, value) params = { zyx_mode: 2, type: 'middle', @@ -172,117 +159,114 @@ module.exports = class deviceLight { case 59: //* ** L1 ***\\ params = { mode: 1, - bright: value + colorR: newRGB[0], + colorG: newRGB[1], + colorB: newRGB[2] } break } - break - } - await utils.sleep(250) - await this.platform.sendDeviceUpdate(accessory, params) - switch (type) { - case 'hue': + await utils.sleep(250) + await this.platform.sendDeviceUpdate(accessory, params) lightService.updateCharacteristic(Characteristic.Hue, value) break - case 'bri': - lightService.updateCharacteristic(Characteristic.Brightness, value) - break } } catch (err) { this.platform.deviceUpdateError(accessory, err, true) } } - externalSingleLightUpdate (accessory, params) { + externalUpdate (accessory, params) { try { - let newColour - let mode - let isOn = false - const lightService = accessory.getService(Service.Lightbulb) - if (accessory.context.eweUIID === 22 && Object.prototype.hasOwnProperty.call(params, 'state')) { - isOn = params.state === 'on' - } else if (accessory.context.eweUIID !== 22 && Object.prototype.hasOwnProperty.call(params, 'switch')) { - isOn = params.switch === 'on' - } else { - isOn = lightService.getCharacteristic(Characteristic.On).value - } - if (isOn) { - lightService.updateCharacteristic(Characteristic.On, true) - switch (accessory.context.eweUIID) { - case 36: // KING-M4 - if (Object.prototype.hasOwnProperty.call(params, 'bright')) { - const nb = Math.round(((params.bright - 10) * 10) / 9) // eWeLink scale is 10-100 and HomeKit scale is 0-100. - lightService.updateCharacteristic(Characteristic.Brightness, nb) - } - break - case 44: // D1 - if (Object.prototype.hasOwnProperty.call(params, 'brightness')) { - lightService.updateCharacteristic(Characteristic.Brightness, params.brightness) - } - break - case 22: // B1 - if (Object.prototype.hasOwnProperty.call(params, 'zyx_mode')) { - mode = parseInt(params.zyx_mode) - } else if (Object.prototype.hasOwnProperty.call(params, 'channel0') && parseInt(params.channel0) + parseInt(params.channel1) > 0) { - mode = 1 - } else { - mode = 2 - } - if (mode === 2) { - lightService.updateCharacteristic(Characteristic.On, true) - newColour = convert.rgb.hsv( - parseInt(params.channel2), - parseInt(params.channel3), - parseInt(params.channel4) - ) - lightService - .updateCharacteristic(Characteristic.Hue, newColour[0]) - .updateCharacteristic(Characteristic.Saturation, 100) - .updateCharacteristic(Characteristic.Brightness, 100) - } else if (mode === 1) { - throw new Error('has been set to white mode which is not supported') - } - break - case 59: // L1 - if (Object.prototype.hasOwnProperty.call(params, 'bright')) { - lightService.updateCharacteristic(Characteristic.Brightness, params.bright) - } - if (Object.prototype.hasOwnProperty.call(params, 'colorR')) { - newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB) - lightService - .updateCharacteristic(Characteristic.Hue, newColour[0]) - .updateCharacteristic(Characteristic.Saturation, newColour[1]) - } - break - default: - return + if ( + cns.devicesSingleSwitch.includes(accessory.context.eweUIID) && + cns.devicesSingleSwitchLight.includes(accessory.context.eweModel) + ) { + let newColour + let mode + let isOn = false + const lightService = accessory.getService(Service.Lightbulb) + if (accessory.context.eweUIID === 22 && Object.prototype.hasOwnProperty.call(params, 'state')) { + isOn = params.state === 'on' + } else if (accessory.context.eweUIID !== 22 && Object.prototype.hasOwnProperty.call(params, 'switch')) { + isOn = params.switch === 'on' + } else { + isOn = lightService.getCharacteristic(Characteristic.On).value } - } else { - lightService.updateCharacteristic(Characteristic.On, false) - } - } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) - } - } - - externalMultiLightUpdate (accessory, params) { - try { - if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return - const idToCheck = accessory.context.hbDeviceId.slice(0, -1) - let primaryState = false - for (let i = 1; i <= accessory.context.channelCount; i++) { - if (this.platform.devicesInHB.has(idToCheck + i)) { - const oAccessory = this.platform.devicesInHB.get(idToCheck + i) - oAccessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === 'on') - if (params.switches[i - 1].switch === 'on') { - primaryState = true + if (isOn) { + lightService.updateCharacteristic(Characteristic.On, true) + switch (accessory.context.eweUIID) { + case 36: // KING-M4 + if (Object.prototype.hasOwnProperty.call(params, 'bright')) { + const nb = Math.round(((params.bright - 10) * 10) / 9) // eWeLink scale is 10-100 and HomeKit scale is 0-100. + lightService.updateCharacteristic(Characteristic.Brightness, nb) + } + break + case 44: // D1 + if (Object.prototype.hasOwnProperty.call(params, 'brightness')) { + lightService.updateCharacteristic(Characteristic.Brightness, params.brightness) + } + break + case 22: // B1 + if (Object.prototype.hasOwnProperty.call(params, 'zyx_mode')) { + mode = parseInt(params.zyx_mode) + } else if (Object.prototype.hasOwnProperty.call(params, 'channel0') && parseInt(params.channel0) + parseInt(params.channel1) > 0) { + mode = 1 + } else { + mode = 2 + } + if (mode === 2) { + lightService.updateCharacteristic(Characteristic.On, true) + newColour = convert.rgb.hsv( + parseInt(params.channel2), + parseInt(params.channel3), + parseInt(params.channel4) + ) + lightService + .updateCharacteristic(Characteristic.Hue, newColour[0]) + .updateCharacteristic(Characteristic.Saturation, 100) + .updateCharacteristic(Characteristic.Brightness, 100) + } else if (mode === 1) { + throw new Error('has been set to white mode which is not supported') + } + break + case 59: // L1 + if (Object.prototype.hasOwnProperty.call(params, 'bright')) { + lightService.updateCharacteristic(Characteristic.Brightness, params.bright) + } + if (Object.prototype.hasOwnProperty.call(params, 'colorR')) { + newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB) + lightService + .updateCharacteristic(Characteristic.Hue, newColour[0]) + .updateCharacteristic(Characteristic.Saturation, newColour[1]) + } + break + default: + return } + } else { + lightService.updateCharacteristic(Characteristic.On, false) + } + } else if ( + cns.devicesMultiSwitch.includes(accessory.context.eweUIID) && + cns.devicesMultiSwitchLight.includes(accessory.context.eweModel) + ) { + if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return + const idToCheck = accessory.context.hbDeviceId.slice(0, -1) + let primaryState = false + for (let i = 1; i <= accessory.context.channelCount; i++) { + if (this.platform.devicesInHB.has(idToCheck + i)) { + const oAccessory = this.platform.devicesInHB.get(idToCheck + i) + oAccessory + .getService(Service.Lightbulb) + .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === 'on') + if (params.switches[i - 1].switch === 'on') { + primaryState = true + } + } + } + if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { + accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, primaryState) } - } - if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, primaryState) } } catch (err) { this.platform.deviceUpdateError(accessory, err, false) diff --git a/lib/device/lock.js b/lib/device/lock.js index e82e3882..8a4972be 100644 --- a/lib/device/lock.js +++ b/lib/device/lock.js @@ -8,7 +8,7 @@ module.exports = class deviceLock { Characteristic = platform.api.hap.Characteristic } - async internalLockUpdate (accessory, value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { let lockConfig @@ -37,7 +37,7 @@ module.exports = class deviceLock { } } - externalLockUpdate (accessory, params) { + externalUpdate (accessory, params) { try { if (!Object.prototype.hasOwnProperty.call(params, 'switch')) return let lockConfig diff --git a/lib/device/outlet.js b/lib/device/outlet.js index c244e42f..56e31434 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -9,7 +9,7 @@ module.exports = class deviceOutlet { EveService = new hbLib.EveHomeKitTypes(platform.api) } - async internalOutletUpdate (accessory, value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { const params = { @@ -23,7 +23,7 @@ module.exports = class deviceOutlet { } } - externalOutletUpdate (accessory, params) { + externalUpdate (accessory, params) { try { const outletService = accessory.getService(Service.Outlet) if (Object.prototype.hasOwnProperty.call(params, 'switch')) { diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index cb49dd63..2e988d4c 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -8,7 +8,7 @@ module.exports = class deviceRFBridge { Characteristic = platform.api.hap.Characteristic } - async internalRFUpdate (accessory, rfChl, service, callback) { + async internalUpdate (accessory, rfChl, service, callback) { callback() try { const params = { @@ -25,7 +25,7 @@ module.exports = class deviceRFBridge { } } - externalRFUpdate (accessory, params) { + externalUpdate (accessory, params) { try { if (!Object.prototype.hasOwnProperty.call(params, 'updateSource')) return const timeNow = new Date() diff --git a/lib/device/scm.js b/lib/device/scm.js index 501bdb29..98dc1357 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -8,7 +8,7 @@ module.exports = class deviceSCM { Characteristic = platform.api.hap.Characteristic } - async internalSCMUpdate (accessory, value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { const params = { @@ -23,7 +23,7 @@ module.exports = class deviceSCM { } } - externalSCMUpdate (accessory, params) { + externalUpdate (accessory, params) { try { if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switches[0].switch === 'on') diff --git a/lib/device/sensor.js b/lib/device/sensor.js index 844bca01..47a4bd2b 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -7,7 +7,7 @@ module.exports = class deviceSensor { Characteristic = platform.api.hap.Characteristic } - externalSensorUpdate (accessory, params) { + externalUpdate (accessory, params) { try { if (Object.prototype.hasOwnProperty.call(params, 'battery')) { const batteryService = diff --git a/lib/device/switch.js b/lib/device/switch.js index 9a70c3c1..a7422968 100644 --- a/lib/device/switch.js +++ b/lib/device/switch.js @@ -8,7 +8,7 @@ module.exports = class deviceSwitch { Characteristic = platform.api.hap.Characteristic } - async internalSwitchUpdate (accessory, value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { let oAccessory @@ -82,33 +82,29 @@ module.exports = class deviceSwitch { } } - externalSingleSwitchUpdate (accessory, params) { + externalUpdate (accessory, params) { try { - if (!Object.prototype.hasOwnProperty.call(params, 'switch')) return - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switch === 'on') - } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) - } - } - - externalMultiSwitchUpdate (accessory, params) { - try { - if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return - const idToCheck = accessory.context.hbDeviceId.slice(0, -1) - let primaryState = false - for (let i = 1; i <= accessory.context.channelCount; i++) { - if (this.platform.devicesInHB.has(idToCheck + i)) { - const oAccessory = this.platform.devicesInHB.get(idToCheck + i) - oAccessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === 'on') - if (params.switches[i - 1].switch === 'on') { - primaryState = true + if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID)) { + if (!Object.prototype.hasOwnProperty.call(params, 'switch')) return + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switch === 'on') + } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID)) { + if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return + const idToCheck = accessory.context.hbDeviceId.slice(0, -1) + let primaryState = false + for (let i = 1; i <= accessory.context.channelCount; i++) { + if (this.platform.devicesInHB.has(idToCheck + i)) { + const oAccessory = this.platform.devicesInHB.get(idToCheck + i) + oAccessory + .getService(Service.Switch) + .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === 'on') + if (params.switches[i - 1].switch === 'on') { + primaryState = true + } } } - } - if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState) + if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { + accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState) + } } } catch (err) { this.platform.deviceUpdateError(accessory, err, false) diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index ba86d219..b987d601 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -7,7 +7,7 @@ module.exports = class deviceThermostat { Characteristic = platform.api.hap.Characteristic } - async internalThermostatUpdate (accessory, value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { const params = { @@ -22,7 +22,7 @@ module.exports = class deviceThermostat { } } - externalThermostatUpdate (accessory, params) { + externalUpdate (accessory, params) { try { if ( !this.platform.config.hideTHSwitch && diff --git a/lib/device/usb.js b/lib/device/usb.js index 67a58833..a2305136 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -8,7 +8,7 @@ module.exports = class deviceUSB { Characteristic = platform.api.hap.Characteristic } - async internalUSBUpdate (accessory, value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { const params = { @@ -23,7 +23,7 @@ module.exports = class deviceUSB { } } - externalUSBUpdate (accessory, params) { + externalUpdate (accessory, params) { try { if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switches[0].switch === 'on') diff --git a/lib/device/valve.js b/lib/device/valve.js index c7d1dab8..8522fd19 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -6,7 +6,7 @@ module.exports = class deviceValve { Characteristic = platform.api.hap.Characteristic } - async internalValveUpdate (accessory, valve, value, callback) { + async internalUpdate (accessory, valve, value, callback) { callback() try { let valveConfig @@ -54,7 +54,7 @@ module.exports = class deviceValve { } } - externalValveUpdate (accessory, params) { + externalUpdate (accessory, params) { try { if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return let valveConfig diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index 365cedb8..d4e9cec5 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -7,7 +7,7 @@ module.exports = class deviceZBDev { Characteristic = platform.api.hap.Characteristic } - externalZBUpdate (accessory, params) { + externalUpdate (accessory, params) { try { //* ** credit @tasict ***\\ if (Object.prototype.hasOwnProperty.call(params, 'battery')) { From 8c9ab90b1d2042435faa05785a9f627307c8d0d9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 09:05:28 +0100 Subject: [PATCH 0279/3183] code cleanups --- lib/eWeLink.js | 276 +++++++++++-------------------------------------- 1 file changed, 58 insertions(+), 218 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 216a93af..92ff7214 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -29,9 +29,8 @@ class eWeLink { constructor (log, config, api) { if (!log || !api || !config) return if (!config.username || !config.password || !config.countryCode) { - log.error('*********** Cannot load homebridge-ewelink ************') - log.error('eWeLink credentials missing from the Homebridge config.') - log.error('*******************************************************') + log.error('************* Cannot load homebridge-ewelink *************') + log.error('*** eWeLink credentials missing from Homebridge config ***') return } this.log = log @@ -65,29 +64,22 @@ class eWeLink { this.lanDevices = await this.lanClient.getHosts() await this.lanClient.startMonitor(); (() => { - //* ** Make a map of custom groups from Homebridge config ***\\ if (Object.keys(this.config.groups || []).length > 0) { this.config.groups .filter(g => Object.prototype.hasOwnProperty.call(g, 'type') && cns.allowedGroups.includes(g.type)) .filter(g => Object.prototype.hasOwnProperty.call(g, 'deviceId') && this.devicesInEW.has(g.deviceId)) .forEach(g => this.cusG.set(g.deviceId + 'SWX', g)) } - //* ** Make a map of RF Bridge custom sensors from Homebridge config ***\\ if (Object.keys(this.config.bridgeSensors || []).length > 0) { this.config.bridgeSensors .filter(s => Object.prototype.hasOwnProperty.call(s, 'deviceId') && this.devicesInEW.has(s.deviceId)) .forEach(s => this.cusS.set(s.fullDeviceId, s)) } - //* ** Logging always helps to see if everything is okay so far ***\\ this.log('[%s] eWeLink devices loaded from the Homebridge cache.', this.devicesInHB.size) this.log('[%s] primary devices loaded from your eWeLink account.', this.devicesInEW.size) - //* ** Remove Homebridge accessories that don't appear in eWeLink ***\\ this.devicesInHB.forEach(a => { - if (!this.devicesInEW.has(a.context.eweDeviceId)) { - this.removeAccessory(a) - } + if (!this.devicesInEW.has(a.context.eweDeviceId)) this.removeAccessory(a) }) - //* ** Synchronise devices between eWeLink and Homebridge and set up WS/LAN listeners ***\\ this.devicesInEW.forEach(d => this.initialiseDevice(d)) this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)) this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)) @@ -111,17 +103,16 @@ class eWeLink { } ) this.log("eWeLink sync complete. Don't forget to ⭐ī¸ this plugin on GitHub!") - if (this.config.debugReqRes || false) { + if (this.config.debugReqRes) { this.log.warn("Note: 'Request & Response Logging' is not advised for long-term use.") } })() } catch (err) { - this.log.error('************** Cannot load homebridge-ewelink **************') + this.log.error('************* Cannot load homebridge-ewelink *************') this.log.error(this.debug ? err : err.message) - this.log.error('************************************************************') try { - if (this.lanClient) await this.lanClient.closeConnection() - if (this.wsClient) await this.wsClient.closeConnection() + if (this.lanClient) this.lanClient.closeConnection() + if (this.wsClient) this.wsClient.closeConnection() } catch (err) { this.log.warn(this.debug ? err : err.message) } @@ -129,10 +120,10 @@ class eWeLink { } } - async eWeLinkShutdown () { + eWeLinkShutdown () { try { - if (this.lanClient) await this.lanClient.closeConnection() - if (this.wsClient) await this.wsClient.closeConnection() + if (this.lanClient) this.lanClient.closeConnection() + if (this.wsClient) this.wsClient.closeConnection() } catch (err) { this.log.warn(this.debug ? err : err.message) } @@ -141,23 +132,12 @@ class eWeLink { initialiseDevice (device) { let accessory - //* ** CURTAINS ***\\ if (cns.devicesCurtain.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX', 'curtain', false, { cacheCurrentPosition: 0 }) - //* ** @UPGRADE from v2 -> v3 23.09.2020 ***\\ - if (Object.prototype.hasOwnProperty.call(accessory.context, 'prevPos')) { - accessory.context.cacheCurrentPosition = accessory.context.prevPos - delete accessory.context.prevPos - //* ** @ENDUPGRADE ***\\ - } - if (!Object.prototype.hasOwnProperty.call(accessory.context, 'cacheCurrentPosition')) { - accessory.context.cacheCurrentPosition = 0 - //* ** @ENDUPGRADE ***\\ - } } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'blind') { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') @@ -166,13 +146,6 @@ class eWeLink { cachePositionState: 2, cacheTargetPosition: 0 }) - //* ** @UPGRADE from v2 -> v3 23.09.2020 ***\\ - if (!Object.prototype.hasOwnProperty.call(accessory.context, 'cacheCurrentPosition')) { - accessory.context.cacheCurrentPosition = 0 - accessory.context.cachePositionState = 2 - accessory.context.cacheTargetPosition = 0 - } - //* ** @ENDUPGRADE ***\\ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage') { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') @@ -180,12 +153,6 @@ class eWeLink { cacheCurrentDoorState: 1, cacheTargetDoorState: 1 }) - //* ** @UPGRADE from v2 -> v3 23.09.2020 ***\\ - if (!Object.prototype.hasOwnProperty.call(accessory.context, 'cacheCurrentDoorState')) { - accessory.context.cacheCurrentDoorState = 1 - accessory.context.cacheTargetDoorState = 1 - } - //* ** @ENDUPGRADE ***\\ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage_eachen') { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') @@ -212,16 +179,6 @@ class eWeLink { : this.addAccessory(device, device.deviceid + 'SWX', 'thermostat', false, { sensorType: device.params.sensorType }) - //* ** @UPGRADE from v2 -> v3 23.09.2020 ***\\ - if (!Object.prototype.hasOwnProperty.call(accessory.context, 'sensorType')) { - accessory.context.sensorType = device.params.sensorType - } - if (accessory.context.sensorType === 'DS18B20') { - if (accessory.getService(Service.HumiditySensor)) { - accessory.removeService(Service.HumiditySensor) - } - } - //* ** @ENDUPGRADE ***\\ if (accessory.context.sensorType !== device.params.sensorType) { accessory.context.sensorType = device.params.sensorType this.devicesInHB.set(accessory.context.hbDeviceId, accessory) @@ -334,7 +291,7 @@ class eWeLink { rfMap }) accessory.control = new DeviceRFBridge(this) - // this.log.error(JSON.stringify(accessory.context, null, 2)) + this.hiddenMasters.push(device.deviceid) rfMap.forEach(subDevice => { const swNumber = rfChlCounter + 1 let subAccessory @@ -374,42 +331,23 @@ class eWeLink { subAccessory.context.reachableWAN = device.online subAccessory.context.reachableLAN = false this.devicesInHB.set(subAccessory.context.hbDeviceId, subAccessory) - // this.log.warn(JSON.stringify(subAccessory.context, null, 2)) rfChlCounter += Object.keys(subDevice.buttons || {}).length }) accessory.context.channelCount = rfChlCounter this.devicesInHB.set(accessory.context.hbDeviceId, accessory) - } else if (cns.devicesZBBridge.includes(device.extra.uiid)) { - // Nothing to do here but needed to avoid the below not supported error - //* ** @UPGRADE from v2 -> v3 23.09.2020 ***\\ - if ((accessory = this.devicesInHB.get(device.deviceid + 'SWX'))) { - this.removeAccessory(accessory) - } - //* ** @ENDUPGRADE ***\\ } else if (cns.devicesZB.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX', 'zb_dev') - //* ** @UPGRADE from v2 -> v3 23.09.2020 ***\\ - if (accessory.context.type === 'zb_sub') { - accessory.context.type = 'zb_dev' - } - //* ** @ENDUPGRADE ***\\ } else if (cns.devicesCamera.includes(device.extra.uiid)) { - this.log.warn( - ' → [%s] please see "https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-Sonoff-Camera".', - device.name - ) + this.log.warn(' → [%s] please see the homebridge-ewelink wiki for details to enable the camera', device.name) return - } else { - this.log.warn( - ' → [%s] cannot be added as it is not supported by this plugin. Please make a GitHub issue request.', - device.name - ) + } else if (!cns.devicesZBBridge.includes(device.extra.uiid)) { + this.log.warn(' → [%s] has not been added as it is not supported. Please make a GitHub issue request.', device.name) return } if (!accessory) return - if (!this.hiddenMasters.includes(device.deviceid)) { + if (this.hiddenMasters.includes(device.deviceid)) { accessory .getService(Service.AccessoryInformation) .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) @@ -433,18 +371,11 @@ class eWeLink { } this.log(' → [%s] initialised %s.', device.name, str) this.devicesInHB.set(accessory.context.hbDeviceId, accessory) - if (!this.config.disableHTTPRefresh && !(accessory.context.switchNumber === '0' && this.hiddenMasters.includes(device.deviceid))) { - if (!this.refreshAccessory(accessory, device.params)) { - this.log.warn( - '[%s] could not be initialised. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.) [debug:%s:%s].', - accessory.displayName, - accessory.context.type, - accessory.context.channelCount - ) - this.log.warn( - 'If you are unsure how to do this, please see "https://github.com/bwp91/homebridge-ewelink/wiki/How-to-remove-an-accessory-from-the-cache' - ) - } + if (this.config.disableHTTPRefresh) return + try { + accessory.control.externalUpdate(accessory, device.params) + } catch (err) { + this.log.warn('[%s] could not be initialised as %s.', accessory.displayName, this.debug ? err : err.message) } } @@ -516,7 +447,7 @@ class eWeLink { } cService .getCharacteristic(Characteristic.TargetPosition) - .on('set', (value, callback) => accessory.control.internalCurtainUpdate(accessory, value, callback)) + .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) break } case 'blind': { @@ -532,7 +463,7 @@ class eWeLink { } wcService .getCharacteristic(Characteristic.TargetPosition) - .on('set', (value, callback) => accessory.control.internalBlindUpdate(accessory, value, callback)) + .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) break } case 'garage': { @@ -548,7 +479,7 @@ class eWeLink { } gdService .getCharacteristic(Characteristic.TargetDoorState) - .on('set', (value, callback) => accessory.control.internalGarageUpdate(accessory, value, callback)) + .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) break } case 'garage_eachen': { @@ -564,7 +495,7 @@ class eWeLink { } gdeService .getCharacteristic(Characteristic.TargetDoorState) - .on('set', (value, callback) => accessory.control.internalGarageEachenUpdate(accessory, value, callback)) + .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) break } case 'lock': { @@ -572,7 +503,7 @@ class eWeLink { const lmService = accessory.getService(Service.LockMechanism) || accessory.addService(Service.LockMechanism) lmService .getCharacteristic(Characteristic.LockTargetState) - .on('set', (value, callback) => accessory.control.internalLockUpdate(accessory, value, callback)) + .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) break } case 'valve': { @@ -594,7 +525,7 @@ class eWeLink { valveService .getCharacteristic(Characteristic.Active) .on('set', (value, callback) => - accessory.control.internalValveUpdate(accessory, 'Valve ' + v, value, callback) + accessory.control.internalUpdate(accessory, 'Valve ' + v, value, callback) ) valveService.getCharacteristic(Characteristic.SetDuration).on('set', (value, callback) => { if (valveService.getCharacteristic(Characteristic.InUse).value) { @@ -621,16 +552,16 @@ class eWeLink { const fanLightService = accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb) fanService .getCharacteristic(Characteristic.Active) - .on('set', (value, callback) => accessory.control.internalFanUpdate(accessory, 'power', value, callback)) + .on('set', (value, callback) => accessory.control.internalUpdate(accessory, 'power', value, callback)) fanService .getCharacteristic(Characteristic.RotationSpeed) - .on('set', (value, callback) => accessory.control.internalFanUpdate(accessory, 'speed', value, callback)) + .on('set', (value, callback) => accessory.control.internalUpdate(accessory, 'speed', value, callback)) .setProps({ minStep: 33 }) fanLightService .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => accessory.control.internalFanUpdate(accessory, 'light', value, callback)) + .on('set', (value, callback) => accessory.control.internalUpdate(accessory, 'light', value, callback)) break } case 'thermostat': { @@ -644,7 +575,7 @@ class eWeLink { const switchService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch) switchService .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => accessory.control.internalThermostatUpdate(accessory, value, callback)) + .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) } if (!this.config.disableEveLogging) { accessory.log = this.log @@ -691,7 +622,7 @@ class eWeLink { } outletService .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => accessory.control.internalOutletUpdate(accessory, value, callback)) + .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) if (accessory.context.eweModel !== 'S26' && !this.config.disableEveLogging) { accessory.log = this.log accessory.eveLogger = new EveHistoryService('energy', accessory, { @@ -767,7 +698,7 @@ class eWeLink { const usbService = accessory.getService(Service.Outlet) || accessory.addService(Service.Outlet) usbService .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => accessory.control.internalUSBUpdate(accessory, value, callback)) + .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) break } case 'scm': { @@ -775,7 +706,7 @@ class eWeLink { const scmService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch) scmService .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => accessory.control.internalSCMUpdate(accessory, value, callback)) + .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) break } case 'light': { @@ -783,32 +714,32 @@ class eWeLink { const lightService = accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb) lightService .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => accessory.control.internalLightbulbUpdate(accessory, value, callback)) + .on('set', (value, callback) => accessory.control.internalUpdate(accessory, 'onoff', value, callback)) if (cns.devicesBrightable.includes(accessory.context.eweUIID)) { lightService.getCharacteristic(Characteristic.Brightness).on('set', (value, callback) => { if (value > 0) { if (!lightService.getCharacteristic(Characteristic.On).value) { - accessory.control.internalLightbulbUpdate(accessory, true, function () {}) + accessory.control.internalUpdate(accessory, 'onoff', true, function () {}) } - accessory.control.internalBrightnessUpdate(accessory, value, callback) + accessory.control.internalUpdate(accessory, 'brightness', value, callback) } else { - accessory.control.internalLightbulbUpdate(accessory, false, callback) + accessory.control.internalUpdate(accessory, 'onoff', false, callback) } }) } else if (cns.devicesColourable.includes(accessory.context.eweUIID)) { lightService.getCharacteristic(Characteristic.Brightness).on('set', (value, callback) => { if (value > 0) { if (!lightService.getCharacteristic(Characteristic.On).value) { - accessory.control.internalLightbulbUpdate(accessory, true, function () {}) + accessory.control.internalUpdate(accessory, 'onoff', true, function () {}) } - accessory.control.internalHSBUpdate(accessory, 'bri', value, callback) + accessory.control.internalUpdate(accessory, 'c_brightness', value, callback) } else { - accessory.control.internalLightbulbUpdate(accessory, false, callback) + accessory.control.internalUpdate(accessory, 'onoff', false, callback) } }) lightService .getCharacteristic(Characteristic.Hue) - .on('set', (value, callback) => accessory.control.internalHSBUpdate(accessory, 'hue', value, callback)) + .on('set', (value, callback) => accessory.control.internalUpdate(accessory, 'c_hue', value, callback)) lightService.getCharacteristic(Characteristic.Saturation).on('set', (value, callback) => callback()) } break @@ -818,7 +749,7 @@ class eWeLink { const switchService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch) switchService .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => accessory.control.internalSwitchUpdate(accessory, value, callback)) + .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) break } case 'rf_sub': { @@ -850,11 +781,9 @@ class eWeLink { Object.entries(accessory.context.buttons).forEach(([chan, name]) => { accessory.getService(name) || accessory.addService(Service.Switch, name, 'switch' + chan) accessory.getService(name).updateCharacteristic(Characteristic.On, false) - accessory - .getService(name) - .getCharacteristic(Characteristic.On) + accessory.getService(name).getCharacteristic(Characteristic.On) .on('set', (value, callback) => { - value ? accessory.control.internalRFUpdate(accessory, chan, name, callback) : callback() + value ? accessory.control.internalUpdate(accessory, chan, name, callback) : callback() }) }) break @@ -913,76 +842,6 @@ class eWeLink { } } - refreshAccessory (accessory, newParams) { - switch (accessory.context.type) { - case 'valve': - accessory.control.externalValveUpdate(accessory, newParams) - return true - case 'curtain': - accessory.control.externalCurtainUpdate(accessory, newParams) - return true - case 'blind': - return true - case 'garage': - accessory.control.externalGarageUpdate(accessory, newParams) - return true - case 'garage_eachen': - accessory.control.externalGarageEachenUpdate(accessory, newParams) - return true - case 'lock': - accessory.control.externalLockUpdate(accessory, newParams) - return true - case 'sensor': - accessory.control.externalSensorUpdate(accessory, newParams) - return true - case 'fan': - accessory.control.externalFanUpdate(accessory, newParams) - return true - case 'thermostat': - accessory.control.externalThermostatUpdate(accessory, newParams) - return true - case 'outlet': - accessory.control.externalOutletUpdate(accessory, newParams) - return true - case 'usb': - accessory.control.externalUSBUpdate(accessory, newParams) - return true - case 'scm': - accessory.control.externalSCMUpdate(accessory, newParams) - return true - case 'light': - if ( - cns.devicesSingleSwitch.includes(accessory.context.eweUIID) && - cns.devicesSingleSwitchLight.includes(accessory.context.eweModel) - ) { - accessory.control.externalSingleLightUpdate(accessory, newParams) - } else if ( - cns.devicesMultiSwitch.includes(accessory.context.eweUIID) && - cns.devicesMultiSwitchLight.includes(accessory.context.eweModel) - ) { - accessory.control.externalMultiLightUpdate(accessory, newParams) - } - return true - case 'switch': - if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID)) { - accessory.control.externalSingleSwitchUpdate(accessory, newParams) - } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID)) { - accessory.control.externalMultiSwitchUpdate(accessory, newParams) - } - return true - case 'rf_pri': - accessory.control.externalRFUpdate(accessory, newParams) - return true - case 'rf_sub': - return true - case 'zb_dev': - accessory.control.externalZBUpdate(accessory, newParams) - return true - default: - return false - } - } - removeAccessory (accessory) { try { this.api.unregisterPlatformAccessories('homebridge-ewelink', 'eWeLink', [accessory]) @@ -1025,11 +884,7 @@ class eWeLink { accessory.context.reachableWAN = device.params.online this.devicesInHB.set(accessory.context.hbDeviceId, accessory) reachableChange = true - this.log.warn( - '[%s] has been reported [%s] via [WS].', - accessory.displayName, - accessory.context.reachableWAN ? 'online' : 'offline' - ) + this.log.warn('[%s] reported [%sline] via [WS].', accessory.displayName, accessory.context.reachableWAN ? 'on' : 'off') if (accessory.context.reachableWAN) { try { this.wsClient.requestUpdate(accessory) @@ -1063,38 +918,23 @@ class eWeLink { } } if (this.debug) { - this.log( - '[%s] externally updated from above %s message and will be refreshed.', - accessory.displayName, - device.params.updateSource - ) + this.log('[%s] %s update received and will be refreshed.', accessory.displayName, device.params.updateSource) } - if (!this.refreshAccessory(accessory, device.params)) { - this.log.warn( - '[%s] cannot be refreshed. Please try removing accessory from the Homebridge cache along with any secondary devices (SW1, SW2, etc.). [debug:%s:%s]', - accessory.displayName, - accessory.context.type, - accessory.context.channelCount - ) - this.log.warn( - 'If you are unsure how to do this, please see "https://github.com/bwp91/homebridge-ewelink/wiki/How-to-remove-an-accessory-from-the-cache' - ) + try { + accessory.control.externalUpdate(accessory, device.params) + } catch (err) { + this.log.warn('[%s] could not be refreshed as %s.', accessory.displayName, this.debug ? err : err.message) } } else { - if (!(this.config.hideDevFromHB || '').includes(deviceId)) { - this.log.warn( - '[%s] update received via %s does not exist in Homebridge so device will be added.', - deviceId, - device.params.updateSource - ) - try { - const device = await this.httpClient.getDevice(deviceId) - this.initialiseDevice(device) - this.lanClient.addDeviceToMap(device) - } catch (err) { - this.log.error('[%s] error getting info [%s]', deviceId, err) - this.log.error('[%s] Please try restarting Homebridge so this device is added.', deviceId) + try { + if (!(this.config.hideDevFromHB || '').includes(deviceId)) { + this.log.warn('[%s] %s update received for new device which will be added.', deviceId, device.params.updateSource) + const newDevice = await this.httpClient.getDevice(deviceId) + this.initialiseDevice(newDevice) + this.lanClient.addDeviceToMap(newDevice) } + } catch (err) { + this.log.warn('[%s] error getting info [%s]. Restart Homebeidge to add device.', deviceId, err.message) } } } From eb78373fd907dd61f686205ef667bd4fe2b7628b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 09:07:43 +0100 Subject: [PATCH 0280/3183] 3.2.0-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9c316094..463b984a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.2.0-0", + "version": "3.2.0-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 5fe27906..af23f2ff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.2.0-0", + "version": "3.2.0-1", "author": "bwp91", "contributors": [ "gbro115", From 450fe6ee139e5ad4cc6fd50eb2a7d4eb6c80ad75 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 10:39:27 +0100 Subject: [PATCH 0281/3183] code format --- lib/eWeLink.js | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 92ff7214..8a6cf223 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -51,7 +51,7 @@ class eWeLink { async eWeLinkSetup () { try { - this.log('Plugin has finished initialising. Synching with eWeLink.') + this.log('Plugin has finished initialising. Syncing with eWeLink.') this.httpClient = new EWeLinkHTTP(this.config, this.log) await this.httpClient.getHost() this.authData = await this.httpClient.login() @@ -102,7 +102,7 @@ class eWeLink { stopOnError: false } ) - this.log("eWeLink sync complete. Don't forget to ⭐ī¸ this plugin on GitHub!") + this.log("eWeLink sync complete. Don't forget to ⭐ī¸ this plugin on GitHub if you're finding it useful!") if (this.config.debugReqRes) { this.log.warn("Note: 'Request & Response Logging' is not advised for long-term use.") } @@ -183,11 +183,7 @@ class eWeLink { accessory.context.sensorType = device.params.sensorType this.devicesInHB.set(accessory.context.hbDeviceId, accessory) } - } else if ( - cns.devicesOutlet.includes(device.extra.uiid) || - (cns.devicesSingleSwitch.includes(device.extra.uiid) && - cns.devicesSingleSwitchOutlet.includes(device.productModel)) - ) { + } else if (cns.devicesOutlet.includes(device.extra.uiid) || (cns.devicesSingleSwitch.includes(device.extra.uiid) && cns.devicesSingleSwitchOutlet.includes(device.productModel))) { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX', 'outlet') @@ -199,17 +195,11 @@ class eWeLink { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX', 'scm') - } else if ( - cns.devicesSingleSwitch.includes(device.extra.uiid) && - cns.devicesSingleSwitchLight.includes(device.productModel) - ) { + } else if (cns.devicesSingleSwitch.includes(device.extra.uiid) && cns.devicesSingleSwitchLight.includes(device.productModel)) { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX', 'light') - } else if ( - cns.devicesMultiSwitch.includes(device.extra.uiid) && - cns.devicesMultiSwitchLight.includes(device.productModel) - ) { + } else if (cns.devicesMultiSwitch.includes(device.extra.uiid) && cns.devicesMultiSwitchLight.includes(device.productModel)) { if (this.config.hideMasters) { if (this.devicesInHB.has(device.deviceid + 'SW0')) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) From c70c327c74c8d3b6c38cf438b6a222b9c2ef1dd3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 10:43:36 +0100 Subject: [PATCH 0282/3183] logic error --- lib/eWeLink.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 8a6cf223..fa86bde0 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -337,7 +337,7 @@ class eWeLink { return } if (!accessory) return - if (this.hiddenMasters.includes(device.deviceid)) { + if (!this.hiddenMasters.includes(device.deviceid)) { accessory .getService(Service.AccessoryInformation) .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) From dc7dc7895ad86067da8589c9bd79079af8ba0509 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 10:49:16 +0100 Subject: [PATCH 0283/3183] Update FUNDING.yml --- .github/FUNDING.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 9ccddac1..72a6f9c3 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,4 +1,4 @@ github: bwp91 patreon: bwp91 ko_fi: bwp91 -custom: https://www.paypal.me/BenPotter +custom: ["https://www.paypal.me/BenPotter", "https://www.gofundme.com/f/aspergers-has-rules-my-life"] From 770808a09eccc7549d3a3f9c6780013b09584ff2 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 10:50:17 +0100 Subject: [PATCH 0284/3183] Update FUNDING.yml --- .github/FUNDING.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 72a6f9c3..0729bbfe 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,4 +1,4 @@ github: bwp91 patreon: bwp91 ko_fi: bwp91 -custom: ["https://www.paypal.me/BenPotter", "https://www.gofundme.com/f/aspergers-has-rules-my-life"] +custom: ["https://www.paypal.me/BenPotter", "https://www.gofundme.com/f/bwp91"] From 7173da66ce4e34f2b65d436f71d948c4705d6dde Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 10:54:45 +0100 Subject: [PATCH 0285/3183] Update package.json --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index af23f2ff..fd2e214f 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,10 @@ { "type": "github", "url": "https://github.com/sponsors/bwp91" + }, + { + "type": "gofundme", + "url": "https://www.gofundme.com/f/bwp91" } ], "dependencies": { From 64d6f0d3e5fc704494ae9141c046a767df9ab43d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 12:01:56 +0100 Subject: [PATCH 0286/3183] clarify custom device types --- config.schema.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/config.schema.json b/config.schema.json index 24211140..5732a4f1 100644 --- a/config.schema.json +++ b/config.schema.json @@ -111,7 +111,7 @@ "groups": { "type": "array", "title": "Custom Device Types", - "description": "You can use this setting to set up custom device types within Homebridge. Currently only blinds, garage doors and locks are supported.", + "description": "You can use this setting to set up custom simulated HomeKit accessories from a generic single/multi-switch device.", "items": { "type": "object", "properties": { @@ -127,31 +127,31 @@ "description": "The new type for this device.", "oneOf": [ { - "title": "Blind (Generic Setup)", + "title": "Blind (using channel 0 for 'UP' and channel 1 for 'DOWN' of a multi-channel device)", "enum": [ "blind" ] }, { - "title": "Garage Door (Generic Setup)", + "title": "Garage Door (using a single/multi-channel device)", "enum": [ "garage" ] }, { - "title": "Garage Door (Eachen GD-DC5)", + "title": "Garage Door (using the Eachen GD-DC5)", "enum": [ "garage_eachen" ] }, { - "title": "Lock (Generic Setup)", + "title": "Lock (using a single channel device)", "enum": [ "lock" ] }, { - "title": "Irrigation (Generic Setup)", + "title": "Irrigation (using channels 0 and 1 of a multi-channel device)", "enum": [ "valve" ] @@ -320,7 +320,7 @@ { "key": "groups", "expandable": true, - "title": "Custom Device Types", + "title": "Custom Device Simulations", "add": "Add Another Type", "type": "array", "items": [ From 351455c6685f32ea03dfe644d3cfcc54ec2987ac Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 14:30:45 +0100 Subject: [PATCH 0287/3183] code reformat --- lib/device/blind.js | 14 +- lib/device/curtain.js | 14 +- lib/device/fan.js | 16 +- lib/device/garage-eachen.js | 14 +- lib/device/garage.js | 14 +- lib/device/light.js | 33 ++- lib/device/lock.js | 6 +- lib/device/outlet.js | 99 +++++++- lib/device/rf-bridge.js | 36 ++- lib/device/scm.js | 6 +- lib/device/sensor.js | 4 +- lib/device/switch.js | 6 +- lib/device/thermostat.js | 36 ++- lib/device/usb.js | 6 +- lib/device/valve.js | 34 ++- lib/device/zb-dev.js | 48 +++- lib/eWeLink.js | 438 ++++-------------------------------- 17 files changed, 407 insertions(+), 417 deletions(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index 6584d7b3..242eeaaf 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -3,10 +3,22 @@ let Characteristic, Service const cns = require('./../constants') const utils = require('./../utils') module.exports = class deviceBlind { - constructor (platform) { + constructor (platform, accessory) { this.platform = platform Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic + let wcService + if (!(wcService = accessory.getService(Service.WindowCovering))) { + accessory + .addService(Service.WindowCovering) + .setCharacteristic(Characteristic.CurrentPosition, 0) + .setCharacteristic(Characteristic.TargetPosition, 0) + .setCharacteristic(Characteristic.PositionState, 2) + wcService = accessory.getService(Service.WindowCovering) + } + wcService + .getCharacteristic(Characteristic.TargetPosition) + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) } async internalUpdate (accessory, value, callback) { diff --git a/lib/device/curtain.js b/lib/device/curtain.js index 1b5d07cb..d96de66a 100644 --- a/lib/device/curtain.js +++ b/lib/device/curtain.js @@ -1,10 +1,22 @@ 'use strict' let Characteristic, Service module.exports = class deviceCurtain { - constructor (platform) { + constructor (platform, accessory) { this.platform = platform Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic + let cService + if (!(cService = accessory.getService(Service.WindowCovering))) { + accessory + .addService(Service.WindowCovering) + .setCharacteristic(Characteristic.CurrentPosition, 0) + .setCharacteristic(Characteristic.TargetPosition, 0) + .setCharacteristic(Characteristic.PositionState, 2) + cService = accessory.getService(Service.WindowCovering) + } + cService + .getCharacteristic(Characteristic.TargetPosition) + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) } async internalUpdate (accessory, value, callback) { diff --git a/lib/device/fan.js b/lib/device/fan.js index 16221475..2eac5d9b 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -1,10 +1,24 @@ 'use strict' let Characteristic, Service module.exports = class deviceFan { - constructor (platform) { + constructor (platform, accessory) { this.platform = platform Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic + const fanService = accessory.getService(Service.Fanv2) || accessory.addService(Service.Fanv2) + const fanLightService = accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb) + fanService + .getCharacteristic(Characteristic.Active) + .on('set', (value, callback) => this.internalUpdate(accessory, 'power', value, callback)) + fanService + .getCharacteristic(Characteristic.RotationSpeed) + .on('set', (value, callback) => this.internalUpdate(accessory, 'speed', value, callback)) + .setProps({ + minStep: 33 + }) + fanLightService + .getCharacteristic(Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(accessory, 'light', value, callback)) } async internalUpdate (accessory, type, value, callback) { diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index dc27d4e6..91bd7e81 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -2,10 +2,22 @@ let Characteristic, Service const utils = require('./../utils') module.exports = class deviceGarageEachen { - constructor (platform) { + constructor (platform, accessory) { this.platform = platform Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic + let gdeService + if (!(gdeService = accessory.getService(Service.GarageDoorOpener))) { + accessory + .addService(Service.GarageDoorOpener) + .setCharacteristic(Characteristic.CurrentDoorState, 1) + .setCharacteristic(Characteristic.TargetDoorState, 1) + .setCharacteristic(Characteristic.ObstructionDetected, false) + gdeService = accessory.getService(Service.GarageDoorOpener) + } + gdeService + .getCharacteristic(Characteristic.TargetDoorState) + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) } async internalUpdate (accessory, value, callback) { diff --git a/lib/device/garage.js b/lib/device/garage.js index 4c1270dc..599316e7 100644 --- a/lib/device/garage.js +++ b/lib/device/garage.js @@ -2,10 +2,22 @@ let Characteristic, Service const utils = require('./../utils') module.exports = class deviceGarage { - constructor (platform) { + constructor (platform, accessory) { this.platform = platform Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic + let gdService + if (!(gdService = accessory.getService(Service.GarageDoorOpener))) { + accessory + .addService(Service.GarageDoorOpener) + .setCharacteristic(Characteristic.CurrentDoorState, 1) + .setCharacteristic(Characteristic.TargetDoorState, 1) + .setCharacteristic(Characteristic.ObstructionDetected, false) + gdService = accessory.getService(Service.GarageDoorOpener) + } + gdService + .getCharacteristic(Characteristic.TargetDoorState) + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) } async internalUpdate (accessory, value, callback) { diff --git a/lib/device/light.js b/lib/device/light.js index 3b210f76..7d67c7d0 100644 --- a/lib/device/light.js +++ b/lib/device/light.js @@ -4,10 +4,41 @@ const cns = require('./../constants') const convert = require('color-convert') const utils = require('./../utils') module.exports = class deviceLight { - constructor (platform) { + constructor (platform, accessory) { this.platform = platform Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic + const lightService = accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb) + lightService + .getCharacteristic(Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(accessory, 'onoff', value, callback)) + if (cns.devicesBrightable.includes(accessory.context.eweUIID)) { + lightService.getCharacteristic(Characteristic.Brightness).on('set', (value, callback) => { + if (value > 0) { + if (!lightService.getCharacteristic(Characteristic.On).value) { + this.internalUpdate(accessory, 'onoff', true, function () {}) + } + this.internalUpdate(accessory, 'brightness', value, callback) + } else { + this.internalUpdate(accessory, 'onoff', false, callback) + } + }) + } else if (cns.devicesColourable.includes(accessory.context.eweUIID)) { + lightService.getCharacteristic(Characteristic.Brightness).on('set', (value, callback) => { + if (value > 0) { + if (!lightService.getCharacteristic(Characteristic.On).value) { + this.internalUpdate(accessory, 'onoff', true, function () {}) + } + this.internalUpdate(accessory, 'c_brightness', value, callback) + } else { + this.internalUpdate(accessory, 'onoff', false, callback) + } + }) + lightService + .getCharacteristic(Characteristic.Hue) + .on('set', (value, callback) => this.internalUpdate(accessory, 'c_hue', value, callback)) + lightService.getCharacteristic(Characteristic.Saturation).on('set', (value, callback) => callback()) + } } async internalUpdate (accessory, type, value, callback) { diff --git a/lib/device/lock.js b/lib/device/lock.js index 8a4972be..b335b281 100644 --- a/lib/device/lock.js +++ b/lib/device/lock.js @@ -2,10 +2,14 @@ let Characteristic, Service const utils = require('./../utils') module.exports = class deviceLock { - constructor (platform) { + constructor (platform, accessory) { this.platform = platform Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic + const lmService = accessory.getService(Service.LockMechanism) || accessory.addService(Service.LockMechanism) + lmService + .getCharacteristic(Characteristic.LockTargetState) + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) } async internalUpdate (accessory, value, callback) { diff --git a/lib/device/outlet.js b/lib/device/outlet.js index 56e31434..9941c0ee 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -1,12 +1,107 @@ 'use strict' -let Characteristic, EveService, Service +let Characteristic, EveHistoryService, EveService, Service +const corrInterval = require('correcting-interval') +const fakegato = require('fakegato-history') const hbLib = require('homebridge-lib') module.exports = class deviceOutlet { - constructor (platform, homebridge) { + constructor (platform, accessory) { this.platform = platform Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic EveService = new hbLib.EveHomeKitTypes(platform.api) + EveHistoryService = fakegato(platform.api) + let outletService + if (!(outletService = accessory.getService(Service.Outlet))) { + accessory.addService(Service.Outlet) + outletService = accessory.getService(Service.Outlet) + if (accessory.context.eweModel !== 'S26' && !this.platform.config.disableEveLogging) { + outletService.addCharacteristic(EveService.Characteristics.Voltage) + outletService.addCharacteristic(EveService.Characteristics.CurrentConsumption) + outletService.addCharacteristic(EveService.Characteristics.ElectricCurrent) + outletService.addCharacteristic(EveService.Characteristics.TotalConsumption) + outletService.addCharacteristic(EveService.Characteristics.ResetTotal) + accessory.context = { + ...accessory.context, + ...{ + extraPersistedData: {}, + lastReset: 0, + totalEnergy: 0, + totalEnergyTemp: 0 + } + } + } + } + outletService + .getCharacteristic(Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + if (accessory.context.eweModel !== 'S26' && !this.platform.config.disableEveLogging) { + accessory.log = this.platform.log + accessory.eveLogger = new EveHistoryService('energy', accessory, { + storage: 'fs', + minutes: 5, + path: this.platform.eveLogPath + }) + corrInterval.setCorrectingInterval(() => { + const isOn = outletService.getCharacteristic(Characteristic.On).value + const currentWatt = isOn + ? outletService.getCharacteristic(EveService.Characteristics.CurrentConsumption).value + : 0 + if (accessory.eveLogger.isHistoryLoaded()) { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.totalEnergy = + accessory.context.extraPersistedData.totalenergy + + accessory.context.totalEnergyTemp + + (currentWatt * 10) / 3600 / 1000 + accessory.eveLogger.setExtraPersistedData({ + totalenergy: accessory.context.totalEnergy, + lastReset: accessory.context.extraPersistedData.lastReset + }) + } else { + accessory.context.totalEnergy = accessory.context.totalEnergyTemp + (currentWatt * 10) / 3600 / 1000 + accessory.eveLogger.setExtraPersistedData({ + totalenergy: accessory.context.totalEnergy, + lastReset: 0 + }) + } + accessory.context.totalEnergytemp = 0 + } else { + accessory.context.totalEnergyTemp += (currentWatt * 10) / 3600 / 1000 + accessory.context.totalEnergy = accessory.context.totalEnergyTemp + } + accessory.eveLogger.addEntry({ + time: Date.now(), + power: currentWatt + }) + }, 300000) + outletService + .getCharacteristic(EveService.Characteristics.TotalConsumption) + .on('get', callback => { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower + } + callback(null, accessory.context.totalEnergy) + }) + outletService + .getCharacteristic(EveService.Characteristics.ResetTotal) + .on('set', (value, callback) => { + accessory.context.totalEnergy = 0 + accessory.context.lastReset = value + accessory.eveLogger.setExtraPersistedData({ + totalPower: 0, + lastReset: value + }) + callback() + }) + .on('get', callback => { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.lastReset = accessory.context.extraPersistedData.lastReset + } + callback(null, accessory.context.lastReset) + }) + } } async internalUpdate (accessory, value, callback) { diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index 2e988d4c..59f267ce 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -2,10 +2,44 @@ let Characteristic, Service const utils = require('./../utils') module.exports = class deviceRFBridge { - constructor (platform) { + constructor (platform, accessory) { this.platform = platform Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic + switch (accessory.context.subType) { + case 'water': + accessory.getService(Service.LeakSensor) || accessory.addService(Service.LeakSensor) + break + case 'fire': + case 'smoke': + accessory.getService(Service.SmokeSensor) || accessory.addService(Service.SmokeSensor) + break + case 'co': + accessory.getService(Service.CarbonMonoxideSensor) || accessory.addService(Service.CarbonMonoxideSensor) + break + case 'co2': + accessory.getService(Service.CarbonDioxideSensor) || accessory.addService(Service.CarbonDioxideSensor) + break + case 'contact': + accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor) + break + case 'occupancy': + accessory.getService(Service.OccupancySensor) || accessory.addService(Service.OccupancySensor) + break + default: + accessory.getService(Service.MotionSensor) || accessory.addService(Service.MotionSensor) + break + case 'button': + Object.entries(accessory.context.buttons).forEach(([chan, name]) => { + accessory.getService(name) || accessory.addService(Service.Switch, name, 'switch' + chan) + accessory.getService(name).updateCharacteristic(Characteristic.On, false) + accessory.getService(name).getCharacteristic(Characteristic.On) + .on('set', (value, callback) => { + value ? this.internalUpdate(accessory, chan, name, callback) : callback() + }) + }) + break + } } async internalUpdate (accessory, rfChl, service, callback) { diff --git a/lib/device/scm.js b/lib/device/scm.js index 98dc1357..577c2e69 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -2,10 +2,14 @@ let Characteristic, Service const cns = require('./../constants') module.exports = class deviceSCM { - constructor (platform) { + constructor (platform, accessory) { this.platform = platform Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic + const scmService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch) + scmService + .getCharacteristic(Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) } async internalUpdate (accessory, value, callback) { diff --git a/lib/device/sensor.js b/lib/device/sensor.js index 47a4bd2b..5c3741b4 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -1,10 +1,12 @@ 'use strict' let Characteristic, Service module.exports = class deviceSensor { - constructor (platform) { + constructor (platform, accessory) { this.platform = platform Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic + accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor) + accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService) } externalUpdate (accessory, params) { diff --git a/lib/device/switch.js b/lib/device/switch.js index a7422968..19c7a331 100644 --- a/lib/device/switch.js +++ b/lib/device/switch.js @@ -2,10 +2,14 @@ let Characteristic, Service const cns = require('./../constants') module.exports = class deviceSwitch { - constructor (platform) { + constructor (platform, accessory) { this.platform = platform Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic + const switchService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch) + switchService + .getCharacteristic(Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) } async internalUpdate (accessory, value, callback) { diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index b987d601..ed36e577 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -1,10 +1,42 @@ 'use strict' -let Characteristic, Service +let Characteristic, EveHistoryService, Service +const corrInterval = require('correcting-interval') +const fakegato = require('fakegato-history') module.exports = class deviceThermostat { - constructor (platform) { + constructor (platform, accessory) { this.platform = platform Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic + EveHistoryService = fakegato(platform.api) + const tempService = accessory.getService(Service.TemperatureSensor) || accessory.addService(Service.TemperatureSensor) + let humiService = false + if (accessory.context.sensorType !== 'DS18B20') { + humiService = accessory.getService(Service.HumiditySensor) || accessory.addService(Service.HumiditySensor) + } + if (!this.platform.config.hideTHSwitch) { + const switchService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch) + switchService + .getCharacteristic(Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + } + if (!this.platform.config.disableEveLogging) { + accessory.log = this.platform.log + accessory.eveLogger = new EveHistoryService('weather', accessory, { + storage: 'fs', + minutes: 5, + path: this.platform.eveLogPath + }) + corrInterval.setCorrectingInterval(() => { + const dataToAdd = { + time: Date.now(), + temp: tempService.getCharacteristic(Characteristic.CurrentTemperature).value + } + if (humiService) { + dataToAdd.humidity = humiService.getCharacteristic(Characteristic.CurrentRelativeHumidity).value + } + accessory.eveLogger.addEntry(dataToAdd) + }, 300000) + } } async internalUpdate (accessory, value, callback) { diff --git a/lib/device/usb.js b/lib/device/usb.js index a2305136..13a2c87b 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -2,10 +2,14 @@ let Characteristic, Service const cns = require('./../constants') module.exports = class deviceUSB { - constructor (platform) { + constructor (platform, accessory) { this.platform = platform Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic + const usbService = accessory.getService(Service.Outlet) || accessory.addService(Service.Outlet) + usbService + .getCharacteristic(Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) } async internalUpdate (accessory, value, callback) { diff --git a/lib/device/valve.js b/lib/device/valve.js index 8522fd19..8363706d 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -1,9 +1,39 @@ 'use strict' -let Characteristic +let Characteristic, Service module.exports = class deviceValve { - constructor (platform) { + constructor (platform, accessory) { this.platform = platform + Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic + const arr = ['A', 'B'] + arr.forEach(v => { + let valveService + if (!(valveService = accessory.getService('Valve ' + v))) { + accessory + .addService(Service.Valve, 'Valve ' + v, 'valve' + v.toLowerCase()) + .setCharacteristic(Characteristic.Active, 0) + .setCharacteristic(Characteristic.InUse, 0) + .setCharacteristic(Characteristic.ValveType, 1) + .setCharacteristic(Characteristic.SetDuration, Math.round((accessory.context.operationTime || 1200) / 10)) + .addCharacteristic(Characteristic.RemainingDuration) + valveService = accessory.getService('Valve ' + v) + } + valveService + .getCharacteristic(Characteristic.Active) + .on('set', (value, callback) => + this.internalUpdate(accessory, 'Valve ' + v, value, callback) + ) + valveService.getCharacteristic(Characteristic.SetDuration).on('set', (value, callback) => { + if (valveService.getCharacteristic(Characteristic.InUse).value) { + valveService.updateCharacteristic(Characteristic.RemainingDuration, value) + clearTimeout(valveService.timer) + valveService.timer = setTimeout(() => { + valveService.setCharacteristic(Characteristic.Active, 0) + }, value * 1000) + } + callback() + }) + }) } async internalUpdate (accessory, valve, value, callback) { diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index d4e9cec5..21c309a2 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -1,10 +1,54 @@ 'use strict' -let Characteristic, Service +let Characteristic, Service, EveHistoryService +const corrInterval = require('correcting-interval') +const fakegato = require('fakegato-history') module.exports = class deviceZBDev { - constructor (platform) { + constructor (platform, accessory) { this.platform = platform Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic + EveHistoryService = fakegato(platform.api) + accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService) + switch (accessory.context.eweUIID) { + case 1000: { + const zbspsService = + accessory.getService(Service.StatelessProgrammableSwitch) || + accessory.addService(Service.StatelessProgrammableSwitch) + if (this.platform.config.hideZBLDPress) { + zbspsService.getCharacteristic(Characteristic.ProgrammableSwitchEvent).setProps({ + validValues: [0] + }) + } + break + } + case 1770: { + const zbTempService = + accessory.getService(Service.TemperatureSensor) || accessory.addService(Service.TemperatureSensor) + const zbHumiService = + accessory.getService(Service.HumiditySensor) || accessory.addService(Service.HumiditySensor) + accessory.log = this.platform.log + accessory.eveLogger = new EveHistoryService('weather', accessory, { + storage: 'fs', + minutes: 5, + path: this.platform.eveLogPath + }) + corrInterval.setCorrectingInterval(() => { + const dataToAdd = { + time: Date.now(), + temp: zbTempService.getCharacteristic(Characteristic.CurrentTemperature).value, + humidity: zbHumiService.getCharacteristic(Characteristic.CurrentRelativeHumidity).value + } + accessory.eveLogger.addEntry(dataToAdd) + }, 300000) + break + } + case 2026: + accessory.getService(Service.MotionSensor) || accessory.addService(Service.MotionSensor) + break + case 3026: + accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor) + break + } } externalUpdate (accessory, params) { diff --git a/lib/eWeLink.js b/lib/eWeLink.js index fa86bde0..cc2310a3 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1,7 +1,6 @@ 'use strict' -let Accessory, Characteristic, EveService, EveHistoryService, Service +let Characteristic, Service const cns = require('./constants') -const corrInterval = require('correcting-interval') const DeviceCurtain = require('./device/curtain') const DeviceBlind = require('./device/blind') const DeviceGarage = require('./device/garage') @@ -21,8 +20,6 @@ const DeviceZBDev = require('./device/zb-dev') const EWeLinkHTTP = require('./eWeLinkHTTP') const EWeLinkWS = require('./eWeLinkWS') const EWeLinkLAN = require('./eWeLinkLAN') -const fakegato = require('fakegato-history') -const hbLib = require('homebridge-lib') const promInterval = require('interval-promise') const utils = require('./utils') class eWeLink { @@ -164,7 +161,10 @@ class eWeLink { } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'valve') { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', 'valve') + : this.addAccessory(device, device.deviceid + 'SWX', 'valve', false, { + operationTime: this.cusG.get(device.deviceid + 'SWX').operationTime + }) + accessory.context.operationTime = this.cusG.get(device.deviceid + 'SWX').operationTime } else if (cns.devicesSensor.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') @@ -206,7 +206,7 @@ class eWeLink { } this.hiddenMasters.push(device.deviceid) accessory = this.addAccessory(device, device.deviceid + 'SW0', 'light', true) - accessory.control = new DeviceLight(this) + accessory.control = new DeviceLight(this, accessory) } else { accessory = this.devicesInHB.has(device.deviceid + 'SW0') ? this.devicesInHB.get(device.deviceid + 'SW0') @@ -240,7 +240,7 @@ class eWeLink { } this.hiddenMasters.push(device.deviceid) accessory = this.addAccessory(device, device.deviceid + 'SW0', 'switch', true) - accessory.control = new DeviceSwitch(this) + accessory.control = new DeviceSwitch(this, accessory) } else { accessory = this.devicesInHB.has(device.deviceid + 'SW0') ? this.devicesInHB.get(device.deviceid + 'SW0') @@ -280,7 +280,7 @@ class eWeLink { : this.addAccessory(device, device.deviceid + 'SW0', 'rf_pri', true, { rfMap }) - accessory.control = new DeviceRFBridge(this) + accessory.control = new DeviceRFBridge(this, accessory) this.hiddenMasters.push(device.deviceid) rfMap.forEach(subDevice => { const swNumber = rfChlCounter + 1 @@ -383,7 +383,7 @@ class eWeLink { newDeviceName = this.config.nameOverride[hbDeviceId] } try { - const accessory = new Accessory(newDeviceName, this.api.hap.uuid.generate(hbDeviceId).toString()) + const accessory = new this.api.platformAccessory(newDeviceName, this.api.hap.uuid.generate(hbDeviceId).toString()) if (!hidden) { accessory .getService(Service.AccessoryInformation) @@ -424,407 +424,54 @@ class eWeLink { accessory.context.reachableWAN = true accessory.context.reachableLAN = true switch (accessory.context.type) { - case 'curtain': { - accessory.control = new DeviceCurtain(this) - let cService - if (!(cService = accessory.getService(Service.WindowCovering))) { - accessory - .addService(Service.WindowCovering) - .setCharacteristic(Characteristic.CurrentPosition, 0) - .setCharacteristic(Characteristic.TargetPosition, 0) - .setCharacteristic(Characteristic.PositionState, 2) - cService = accessory.getService(Service.WindowCovering) - } - cService - .getCharacteristic(Characteristic.TargetPosition) - .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) + case 'curtain': + accessory.control = new DeviceCurtain(this, accessory) break - } - case 'blind': { - accessory.control = new DeviceBlind(this) - let wcService - if (!(wcService = accessory.getService(Service.WindowCovering))) { - accessory - .addService(Service.WindowCovering) - .setCharacteristic(Characteristic.CurrentPosition, 0) - .setCharacteristic(Characteristic.TargetPosition, 0) - .setCharacteristic(Characteristic.PositionState, 2) - wcService = accessory.getService(Service.WindowCovering) - } - wcService - .getCharacteristic(Characteristic.TargetPosition) - .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) + case 'blind': + accessory.control = new DeviceBlind(this, accessory) break - } - case 'garage': { - accessory.control = new DeviceGarage(this) - let gdService - if (!(gdService = accessory.getService(Service.GarageDoorOpener))) { - accessory - .addService(Service.GarageDoorOpener) - .setCharacteristic(Characteristic.CurrentDoorState, 1) - .setCharacteristic(Characteristic.TargetDoorState, 1) - .setCharacteristic(Characteristic.ObstructionDetected, false) - gdService = accessory.getService(Service.GarageDoorOpener) - } - gdService - .getCharacteristic(Characteristic.TargetDoorState) - .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) + case 'garage': + accessory.control = new DeviceGarage(this, accessory) break - } - case 'garage_eachen': { - accessory.control = new DeviceGarageEachen(this) - let gdeService - if (!(gdeService = accessory.getService(Service.GarageDoorOpener))) { - accessory - .addService(Service.GarageDoorOpener) - .setCharacteristic(Characteristic.CurrentDoorState, 1) - .setCharacteristic(Characteristic.TargetDoorState, 1) - .setCharacteristic(Characteristic.ObstructionDetected, false) - gdeService = accessory.getService(Service.GarageDoorOpener) - } - gdeService - .getCharacteristic(Characteristic.TargetDoorState) - .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) + case 'garage_eachen': + accessory.control = new DeviceGarageEachen(this, accessory) break - } - case 'lock': { - accessory.control = new DeviceLock(this) - const lmService = accessory.getService(Service.LockMechanism) || accessory.addService(Service.LockMechanism) - lmService - .getCharacteristic(Characteristic.LockTargetState) - .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) + case 'lock': + accessory.control = new DeviceLock(this, accessory) break - } - case 'valve': { - accessory.control = new DeviceValve(this) - const valveConfig = this.cusG.get(accessory.context.hbDeviceId) - const arr = ['A', 'B'] - arr.forEach(v => { - let valveService - if (!(valveService = accessory.getService('Valve ' + v))) { - accessory - .addService(Service.Valve, 'Valve ' + v, 'valve' + v.toLowerCase()) - .setCharacteristic(Characteristic.Active, 0) - .setCharacteristic(Characteristic.InUse, 0) - .setCharacteristic(Characteristic.ValveType, 1) - .setCharacteristic(Characteristic.SetDuration, Math.round(valveConfig.operationTime / 10) || 120) - .addCharacteristic(Characteristic.RemainingDuration) - valveService = accessory.getService('Valve ' + v) - } - valveService - .getCharacteristic(Characteristic.Active) - .on('set', (value, callback) => - accessory.control.internalUpdate(accessory, 'Valve ' + v, value, callback) - ) - valveService.getCharacteristic(Characteristic.SetDuration).on('set', (value, callback) => { - if (valveService.getCharacteristic(Characteristic.InUse).value) { - valveService.updateCharacteristic(Characteristic.RemainingDuration, value) - clearTimeout(valveService.timer) - valveService.timer = setTimeout(() => { - valveService.setCharacteristic(Characteristic.Active, 0) - }, value * 1000) - } - callback() - }) - }) + case 'valve': + accessory.control = new DeviceValve(this, accessory) break - } - case 'sensor': { - accessory.control = new DeviceSensor(this) - accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor) - accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService) + case 'sensor': + accessory.control = new DeviceSensor(this, accessory) break - } - case 'fan': { - accessory.control = new DeviceFan(this) - const fanService = accessory.getService(Service.Fanv2) || accessory.addService(Service.Fanv2) - const fanLightService = accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb) - fanService - .getCharacteristic(Characteristic.Active) - .on('set', (value, callback) => accessory.control.internalUpdate(accessory, 'power', value, callback)) - fanService - .getCharacteristic(Characteristic.RotationSpeed) - .on('set', (value, callback) => accessory.control.internalUpdate(accessory, 'speed', value, callback)) - .setProps({ - minStep: 33 - }) - fanLightService - .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => accessory.control.internalUpdate(accessory, 'light', value, callback)) + case 'fan': + accessory.control = new DeviceFan(this, accessory) break - } - case 'thermostat': { - accessory.control = new DeviceThermostat(this) - const tempService = accessory.getService(Service.TemperatureSensor) || accessory.addService(Service.TemperatureSensor) - let humiService = false - if (accessory.context.sensorType !== 'DS18B20') { - humiService = accessory.getService(Service.HumiditySensor) || accessory.addService(Service.HumiditySensor) - } - if (!this.config.hideTHSwitch) { - const switchService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch) - switchService - .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) - } - if (!this.config.disableEveLogging) { - accessory.log = this.log - accessory.eveLogger = new EveHistoryService('weather', accessory, { - storage: 'fs', - minutes: 5, - path: this.eveLogPath - }) - corrInterval.setCorrectingInterval(() => { - const dataToAdd = { - time: Date.now(), - temp: tempService.getCharacteristic(Characteristic.CurrentTemperature).value - } - if (humiService) { - dataToAdd.humidity = humiService.getCharacteristic(Characteristic.CurrentRelativeHumidity).value - } - accessory.eveLogger.addEntry(dataToAdd) - }, 300000) - } + case 'thermostat': + accessory.control = new DeviceThermostat(this, accessory) break - } - case 'outlet': { - accessory.control = new DeviceOutlet(this) - let outletService - if (!(outletService = accessory.getService(Service.Outlet))) { - accessory.addService(Service.Outlet) - outletService = accessory.getService(Service.Outlet) - if (accessory.context.eweModel !== 'S26' && !this.config.disableEveLogging) { - outletService.addCharacteristic(EveService.Characteristics.Voltage) - outletService.addCharacteristic(EveService.Characteristics.CurrentConsumption) - outletService.addCharacteristic(EveService.Characteristics.ElectricCurrent) - outletService.addCharacteristic(EveService.Characteristics.TotalConsumption) - outletService.addCharacteristic(EveService.Characteristics.ResetTotal) - accessory.context = { - ...accessory.context, - ...{ - extraPersistedData: {}, - lastReset: 0, - totalEnergy: 0, - totalEnergyTemp: 0 - } - } - } - } - outletService - .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) - if (accessory.context.eweModel !== 'S26' && !this.config.disableEveLogging) { - accessory.log = this.log - accessory.eveLogger = new EveHistoryService('energy', accessory, { - storage: 'fs', - minutes: 5, - path: this.eveLogPath - }) - corrInterval.setCorrectingInterval(() => { - const isOn = outletService.getCharacteristic(Characteristic.On).value - const currentWatt = isOn - ? outletService.getCharacteristic(EveService.Characteristics.CurrentConsumption).value - : 0 - if (accessory.eveLogger.isHistoryLoaded()) { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalEnergy = - accessory.context.extraPersistedData.totalenergy + - accessory.context.totalEnergyTemp + - (currentWatt * 10) / 3600 / 1000 - accessory.eveLogger.setExtraPersistedData({ - totalenergy: accessory.context.totalEnergy, - lastReset: accessory.context.extraPersistedData.lastReset - }) - } else { - accessory.context.totalEnergy = accessory.context.totalEnergyTemp + (currentWatt * 10) / 3600 / 1000 - accessory.eveLogger.setExtraPersistedData({ - totalenergy: accessory.context.totalEnergy, - lastReset: 0 - }) - } - accessory.context.totalEnergytemp = 0 - } else { - accessory.context.totalEnergyTemp += (currentWatt * 10) / 3600 / 1000 - accessory.context.totalEnergy = accessory.context.totalEnergyTemp - } - accessory.eveLogger.addEntry({ - time: Date.now(), - power: currentWatt - }) - }, 300000) - outletService - .getCharacteristic(EveService.Characteristics.TotalConsumption) - .on('get', callback => { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower - } - callback(null, accessory.context.totalEnergy) - }) - outletService - .getCharacteristic(EveService.Characteristics.ResetTotal) - .on('set', (value, callback) => { - accessory.context.totalEnergy = 0 - accessory.context.lastReset = value - accessory.eveLogger.setExtraPersistedData({ - totalPower: 0, - lastReset: value - }) - callback() - }) - .on('get', callback => { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.lastReset = accessory.context.extraPersistedData.lastReset - } - callback(null, accessory.context.lastReset) - }) - } + case 'outlet': + accessory.control = new DeviceOutlet(this, accessory) break - } - case 'usb': { - accessory.control = new DeviceUSB(this) - const usbService = accessory.getService(Service.Outlet) || accessory.addService(Service.Outlet) - usbService - .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) + case 'usb': + accessory.control = new DeviceUSB(this, accessory) break - } - case 'scm': { - accessory.control = new DeviceSCM(this) - const scmService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch) - scmService - .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) + case 'scm': + accessory.control = new DeviceSCM(this, accessory) break - } - case 'light': { - accessory.control = new DeviceLight(this) - const lightService = accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb) - lightService - .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => accessory.control.internalUpdate(accessory, 'onoff', value, callback)) - if (cns.devicesBrightable.includes(accessory.context.eweUIID)) { - lightService.getCharacteristic(Characteristic.Brightness).on('set', (value, callback) => { - if (value > 0) { - if (!lightService.getCharacteristic(Characteristic.On).value) { - accessory.control.internalUpdate(accessory, 'onoff', true, function () {}) - } - accessory.control.internalUpdate(accessory, 'brightness', value, callback) - } else { - accessory.control.internalUpdate(accessory, 'onoff', false, callback) - } - }) - } else if (cns.devicesColourable.includes(accessory.context.eweUIID)) { - lightService.getCharacteristic(Characteristic.Brightness).on('set', (value, callback) => { - if (value > 0) { - if (!lightService.getCharacteristic(Characteristic.On).value) { - accessory.control.internalUpdate(accessory, 'onoff', true, function () {}) - } - accessory.control.internalUpdate(accessory, 'c_brightness', value, callback) - } else { - accessory.control.internalUpdate(accessory, 'onoff', false, callback) - } - }) - lightService - .getCharacteristic(Characteristic.Hue) - .on('set', (value, callback) => accessory.control.internalUpdate(accessory, 'c_hue', value, callback)) - lightService.getCharacteristic(Characteristic.Saturation).on('set', (value, callback) => callback()) - } + case 'light': + accessory.control = new DeviceLight(this, accessory) break - } - case 'switch': { - accessory.control = new DeviceSwitch(this) - const switchService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch) - switchService - .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => accessory.control.internalUpdate(accessory, value, callback)) + case 'switch': + accessory.control = new DeviceSwitch(this, accessory) break - } - case 'rf_sub': { - accessory.control = new DeviceRFBridge(this) - switch (accessory.context.subType) { - case 'water': - accessory.getService(Service.LeakSensor) || accessory.addService(Service.LeakSensor) - break - case 'fire': - case 'smoke': - accessory.getService(Service.SmokeSensor) || accessory.addService(Service.SmokeSensor) - break - case 'co': - accessory.getService(Service.CarbonMonoxideSensor) || accessory.addService(Service.CarbonMonoxideSensor) - break - case 'co2': - accessory.getService(Service.CarbonDioxideSensor) || accessory.addService(Service.CarbonDioxideSensor) - break - case 'contact': - accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor) - break - case 'occupancy': - accessory.getService(Service.OccupancySensor) || accessory.addService(Service.OccupancySensor) - break - default: - accessory.getService(Service.MotionSensor) || accessory.addService(Service.MotionSensor) - break - case 'button': - Object.entries(accessory.context.buttons).forEach(([chan, name]) => { - accessory.getService(name) || accessory.addService(Service.Switch, name, 'switch' + chan) - accessory.getService(name).updateCharacteristic(Characteristic.On, false) - accessory.getService(name).getCharacteristic(Characteristic.On) - .on('set', (value, callback) => { - value ? accessory.control.internalUpdate(accessory, chan, name, callback) : callback() - }) - }) - break - } + case 'rf_sub': + accessory.control = new DeviceRFBridge(this, accessory) break - } - case 'zb_dev': { //* ** credit @tasict ***\\ - accessory.control = new DeviceZBDev(this) - accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService) - switch (accessory.context.eweUIID) { - case 1000: { - const zbspsService = - accessory.getService(Service.StatelessProgrammableSwitch) || - accessory.addService(Service.StatelessProgrammableSwitch) - if (this.config.hideZBLDPress) { - zbspsService.getCharacteristic(Characteristic.ProgrammableSwitchEvent).setProps({ - validValues: [0] - }) - } - break - } - case 1770: { - const zbTempService = - accessory.getService(Service.TemperatureSensor) || accessory.addService(Service.TemperatureSensor) - const zbHumiService = - accessory.getService(Service.HumiditySensor) || accessory.addService(Service.HumiditySensor) - accessory.log = this.log - accessory.eveLogger = new EveHistoryService('weather', accessory, { - storage: 'fs', - minutes: 5, - path: this.eveLogPath - }) - corrInterval.setCorrectingInterval(() => { - const dataToAdd = { - time: Date.now(), - temp: zbTempService.getCharacteristic(Characteristic.CurrentTemperature).value, - humidity: zbHumiService.getCharacteristic(Characteristic.CurrentRelativeHumidity).value - } - accessory.eveLogger.addEntry(dataToAdd) - }, 300000) - break - } - case 2026: - accessory.getService(Service.MotionSensor) || accessory.addService(Service.MotionSensor) - break - case 3026: - accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor) - break - } + case 'zb_dev': //* ** credit @tasict ***\\ + accessory.control = new DeviceZBDev(this, accessory) break - } } this.devicesInHB.set(accessory.context.hbDeviceId, accessory) } catch (err) { @@ -944,10 +591,7 @@ class eWeLink { } } module.exports = function (homebridge) { - Accessory = homebridge.platformAccessory Characteristic = homebridge.hap.Characteristic - EveService = new hbLib.EveHomeKitTypes(homebridge) - EveHistoryService = fakegato(homebridge) Service = homebridge.hap.Service return eWeLink } From ad4de39b217648e6f5f7c501d9a034b1caf66ce5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 16:15:57 +0100 Subject: [PATCH 0288/3183] code overhaul --- lib/constants.js | 18 +- lib/device/valve.js | 3 +- lib/eWeLink.js | 547 ++++++++++++++++++++------------------------ 3 files changed, 251 insertions(+), 317 deletions(-) diff --git a/lib/constants.js b/lib/constants.js index 0f618fb6..b23eb05b 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -7,39 +7,23 @@ module.exports = { devicesHideable: ['switch', 'light'], devicesNonLAN: [22, 28, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], - devicesSingleSwitchParams: ['switch'], - devicesSingleSwitchOutlet: ['Sonoff Pow', 'S26'], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], - devicesMultiSwitchParams: ['switches'], devicesSingleSwitchLight: ['T1 1C', 'L1', 'B1', 'B1_R2', 'TX1C', 'D1', 'D1R1', 'KING-M4', 'Slampher', 'GTTA59'], - devicesSingleSwitchLightParams: ['switch', 'state', 'bright', 'colorR', 'brightness', 'channel0', 'channel2', 'xyz_mode'], devicesMultiSwitchLight: ['T1 2C', 'T1 3C', 'TX2C', 'TX3C'], - devicesMultiSwitchLightParams: ['switches'], + devicesSingleSwitchOutlet: ['Sonoff Pow', 'S26'], devicesBrightable: [36, 44], devicesColourable: [22, 59], devicesCurtain: [11], - devicesCurtainParams: ['switch', 'setclose'], devicesSensor: [102], - devicesSensorParams: ['switch', 'battery'], devicesThermostat: [15], - devicesThermostatParams: ['currentTemperature', 'currentHumidity', 'switch', 'masterSwitch'], devicesFan: [34], - devicesFanParams: ['switches', 'light', 'fan', 'speed'], devicesOutlet: [32], - devicesOutletParams: ['switch', 'power', 'voltage', 'current'], devicesCamera: [87], devicesUSB: [77], - devicesUSBParams: ['switches'], devicesSCM: [78], - devicesSCMParams: ['switches'], devicesRFBridge: [28], - devicesRFBridgeParams: ['cmd'], devicesZBBridge: [66], - devicesZBBridgeParams: ['key', 'temperature', 'humidity', 'motion', 'lock', 'trigTime', 'battery'], devicesZB: [1000, 1770, 2026, 3026], - devicesValveParams: ['switches'], - devicesGarageParams: ['switch', 'switches'], - devicesLockParams: ['switch'], paramsToKeep: ['battery', 'bright', 'brightness', 'channel', 'cmd', 'colorB', 'colorG', 'colorR', 'current', 'currentHumidity', 'currentTemperature', 'fan', 'humidity', 'key', 'light', 'lock', 'mainSwitch', 'mode', 'motion', 'online', 'power', 'rfChl', 'rfList', 'rfTrig', 'sensorType', 'setclose', 'speed', 'state', 'switch', 'switches', 'temperature', 'trigTime', 'type', 'voltage', 'zyx_mode'], defaultMultiSwitchOff: [{ switch: 'off', diff --git a/lib/device/valve.js b/lib/device/valve.js index 8363706d..9aab7584 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -8,13 +8,14 @@ module.exports = class deviceValve { const arr = ['A', 'B'] arr.forEach(v => { let valveService + const valveConfig = this.platform.cusG.get(accessory.context.hbDeviceId) if (!(valveService = accessory.getService('Valve ' + v))) { accessory .addService(Service.Valve, 'Valve ' + v, 'valve' + v.toLowerCase()) .setCharacteristic(Characteristic.Active, 0) .setCharacteristic(Characteristic.InUse, 0) .setCharacteristic(Characteristic.ValveType, 1) - .setCharacteristic(Characteristic.SetDuration, Math.round((accessory.context.operationTime || 1200) / 10)) + .setCharacteristic(Characteristic.SetDuration, Math.round((valveConfig.operationTime || 1200) / 10)) .addCharacteristic(Characteristic.RemainingDuration) valveService = accessory.getService('Valve ' + v) } diff --git a/lib/eWeLink.js b/lib/eWeLink.js index cc2310a3..2e4d277d 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -94,10 +94,7 @@ class eWeLink { this.log.warn(this.debug ? err : err.message) } } - }, - 1800000, { - stopOnError: false - } + }, 1800000, { stopOnError: false } ) this.log("eWeLink sync complete. Don't forget to ⭐ī¸ this plugin on GitHub if you're finding it useful!") if (this.config.debugReqRes) { @@ -129,247 +126,257 @@ class eWeLink { initialiseDevice (device) { let accessory - if (cns.devicesCurtain.includes(device.extra.uiid)) { - accessory = this.devicesInHB.has(device.deviceid + 'SWX') - ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', 'curtain', false, { - cacheCurrentPosition: 0 - }) - } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'blind') { - accessory = this.devicesInHB.has(device.deviceid + 'SWX') - ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', 'blind', false, { - cacheCurrentPosition: 0, - cachePositionState: 2, - cacheTargetPosition: 0 - }) - } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage') { - accessory = this.devicesInHB.has(device.deviceid + 'SWX') - ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', 'garage', false, { - cacheCurrentDoorState: 1, - cacheTargetDoorState: 1 - }) - } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage_eachen') { - accessory = this.devicesInHB.has(device.deviceid + 'SWX') - ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', 'garage_eachen') - } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'lock') { - accessory = this.devicesInHB.has(device.deviceid + 'SWX') - ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', 'lock') - } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'valve') { - accessory = this.devicesInHB.has(device.deviceid + 'SWX') - ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', 'valve', false, { - operationTime: this.cusG.get(device.deviceid + 'SWX').operationTime - }) - accessory.context.operationTime = this.cusG.get(device.deviceid + 'SWX').operationTime - } else if (cns.devicesSensor.includes(device.extra.uiid)) { - accessory = this.devicesInHB.has(device.deviceid + 'SWX') - ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', 'sensor') - } else if (cns.devicesFan.includes(device.extra.uiid)) { - accessory = this.devicesInHB.has(device.deviceid + 'SWX') - ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', 'fan') - } else if (cns.devicesThermostat.includes(device.extra.uiid)) { - accessory = this.devicesInHB.has(device.deviceid + 'SWX') - ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', 'thermostat', false, { - sensorType: device.params.sensorType - }) - if (accessory.context.sensorType !== device.params.sensorType) { - accessory.context.sensorType = device.params.sensorType - this.devicesInHB.set(accessory.context.hbDeviceId, accessory) - } - } else if (cns.devicesOutlet.includes(device.extra.uiid) || (cns.devicesSingleSwitch.includes(device.extra.uiid) && cns.devicesSingleSwitchOutlet.includes(device.productModel))) { - accessory = this.devicesInHB.has(device.deviceid + 'SWX') - ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', 'outlet') - } else if (cns.devicesUSB.includes(device.extra.uiid)) { - accessory = this.devicesInHB.has(device.deviceid + 'SWX') - ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', 'usb') - } else if (cns.devicesSCM.includes(device.extra.uiid)) { - accessory = this.devicesInHB.has(device.deviceid + 'SWX') - ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', 'scm') - } else if (cns.devicesSingleSwitch.includes(device.extra.uiid) && cns.devicesSingleSwitchLight.includes(device.productModel)) { - accessory = this.devicesInHB.has(device.deviceid + 'SWX') - ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', 'light') - } else if (cns.devicesMultiSwitch.includes(device.extra.uiid) && cns.devicesMultiSwitchLight.includes(device.productModel)) { - if (this.config.hideMasters) { - if (this.devicesInHB.has(device.deviceid + 'SW0')) { - this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) + try { + if (cns.devicesCurtain.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', false, { cacheCurrentPosition: 0 }) + accessory.control = new DeviceCurtain(this, accessory) + } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'blind') { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', false, { + cacheCurrentPosition: 0, + cachePositionState: 2, + cacheTargetPosition: 0 + }) + accessory.control = new DeviceBlind(this, accessory) + } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage') { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', false, { + cacheCurrentDoorState: 1, + cacheTargetDoorState: 1 + }) + accessory.control = new DeviceGarage(this, accessory) + } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage_eachen') { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new DeviceGarageEachen(this, accessory) + } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'lock') { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new DeviceLock(this, accessory) + } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'valve') { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new DeviceValve(this, accessory) + } else if (cns.devicesSensor.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', false, { type: 'sensor' }) + accessory.control = new DeviceSensor(this, accessory) + } else if (cns.devicesFan.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new DeviceFan(this, accessory) + } else if (cns.devicesThermostat.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', false, { + sensorType: device.params.sensorType + }) + if (accessory.context.sensorType !== device.params.sensorType) { + accessory.context.sensorType = device.params.sensorType } - this.hiddenMasters.push(device.deviceid) - accessory = this.addAccessory(device, device.deviceid + 'SW0', 'light', true) + accessory.control = new DeviceThermostat(this, accessory) + } else if (cns.devicesOutlet.includes(device.extra.uiid) || (cns.devicesSingleSwitch.includes(device.extra.uiid) && cns.devicesSingleSwitchOutlet.includes(device.productModel))) { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new DeviceOutlet(this, accessory) + } else if (cns.devicesUSB.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new DeviceUSB(this, accessory) + } else if (cns.devicesSCM.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new DeviceSCM(this, accessory) + } else if (cns.devicesSingleSwitch.includes(device.extra.uiid) && cns.devicesSingleSwitchLight.includes(device.productModel)) { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceLight(this, accessory) - } else { - accessory = this.devicesInHB.has(device.deviceid + 'SW0') - ? this.devicesInHB.get(device.deviceid + 'SW0') - : this.addAccessory(device, device.deviceid + 'SW0', 'light') - } - for (let i = 1; i <= cns.chansFromUiid[device.extra.uiid]; i++) { - if ((this.config.hideFromHB || '').includes(device.deviceid + 'SW' + i)) { - if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { - this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + i)) + } else if (cns.devicesMultiSwitch.includes(device.extra.uiid) && cns.devicesMultiSwitchLight.includes(device.productModel)) { + if (this.config.hideMasters) { + if (this.devicesInHB.has(device.deviceid + 'SW0')) { + this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) } + this.hiddenMasters.push(device.deviceid) + accessory = this.addAccessory(device, device.deviceid + 'SW0', true) } else { - const oAccessory = this.devicesInHB.has(device.deviceid + 'SW' + i) - ? this.devicesInHB.get(device.deviceid + 'SW' + i) - : this.addAccessory(device, device.deviceid + 'SW' + i, 'light') - oAccessory - .getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) - oAccessory.context.reachableWAN = device.online - oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false - this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) + accessory = this.devicesInHB.has(device.deviceid + 'SW0') + ? this.devicesInHB.get(device.deviceid + 'SW0') + : this.addAccessory(device, device.deviceid + 'SW0') } - } - } else if (cns.devicesSingleSwitch.includes(device.extra.uiid)) { - accessory = this.devicesInHB.has(device.deviceid + 'SWX') - ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', 'switch') - } else if (cns.devicesMultiSwitch.includes(device.extra.uiid)) { - if (this.config.hideMasters) { - if (this.devicesInHB.has(device.deviceid + 'SW0')) { - this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) + accessory.control = new DeviceLight(this, accessory) + for (let i = 1; i <= cns.chansFromUiid[device.extra.uiid]; i++) { + if ((this.config.hideFromHB || '').includes(device.deviceid + 'SW' + i)) { + if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { + this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + i)) + } + } else { + const oAccessory = this.devicesInHB.has(device.deviceid + 'SW' + i) + ? this.devicesInHB.get(device.deviceid + 'SW' + i) + : this.addAccessory(device, device.deviceid + 'SW' + i) + oAccessory + .getService(Service.AccessoryInformation) + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) + oAccessory.context.reachableWAN = device.online + oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) + oAccessory.control = new DeviceLight(this, oAccessory) + } } - this.hiddenMasters.push(device.deviceid) - accessory = this.addAccessory(device, device.deviceid + 'SW0', 'switch', true) + } else if (cns.devicesSingleSwitch.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceSwitch(this, accessory) - } else { - accessory = this.devicesInHB.has(device.deviceid + 'SW0') - ? this.devicesInHB.get(device.deviceid + 'SW0') - : this.addAccessory(device, device.deviceid + 'SW0', 'switch') - } - for (let i = 1; i <= cns.chansFromUiid[device.extra.uiid]; i++) { - if ((this.config.hideFromHB || '').includes(device.deviceid + 'SW' + i)) { - if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { - this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + i)) + } else if (cns.devicesMultiSwitch.includes(device.extra.uiid)) { + if (this.config.hideMasters) { + if (this.devicesInHB.has(device.deviceid + 'SW0')) { + this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) } + this.hiddenMasters.push(device.deviceid) + accessory = this.addAccessory(device, device.deviceid + 'SW0', true) } else { - const oAccessory = this.devicesInHB.has(device.deviceid + 'SW' + i) - ? this.devicesInHB.get(device.deviceid + 'SW' + i) - : this.addAccessory(device, device.deviceid + 'SW' + i, 'switch') - oAccessory - .getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) - oAccessory.context.reachableWAN = device.online - oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false - this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) + accessory = this.devicesInHB.has(device.deviceid + 'SW0') + ? this.devicesInHB.get(device.deviceid + 'SW0') + : this.addAccessory(device, device.deviceid + 'SW0') } - } - } else if (cns.devicesRFBridge.includes(device.extra.uiid)) { - let rfChlCounter = 0 - const rfMap = [] - if (Object.prototype.hasOwnProperty.call(device, 'tags') && Object.prototype.hasOwnProperty.call(device.tags, 'zyx_info')) { - device.tags.zyx_info.forEach(remote => - rfMap.push({ - name: remote.name, - type: remote.remote_type, - buttons: Object.assign({}, ...remote.buttonName) - }) - ) - } - const accessory = this.devicesInHB.has(device.deviceid + 'SW0') - ? this.devicesInHB.get(device.deviceid + 'SW0') - : this.addAccessory(device, device.deviceid + 'SW0', 'rf_pri', true, { - rfMap - }) - accessory.control = new DeviceRFBridge(this, accessory) - this.hiddenMasters.push(device.deviceid) - rfMap.forEach(subDevice => { - const swNumber = rfChlCounter + 1 - let subAccessory - let subType - let subExtraContext = {} - switch (subDevice.type) { - case '1': - case '2': - case '3': - case '4': - subType = 'button' - break - case '6': - subType = this.cusS.has(device.deviceid + 'SW' + swNumber) - ? this.cusS.get(device.deviceid + 'SW' + swNumber).type - : 'motion' - break - default: - return + accessory.control = new DeviceSwitch(this, accessory) + for (let i = 1; i <= cns.chansFromUiid[device.extra.uiid]; i++) { + if ((this.config.hideFromHB || '').includes(device.deviceid + 'SW' + i)) { + if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { + this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + i)) + } + } else { + const oAccessory = this.devicesInHB.has(device.deviceid + 'SW' + i) + ? this.devicesInHB.get(device.deviceid + 'SW' + i) + : this.addAccessory(device, device.deviceid + 'SW' + i) + oAccessory + .getService(Service.AccessoryInformation) + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) + oAccessory.context.reachableWAN = device.online + oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) + oAccessory.control = new DeviceSwitch(this, oAccessory) + } } - subExtraContext = { - buttons: subDevice.buttons, - subType, - swNumber + } else if (cns.devicesRFBridge.includes(device.extra.uiid)) { + let rfChlCounter = 0 + const rfMap = [] + if (Object.prototype.hasOwnProperty.call(device, 'tags') && Object.prototype.hasOwnProperty.call(device.tags, 'zyx_info')) { + device.tags.zyx_info.forEach(remote => + rfMap.push({ + name: remote.name, + type: remote.remote_type, + buttons: Object.assign({}, ...remote.buttonName) + }) + ) } - if ((subAccessory = this.devicesInHB.get(device.deviceid + 'SW' + swNumber))) { - if (subAccessory.context.subType !== subType || subAccessory.context.swNumber !== swNumber) { - this.removeAccessory(subAccessory) + accessory = this.devicesInHB.has(device.deviceid + 'SW0') + ? this.devicesInHB.get(device.deviceid + 'SW0') + : this.addAccessory(device, device.deviceid + 'SW0', true, { + rfMap + }, 'rf_pri') + accessory.control = new DeviceRFBridge(this, accessory) + this.hiddenMasters.push(device.deviceid) + rfMap.forEach(subDevice => { + const swNumber = rfChlCounter + 1 + let subAccessory + let subType + let subExtraContext = {} + switch (subDevice.type) { + case '1': + case '2': + case '3': + case '4': + subType = 'button' + break + case '6': + subType = this.cusS.has(device.deviceid + 'SW' + swNumber) + ? this.cusS.get(device.deviceid + 'SW' + swNumber).type + : 'motion' + break + default: + return } - } - subAccessory = this.devicesInHB.has(device.deviceid + 'SW' + swNumber) - ? this.devicesInHB.get(device.deviceid + 'SW' + swNumber) - : this.addAccessory(device, device.deviceid + 'SW' + swNumber, 'rf_sub', false, subExtraContext) - subAccessory + subExtraContext = { + buttons: subDevice.buttons, + subType, + swNumber + } + if ((subAccessory = this.devicesInHB.get(device.deviceid + 'SW' + swNumber))) { + if (subAccessory.context.subType !== subType || subAccessory.context.swNumber !== swNumber) { + this.removeAccessory(subAccessory) + } + } + subAccessory = this.devicesInHB.has(device.deviceid + 'SW' + swNumber) + ? this.devicesInHB.get(device.deviceid + 'SW' + swNumber) + : this.addAccessory(device, device.deviceid + 'SW' + swNumber, false, subExtraContext, 'rf_sub') + subAccessory + .getService(Service.AccessoryInformation) + .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) + subAccessory.context.reachableWAN = device.online + subAccessory.context.reachableLAN = false + this.devicesInHB.set(subAccessory.context.hbDeviceId, subAccessory) + subAccessory.control = new DeviceRFBridge(this, subAccessory) + rfChlCounter += Object.keys(subDevice.buttons || {}).length + }) + accessory.context.channelCount = rfChlCounter + this.devicesInHB.set(accessory.context.hbDeviceId, accessory) + } else if (cns.devicesZB.includes(device.extra.uiid)) { + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new DeviceZBDev(this, accessory) + } else if (cns.devicesCamera.includes(device.extra.uiid)) { + this.log.warn(' → [%s] please see the homebridge-ewelink wiki for details to enable the camera', device.name) + return + } else if (!cns.devicesZBBridge.includes(device.extra.uiid)) { + this.log.warn(' → [%s] has not been added as it is not supported. Please make a GitHub issue request.', device.name) + return + } + if (!this.hiddenMasters.includes(device.deviceid)) { + accessory .getService(Service.AccessoryInformation) .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) - subAccessory.context.reachableWAN = device.online - subAccessory.context.reachableLAN = false - this.devicesInHB.set(subAccessory.context.hbDeviceId, subAccessory) - rfChlCounter += Object.keys(subDevice.buttons || {}).length - }) - accessory.context.channelCount = rfChlCounter - this.devicesInHB.set(accessory.context.hbDeviceId, accessory) - } else if (cns.devicesZB.includes(device.extra.uiid)) { - accessory = this.devicesInHB.has(device.deviceid + 'SWX') - ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', 'zb_dev') - } else if (cns.devicesCamera.includes(device.extra.uiid)) { - this.log.warn(' → [%s] please see the homebridge-ewelink wiki for details to enable the camera', device.name) - return - } else if (!cns.devicesZBBridge.includes(device.extra.uiid)) { - this.log.warn(' → [%s] has not been added as it is not supported. Please make a GitHub issue request.', device.name) - return - } - if (!accessory) return - if (!this.hiddenMasters.includes(device.deviceid)) { - accessory - .getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) - } - accessory.context.reachableWAN = device.online - accessory.context.reachableLAN = this.lanDevices.has(device.deviceid) - ? this.lanDevices.get(device.deviceid).online - : false - accessory.context.inUse = false - let str = accessory.context.reachableLAN - ? 'and found locally with IP [' + this.lanDevices.get(device.deviceid).ip + ']' - : 'but LAN mode unavailable as device ' - if (!accessory.context.reachableLAN) { - if (cns.devicesNonLAN.includes(device.extra.uiid)) { - str += "doesn't support it" - } else if (Object.prototype.hasOwnProperty.call(device, 'sharedBy') && Object.prototype.hasOwnProperty.call(device.sharedBy, 'email')) { - str += 'is shared (' + device.sharedBy.email + ')' - } else { - str += 'is unreachable' } - } - this.log(' → [%s] initialised %s.', device.name, str) - this.devicesInHB.set(accessory.context.hbDeviceId, accessory) - if (this.config.disableHTTPRefresh) return - try { - accessory.control.externalUpdate(accessory, device.params) + accessory.context.reachableWAN = device.online + accessory.context.reachableLAN = this.lanDevices.has(device.deviceid) + ? this.lanDevices.get(device.deviceid).online + : false + accessory.context.inUse = false + let str = accessory.context.reachableLAN + ? 'and found locally with IP [' + this.lanDevices.get(device.deviceid).ip + ']' + : 'but LAN mode unavailable as device ' + if (!accessory.context.reachableLAN) { + if (cns.devicesNonLAN.includes(device.extra.uiid)) { + str += "doesn't support it" + } else if (Object.prototype.hasOwnProperty.call(device, 'sharedBy') && Object.prototype.hasOwnProperty.call(device.sharedBy, 'email')) { + str += 'is shared (' + device.sharedBy.email + ')' + } else { + str += 'is unreachable' + } + } + if (!this.config.disableHTTPRefresh) accessory.control.externalUpdate(accessory, device.params) + this.devicesInHB.set(accessory.context.hbDeviceId, accessory) + this.log(' → [%s] initialised %s.', device.name, str) } catch (err) { this.log.warn('[%s] could not be initialised as %s.', accessory.displayName, this.debug ? err : err.message) } } - addAccessory (device, hbDeviceId, type, hidden = false, extraContext = {}) { + addAccessory (device, hbDeviceId, hidden = false, extraContext = {}, type = '') { const switchNumber = hbDeviceId.substr(-1).toString() let newDeviceName = type === 'rf_sub' ? device.tags.zyx_info[switchNumber - 1].name : device.name const channelCount = @@ -401,14 +408,12 @@ class eWeLink { eweModel: device.productModel, eweApiKey: device.apikey, switchNumber, - channelCount, - type + channelCount }, ...extraContext } if (!hidden) { this.api.registerPlatformAccessories('homebridge-ewelink', 'eWeLink', [accessory]) - this.configureAccessory(accessory) this.log(' → [%s] has been added to Homebridge.', newDeviceName) } return accessory @@ -418,77 +423,6 @@ class eWeLink { } } - configureAccessory (accessory) { - if (!this.log) return - try { - accessory.context.reachableWAN = true - accessory.context.reachableLAN = true - switch (accessory.context.type) { - case 'curtain': - accessory.control = new DeviceCurtain(this, accessory) - break - case 'blind': - accessory.control = new DeviceBlind(this, accessory) - break - case 'garage': - accessory.control = new DeviceGarage(this, accessory) - break - case 'garage_eachen': - accessory.control = new DeviceGarageEachen(this, accessory) - break - case 'lock': - accessory.control = new DeviceLock(this, accessory) - break - case 'valve': - accessory.control = new DeviceValve(this, accessory) - break - case 'sensor': - accessory.control = new DeviceSensor(this, accessory) - break - case 'fan': - accessory.control = new DeviceFan(this, accessory) - break - case 'thermostat': - accessory.control = new DeviceThermostat(this, accessory) - break - case 'outlet': - accessory.control = new DeviceOutlet(this, accessory) - break - case 'usb': - accessory.control = new DeviceUSB(this, accessory) - break - case 'scm': - accessory.control = new DeviceSCM(this, accessory) - break - case 'light': - accessory.control = new DeviceLight(this, accessory) - break - case 'switch': - accessory.control = new DeviceSwitch(this, accessory) - break - case 'rf_sub': - accessory.control = new DeviceRFBridge(this, accessory) - break - case 'zb_dev': //* ** credit @tasict ***\\ - accessory.control = new DeviceZBDev(this, accessory) - break - } - this.devicesInHB.set(accessory.context.hbDeviceId, accessory) - } catch (err) { - this.log.warn('[%s] could not be configured as %s.', accessory.displayName, err) - } - } - - removeAccessory (accessory) { - try { - this.api.unregisterPlatformAccessories('homebridge-ewelink', 'eWeLink', [accessory]) - this.devicesInHB.delete(accessory.context.hbDeviceId) - this.log(' → [%s] was removed from Homebridge.', accessory.displayName) - } catch (err) { - this.log.warn(" → [%s] wasn't removed as %s.", accessory.displayName, err) - } - } - async sendDeviceUpdate (accessory, params) { const payload = { apikey: accessory.context.eweApiKey, @@ -571,7 +505,7 @@ class eWeLink { this.lanClient.addDeviceToMap(newDevice) } } catch (err) { - this.log.warn('[%s] error getting info [%s]. Restart Homebeidge to add device.', deviceId, err.message) + this.log.warn('[%s] error getting info [%s]. Restart Homebridge to add device.', deviceId, err.message) } } } @@ -589,6 +523,21 @@ class eWeLink { } } } + + configureAccessory (accessory) { + if (!this.log) return + this.devicesInHB.set(accessory.context.hbDeviceId, accessory) + } + + removeAccessory (accessory) { + try { + this.api.unregisterPlatformAccessories('homebridge-ewelink', 'eWeLink', [accessory]) + this.devicesInHB.delete(accessory.context.hbDeviceId) + this.log(' → [%s] was removed from Homebridge.', accessory.displayName) + } catch (err) { + this.log.warn(" → [%s] wasn't removed as %s.", accessory.displayName, err) + } + } } module.exports = function (homebridge) { Characteristic = homebridge.hap.Characteristic From 2642cd19bccc3d2984a90e1c8156f6bf5f7beecc Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 16:20:03 +0100 Subject: [PATCH 0289/3183] 3.2.0-2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 463b984a..5290496b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.2.0-1", + "version": "3.2.0-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index fd2e214f..58aea4f0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.2.0-1", + "version": "3.2.0-2", "author": "bwp91", "contributors": [ "gbro115", From c5ebf8f03c32fdc61e57136b976ff3c9c9f7cc63 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 17:32:38 +0100 Subject: [PATCH 0290/3183] 3.2.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5290496b..832f0d92 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.2.0-2", + "version": "3.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 58aea4f0..f11902c2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.2.0-2", + "version": "3.2.0", "author": "bwp91", "contributors": [ "gbro115", From 690f5c48890216f64df9ac42afd3d070557a8589 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 19:13:20 +0100 Subject: [PATCH 0291/3183] rename section --- config.schema.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config.schema.json b/config.schema.json index 5732a4f1..fe60e161 100644 --- a/config.schema.json +++ b/config.schema.json @@ -312,7 +312,6 @@ "inUsePowerThreshold", "sensorTimeLength", "sensorTimeDifference", - "valveTimeLength", "hideTHSwitch", "hideZBLDPress" ] @@ -320,7 +319,7 @@ { "key": "groups", "expandable": true, - "title": "Custom Device Simulations", + "title": "Custom Accessory Simulations", "add": "Add Another Type", "type": "array", "items": [ From dcbec76d7d5790dca81e2f1083bd7e82b51ed565 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 19:14:32 +0100 Subject: [PATCH 0292/3183] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 33b6d570..138c863d 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ * [Beta Version](https://github.com/bwp91/homebridge-ewelink/wiki/Beta-Version) ### Features * [Supported Devices](https://github.com/bwp91/homebridge-ewelink/wiki/Supported-Devices) +* [Custom Accessory Simulations](https://github.com/bwp91/homebridge-ewelink/wiki/Custom-Accessory-Simulations) * [Connection Methods](https://github.com/bwp91/homebridge-ewelink/wiki/Connection-Methods) ### How-to Guides * [How to set up RF Bridge sensors](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-RF-Bridge-sensors) From 1c1c6cd614cca80c5de425cc6d99579713f0c786 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 19:16:41 +0100 Subject: [PATCH 0293/3183] Update config.schema.json --- config.schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.schema.json b/config.schema.json index fe60e161..74ce6699 100644 --- a/config.schema.json +++ b/config.schema.json @@ -110,7 +110,7 @@ }, "groups": { "type": "array", - "title": "Custom Device Types", + "title": "Accessory Simulations", "description": "You can use this setting to set up custom simulated HomeKit accessories from a generic single/multi-switch device.", "items": { "type": "object", @@ -319,7 +319,7 @@ { "key": "groups", "expandable": true, - "title": "Custom Accessory Simulations", + "title": "Accessory Simulations", "add": "Add Another Type", "type": "array", "items": [ From e361c0cb49af9691c8ecef78aea4aca3278b8661 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 19:17:43 +0100 Subject: [PATCH 0294/3183] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 138c863d..4f0e0eb3 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ * [Beta Version](https://github.com/bwp91/homebridge-ewelink/wiki/Beta-Version) ### Features * [Supported Devices](https://github.com/bwp91/homebridge-ewelink/wiki/Supported-Devices) -* [Custom Accessory Simulations](https://github.com/bwp91/homebridge-ewelink/wiki/Custom-Accessory-Simulations) +* [Accessory Simulations](https://github.com/bwp91/homebridge-ewelink/wiki/Accessory-Simulations) * [Connection Methods](https://github.com/bwp91/homebridge-ewelink/wiki/Connection-Methods) ### How-to Guides * [How to set up RF Bridge sensors](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-RF-Bridge-sensors) From ab0099437af5681d08b733bc502f2cd6bdb91c2b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 19:45:08 +0100 Subject: [PATCH 0295/3183] Update config.schema.json --- config.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.schema.json b/config.schema.json index 74ce6699..d28e2210 100644 --- a/config.schema.json +++ b/config.schema.json @@ -55,7 +55,7 @@ "hideFromHB": { "type": "string", "title": "Hide Device Channels", - "description": "A list of SW1, SW2, SW3 and SW4 to hide from Homebridge. For example '10009553c8SW1' or multiple channels separated with a comma '10009553c8SW1,10009553c9SW2'. Only channels from switches and lights can be hidden. This setting cannot be used to hide master devices (SW0).", + "description": "A list of SW1, SW2, SW3 and SW4 to hide from Homebridge. For example '10009553c8SW1' or multiple channels separated with a comma '10009553c8SW1,10009553c9SW2'. Only channels from lights and switches can be hidden.", "default": "" }, "disableHTTPRefresh": { From 6b608ae5ccb7acc2211135136aef2687f9673e4d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 21:06:16 +0100 Subject: [PATCH 0296/3183] . --- lib/eWeLink.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 2e4d277d..a2adc494 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -340,7 +340,7 @@ class eWeLink { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceZBDev(this, accessory) } else if (cns.devicesCamera.includes(device.extra.uiid)) { - this.log.warn(' → [%s] please see the homebridge-ewelink wiki for details to enable the camera', device.name) + this.log.warn(' → [%s] please see the homebridge-ewelink wiki for details to enable the camera.', device.name) return } else if (!cns.devicesZBBridge.includes(device.extra.uiid)) { this.log.warn(' → [%s] has not been added as it is not supported. Please make a GitHub issue request.', device.name) From cb9b3a4db7f41434f5c7fbece358e7d73c6f3d6d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 1 Oct 2020 22:34:38 +0100 Subject: [PATCH 0297/3183] keywords --- package.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f11902c2..7abb45cf 100644 --- a/package.json +++ b/package.json @@ -27,9 +27,13 @@ "keywords": [ "homebridge", "homebridge-plugin", - "homekit", "sonoff", - "ewelink" + "homekit", + "siri", + "ewelink", + "homebridge-ewelink", + "hoobs", + "eachen" ], "engines": { "node": ">=10.0.0", From 60097185629f3d8cbd537f43c8d324f086e6fd80 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 2 Oct 2020 11:48:56 +0100 Subject: [PATCH 0298/3183] log ws message --- lib/eWeLinkWS.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 3c305920..5d585aa8 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -196,15 +196,15 @@ module.exports = class eWeLinkWS { } if (this.wsp && this.wsIsOpen) { try { - const device = await this.wsp.sendRequest(jsonToSend, { - requestId: sequence - }) if (this.debugReqRes) { const msg = JSON.stringify(json, null, 2).replace(json.apikey, '**hidden**').replace(json.apiKey, '**hidden**').replace(json.deviceid, '**hidden**') this.log.warn('WS message sent. This text is yellow for clarity.\n%s', msg) } else if (this.debug) { this.log('WS message sent.') } + const device = await this.wsp.sendRequest(jsonToSend, { + requestId: sequence + }) device.error = Object.prototype.hasOwnProperty.call(device, 'error') ? device.error : 504 switch (device.error) { case 0: From d830462b5756c6a58c4d5c113b707cec72bf1137 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 2 Oct 2020 11:49:08 +0100 Subject: [PATCH 0299/3183] button fixes --- lib/device/rf-bridge.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index 59f267ce..b2124215 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -50,10 +50,10 @@ module.exports = class deviceRFBridge { rfChl: parseInt(rfChl) } const rfService = accessory.getService(service) - await this.platform.sendDeviceUpdate(accessory, params) rfService.updateCharacteristic(Characteristic.On, true) - await utils.sleep(3000) + await utils.sleep(1000) rfService.updateCharacteristic(Characteristic.On, false) + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { this.platform.deviceUpdateError(accessory, err, true) } @@ -68,6 +68,7 @@ module.exports = class deviceRFBridge { this.platform.devicesInHB.forEach(acc => { if ( acc.context.eweDeviceId === accessory.context.eweDeviceId && + Object.prototype.hasOwnProperty.call(acc.context, 'buttons') && Object.prototype.hasOwnProperty.call(acc.context.buttons, params.rfChl.toString()) ) { oAccessory = acc @@ -107,7 +108,7 @@ module.exports = class deviceRFBridge { if (diff < (this.platform.config.sensorTimeDifference || 120)) { switch (oAccessory.context.subType) { case 'button': - break + return case 'water': serv = Service.LeakSensor char = Characteristic.LeakDetected From a6c1f448b889366620432c2c2c03930aa023296b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 2 Oct 2020 11:52:21 +0100 Subject: [PATCH 0300/3183] 3.2.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 832f0d92..bed97bc7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.2.0", + "version": "3.2.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 7abb45cf..1ffe3219 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.2.0", + "version": "3.2.1", "author": "bwp91", "contributors": [ "gbro115", From 70cf1b69b40ff00db6126563f77f6fbb760c8aa2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 2 Oct 2020 14:41:55 +0100 Subject: [PATCH 0301/3183] remove old switches on change to custom --- lib/eWeLink.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index a2adc494..b602d7a4 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -127,6 +127,16 @@ class eWeLink { initialiseDevice (device) { let accessory try { + if (this.cusG.has(device.deviceid + 'SWX')) { + const all = ['X', '0', '1', '2', '3', '4'] + all.forEach(v => { + if (this.devicesInHB.has(device.deviceid + 'SW' + v)) { + if (this.devicesInHB.get(device.deviceid + 'SW' + v).getService(Service.Switch)) { + this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + v)) + } + } + }) + } if (cns.devicesCurtain.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') From 8063075bf73f14c297c648d687cbb6827a14a9e1 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 2 Oct 2020 16:44:17 +0100 Subject: [PATCH 0302/3183] catch no displayName --- lib/eWeLink.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index b602d7a4..b862c315 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -382,7 +382,7 @@ class eWeLink { this.devicesInHB.set(accessory.context.hbDeviceId, accessory) this.log(' → [%s] initialised %s.', device.name, str) } catch (err) { - this.log.warn('[%s] could not be initialised as %s.', accessory.displayName, this.debug ? err : err.message) + this.log.warn('[%s] could not be initialised as %s.', accessory.displayName || device.name, this.debug ? err : err.message) } } From bfc574ec967fa31593196090efb3ac3c672635f9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 2 Oct 2020 16:44:30 +0100 Subject: [PATCH 0303/3183] remove outlet switch if exists --- lib/constants.js | 2 +- lib/device/outlet.js | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/constants.js b/lib/constants.js index b23eb05b..27f4f0ce 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -10,7 +10,7 @@ module.exports = { devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], devicesSingleSwitchLight: ['T1 1C', 'L1', 'B1', 'B1_R2', 'TX1C', 'D1', 'D1R1', 'KING-M4', 'Slampher', 'GTTA59'], devicesMultiSwitchLight: ['T1 2C', 'T1 3C', 'TX2C', 'TX3C'], - devicesSingleSwitchOutlet: ['Sonoff Pow', 'S26'], + devicesSingleSwitchOutlet: ['Sonoff Pow', 'S20', 'S26', 'S55'], devicesBrightable: [36, 44], devicesColourable: [22, 59], devicesCurtain: [11], diff --git a/lib/device/outlet.js b/lib/device/outlet.js index 9941c0ee..29cd1938 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -1,5 +1,6 @@ 'use strict' let Characteristic, EveHistoryService, EveService, Service +const cns = require('./../constants') const corrInterval = require('correcting-interval') const fakegato = require('fakegato-history') const hbLib = require('homebridge-lib') @@ -10,11 +11,14 @@ module.exports = class deviceOutlet { Characteristic = platform.api.hap.Characteristic EveService = new hbLib.EveHomeKitTypes(platform.api) EveHistoryService = fakegato(platform.api) + if (accessory.getService(Service.Switch)) { + accessory.removeService(Service.Switch) + } let outletService if (!(outletService = accessory.getService(Service.Outlet))) { accessory.addService(Service.Outlet) outletService = accessory.getService(Service.Outlet) - if (accessory.context.eweModel !== 'S26' && !this.platform.config.disableEveLogging) { + if (!cns.devicesSingleSwitchOutlet.includes(accessory.context.eweModel) && !this.platform.config.disableEveLogging) { outletService.addCharacteristic(EveService.Characteristics.Voltage) outletService.addCharacteristic(EveService.Characteristics.CurrentConsumption) outletService.addCharacteristic(EveService.Characteristics.ElectricCurrent) @@ -34,7 +38,7 @@ module.exports = class deviceOutlet { outletService .getCharacteristic(Characteristic.On) .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) - if (accessory.context.eweModel !== 'S26' && !this.platform.config.disableEveLogging) { + if (!cns.devicesSingleSwitchOutlet.includes(accessory.context.eweModel) && !this.platform.config.disableEveLogging) { accessory.log = this.platform.log accessory.eveLogger = new EveHistoryService('energy', accessory, { storage: 'fs', @@ -123,13 +127,13 @@ module.exports = class deviceOutlet { const outletService = accessory.getService(Service.Outlet) if (Object.prototype.hasOwnProperty.call(params, 'switch')) { outletService.updateCharacteristic(Characteristic.On, params.switch === 'on') - if (accessory.context.eweModel === 'S26' || this.platform.config.disableEveLogging) { + if (cns.devicesSingleSwitchOutlet.includes(accessory.context.eweModel) || this.platform.config.disableEveLogging) { outletService.updateCharacteristic(Characteristic.OutletInUse, params.switch === 'on') } } if (Object.prototype.hasOwnProperty.call(params, 'power')) { outletService.updateCharacteristic(EveService.Characteristics.CurrentConsumption, parseFloat(params.power)) - if (accessory.context.eweModel !== 'S26' && !this.platform.config.disableEveLogging) { + if (!cns.devicesSingleSwitchOutlet.includes(accessory.context.eweModel) && !this.platform.config.disableEveLogging) { outletService.updateCharacteristic( Characteristic.OutletInUse, parseFloat(params.power) > (this.platform.config.inUsePowerThreshold || 0) From 125713f62b8cded77b023a1fbf50b6f467dbb13a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 2 Oct 2020 16:46:33 +0100 Subject: [PATCH 0304/3183] 3.2.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index bed97bc7..64f8b6ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.2.1", + "version": "3.2.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1ffe3219..434c0146 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.2.1", + "version": "3.2.2", "author": "bwp91", "contributors": [ "gbro115", From 997d2b4c2555ace7d218f522565619f2a2d7778d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 2 Oct 2020 17:16:31 +0100 Subject: [PATCH 0305/3183] Update eWeLink.js --- lib/eWeLink.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index b862c315..c7e8ee8c 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -382,7 +382,10 @@ class eWeLink { this.devicesInHB.set(accessory.context.hbDeviceId, accessory) this.log(' → [%s] initialised %s.', device.name, str) } catch (err) { - this.log.warn('[%s] could not be initialised as %s.', accessory.displayName || device.name, this.debug ? err : err.message) + const deviceName = accessory && Object.prototype.hasOwnProperty.call(accessory, 'displayName') + ? accessory.displayName + : device.name + this.log.warn('[%s] could not be initialised as %s.', deviceName, this.debug ? err : err.message) } } From ac2a6127de415e30125d6c0214d8c74ee54b9949 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 2 Oct 2020 17:16:55 +0100 Subject: [PATCH 0306/3183] 3.2.3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 64f8b6ec..a1f6ebb6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.2.2", + "version": "3.2.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 434c0146..41507cb7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.2.2", + "version": "3.2.3", "author": "bwp91", "contributors": [ "gbro115", From 38288f2a787e36563bfc20d795e4bfcd1eccaa97 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 3 Oct 2020 14:21:22 +0100 Subject: [PATCH 0307/3183] remove outlet switch fix --- lib/device/outlet.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/outlet.js b/lib/device/outlet.js index 29cd1938..bb86951d 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -12,7 +12,7 @@ module.exports = class deviceOutlet { EveService = new hbLib.EveHomeKitTypes(platform.api) EveHistoryService = fakegato(platform.api) if (accessory.getService(Service.Switch)) { - accessory.removeService(Service.Switch) + accessory.removeService(accessory.getService(Service.Switch)) } let outletService if (!(outletService = accessory.getService(Service.Outlet))) { From 3dd376b7d9b9f4d374db0fe730e7bf5ca4491de9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 3 Oct 2020 14:22:26 +0100 Subject: [PATCH 0308/3183] code format --- lib/device/garage-eachen.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 91bd7e81..3d08ba86 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -62,9 +62,9 @@ module.exports = class deviceGarageEachen { if (garageConfig.type !== 'garage_eachen') { throw new Error('improper configuration') } - const gdService = accessory.getService(Service.GarageDoorOpener) - gdService.updateCharacteristic(Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) - gdService.updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) + accessory.getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) + .updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) } catch (err) { this.platform.deviceUpdateError(accessory, err, false) } From e97e178c350454a49c0f0062624d372342435657 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 3 Oct 2020 14:33:43 +0100 Subject: [PATCH 0309/3183] remove zb bridge device check --- lib/eWeLink.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index c7e8ee8c..c054ee19 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -344,6 +344,10 @@ class eWeLink { }) accessory.context.channelCount = rfChlCounter this.devicesInHB.set(accessory.context.hbDeviceId, accessory) + } else if (cns.devicesZBBridge.includes(device.extra.uiid)) { + if (this.devicesInHB.has(device.deviceid + 'SW0')) { + this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) + } } else if (cns.devicesZB.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') @@ -352,7 +356,7 @@ class eWeLink { } else if (cns.devicesCamera.includes(device.extra.uiid)) { this.log.warn(' → [%s] please see the homebridge-ewelink wiki for details to enable the camera.', device.name) return - } else if (!cns.devicesZBBridge.includes(device.extra.uiid)) { + } else { this.log.warn(' → [%s] has not been added as it is not supported. Please make a GitHub issue request.', device.name) return } From 3a860f7859498d6860cf63c357b61778d1fbe68e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 3 Oct 2020 14:44:26 +0100 Subject: [PATCH 0310/3183] 3.2.4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a1f6ebb6..51a19856 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.2.3", + "version": "3.2.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 41507cb7..4a18f3e2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.2.3", + "version": "3.2.4", "author": "bwp91", "contributors": [ "gbro115", From a88b9316997c2a122c89d629f88ceacad9e2de2d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 3 Oct 2020 19:28:23 +0100 Subject: [PATCH 0311/3183] lan-> ws improvements --- lib/eWeLink.js | 9 ++--- lib/eWeLinkLAN.js | 95 +++++++++++++++++++++++++---------------------- 2 files changed, 54 insertions(+), 50 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index c054ee19..57d8470c 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -446,13 +446,12 @@ class eWeLink { deviceid: accessory.context.eweDeviceId, params } - try { - await utils.sleep(Math.random() * 100 + 200) - await this.lanClient.sendUpdate(payload) - } catch (err) { + await utils.sleep(Math.random() * 100 + 200) + const res = await this.lanClient.sendUpdate(payload) + if (res !== 'ok') { if (accessory.context.reachableWAN) { if (this.debug) { - this.log.warn('[%s] Reverting to web socket as LAN mode warning - %s.', accessory.displayName, this.debug ? err : err.message) + this.log('[%s] Reverting to web socket as %s.', accessory.displayName, res) } await this.wsClient.sendUpdate(payload) } else { diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 67bfbae3..df0655c6 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -107,54 +107,59 @@ module.exports = class eWeLinkLAN { } async sendUpdate (json) { - if (!this.deviceMap.get(json.deviceid).online) { - throw new Error("device isn't reachable via LAN mode") - } - let apiKey - let suffix - const params = {} - if (Object.prototype.hasOwnProperty.call(json.params, 'switches')) { - params.switches = json.params.switches - suffix = 'switches' - } else if (Object.prototype.hasOwnProperty.call(json.params, 'switch')) { - params.switch = json.params.switch - suffix = 'switch' - } else { - throw new Error("device isn't reachable via LAN mode") - } - if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { - const key = crypto.createHash('md5').update(Buffer.from(apiKey, 'utf8')).digest() - const iv = crypto.randomBytes(16) - const enc = crypto.createCipheriv('aes-128-cbc', key, iv) - const data = { - data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString('base64'), - deviceid: json.deviceid, - encrypt: true, - iv: iv.toString('base64'), - selfApikey: '123', - sequence: Date.now().toString() + try { + if (!this.deviceMap.get(json.deviceid).online) { + throw new Error("device isn't reachable via LAN mode") } - if (this.debugReqRes) { - const msg = JSON.stringify(json, null, 2) - .replace(json.apikey, '**hidden**') - .replace(json.apikey, '**hidden**') - .replace(json.deviceid, '**hidden**') - this.log.warn('LAN message sent. This text is yellow for clarity.\n%s', msg) - } else if (this.debug) { - this.log('LAN message sent.') + let apiKey + let suffix + const params = {} + if (Object.prototype.hasOwnProperty.call(json.params, 'switches')) { + params.switches = json.params.switches + suffix = 'switches' + } else if (Object.prototype.hasOwnProperty.call(json.params, 'switch')) { + params.switch = json.params.switch + suffix = 'switch' + } else { + throw new Error("device isn't reachable via LAN mode") } - const res = await axios({ - method: 'post', - url: 'http://' + this.deviceMap.get(json.deviceid).ip + ':8081/zeroconf/' + suffix, - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json' - }, - data - }) - if (!Object.prototype.hasOwnProperty.call(res.data, 'error') || res.data.error !== 0) { - throw new Error(res.data) + if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { + const key = crypto.createHash('md5').update(Buffer.from(apiKey, 'utf8')).digest() + const iv = crypto.randomBytes(16) + const enc = crypto.createCipheriv('aes-128-cbc', key, iv) + const data = { + data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString('base64'), + deviceid: json.deviceid, + encrypt: true, + iv: iv.toString('base64'), + selfApikey: '123', + sequence: Date.now().toString() + } + if (this.debugReqRes) { + const msg = JSON.stringify(json, null, 2) + .replace(json.apikey, '**hidden**') + .replace(json.apikey, '**hidden**') + .replace(json.deviceid, '**hidden**') + this.log.warn('LAN message sent. This text is yellow for clarity.\n%s', msg) + } else if (this.debug) { + this.log('LAN message sent.') + } + const res = await axios({ + method: 'post', + url: 'http://' + this.deviceMap.get(json.deviceid).ip + ':8081/zeroconf/' + suffix, + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + }, + data + }) + if (!Object.prototype.hasOwnProperty.call(res.data, 'error') || res.data.error !== 0) { + throw new Error(res.data) + } + return 'ok' } + } catch (err) { + return err.message } } From 7ffabbbc26b1c5db4d2fdeb826c8aa61613b59da Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 3 Oct 2020 19:50:37 +0100 Subject: [PATCH 0312/3183] hide custom SW0 --- config.schema.json | 10 +++++----- lib/eWeLink.js | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/config.schema.json b/config.schema.json index d28e2210..7e27b86d 100644 --- a/config.schema.json +++ b/config.schema.json @@ -43,19 +43,19 @@ "hideDevFromHB": { "type": "string", "title": "Hide Devices", - "description": "A list of eWeLink devices to hide from Homebridge. For example '10009553c8' or multiple devices separated with a comma '10009553c8,10009553c9'.", + "description": "A list of eWeLink devices to hide from Homebridge. For example '10009553c8' or multiple separated with a comma '10009553c8,10009553c9'.", "default": "" }, "hideMasters": { - "type": "boolean", - "title": "Hide Master Switches", - "description": "If enabled, the 'SW0' accessory of multi-channel light and switch devices will be hidden from Homebridge.", + "type": "string", + "title": "Hide Master Lights/Switches", + "description": "A list of SW0 lights/switches to hide from Homebridge. For example '10009553c8' or multiple separated with a comma '10009553c8,10009553c9'.", "default": false }, "hideFromHB": { "type": "string", "title": "Hide Device Channels", - "description": "A list of SW1, SW2, SW3 and SW4 to hide from Homebridge. For example '10009553c8SW1' or multiple channels separated with a comma '10009553c8SW1,10009553c9SW2'. Only channels from lights and switches can be hidden.", + "description": "A list of SW1, SW2, SW3 and SW4 channels to hide from Homebridge. For example '10009553c8SW1' or multiple separated with a comma '10009553c8SW1,10009553c9SW2'.", "default": "" }, "disableHTTPRefresh": { diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 57d8470c..8ef86134 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -215,7 +215,7 @@ class eWeLink { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceLight(this, accessory) } else if (cns.devicesMultiSwitch.includes(device.extra.uiid) && cns.devicesMultiSwitchLight.includes(device.productModel)) { - if (this.config.hideMasters) { + if ((this.config.hideMasters || '').includes(device.deviceid)) { if (this.devicesInHB.has(device.deviceid + 'SW0')) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) } @@ -251,7 +251,7 @@ class eWeLink { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceSwitch(this, accessory) } else if (cns.devicesMultiSwitch.includes(device.extra.uiid)) { - if (this.config.hideMasters) { + if ((this.config.hideMasters || '').includes(device.deviceid)) { if (this.devicesInHB.has(device.deviceid + 'SW0')) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) } From 2f3fe0cc2ef239bb561a081e41efa7d67c19cea5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 3 Oct 2020 20:38:02 +0100 Subject: [PATCH 0313/3183] 3.3.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 51a19856..249642de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.2.4", + "version": "3.3.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 4a18f3e2..733f7ef9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.2.4", + "version": "3.3.0", "author": "bwp91", "contributors": [ "gbro115", From 66d0c93eb8b00439ef3a29fd109aa3ad6c5fe07b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 3 Oct 2020 21:57:34 +0100 Subject: [PATCH 0314/3183] notifications fix --- lib/device/garage-eachen.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 3d08ba86..85953acb 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -41,7 +41,7 @@ module.exports = class deviceGarageEachen { .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2) params.switch = value === 0 ? 'on' : 'off' await this.platform.sendDeviceUpdate(accessory, params) - await utils.sleep(garageConfig.operationTime * 100) + await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos) accessory.context.inUse = false } catch (err) { @@ -50,7 +50,7 @@ module.exports = class deviceGarageEachen { } } - externalUpdate (accessory, params) { + async externalUpdate (accessory, params) { try { if (!Object.prototype.hasOwnProperty.call(params, 'switch') || accessory.context.inUse) { return @@ -62,9 +62,10 @@ module.exports = class deviceGarageEachen { if (garageConfig.type !== 'garage_eachen') { throw new Error('improper configuration') } - accessory.getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) - .updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) + const gdService = accessory.getService(Service.GarageDoorOpener) + gdService.updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) + await utils.sleep(1000) + gdService.updateCharacteristic(Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) } catch (err) { this.platform.deviceUpdateError(accessory, err, false) } From c25269676751e26dd146d613b791992675e4d137 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 3 Oct 2020 21:58:32 +0100 Subject: [PATCH 0315/3183] 3.3.1-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 249642de..e421ac5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.0", + "version": "3.3.1-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 733f7ef9..1d63b615 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.0", + "version": "3.3.1-0", "author": "bwp91", "contributors": [ "gbro115", From a28c15d69dfa491bbf613aae98ffff6b3423fda2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 3 Oct 2020 22:30:10 +0100 Subject: [PATCH 0316/3183] async externalUpdate --- lib/device/blind.js | 2 +- lib/device/curtain.js | 2 +- lib/device/fan.js | 2 +- lib/device/garage.js | 21 ++++++++++----------- lib/device/light.js | 2 +- lib/device/lock.js | 15 +++++++-------- lib/device/outlet.js | 2 +- lib/device/rf-bridge.js | 2 +- lib/device/scm.js | 2 +- lib/device/sensor.js | 14 +++++++------- lib/device/switch.js | 2 +- lib/device/thermostat.js | 2 +- lib/device/usb.js | 2 +- lib/device/valve.js | 2 +- lib/device/zb-dev.js | 2 +- 15 files changed, 36 insertions(+), 38 deletions(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index 242eeaaf..3259d21a 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -80,7 +80,7 @@ module.exports = class deviceBlind { } } - externalUpdate (accessory, params) { + async externalUpdate (accessory, params) { return true } } diff --git a/lib/device/curtain.js b/lib/device/curtain.js index d96de66a..2f5f7c6c 100644 --- a/lib/device/curtain.js +++ b/lib/device/curtain.js @@ -46,7 +46,7 @@ module.exports = class deviceCurtain { } } - externalUpdate (accessory, params) { + async externalUpdate (accessory, params) { try { const cService = accessory.getService(Service.WindowCovering) if (!Object.prototype.hasOwnProperty.call(params, 'switch') && !Object.prototype.hasOwnProperty.call(params, 'setclose')) { diff --git a/lib/device/fan.js b/lib/device/fan.js index 2eac5d9b..045e0b64 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -63,7 +63,7 @@ module.exports = class deviceFan { } } - externalUpdate (accessory, params) { + async externalUpdate (accessory, params) { try { let light let status diff --git a/lib/device/garage.js b/lib/device/garage.js index 599316e7..5341153c 100644 --- a/lib/device/garage.js +++ b/lib/device/garage.js @@ -73,7 +73,7 @@ module.exports = class deviceGarage { break } await this.platform.sendDeviceUpdate(accessory, params) - await utils.sleep(garageConfig.operationTime * 100) + await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) if (!sAccessory) { gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos) accessory.context.cacheCurrentDoorState = newPos @@ -84,7 +84,7 @@ module.exports = class deviceGarage { } } - externalUpdate (accessory, params) { + async externalUpdate (accessory, params) { try { if (!Object.prototype.hasOwnProperty.call(params, 'switch') && !Object.prototype.hasOwnProperty.call(params, 'switches')) { return @@ -118,20 +118,19 @@ module.exports = class deviceGarage { break } accessory.context.inUse = true - if (!garageConfig.sensorId) { + if (garageConfig.sensorId) { + await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) + } else { gcService - .updateCharacteristic(Characteristic.CurrentDoorState, newPos) .updateCharacteristic(Characteristic.TargetDoorState, newPos - 2) + .updateCharacteristic(Characteristic.CurrentDoorState, newPos) accessory.context.cacheCurrentDoorState = newPos accessory.context.cacheTargetDoorState = newPos - 2 - setTimeout(() => { - gcService.updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2) - accessory.context.cacheCurrentDoorState = newPos - 2 - }, parseInt(garageConfig.operationTime) * 100) + await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) + gcService.updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2) + accessory.context.cacheCurrentDoorState = newPos - 2 } - setTimeout(() => { - accessory.context.inUse = false - }, parseInt(garageConfig.operationTime) * 100) + accessory.context.inUse = false } catch (err) { accessory.context.inUse = false this.platform.deviceUpdateError(accessory, err, false) diff --git a/lib/device/light.js b/lib/device/light.js index 7d67c7d0..066b0daf 100644 --- a/lib/device/light.js +++ b/lib/device/light.js @@ -206,7 +206,7 @@ module.exports = class deviceLight { } } - externalUpdate (accessory, params) { + async externalUpdate (accessory, params) { try { if ( cns.devicesSingleSwitch.includes(accessory.context.eweUIID) && diff --git a/lib/device/lock.js b/lib/device/lock.js index b335b281..6996f00b 100644 --- a/lib/device/lock.js +++ b/lib/device/lock.js @@ -31,7 +31,7 @@ module.exports = class deviceLock { lmService .updateCharacteristic(Characteristic.LockTargetState, 0) .updateCharacteristic(Characteristic.LockCurrentState, 0) - await utils.sleep(lockConfig.operationTime * 100) + await utils.sleep(Math.max(lockConfig.operationTime * 100, 1000)) lmService .updateCharacteristic(Characteristic.LockTargetState, 1) .updateCharacteristic(Characteristic.LockCurrentState, 1) @@ -41,7 +41,7 @@ module.exports = class deviceLock { } } - externalUpdate (accessory, params) { + async externalUpdate (accessory, params) { try { if (!Object.prototype.hasOwnProperty.call(params, 'switch')) return let lockConfig @@ -59,12 +59,11 @@ module.exports = class deviceLock { lmService .updateCharacteristic(Characteristic.LockCurrentState, 0) .updateCharacteristic(Characteristic.LockTargetState, 0) - setTimeout(() => { - lmService - .updateCharacteristic(Characteristic.LockCurrentState, 1) - .updateCharacteristic(Characteristic.LockTargetState, 1) - accessory.context.inUse = false - }, parseInt(lockConfig.operationTime) * 100) + await utils.sleep(Math.max(lockConfig.operationTime * 100, 1000)) + lmService + .updateCharacteristic(Characteristic.LockCurrentState, 1) + .updateCharacteristic(Characteristic.LockTargetState, 1) + accessory.context.inUse = false } catch (err) { accessory.context.inUse = false this.platform.deviceUpdateError(accessory, err, false) diff --git a/lib/device/outlet.js b/lib/device/outlet.js index bb86951d..fe05aebe 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -122,7 +122,7 @@ module.exports = class deviceOutlet { } } - externalUpdate (accessory, params) { + async externalUpdate (accessory, params) { try { const outletService = accessory.getService(Service.Outlet) if (Object.prototype.hasOwnProperty.call(params, 'switch')) { diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index b2124215..0f60a023 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -59,7 +59,7 @@ module.exports = class deviceRFBridge { } } - externalUpdate (accessory, params) { + async externalUpdate (accessory, params) { try { if (!Object.prototype.hasOwnProperty.call(params, 'updateSource')) return const timeNow = new Date() diff --git a/lib/device/scm.js b/lib/device/scm.js index 577c2e69..8c62b37f 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -27,7 +27,7 @@ module.exports = class deviceSCM { } } - externalUpdate (accessory, params) { + async externalUpdate (accessory, params) { try { if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switches[0].switch === 'on') diff --git a/lib/device/sensor.js b/lib/device/sensor.js index 5c3741b4..83d4cd5e 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -1,5 +1,6 @@ 'use strict' let Characteristic, Service +const utils = require('./../utils') module.exports = class deviceSensor { constructor (platform, accessory) { this.platform = platform @@ -9,7 +10,7 @@ module.exports = class deviceSensor { accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService) } - externalUpdate (accessory, params) { + async externalUpdate (accessory, params) { try { if (Object.prototype.hasOwnProperty.call(params, 'battery')) { const batteryService = @@ -37,12 +38,11 @@ module.exports = class deviceSensor { .updateCharacteristic(Characteristic.CurrentDoorState, 1) break case 1: - setTimeout(() => { - oAccessory - .getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.TargetDoorState, 0) - .updateCharacteristic(Characteristic.CurrentDoorState, 0) - }, group.operationTime * 100) + await utils.sleep(Math.max(group.operationTime * 100, 1000)) + oAccessory + .getService(Service.GarageDoorOpener) + .updateCharacteristic(Characteristic.TargetDoorState, 0) + .updateCharacteristic(Characteristic.CurrentDoorState, 0) break } } diff --git a/lib/device/switch.js b/lib/device/switch.js index 19c7a331..97ee0293 100644 --- a/lib/device/switch.js +++ b/lib/device/switch.js @@ -86,7 +86,7 @@ module.exports = class deviceSwitch { } } - externalUpdate (accessory, params) { + async externalUpdate (accessory, params) { try { if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID)) { if (!Object.prototype.hasOwnProperty.call(params, 'switch')) return diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index ed36e577..5fd997ac 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -54,7 +54,7 @@ module.exports = class deviceThermostat { } } - externalUpdate (accessory, params) { + async externalUpdate (accessory, params) { try { if ( !this.platform.config.hideTHSwitch && diff --git a/lib/device/usb.js b/lib/device/usb.js index 13a2c87b..6c230010 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -27,7 +27,7 @@ module.exports = class deviceUSB { } } - externalUpdate (accessory, params) { + async externalUpdate (accessory, params) { try { if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switches[0].switch === 'on') diff --git a/lib/device/valve.js b/lib/device/valve.js index 9aab7584..67bf6d30 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -85,7 +85,7 @@ module.exports = class deviceValve { } } - externalUpdate (accessory, params) { + async externalUpdate (accessory, params) { try { if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return let valveConfig diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index 21c309a2..478544b1 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -51,7 +51,7 @@ module.exports = class deviceZBDev { } } - externalUpdate (accessory, params) { + async externalUpdate (accessory, params) { try { //* ** credit @tasict ***\\ if (Object.prototype.hasOwnProperty.call(params, 'battery')) { From f2355e3bfa438c3991d5046789afeae2c4c964e4 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 11:05:47 +0100 Subject: [PATCH 0317/3183] double notifications fix --- lib/device/garage-eachen.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 85953acb..4a4af8be 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -62,11 +62,14 @@ module.exports = class deviceGarageEachen { if (garageConfig.type !== 'garage_eachen') { throw new Error('improper configuration') } + accessory.context.inUse = true const gdService = accessory.getService(Service.GarageDoorOpener) gdService.updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) - await utils.sleep(1000) + await utils.sleep(1500) gdService.updateCharacteristic(Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) + accessory.context.inUse = false } catch (err) { + accessory.context.inUse = false this.platform.deviceUpdateError(accessory, err, false) } } From 5275e07be5df1a7a1aa9f9570fdc58b470aa4275 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 11:06:34 +0100 Subject: [PATCH 0318/3183] 3.3.1-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index e421ac5d..65ca6ac4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.1-0", + "version": "3.3.1-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1d63b615..cc2fd61d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.1-0", + "version": "3.3.1-1", "author": "bwp91", "contributors": [ "gbro115", From 9fa831eaf8df07ab83df21d101c4f72fc525dbde Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 11:14:26 +0100 Subject: [PATCH 0319/3183] Update garage-eachen.js --- lib/device/garage-eachen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 4a4af8be..584319c2 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -65,7 +65,7 @@ module.exports = class deviceGarageEachen { accessory.context.inUse = true const gdService = accessory.getService(Service.GarageDoorOpener) gdService.updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) - await utils.sleep(1500) + await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) gdService.updateCharacteristic(Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) accessory.context.inUse = false } catch (err) { From 32ded0523a2181749047528031c1106adc2259b8 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 11:15:28 +0100 Subject: [PATCH 0320/3183] 3.3.1-2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 65ca6ac4..9593ffe4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.1-1", + "version": "3.3.1-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index cc2fd61d..0bf467e4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.1-1", + "version": "3.3.1-2", "author": "bwp91", "contributors": [ "gbro115", From a819f2c51d28eb3b036ec60b573f475c1d11b40a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 11:23:01 +0100 Subject: [PATCH 0321/3183] Update sensor.js --- lib/device/sensor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/sensor.js b/lib/device/sensor.js index 83d4cd5e..dac9afc2 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -27,7 +27,7 @@ module.exports = class deviceSensor { let oAccessory = false const contactService = accessory.getService(Service.ContactSensor) contactService.updateCharacteristic(Characteristic.ContactSensorState, newState) - this.platform.cusG.forEach(group => { + this.platform.cusG.forEach(async group => { if (group.sensorId === accessory.context.eweDeviceId && group.type === 'garage') { if ((oAccessory = this.platform.devicesInHB.get(group.deviceId + 'SWX'))) { switch (newState) { From a2bb9ccf0cb2e663cf989b753f8a6fb55a399d16 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 11:23:31 +0100 Subject: [PATCH 0322/3183] 3.3.1-3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9593ffe4..38a4ffea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.1-2", + "version": "3.3.1-3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 0bf467e4..7334fd6b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.1-2", + "version": "3.3.1-3", "author": "bwp91", "contributors": [ "gbro115", From 737f54d5591b29ea36959e0442bb23d178f7e3bc Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 13:36:35 +0100 Subject: [PATCH 0323/3183] settimeout to await --- lib/device/rf-bridge.js | 7 +++---- lib/eWeLinkWS.js | 10 ++++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index 0f60a023..a791b1ef 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -90,7 +90,7 @@ module.exports = class deviceRFBridge { //* ** RF Sensor ***\\ Object.keys(params) .filter(name => /rfTrig/.test(name)) - .forEach(chan => { + .forEach(async chan => { this.platform.devicesInHB.forEach(acc => { if ( acc.context.eweDeviceId === accessory.context.eweDeviceId && @@ -140,9 +140,8 @@ module.exports = class deviceRFBridge { break } oAccessory.getService(serv).updateCharacteristic(char, 1) - setTimeout(() => { - oAccessory.getService(serv).updateCharacteristic(char, 0) - }, (this.platform.config.sensorTimeLength || 2) * 1000) + await utils.sleep((this.platform.config.sensorTimeLength || 2) * 1000) + oAccessory.getService(serv).updateCharacteristic(char, 0) } } }) diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 5d585aa8..91633aef 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -155,13 +155,14 @@ module.exports = class eWeLinkWS { } } }) - this.wsp.onClose.addListener(e => { + this.wsp.onClose.addListener(async e => { this.wsIsOpen = false if (e !== 1005) { this.log.warn('Web socket closed [%s].', e) if (e !== 1000) { this.log('Web socket will try to reconnect in five seconds.') - setTimeout(() => this.login(), 5000) + await utils.sleep(5000) + this.login() } else { this.log('Please try restarting Homebridge so that this plugin can work again.') } @@ -172,12 +173,13 @@ module.exports = class eWeLinkWS { } this.wsp.removeAllListeners() }) - this.wsp.onError.addListener(e => { + this.wsp.onError.addListener(async e => { this.log.warn('Web socket error - [%s].', e) if (e.code === 'ECONNREFUSED') { this.log.warn('Web socket will try to reconnect in five seconds then try the command again.') this.wsp.removeAllListeners() - setTimeout(() => this.login(), 5000) + await utils.sleep(5000) + this.login() } else { this.log.warn('If this was unexpected then please try restarting Homebridge.') } From b2932c17cc2e1d69afa0a79dced046b7a1e95281 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 13:54:21 +0100 Subject: [PATCH 0324/3183] Create i --- docs/i | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/i diff --git a/docs/i b/docs/i new file mode 100644 index 00000000..e69de29b From bac625c0c50dfddaefe47a5b3cbc223d64856526 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 13:54:53 +0100 Subject: [PATCH 0325/3183] Delete i --- docs/i | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/i diff --git a/docs/i b/docs/i deleted file mode 100644 index e69de29b..00000000 From 38eb388ad8024db3151415f92116762b9fa2f36a Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 13:56:27 +0100 Subject: [PATCH 0326/3183] Create .gitkeep --- docs/.gitkeep | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/.gitkeep diff --git a/docs/.gitkeep b/docs/.gitkeep new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/docs/.gitkeep @@ -0,0 +1 @@ + From 373e69d27da7ddda4bc3c1212e8a79a954112785 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 13:56:46 +0100 Subject: [PATCH 0327/3183] Set theme jekyll-theme-cayman --- docs/_config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/_config.yml diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 00000000..c4192631 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-cayman \ No newline at end of file From f6dccd6129c5e3faeff8f2d430f9ea2db195b1c2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 14:04:30 +0100 Subject: [PATCH 0328/3183] Create index.md --- docs/index.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 docs/index.md diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..4f0e0eb3 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,40 @@ +

+ Homebridge Verified +

+ + +# homebridge-ewelink + + Homebridge plugin to control eWeLink devices with original firmware. + + [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) + [![npm](https://img.shields.io/npm/v/homebridge-ewelink/latest?label=release)](https://www.npmjs.com/package/homebridge-ewelink) + [![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://www.npmjs.com/package/homebridge-ewelink) + [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) + [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) + [![Discord](https://img.shields.io/discord/432663330281226270?color=728ED5&logo=discord&label=discord)](https://discord.com/channels/432663330281226270/742733745743855627) + [![Contribute](https://img.shields.io/badge/contribute-a%20drink-yellow)](https://ko-fi.com/bwp91) + + + +### Setup +* [Installation (Homebridge)](https://github.com/bwp91/homebridge-ewelink/wiki/Installation-(Homebridge)) +* [Installation (HOOBS)](https://github.com/bwp91/homebridge-ewelink/wiki/Installation-(HOOBS)) +* [Configuration](https://github.com/bwp91/homebridge-ewelink/wiki/Configuration) +* [Beta Version](https://github.com/bwp91/homebridge-ewelink/wiki/Beta-Version) +### Features +* [Supported Devices](https://github.com/bwp91/homebridge-ewelink/wiki/Supported-Devices) +* [Accessory Simulations](https://github.com/bwp91/homebridge-ewelink/wiki/Accessory-Simulations) +* [Connection Methods](https://github.com/bwp91/homebridge-ewelink/wiki/Connection-Methods) +### How-to Guides +* [How to set up RF Bridge sensors](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-RF-Bridge-sensors) +* [How to set up Sonoff Camera (GK-200MP2-B)](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-Sonoff-Camera) +* [How to copy Homebridge logs](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-copy-Homebridge-logs) +* [How to enable/disable plugin extended logging](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-enable-disable-plugin-extended-logging) +* [How to remove an accessory from the cache](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-remove-an-accessory-from-the-cache) +### About +* [Support Request](https://github.com/bwp91/homebridge-ewelink/issues/new/choose) +* [Roadmap](https://github.com/bwp91/homebridge-ewelink/wiki/Roadmap) +* [Credits](https://github.com/bwp91/homebridge-ewelink/wiki/Credits) +### Disclaimer +I am in no way affiliated with eWeLink nor any of the device brands (like Sonoff) and this plugin is a personal project that I maintain in my free time. From ee583f3d5a425579279163610f4fd8ae7a13c70a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 14:08:16 +0100 Subject: [PATCH 0329/3183] Create index.html --- docs/index.html | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 docs/index.html diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..61e831cf --- /dev/null +++ b/docs/index.html @@ -0,0 +1,22 @@ + + + + + + + + + +
+ + + + \ No newline at end of file From b0a0cdf4084ae9b6999eefe460864eacf87a9957 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 14:10:03 +0100 Subject: [PATCH 0330/3183] Delete .gitkeep --- docs/.gitkeep | 1 - 1 file changed, 1 deletion(-) delete mode 100644 docs/.gitkeep diff --git a/docs/.gitkeep b/docs/.gitkeep deleted file mode 100644 index 8b137891..00000000 --- a/docs/.gitkeep +++ /dev/null @@ -1 +0,0 @@ - From c3c5dadc6297747a761b5e13ccd0483565689c7b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 14:10:05 +0100 Subject: [PATCH 0331/3183] Delete _config.yml --- docs/_config.yml | 1 - 1 file changed, 1 deletion(-) delete mode 100644 docs/_config.yml diff --git a/docs/_config.yml b/docs/_config.yml deleted file mode 100644 index c4192631..00000000 --- a/docs/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-cayman \ No newline at end of file From d729ca3cac8dc2bdf64131af2536fb65002a784c Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 14:12:40 +0100 Subject: [PATCH 0332/3183] Create .nojekyll --- docs/.nojekyll | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/.nojekyll diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/docs/.nojekyll @@ -0,0 +1 @@ + From 7d1ae2beb17bf4d06b4212167cef5cfa1cc19cc7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 14:14:48 +0100 Subject: [PATCH 0333/3183] Update index.html --- docs/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/index.html b/docs/index.html index 61e831cf..09e9f917 100644 --- a/docs/index.html +++ b/docs/index.html @@ -10,7 +10,6 @@
- - - \ No newline at end of file diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 4f0e0eb3..00000000 --- a/docs/index.md +++ /dev/null @@ -1,40 +0,0 @@ -

- Homebridge Verified -

- - -# homebridge-ewelink - - Homebridge plugin to control eWeLink devices with original firmware. - - [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) - [![npm](https://img.shields.io/npm/v/homebridge-ewelink/latest?label=release)](https://www.npmjs.com/package/homebridge-ewelink) - [![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://www.npmjs.com/package/homebridge-ewelink) - [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) - [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) - [![Discord](https://img.shields.io/discord/432663330281226270?color=728ED5&logo=discord&label=discord)](https://discord.com/channels/432663330281226270/742733745743855627) - [![Contribute](https://img.shields.io/badge/contribute-a%20drink-yellow)](https://ko-fi.com/bwp91) - - - -### Setup -* [Installation (Homebridge)](https://github.com/bwp91/homebridge-ewelink/wiki/Installation-(Homebridge)) -* [Installation (HOOBS)](https://github.com/bwp91/homebridge-ewelink/wiki/Installation-(HOOBS)) -* [Configuration](https://github.com/bwp91/homebridge-ewelink/wiki/Configuration) -* [Beta Version](https://github.com/bwp91/homebridge-ewelink/wiki/Beta-Version) -### Features -* [Supported Devices](https://github.com/bwp91/homebridge-ewelink/wiki/Supported-Devices) -* [Accessory Simulations](https://github.com/bwp91/homebridge-ewelink/wiki/Accessory-Simulations) -* [Connection Methods](https://github.com/bwp91/homebridge-ewelink/wiki/Connection-Methods) -### How-to Guides -* [How to set up RF Bridge sensors](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-RF-Bridge-sensors) -* [How to set up Sonoff Camera (GK-200MP2-B)](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-Sonoff-Camera) -* [How to copy Homebridge logs](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-copy-Homebridge-logs) -* [How to enable/disable plugin extended logging](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-enable-disable-plugin-extended-logging) -* [How to remove an accessory from the cache](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-remove-an-accessory-from-the-cache) -### About -* [Support Request](https://github.com/bwp91/homebridge-ewelink/issues/new/choose) -* [Roadmap](https://github.com/bwp91/homebridge-ewelink/wiki/Roadmap) -* [Credits](https://github.com/bwp91/homebridge-ewelink/wiki/Credits) -### Disclaimer -I am in no way affiliated with eWeLink nor any of the device brands (like Sonoff) and this plugin is a personal project that I maintain in my free time. From 58cfe356aed5f9ed4ef857d7cc5c6ac5040410ce Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 16:12:48 +0100 Subject: [PATCH 0336/3183] Update FUNDING.yml --- .github/FUNDING.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 0729bbfe..aa62079e 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,4 +1,4 @@ github: bwp91 patreon: bwp91 ko_fi: bwp91 -custom: ["https://www.paypal.me/BenPotter", "https://www.gofundme.com/f/bwp91"] +custom: ["https://www.paypal.me/BenPotter"] From 71946d37655423719f85cbbf26e4f2c633356923 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 16:14:28 +0100 Subject: [PATCH 0337/3183] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4f0e0eb3..dcbde453 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ * [How to enable/disable plugin extended logging](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-enable-disable-plugin-extended-logging) * [How to remove an accessory from the cache](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-remove-an-accessory-from-the-cache) ### About +* [About Me](https://github.com/sponsors/bwp91) * [Support Request](https://github.com/bwp91/homebridge-ewelink/issues/new/choose) * [Roadmap](https://github.com/bwp91/homebridge-ewelink/wiki/Roadmap) * [Credits](https://github.com/bwp91/homebridge-ewelink/wiki/Credits) From e761dbc64442bfa884f0c52c696e55ddf071b795 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 16:35:01 +0100 Subject: [PATCH 0338/3183] Update package.json --- package.json | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 7334fd6b..bf30e1ac 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,10 @@ "url": "https://github.com/bwp91/homebridge-ewelink/issues" }, "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/bwp91" + }, { "type": "kofi", "url": "https://ko-fi.com/bwp91" @@ -58,14 +62,6 @@ { "type": "paypal", "url": "https://www.paypal.me/BenPotter" - }, - { - "type": "github", - "url": "https://github.com/sponsors/bwp91" - }, - { - "type": "gofundme", - "url": "https://www.gofundme.com/f/bwp91" } ], "dependencies": { From 8299bdcfd7a3bab41b98f7004b4311fb145ca6e8 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 16:43:04 +0100 Subject: [PATCH 0339/3183] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index dcbde453..af89e280 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,6 @@ [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Discord](https://img.shields.io/discord/432663330281226270?color=728ED5&logo=discord&label=discord)](https://discord.com/channels/432663330281226270/742733745743855627) - [![Contribute](https://img.shields.io/badge/contribute-a%20drink-yellow)](https://ko-fi.com/bwp91) From 98e8f7f8dcc0641340ceaafb4498b286676ae56d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 17:22:39 +0100 Subject: [PATCH 0340/3183] Update config.schema.json --- config.schema.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/config.schema.json b/config.schema.json index 7e27b86d..8d850422 100644 --- a/config.schema.json +++ b/config.schema.json @@ -111,7 +111,7 @@ "groups": { "type": "array", "title": "Accessory Simulations", - "description": "You can use this setting to set up custom simulated HomeKit accessories from a generic single/multi-switch device.", + "description": "You can use this setting to set up custom simulated HomeKit accessories from a generic single/multi-switch device. For more information please see the wiki.", "items": { "type": "object", "properties": { @@ -127,31 +127,31 @@ "description": "The new type for this device.", "oneOf": [ { - "title": "Blind (using channel 0 for 'UP' and channel 1 for 'DOWN' of a multi-channel device)", + "title": "Garage Door (using Eachen GD-DC5)", "enum": [ - "blind" + "garage_eachen" ] }, { - "title": "Garage Door (using a single/multi-channel device)", + "title": "Garage Door (using single/multi-channel device)", "enum": [ "garage" ] }, { - "title": "Garage Door (using the Eachen GD-DC5)", + "title": "Window Blind (using multi-channel device)", "enum": [ - "garage_eachen" + "blind" ] }, { - "title": "Lock (using a single channel device)", + "title": "Lock (using single channel device)", "enum": [ "lock" ] }, { - "title": "Irrigation (using channels 0 and 1 of a multi-channel device)", + "title": "Irrigation/Sprinkler (using multi-channel device)", "enum": [ "valve" ] From c8f87e0165f35f2e0fc9318284ad2765c577f0e2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 4 Oct 2020 17:24:46 +0100 Subject: [PATCH 0341/3183] 3.3.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 38a4ffea..4c1b1d1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.1-3", + "version": "3.3.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index bf30e1ac..8f4350cc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.1-3", + "version": "3.3.1", "author": "bwp91", "contributors": [ "gbro115", From 94a2229c5714513cb63fe31ba11f71c098ab0633 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 09:12:07 +0100 Subject: [PATCH 0342/3183] remove zb bridge device --- lib/eWeLink.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 8ef86134..35f06348 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -345,8 +345,8 @@ class eWeLink { accessory.context.channelCount = rfChlCounter this.devicesInHB.set(accessory.context.hbDeviceId, accessory) } else if (cns.devicesZBBridge.includes(device.extra.uiid)) { - if (this.devicesInHB.has(device.deviceid + 'SW0')) { - this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) + if (this.devicesInHB.has(device.deviceid + 'SWX')) { + this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SWX')) } } else if (cns.devicesZB.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + 'SWX') From b51a2373419786f63ac8f1d1cced5897d4b797c3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 09:13:06 +0100 Subject: [PATCH 0343/3183] 3.3.2-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4c1b1d1b..06075130 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.1", + "version": "3.3.2-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 8f4350cc..b7c3de7c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.1", + "version": "3.3.2-0", "author": "bwp91", "contributors": [ "gbro115", From 7b360120431250d30c4c9745ec2a5d24d516d0d6 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 09:30:02 +0100 Subject: [PATCH 0344/3183] Update eWeLink.js --- lib/eWeLink.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 35f06348..89191bcb 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -348,6 +348,7 @@ class eWeLink { if (this.devicesInHB.has(device.deviceid + 'SWX')) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SWX')) } + return } else if (cns.devicesZB.includes(device.extra.uiid)) { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') From 24a72abfb0b57b53bf01906c2b05b5a7c9411f70 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 09:30:36 +0100 Subject: [PATCH 0345/3183] 3.3.2-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 06075130..f474f3e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.2-0", + "version": "3.3.2-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index b7c3de7c..32148d1d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.2-0", + "version": "3.3.2-1", "author": "bwp91", "contributors": [ "gbro115", From 462ee9cc2c2b6a35b84b3a4c221696758fb89097 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 10:09:03 +0100 Subject: [PATCH 0346/3183] 3.3.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f474f3e1..a4071715 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.2-1", + "version": "3.3.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 32148d1d..85f9cfdb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.2-1", + "version": "3.3.2", "author": "bwp91", "contributors": [ "gbro115", From 36a68b5675f593523a6f51befc67e97a1d9e8669 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 12:52:48 +0100 Subject: [PATCH 0347/3183] Update eWeLinkWS.js --- lib/eWeLinkWS.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 91633aef..70223826 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -162,7 +162,7 @@ module.exports = class eWeLinkWS { if (e !== 1000) { this.log('Web socket will try to reconnect in five seconds.') await utils.sleep(5000) - this.login() + await this.login() } else { this.log('Please try restarting Homebridge so that this plugin can work again.') } @@ -179,7 +179,7 @@ module.exports = class eWeLinkWS { this.log.warn('Web socket will try to reconnect in five seconds then try the command again.') this.wsp.removeAllListeners() await utils.sleep(5000) - this.login() + await this.login() } else { this.log.warn('If this was unexpected then please try restarting Homebridge.') } @@ -193,13 +193,14 @@ module.exports = class eWeLinkWS { ...{ action: 'update', sequence, + ts: 0, userAgent: 'app' } } if (this.wsp && this.wsIsOpen) { try { if (this.debugReqRes) { - const msg = JSON.stringify(json, null, 2).replace(json.apikey, '**hidden**').replace(json.apiKey, '**hidden**').replace(json.deviceid, '**hidden**') + const msg = JSON.stringify(jsonToSend, null, 2).replace(json.apikey, '**hidden**').replace(json.apiKey, '**hidden**').replace(json.deviceid, '**hidden**') this.log.warn('WS message sent. This text is yellow for clarity.\n%s', msg) } else if (this.debug) { this.log('WS message sent.') From c091a73f23936646ba9094bba5f69c80ee984a42 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 13:31:41 +0100 Subject: [PATCH 0348/3183] Update fan.js --- lib/device/fan.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index 045e0b64..b0938678 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -94,7 +94,7 @@ module.exports = class deviceFan { status = params.fan === 'on' ? 1 : 0 speed = params.speed * 33 * status } else { - throw new Error('unknown parameters received') + return } lightService.updateCharacteristic(Characteristic.On, light) fanService From ca85c3043cc4280429a4d690c8cdf0892deeaa32 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 13:33:13 +0100 Subject: [PATCH 0349/3183] 3.3.3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a4071715..010e51ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.2", + "version": "3.3.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 85f9cfdb..5556796a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.2", + "version": "3.3.3", "author": "bwp91", "contributors": [ "gbro115", From 640dd8aeca27c18706d82ba730819dae5b997545 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 15:35:24 +0100 Subject: [PATCH 0350/3183] ws improvements --- lib/eWeLinkWS.js | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 70223826..e215542d 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -104,13 +104,16 @@ module.exports = class eWeLinkWS { this.log.error('WS login failed [%s].', this.debug ? err : err.message) } }) - this.wsp.onUnpackedMessage.addListener((device) => { + this.wsp.onUnpackedMessage.addListener(device => { if (device === 'pong') return let onlineStatus = true if (!Object.prototype.hasOwnProperty.call(device, 'params')) device.params = {} if (Object.prototype.hasOwnProperty.call(device, 'deviceid') && Object.prototype.hasOwnProperty.call(device, 'error')) { device.action = 'update' onlineStatus = device.error === 0 + if (this.debug) { + this.log.warn('WS message received.\n%s', JSON.stringify(device, null, 2).replace(this.apiKey, '**hidden**')) + } } if (Object.prototype.hasOwnProperty.call(device, 'action')) { switch (device.action) { @@ -157,32 +160,32 @@ module.exports = class eWeLinkWS { }) this.wsp.onClose.addListener(async e => { this.wsIsOpen = false - if (e !== 1005) { - this.log.warn('Web socket closed [%s].', e) - if (e !== 1000) { - this.log('Web socket will try to reconnect in five seconds.') - await utils.sleep(5000) - await this.login() - } else { - this.log('Please try restarting Homebridge so that this plugin can work again.') - } - } if (this.hbInterval) { clearInterval(this.hbInterval) this.hbInterval = null } this.wsp.removeAllListeners() + if (e === 1005) return + if (this.debug) { + this.log.warn('Web socket closed - [%s].', e) + this.log.warn('Web socket will try to reconnect in five seconds.') + } + await utils.sleep(5000) + await this.login() }) this.wsp.onError.addListener(async e => { - this.log.warn('Web socket error - [%s].', e) - if (e.code === 'ECONNREFUSED') { - this.log.warn('Web socket will try to reconnect in five seconds then try the command again.') - this.wsp.removeAllListeners() - await utils.sleep(5000) - await this.login() - } else { - this.log.warn('If this was unexpected then please try restarting Homebridge.') + this.wsIsOpen = false + if (this.hbInterval) { + clearInterval(this.hbInterval) + this.hbInterval = null + } + this.wsp.removeAllListeners() + if (this.debug) { + this.log.warn('Web socket error - [%s].', e) + this.log.warn('Web socket will try to reconnect in five seconds.') } + await utils.sleep(5000) + await this.login() }) } From c1ccc5d175b4d153395b08b343f628a2c7d90d1b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 15:58:05 +0100 Subject: [PATCH 0351/3183] limit logging --- lib/eWeLinkHTTP.js | 16 ++++++++++++---- lib/eWeLinkLAN.js | 4 +++- lib/eWeLinkWS.js | 10 +++++++--- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index a40122a9..011d25fb 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -67,7 +67,9 @@ module.exports = class eWeLinkHTTP { return this.httpHost } catch (err) { if (Object.prototype.hasOwnProperty.call(err, 'code') && cns.httpRetryCodes.includes(err.code)) { - this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') + if (this.debug) { + this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') + } await utils.sleep(30000) return this.getHost() } else { @@ -128,7 +130,9 @@ module.exports = class eWeLinkHTTP { } } else { if (body.error === 500) { - this.log.warn('An eWeLink error [500] occured. Retrying in 30 seconds.') + if (this.debug) { + this.log.warn('An eWeLink error [500] occured. Retrying in 30 seconds.') + } await utils.sleep(30000) return this.login() } else { @@ -168,7 +172,9 @@ module.exports = class eWeLinkHTTP { return deviceList } catch (err) { if (Object.prototype.hasOwnProperty.call(err, 'code') && cns.httpRetryCodes.includes(err.code)) { - this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') + if (this.debug) { + this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') + } await utils.sleep(30000) return this.getDevices() } else { @@ -204,7 +210,9 @@ module.exports = class eWeLinkHTTP { } } catch (err) { if (Object.prototype.hasOwnProperty.call(err, 'code') && cns.httpRetryCodes.includes(err.code)) { - this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') + if (this.debug) { + this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') + } await utils.sleep(30000) return this.getDevice(deviceId) } else { diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index df0655c6..83a37197 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -75,7 +75,9 @@ module.exports = class eWeLinkLAN { try { params = JSON.parse(pText) } catch (e) { - this.log.warn('[%s] An error occured reading the LAN message [%s]', rdata.id, e) + if (this.debug) { + this.log.warn('[%s] An error occured reading the LAN message [%s]', rdata.id, e) + } return } for (const param in params) { diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index e215542d..1a091f64 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -46,7 +46,9 @@ module.exports = class eWeLinkWS { return body.domain } catch (err) { if (Object.prototype.hasOwnProperty.call(err, 'code') && cns.httpRetryCodes.includes(err.code)) { - this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') + if (this.debug) { + this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') + } await utils.sleep(30000) return this.getDevices() } else { @@ -148,7 +150,9 @@ module.exports = class eWeLinkWS { case 'reportSubDevice': return default: - this.log.warn('[%s] WS message has unknown action.\n' + JSON.stringify(device, null, 2), device.deviceid) + if (this.debug) { + this.log.warn('[%s] WS message has unknown action.\n' + JSON.stringify(device, null, 2), device.deviceid) + } } } else if (Object.prototype.hasOwnProperty.call(device, 'error') && device.error === 0) { // *** Safe to ignore these messages *** \\ @@ -180,7 +184,7 @@ module.exports = class eWeLinkWS { this.hbInterval = null } this.wsp.removeAllListeners() - if (this.debug) { + if (this.debug) { this.log.warn('Web socket error - [%s].', e) this.log.warn('Web socket will try to reconnect in five seconds.') } From 388d5d3ec54bb0082b3b74bf35dff03cde2b139d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 16:01:06 +0100 Subject: [PATCH 0352/3183] 3.4.0-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 010e51ee..14da6f99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.3", + "version": "3.4.0-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 5556796a..0c354d93 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.3.3", + "version": "3.4.0-0", "author": "bwp91", "contributors": [ "gbro115", From 6d63ebf20cb5059baea2e188b8955e89360d9a71 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 18:27:54 +0100 Subject: [PATCH 0353/3183] hide log for no error --- lib/eWeLinkWS.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 1a091f64..baba2465 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -113,7 +113,7 @@ module.exports = class eWeLinkWS { if (Object.prototype.hasOwnProperty.call(device, 'deviceid') && Object.prototype.hasOwnProperty.call(device, 'error')) { device.action = 'update' onlineStatus = device.error === 0 - if (this.debug) { + if (device.error !== 0 && this.debug) { this.log.warn('WS message received.\n%s', JSON.stringify(device, null, 2).replace(this.apiKey, '**hidden**')) } } From 694fd71cacdec7e04d10f759d4aa76f6f932c1ed Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 18:28:38 +0100 Subject: [PATCH 0354/3183] try lan mode ifan03 --- lib/device/fan.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index b0938678..7c1d534a 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -1,5 +1,6 @@ 'use strict' let Characteristic, Service +const cns = require('./../constants') module.exports = class deviceFan { constructor (platform, accessory) { this.platform = platform @@ -27,6 +28,7 @@ module.exports = class deviceFan { let newPower let newSpeed let newLight + let params = {} const lightService = accessory.getService(Service.Lightbulb) const fanService = accessory.getService(Service.Fanv2) switch (type) { @@ -46,13 +48,19 @@ module.exports = class deviceFan { newLight = value break } - const params = { - switches: this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches + if (accessory.context.eweModel === 'iFan03' && accessory.context.reachableLAN) { + + params.light = newLight ? 'on' : 'off' + params.fan = newPower === 1 && newSpeed >= 33 ? 'on' : 'off' + params.speed = newSpeed / 33 + + } else { + params.switches = cns.defaultMultiSwitchOff + params.switches[0].switch = newLight ? 'on' : 'off' + params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? 'on' : 'off' + params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? 'on' : 'off' + params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? 'on' : 'off' } - params.switches[0].switch = newLight ? 'on' : 'off' - params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? 'on' : 'off' - params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? 'on' : 'off' - params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? 'on' : 'off' await this.platform.sendDeviceUpdate(accessory, params) lightService.updateCharacteristic(Characteristic.On, newLight) fanService From c504528905b58ff0baf4235389a678e430dd9bcb Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 18:29:58 +0100 Subject: [PATCH 0355/3183] Update fan.js --- lib/device/fan.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index 7c1d534a..229f1d96 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -28,7 +28,7 @@ module.exports = class deviceFan { let newPower let newSpeed let newLight - let params = {} + const params = {} const lightService = accessory.getService(Service.Lightbulb) const fanService = accessory.getService(Service.Fanv2) switch (type) { @@ -49,11 +49,9 @@ module.exports = class deviceFan { break } if (accessory.context.eweModel === 'iFan03' && accessory.context.reachableLAN) { - params.light = newLight ? 'on' : 'off' params.fan = newPower === 1 && newSpeed >= 33 ? 'on' : 'off' params.speed = newSpeed / 33 - } else { params.switches = cns.defaultMultiSwitchOff params.switches[0].switch = newLight ? 'on' : 'off' From b6abac5061bf04a90e342cf0764ea1732d56d47e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 18:30:40 +0100 Subject: [PATCH 0356/3183] 3.4.0-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 14da6f99..37b5a602 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-0", + "version": "3.4.0-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 0c354d93..08efe5da 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-0", + "version": "3.4.0-1", "author": "bwp91", "contributors": [ "gbro115", From 325b61e937005f765cc65e437a95cee068340079 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 19:07:26 +0100 Subject: [PATCH 0357/3183] ifan test lan mode --- lib/device/fan.js | 10 ++++++++-- lib/eWeLinkLAN.js | 11 ++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index 229f1d96..6e9c3725 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -28,7 +28,6 @@ module.exports = class deviceFan { let newPower let newSpeed let newLight - const params = {} const lightService = accessory.getService(Service.Lightbulb) const fanService = accessory.getService(Service.Fanv2) switch (type) { @@ -49,17 +48,24 @@ module.exports = class deviceFan { break } if (accessory.context.eweModel === 'iFan03' && accessory.context.reachableLAN) { + let params = {} params.light = newLight ? 'on' : 'off' + await this.platform.sendDeviceUpdate(accessory, params) + params = {} params.fan = newPower === 1 && newSpeed >= 33 ? 'on' : 'off' + await this.platform.sendDeviceUpdate(accessory, params) + params = {} params.speed = newSpeed / 33 + await this.platform.sendDeviceUpdate(accessory, params) } else { + const params = {} params.switches = cns.defaultMultiSwitchOff params.switches[0].switch = newLight ? 'on' : 'off' params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? 'on' : 'off' params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? 'on' : 'off' params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? 'on' : 'off' + await this.platform.sendDeviceUpdate(accessory, params) } - await this.platform.sendDeviceUpdate(accessory, params) lightService.updateCharacteristic(Characteristic.On, newLight) fanService .updateCharacteristic(Characteristic.Active, newPower) diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 83a37197..b29abd92 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -122,8 +122,17 @@ module.exports = class eWeLinkLAN { } else if (Object.prototype.hasOwnProperty.call(json.params, 'switch')) { params.switch = json.params.switch suffix = 'switch' + } else if (Object.prototype.hasOwnProperty.call(json.params, 'light')) { + params.light = json.params.light + suffix = 'light' + } else if (Object.prototype.hasOwnProperty.call(json.params, 'fan')) { + params.fan = json.params.fan + suffix = 'fan' + } else if (Object.prototype.hasOwnProperty.call(json.params, 'speed')) { + params.speed = json.params.speed + suffix = 'speed' } else { - throw new Error("device isn't reachable via LAN mode") + throw new Error("device isn't configurable via LAN mode") } if ((apiKey = this.deviceMap.get(json.deviceid).apiKey)) { const key = crypto.createHash('md5').update(Buffer.from(apiKey, 'utf8')).digest() From 5c1b41a57cb91d735b2c595c2872370cff0c9396 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 19:08:16 +0100 Subject: [PATCH 0358/3183] 3.4.0-2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 37b5a602..826bf69b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-1", + "version": "3.4.0-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 08efe5da..45900bec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-1", + "version": "3.4.0-2", "author": "bwp91", "contributors": [ "gbro115", From c6eb692e88c1643300d40fd5be8d3f62f4690870 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 20:00:19 +0100 Subject: [PATCH 0359/3183] Update fan.js --- lib/device/fan.js | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index 6e9c3725..b8f3ec04 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -20,6 +20,9 @@ module.exports = class deviceFan { fanLightService .getCharacteristic(Characteristic.On) .on('set', (value, callback) => this.internalUpdate(accessory, 'light', value, callback)) + if (!Object.prototype.hasOwnProperty.call(accessory.context, 'cacheRotationSpeed')) { + accessory.context.cacheRotationSpeed = 33 + } } async internalUpdate (accessory, type, value, callback) { @@ -30,33 +33,47 @@ module.exports = class deviceFan { let newLight const lightService = accessory.getService(Service.Lightbulb) const fanService = accessory.getService(Service.Fanv2) + const params = {} + if (type === 'speed') { + if (value > 0 && value <= 33) value = 33 + else if (value > 33 && value <= 66) value = 66 + else if (value > 66) value = 99 + } switch (type) { case 'power': newPower = value - newSpeed = value ? 33 : 0 + newSpeed = value ? accessory.context.cacheRotationSpeed : 0 newLight = lightService.getCharacteristic(Characteristic.On).value + if (accessory.context.eweModel === 'iFan03' && accessory.context.reachableLAN) { + params.fan = newPower === 1 ? 'on' : 'off' + await this.platform.sendDeviceUpdate(accessory, params) + } break case 'speed': newPower = value >= 33 ? 1 : 0 newSpeed = value newLight = lightService.getCharacteristic(Characteristic.On).value + if (accessory.context.eweModel === 'iFan03' && accessory.context.reachableLAN) { + if (newPower) { + params.speed = accessory.context.cacheRotationSpeed / 33 + } else { + params.fan = 'off' + } + await this.platform.sendDeviceUpdate(accessory, params) + } break case 'light': newPower = fanService.getCharacteristic(Characteristic.Active).value newSpeed = fanService.getCharacteristic(Characteristic.RotationSpeed).value newLight = value + if (accessory.context.eweModel === 'iFan03' && accessory.context.reachableLAN) { + params.light = newLight ? 'on' : 'off' + await this.platform.sendDeviceUpdate(accessory, params) + } break } if (accessory.context.eweModel === 'iFan03' && accessory.context.reachableLAN) { - let params = {} - params.light = newLight ? 'on' : 'off' - await this.platform.sendDeviceUpdate(accessory, params) - params = {} - params.fan = newPower === 1 && newSpeed >= 33 ? 'on' : 'off' - await this.platform.sendDeviceUpdate(accessory, params) - params = {} - params.speed = newSpeed / 33 - await this.platform.sendDeviceUpdate(accessory, params) + // done } else { const params = {} params.switches = cns.defaultMultiSwitchOff @@ -112,6 +129,7 @@ module.exports = class deviceFan { fanService .updateCharacteristic(Characteristic.Active, status) .updateCharacteristic(Characteristic.RotationSpeed, speed) + if (speed !== 0) accessory.context.cacheRotationSpeed = speed } catch (err) { this.platform.deviceUpdateError(accessory, err, false) } From d6be2b7d1f828e4debe6ef7acce9d6a2b231239c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 20:01:13 +0100 Subject: [PATCH 0360/3183] 3.4.0-3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 826bf69b..a2d9e30f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-2", + "version": "3.4.0-3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 45900bec..2ba4ee62 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-2", + "version": "3.4.0-3", "author": "bwp91", "contributors": [ "gbro115", From 8eaab1d9c10dd97fa7689726b852bd43421502dd Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 21:56:39 +0100 Subject: [PATCH 0361/3183] Update eWeLink.js --- lib/eWeLink.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 89191bcb..1d377181 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -447,7 +447,6 @@ class eWeLink { deviceid: accessory.context.eweDeviceId, params } - await utils.sleep(Math.random() * 100 + 200) const res = await this.lanClient.sendUpdate(payload) if (res !== 'ok') { if (accessory.context.reachableWAN) { From 8ef33b5c650d462097fd29e81835ceb5474df7b5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 21:56:52 +0100 Subject: [PATCH 0362/3183] revert ifan03 lan mode --- lib/device/fan.js | 49 ++++++++++------------------------------------- lib/eWeLinkLAN.js | 9 --------- 2 files changed, 10 insertions(+), 48 deletions(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index b8f3ec04..5629d422 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -1,6 +1,7 @@ 'use strict' let Characteristic, Service const cns = require('./../constants') +const utils = require('./../utils') module.exports = class deviceFan { constructor (platform, accessory) { this.platform = platform @@ -20,9 +21,6 @@ module.exports = class deviceFan { fanLightService .getCharacteristic(Characteristic.On) .on('set', (value, callback) => this.internalUpdate(accessory, 'light', value, callback)) - if (!Object.prototype.hasOwnProperty.call(accessory.context, 'cacheRotationSpeed')) { - accessory.context.cacheRotationSpeed = 33 - } } async internalUpdate (accessory, type, value, callback) { @@ -33,56 +31,30 @@ module.exports = class deviceFan { let newLight const lightService = accessory.getService(Service.Lightbulb) const fanService = accessory.getService(Service.Fanv2) - const params = {} - if (type === 'speed') { - if (value > 0 && value <= 33) value = 33 - else if (value > 33 && value <= 66) value = 66 - else if (value > 66) value = 99 - } + const params = { switches: cns.defaultMultiSwitchOff } switch (type) { case 'power': newPower = value - newSpeed = value ? accessory.context.cacheRotationSpeed : 0 + newSpeed = value ? 33 : 0 newLight = lightService.getCharacteristic(Characteristic.On).value - if (accessory.context.eweModel === 'iFan03' && accessory.context.reachableLAN) { - params.fan = newPower === 1 ? 'on' : 'off' - await this.platform.sendDeviceUpdate(accessory, params) - } break case 'speed': newPower = value >= 33 ? 1 : 0 newSpeed = value newLight = lightService.getCharacteristic(Characteristic.On).value - if (accessory.context.eweModel === 'iFan03' && accessory.context.reachableLAN) { - if (newPower) { - params.speed = accessory.context.cacheRotationSpeed / 33 - } else { - params.fan = 'off' - } - await this.platform.sendDeviceUpdate(accessory, params) - } + await utils.sleep(500) break case 'light': newPower = fanService.getCharacteristic(Characteristic.Active).value newSpeed = fanService.getCharacteristic(Characteristic.RotationSpeed).value newLight = value - if (accessory.context.eweModel === 'iFan03' && accessory.context.reachableLAN) { - params.light = newLight ? 'on' : 'off' - await this.platform.sendDeviceUpdate(accessory, params) - } break } - if (accessory.context.eweModel === 'iFan03' && accessory.context.reachableLAN) { - // done - } else { - const params = {} - params.switches = cns.defaultMultiSwitchOff - params.switches[0].switch = newLight ? 'on' : 'off' - params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? 'on' : 'off' - params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? 'on' : 'off' - params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? 'on' : 'off' - await this.platform.sendDeviceUpdate(accessory, params) - } + params.switches[0].switch = newLight ? 'on' : 'off' + params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? 'on' : 'off' + params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? 'on' : 'off' + params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? 'on' : 'off' + await this.platform.sendDeviceUpdate(accessory, params) lightService.updateCharacteristic(Characteristic.On, newLight) fanService .updateCharacteristic(Characteristic.Active, newPower) @@ -129,9 +101,8 @@ module.exports = class deviceFan { fanService .updateCharacteristic(Characteristic.Active, status) .updateCharacteristic(Characteristic.RotationSpeed, speed) - if (speed !== 0) accessory.context.cacheRotationSpeed = speed } catch (err) { this.platform.deviceUpdateError(accessory, err, false) } } -} +} \ No newline at end of file diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index b29abd92..c9e977ff 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -122,15 +122,6 @@ module.exports = class eWeLinkLAN { } else if (Object.prototype.hasOwnProperty.call(json.params, 'switch')) { params.switch = json.params.switch suffix = 'switch' - } else if (Object.prototype.hasOwnProperty.call(json.params, 'light')) { - params.light = json.params.light - suffix = 'light' - } else if (Object.prototype.hasOwnProperty.call(json.params, 'fan')) { - params.fan = json.params.fan - suffix = 'fan' - } else if (Object.prototype.hasOwnProperty.call(json.params, 'speed')) { - params.speed = json.params.speed - suffix = 'speed' } else { throw new Error("device isn't configurable via LAN mode") } From 20a2d27f8b7e61cf133c3a909fd86cc1977c06ce Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 22:04:04 +0100 Subject: [PATCH 0363/3183] Update fan.js --- lib/device/fan.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index 5629d422..3c97c192 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -105,4 +105,4 @@ module.exports = class deviceFan { this.platform.deviceUpdateError(accessory, err, false) } } -} \ No newline at end of file +} From 290b6fb1be7215c1ac7ab7de6b584cff92231c1f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 5 Oct 2020 22:04:40 +0100 Subject: [PATCH 0364/3183] 3.4.0-4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a2d9e30f..cfd33573 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-3", + "version": "3.4.0-4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 2ba4ee62..8f3d1938 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-3", + "version": "3.4.0-4", "author": "bwp91", "contributors": [ "gbro115", From 453fe724f779062892f83bb3c4fbe84b7a1d002e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 09:19:00 +0100 Subject: [PATCH 0365/3183] code formatting --- lib/constants.js | 28 +++++++++- lib/eWeLink.js | 131 ++++++++++++++++++++++++++++++++++----------- lib/eWeLinkHTTP.js | 31 +++++++---- lib/eWeLinkLAN.js | 13 ++--- lib/eWeLinkWS.js | 45 ++++++---------- 5 files changed, 165 insertions(+), 83 deletions(-) diff --git a/lib/constants.js b/lib/constants.js index 27f4f0ce..5596f43f 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -24,7 +24,19 @@ module.exports = { devicesRFBridge: [28], devicesZBBridge: [66], devicesZB: [1000, 1770, 2026, 3026], - paramsToKeep: ['battery', 'bright', 'brightness', 'channel', 'cmd', 'colorB', 'colorG', 'colorR', 'current', 'currentHumidity', 'currentTemperature', 'fan', 'humidity', 'key', 'light', 'lock', 'mainSwitch', 'mode', 'motion', 'online', 'power', 'rfChl', 'rfList', 'rfTrig', 'sensorType', 'setclose', 'speed', 'state', 'switch', 'switches', 'temperature', 'trigTime', 'type', 'voltage', 'zyx_mode'], + paramsToKeep: [ + 'battery', 'bright', 'brightness', + 'channel', 'cmd', 'colorB', 'colorG', + 'colorR', 'current', 'currentHumidity', + 'currentTemperature', 'fan', 'humidity', + 'key', 'light', 'lock', 'mainSwitch', + 'mode', 'motion', 'online', 'power', + 'rfChl', 'rfList', 'rfTrig', + 'sensorType', 'setclose', 'speed', + 'state', 'switch', 'switches', + 'temperature', 'trigTime', 'type', + 'voltage', 'zyx_mode' + ], defaultMultiSwitchOff: [{ switch: 'off', outlet: 0 @@ -42,6 +54,18 @@ module.exports = { outlet: 3 } ], + defaultCurtainCache: { + cacheCurrentPosition: 0 + }, + defaultBlindCache: { + cacheCurrentPosition: 0, + cachePositionState: 2, + cacheTargetPosition: 0 + }, + defaultGarageCache: { + cacheCurrentDoorState: 1, + cacheTargetDoorState: 1 + }, chansFromUiid: { 1: 1, // "SOCKET" \\ 20, MINI, BASIC, S26 2: 2, // "SOCKET_2" \\ @@ -100,7 +124,7 @@ module.exports = { 65: 0, // "CustomCamera" \\ 66: 0, // "ZIGBEE_MAIN_DEVICE" \\ 67: 0, // "RollingDoor" \\ - 68: 0, // "KOOCHUWAH" \\ + 68: 0, // "KOOCHUWAH" \\ a whhaaaaat? 69: 0, // "ATMOSPHERE_LAMP" \\ 76: 0, // "YI_GE_ER_LAMP" \\ 77: 4, // "SINGLE_SOCKET_MULTIPLE" \\ (1 socket device using data structure of four :() diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 1d377181..ba0235a8 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -128,93 +128,137 @@ class eWeLink { let accessory try { if (this.cusG.has(device.deviceid + 'SWX')) { - const all = ['X', '0', '1', '2', '3', '4'] - all.forEach(v => { - if (this.devicesInHB.has(device.deviceid + 'SW' + v)) { - if (this.devicesInHB.get(device.deviceid + 'SW' + v).getService(Service.Switch)) { - this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + v)) + ;['X', '0', '1', '2', '3', '4'].forEach(sw => { + if (this.devicesInHB.has(device.deviceid + 'SW' + sw)) { + if (this.devicesInHB.get(device.deviceid + 'SW' + sw).getService(Service.Switch)) { + this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + sw)) } } }) } if (cns.devicesCurtain.includes(device.extra.uiid)) { + /*********************** + BLINDS [EWELINK UIID 11] + ***********************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', false, { cacheCurrentPosition: 0 }) + : this.addAccessory(device, device.deviceid + 'SWX', false, cns.defaultCurtainCache) accessory.control = new DeviceCurtain(this, accessory) + /**********************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'blind') { + /**************************** + BLINDS [ACCESSORY SIMULATION] + ****************************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', false, { - cacheCurrentPosition: 0, - cachePositionState: 2, - cacheTargetPosition: 0 - }) + : this.addAccessory(device, device.deviceid + 'SWX', false, cns.defaultBlindCache) accessory.control = new DeviceBlind(this, accessory) + /***************************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage') { + /********************************** + GARAGE DOORS [ACCESSORY SIMULATION] + **********************************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', false, { - cacheCurrentDoorState: 1, - cacheTargetDoorState: 1 - }) + : this.addAccessory(device, device.deviceid + 'SWX', false, cns.defaultGarageCache) accessory.control = new DeviceGarage(this, accessory) + /*********************************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage_eachen') { + /*************************** + GARAGE DOORS [EACHEN GD-DC5] + ***************************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceGarageEachen(this, accessory) + /**************************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'lock') { + /*************************** + LOCKS [ACCESSORY SIMULATION] + ***************************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceLock(this, accessory) + /**************************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'valve') { + /**************************** + VALVES [ACCESSORY SIMULATION] + ****************************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceValve(this, accessory) + /***************************/ } else if (cns.devicesSensor.includes(device.extra.uiid)) { + /******************* + SENSORS [SONOFF DW2] + *******************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX', false, { type: 'sensor' }) accessory.control = new DeviceSensor(this, accessory) + /******************/ } else if (cns.devicesFan.includes(device.extra.uiid)) { + /*** + FANS + ***/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceFan(this, accessory) + /**/ } else if (cns.devicesThermostat.includes(device.extra.uiid)) { + /********** + THERMOSTATS + **********/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX', false, { sensorType: device.params.sensorType }) - if (accessory.context.sensorType !== device.params.sensorType) { - accessory.context.sensorType = device.params.sensorType - } accessory.control = new DeviceThermostat(this, accessory) + /*********/ } else if (cns.devicesOutlet.includes(device.extra.uiid) || (cns.devicesSingleSwitch.includes(device.extra.uiid) && cns.devicesSingleSwitchOutlet.includes(device.productModel))) { + /****** + OUTLETS + ******/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceOutlet(this, accessory) + /*****/ } else if (cns.devicesUSB.includes(device.extra.uiid)) { + /********** + USB OUTLETS + **********/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceUSB(this, accessory) + /*********/ } else if (cns.devicesSCM.includes(device.extra.uiid)) { + /********************************* + SINGLE CHL [MULTIPLE CHL HARDWARE] + *********************************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceSCM(this, accessory) + /********************************/ } else if (cns.devicesSingleSwitch.includes(device.extra.uiid) && cns.devicesSingleSwitchLight.includes(device.productModel)) { + /********************** + LIGHTS [SINGLE CHANNEL] + **********************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceLight(this, accessory) + /*********************/ } else if (cns.devicesMultiSwitch.includes(device.extra.uiid) && cns.devicesMultiSwitchLight.includes(device.productModel)) { + /********************* + LIGHTS [MULTI CHANNEL] + *********************/ if ((this.config.hideMasters || '').includes(device.deviceid)) { if (this.devicesInHB.has(device.deviceid + 'SW0')) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) @@ -245,12 +289,20 @@ class eWeLink { oAccessory.control = new DeviceLight(this, oAccessory) } } + /********************/ } else if (cns.devicesSingleSwitch.includes(device.extra.uiid)) { + /************************ + SWITCHES [SINGLE CHANNEL] + ************************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceSwitch(this, accessory) + /***********************/ } else if (cns.devicesMultiSwitch.includes(device.extra.uiid)) { + /*********************** + SWITCHES [MULTI CHANNEL] + ***********************/ if ((this.config.hideMasters || '').includes(device.deviceid)) { if (this.devicesInHB.has(device.deviceid + 'SW0')) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) @@ -281,7 +333,11 @@ class eWeLink { oAccessory.control = new DeviceSwitch(this, oAccessory) } } + /**********************/ } else if (cns.devicesRFBridge.includes(device.extra.uiid)) { + /********************* + RF BRIDGE + SUBDEVICES + *********************/ let rfChlCounter = 0 const rfMap = [] if (Object.prototype.hasOwnProperty.call(device, 'tags') && Object.prototype.hasOwnProperty.call(device.tags, 'zyx_info')) { @@ -305,20 +361,14 @@ class eWeLink { let subAccessory let subType let subExtraContext = {} - switch (subDevice.type) { - case '1': - case '2': - case '3': - case '4': - subType = 'button' - break - case '6': - subType = this.cusS.has(device.deviceid + 'SW' + swNumber) - ? this.cusS.get(device.deviceid + 'SW' + swNumber).type - : 'motion' - break - default: - return + if (['1', '2', '3', '4'].includes(subDevice.type)) { + subType = 'button' + } else if (subDevice.type === '6') { + subType = this.cusS.has(device.deviceid + 'SW' + swNumber) + ? this.cusS.get(device.deviceid + 'SW' + swNumber).type + : 'motion' + } else { + return } subExtraContext = { buttons: subDevice.buttons, @@ -344,22 +394,39 @@ class eWeLink { }) accessory.context.channelCount = rfChlCounter this.devicesInHB.set(accessory.context.hbDeviceId, accessory) + /********************/ } else if (cns.devicesZBBridge.includes(device.extra.uiid)) { + /************ + ZIGBEE BRIDGE + ************/ if (this.devicesInHB.has(device.deviceid + 'SWX')) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SWX')) } return + /***********/ } else if (cns.devicesZB.includes(device.extra.uiid)) { + /**************** + ZIGBEE SUBDEVICES + ****************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceZBDev(this, accessory) + /***************/ } else if (cns.devicesCamera.includes(device.extra.uiid)) { + /****** + CAMERAS + ******/ this.log.warn(' → [%s] please see the homebridge-ewelink wiki for details to enable the camera.', device.name) return + /*****/ } else { + /********** + UNSUPPORTED + **********/ this.log.warn(' → [%s] has not been added as it is not supported. Please make a GitHub issue request.', device.name) return + /*********/ } if (!this.hiddenMasters.includes(device.deviceid)) { accessory diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 011d25fb..0026d303 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -24,19 +24,19 @@ module.exports = class eWeLinkHTTP { } let dataToSign = [] try { - Object.keys(params).forEach((k) => { + Object.keys(params).forEach(k => { dataToSign.push({ key: k, value: params.k }) }) dataToSign.sort((a, b) => (a.key < b.key ? -1 : 1)) - dataToSign = dataToSign.map((k) => k.key + '=' + k.value).join('&') + dataToSign = dataToSign.map(k => k.key + '=' + k.value).join('&') dataToSign = crypto.createHmac('sha256', cns.appSecret).update(dataToSign).digest('base64') if (this.debugReqRes) { - this.log.warn('Sending HTTP getHost request. This text is yellow for clarity.\n%s', JSON.stringify(params, null, 2)) + this.log.warn('Sending HTTP getHost() request. This text is yellow for clarity.\n%s', JSON.stringify(params, null, 2)) } else if (this.debug) { - this.log('Sending HTTP getHost request.') + this.log('Sending HTTP getHost() request.') } const res = await axios.get('https://api.coolkit.cc:8080/api/user/region', { headers: { @@ -86,9 +86,9 @@ module.exports = class eWeLinkHTTP { this.username.includes('@') ? (data.email = this.username) : (data.phoneNumber = this.username) if (this.debugReqRes) { const msg = JSON.stringify(data, null, 2).replace(this.password, '**hidden**').replace(this.username, '**hidden**') - this.log.warn('Sending HTTP login request. This text is yellow for clarity.\n%s', msg) + this.log.warn('Sending HTTP login() request. This text is yellow for clarity.\n%s', msg) } else if (this.debug) { - this.log('Sending HTTP login request.') + this.log('Sending HTTP login() request.') } const dataToSign = crypto.createHmac('sha256', cns.appSecret).update(JSON.stringify(data)).digest('base64') const res = await axios.post('https://' + this.httpHost + '/v2/user/login', data, { @@ -101,7 +101,12 @@ module.exports = class eWeLinkHTTP { } }) const body = res.data - if (Object.prototype.hasOwnProperty.call(body, 'error') && body.error === 10004 && Object.prototype.hasOwnProperty.call(body, 'data') && Object.prototype.hasOwnProperty.call(body.data, 'region')) { + if ( + Object.prototype.hasOwnProperty.call(body, 'error') && + body.error === 10004 && + Object.prototype.hasOwnProperty.call(body, 'data') && + Object.prototype.hasOwnProperty.call(body.data, 'region') + ) { const givenRegion = body.data.region switch (givenRegion) { case 'eu': @@ -153,7 +158,11 @@ module.exports = class eWeLinkHTTP { } }) const body = res.data - if (!Object.prototype.hasOwnProperty.call(body, 'data') || !Object.prototype.hasOwnProperty.call(body, 'error') || (Object.prototype.hasOwnProperty.call(body, 'error') && body.error !== 0)) { + if ( + !Object.prototype.hasOwnProperty.call(body, 'data') || + !Object.prototype.hasOwnProperty.call(body, 'error') || + (Object.prototype.hasOwnProperty.call(body, 'error') && body.error !== 0) + ) { throw new Error(JSON.stringify(body, null, 2)) } const deviceList = [] @@ -200,7 +209,11 @@ module.exports = class eWeLinkHTTP { } }) const body = res.data - if (!Object.prototype.hasOwnProperty.call(body, 'data') || !Object.prototype.hasOwnProperty.call(body, 'error') || (Object.prototype.hasOwnProperty.call(body, 'error') && body.error !== 0)) { + if ( + !Object.prototype.hasOwnProperty.call(body, 'data') || + !Object.prototype.hasOwnProperty.call(body, 'error') || + (Object.prototype.hasOwnProperty.call(body, 'error') && body.error !== 0) + ) { throw new Error(JSON.stringify(body, null, 2)) } if (body.data.thingList && body.data.thingList.length === 1) { diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index c9e977ff..d0a043b0 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -24,9 +24,7 @@ module.exports = class eWeLinkLAN { } async getHosts () { - const res = await dns.discover({ - name: '_ewelink._tcp.local' - }) + const res = await dns.discover({ name: '_ewelink._tcp.local' }) res.forEach(device => { let d const deviceId = device.fqdn.replace('._ewelink._tcp.local', '').replace('eWeLink_', '') @@ -68,16 +66,12 @@ module.exports = class eWeLinkLAN { online: true, ip: packet.address }) - if (this.debug) { - this.log.warn('[%s] updating IP address to [%s].', rdata.id, packet.address) - } + if (this.debug) this.log.warn('[%s] updating IP address to [%s].', rdata.id, packet.address) } try { params = JSON.parse(pText) } catch (e) { - if (this.debug) { - this.log.warn('[%s] An error occured reading the LAN message [%s]', rdata.id, e) - } + if (this.debug) this.log.warn('[%s] An error occured reading the LAN message [%s]', rdata.id, e) return } for (const param in params) { @@ -139,7 +133,6 @@ module.exports = class eWeLinkLAN { } if (this.debugReqRes) { const msg = JSON.stringify(json, null, 2) - .replace(json.apikey, '**hidden**') .replace(json.apikey, '**hidden**') .replace(json.deviceid, '**hidden**') this.log.warn('LAN message sent. This text is yellow for clarity.\n%s', msg) diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index baba2465..4a6ef090 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -16,7 +16,6 @@ module.exports = class eWeLinkWS { this.apiKey = res.apiKey this.wsIsOpen = false this.emitter = new EventEmitter() - this.delaySend = 0 } async getHost () { @@ -39,16 +38,12 @@ module.exports = class eWeLinkWS { if (!body.domain) { throw new Error('Server did not respond with a web socket host.') } - if (this.debug) { - this.log('Web socket host received [%s].', body.domain) - } + if (this.debug) this.log('Web socket host received [%s].', body.domain) this.wsHost = body.domain return body.domain } catch (err) { if (Object.prototype.hasOwnProperty.call(err, 'code') && cns.httpRetryCodes.includes(err.code)) { - if (this.debug) { - this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') - } + if (this.debug) this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') await utils.sleep(30000) return this.getDevices() } else { @@ -59,16 +54,12 @@ module.exports = class eWeLinkWS { login () { this.wsp = new WSP('wss://' + this.wsHost + ':8080/api/ws', { - createWebSocket: (url) => new WS(url), - extractMessageData: (event) => event, - attachRequestId: (data, requestId) => Object.assign({ - sequence: requestId - }, data), - extractRequestId: (data) => data && data.sequence, - packMessage: (data) => JSON.stringify(data), - unpackMessage: (data) => { - return data === 'pong' ? data : JSON.parse(data) - } + createWebSocket: url => new WS(url), + extractMessageData: event => event, + attachRequestId: (data, requestId) => Object.assign({ sequence: requestId }, data), + extractRequestId: data => data && data.sequence, + packMessage: data => JSON.stringify(data), + unpackMessage: data => data === 'pong' ? data : JSON.parse(data) }) this.wsp.open() this.wsp.onOpen.addListener(async () => { @@ -92,9 +83,7 @@ module.exports = class eWeLinkWS { this.log('Sending WS login request.') } try { - const res = await this.wsp.sendRequest(payload, { - requestId: sequence - }) + const res = await this.wsp.sendRequest(payload, { requestId: sequence }) if (Object.prototype.hasOwnProperty.call(res, 'config') && res.config.hb && res.config.hbInterval && !this.hbInterval) { this.hbInterval = setInterval(() => { this.wsp.send('ping') @@ -157,9 +146,7 @@ module.exports = class eWeLinkWS { } else if (Object.prototype.hasOwnProperty.call(device, 'error') && device.error === 0) { // *** Safe to ignore these messages *** \\ } else { - if (this.debug) { - this.log.warn('WS unknown command received.\n' + JSON.stringify(device, null, 2)) - } + if (this.debug) this.log.warn('WS unknown command received.\n' + JSON.stringify(device, null, 2)) } }) this.wsp.onClose.addListener(async e => { @@ -212,9 +199,7 @@ module.exports = class eWeLinkWS { } else if (this.debug) { this.log('WS message sent.') } - const device = await this.wsp.sendRequest(jsonToSend, { - requestId: sequence - }) + const device = await this.wsp.sendRequest(jsonToSend, { requestId: sequence }) device.error = Object.prototype.hasOwnProperty.call(device, 'error') ? device.error : 504 switch (device.error) { case 0: @@ -249,15 +234,15 @@ module.exports = class eWeLinkWS { if (this.wsp && this.wsIsOpen) { this.wsp.send(JSON.stringify(json)) if (this.debugReqRes) { - const msg = JSON.stringify(json, null, 2).replace(json.apikey, '**hidden**').replace(json.apiKey, '**hidden**').replace(json.deviceid, '**hidden**') + const msg = JSON.stringify(json, null, 2) + .replace(json.apiKey, '**hidden**') + .replace(json.deviceid, '**hidden**') this.log.warn('WS message sent. This text is yellow for clarity.\n%s', msg) } else if (this.debug) { this.log('WS message sent.') } } else { - if (this.debug) { - this.log.warn('Command will be resent when WS is reconnected.') - } + if (this.debug) this.log.warn('Command will be resent when WS is reconnected.') await utils.sleep(30000) return this.requestUpdate(accessory) } From 7fab41c20f2a15601b0aa3146a6cef2228fe6ee5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 09:19:12 +0100 Subject: [PATCH 0366/3183] delay fan speed request --- lib/device/fan.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index 3c97c192..54192e8a 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -42,7 +42,7 @@ module.exports = class deviceFan { newPower = value >= 33 ? 1 : 0 newSpeed = value newLight = lightService.getCharacteristic(Characteristic.On).value - await utils.sleep(500) + await utils.sleep(1000) break case 'light': newPower = fanService.getCharacteristic(Characteristic.Active).value From 4eb237360cc91e4a430542076257ff55d6b53909 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 09:19:56 +0100 Subject: [PATCH 0367/3183] 3.4.0-5 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index cfd33573..9b45a1df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-4", + "version": "3.4.0-5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 8f3d1938..654264ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-4", + "version": "3.4.0-5", "author": "bwp91", "contributors": [ "gbro115", From 662c5588dc5951d10c7591590f9a3c70b208861b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 09:47:22 +0100 Subject: [PATCH 0368/3183] disable ifan lan mode --- lib/constants.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/constants.js b/lib/constants.js index 5596f43f..fa7a1e88 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -5,7 +5,7 @@ module.exports = { httpRetryCodes: ['ENOTFOUND', 'ETIMEDOUT', 'EAI_AGAIN'], allowedGroups: ['blind', 'garage', 'garage_eachen', 'lock', 'valve'], devicesHideable: ['switch', 'light'], - devicesNonLAN: [22, 28, 59, 102], + devicesNonLAN: [22, 28, 34, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], devicesSingleSwitchLight: ['T1 1C', 'L1', 'B1', 'B1_R2', 'TX1C', 'D1', 'D1R1', 'KING-M4', 'Slampher', 'GTTA59'], From 522b9df1e35a4ccd58ed0a62946a33dd5aa9ba12 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 09:47:30 +0100 Subject: [PATCH 0369/3183] delay to power not speed --- lib/device/fan.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index 54192e8a..7ce45545 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -37,12 +37,12 @@ module.exports = class deviceFan { newPower = value newSpeed = value ? 33 : 0 newLight = lightService.getCharacteristic(Characteristic.On).value + await utils.sleep(500) break case 'speed': newPower = value >= 33 ? 1 : 0 newSpeed = value newLight = lightService.getCharacteristic(Characteristic.On).value - await utils.sleep(1000) break case 'light': newPower = fanService.getCharacteristic(Characteristic.Active).value From 7cf7a8577a27a1ab0ab8af226f50406b567590ef Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 09:48:31 +0100 Subject: [PATCH 0370/3183] 3.4.0-6 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9b45a1df..c5cd0baa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-5", + "version": "3.4.0-6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 654264ab..69e4604b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-5", + "version": "3.4.0-6", "author": "bwp91", "contributors": [ "gbro115", From 4469086379ea412d20724a89bcaad5a31297144d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 10:00:59 +0100 Subject: [PATCH 0371/3183] skip lan for non supported --- lib/eWeLink.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index ba0235a8..89c4a133 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -514,7 +514,12 @@ class eWeLink { deviceid: accessory.context.eweDeviceId, params } - const res = await this.lanClient.sendUpdate(payload) + let res + if (cns.devicesNonLAN.includes(accessory.context.eweUIID)) { + res = "device doesn't support LAN mode" + } else { + res = await this.lanClient.sendUpdate(payload) + } if (res !== 'ok') { if (accessory.context.reachableWAN) { if (this.debug) { From b4b5b79311b3f7a1106817a652f22df3a9281b37 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 10:01:09 +0100 Subject: [PATCH 0372/3183] ignore lan update --- lib/device/fan.js | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index 7ce45545..6c11ee32 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -66,13 +66,12 @@ module.exports = class deviceFan { async externalUpdate (accessory, params) { try { - let light - let status - let speed - const lightService = accessory.getService(Service.Lightbulb) - const fanService = accessory.getService(Service.Fanv2) - if (Array.isArray(params.switches)) { - light = params.switches[0].switch === 'on' + if (params.switches && Array.isArray(params.switches)) { + const lightService = accessory.getService(Service.Lightbulb) + const fanService = accessory.getService(Service.Fanv2) + const light = params.switches[0].switch === 'on' + let status + let speed switch (params.switches[1].switch + params.switches[2].switch + params.switches[3].switch) { default: status = 0 @@ -90,17 +89,11 @@ module.exports = class deviceFan { status = 1 speed = 99 } - } else if (Object.prototype.hasOwnProperty.call(params, 'light') && Object.prototype.hasOwnProperty.call(params, 'fan') && Object.prototype.hasOwnProperty.call(params, 'speed')) { - light = params.light === 'on' - status = params.fan === 'on' ? 1 : 0 - speed = params.speed * 33 * status - } else { - return + lightService.updateCharacteristic(Characteristic.On, light) + fanService + .updateCharacteristic(Characteristic.Active, status) + .updateCharacteristic(Characteristic.RotationSpeed, speed) } - lightService.updateCharacteristic(Characteristic.On, light) - fanService - .updateCharacteristic(Characteristic.Active, status) - .updateCharacteristic(Characteristic.RotationSpeed, speed) } catch (err) { this.platform.deviceUpdateError(accessory, err, false) } From 9c70f754f58876e00292ac0d860a20c61312f688 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 10:01:43 +0100 Subject: [PATCH 0373/3183] 3.4.0-7 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index c5cd0baa..48dda852 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-6", + "version": "3.4.0-7", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 69e4604b..f7f18159 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-6", + "version": "3.4.0-7", "author": "bwp91", "contributors": [ "gbro115", From 727bd76602625b9754bbc978aeeb121e7031a0f8 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 10:05:31 +0100 Subject: [PATCH 0374/3183] Update fan.js --- lib/device/fan.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index 6c11ee32..cbe2dc77 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -37,12 +37,12 @@ module.exports = class deviceFan { newPower = value newSpeed = value ? 33 : 0 newLight = lightService.getCharacteristic(Characteristic.On).value - await utils.sleep(500) break case 'speed': newPower = value >= 33 ? 1 : 0 newSpeed = value newLight = lightService.getCharacteristic(Characteristic.On).value + await utils.sleep(500) break case 'light': newPower = fanService.getCharacteristic(Characteristic.Active).value From e352372812baa0cf15397375a901eb53c94ef86f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 10:06:07 +0100 Subject: [PATCH 0375/3183] 3.4.0-8 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 48dda852..848def5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-7", + "version": "3.4.0-8", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f7f18159..8a30734b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-7", + "version": "3.4.0-8", "author": "bwp91", "contributors": [ "gbro115", From 71ff7a89bfc339e497f949f1023fa9f72ec68494 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 10:23:35 +0100 Subject: [PATCH 0376/3183] debug fan --- lib/device/fan.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/device/fan.js b/lib/device/fan.js index cbe2dc77..d5b87fc1 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -59,6 +59,14 @@ module.exports = class deviceFan { fanService .updateCharacteristic(Characteristic.Active, newPower) .updateCharacteristic(Characteristic.RotationSpeed, newSpeed) + this.platform.log.error('**********************************************') + this.platform.log.error( + 'INTERNAL FAN UPDATE: light [%s] power [%s] speed [%s%]', + newLight ? 'on' : 'off', + newPower ? 'on' : 'off', + newSpeed + ) + this.platform.log.error('**********************************************') } catch (err) { this.platform.deviceUpdateError(accessory, err, true) } @@ -93,6 +101,15 @@ module.exports = class deviceFan { fanService .updateCharacteristic(Characteristic.Active, status) .updateCharacteristic(Characteristic.RotationSpeed, speed) + + this.platform.log.error('**********************************************') + this.platform.log.error( + 'EXTERNAL FAN UPDATE: light [%s] power [%s] speed [%s%]', + light ? 'on' : 'off', + status ? 'on' : 'off', + speed + ) + this.platform.log.error('**********************************************') } } catch (err) { this.platform.deviceUpdateError(accessory, err, false) From 45df959c4254606fb29ba977e6c9a80c1e05a3f5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 10:23:44 +0100 Subject: [PATCH 0377/3183] remove fan lan params --- lib/constants.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/constants.js b/lib/constants.js index fa7a1e88..5418c20d 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -28,14 +28,13 @@ module.exports = { 'battery', 'bright', 'brightness', 'channel', 'cmd', 'colorB', 'colorG', 'colorR', 'current', 'currentHumidity', - 'currentTemperature', 'fan', 'humidity', - 'key', 'light', 'lock', 'mainSwitch', - 'mode', 'motion', 'online', 'power', - 'rfChl', 'rfList', 'rfTrig', - 'sensorType', 'setclose', 'speed', - 'state', 'switch', 'switches', - 'temperature', 'trigTime', 'type', - 'voltage', 'zyx_mode' + 'currentTemperature', 'humidity', + 'key', 'lock', 'mainSwitch', 'mode', + 'motion', 'online', 'power', 'rfChl', + 'rfList', 'rfTrig', 'sensorType', + 'setclose', 'state', 'switch', + 'switches', 'temperature', 'trigTime', + 'type', 'voltage', 'zyx_mode' ], defaultMultiSwitchOff: [{ switch: 'off', From a719e3d93b2614c58da9657fdf6ad6d3102ceca7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 10:24:44 +0100 Subject: [PATCH 0378/3183] 3.4.0-9 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 848def5f..b413d338 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-8", + "version": "3.4.0-9", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 8a30734b..0bf49a57 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-8", + "version": "3.4.0-9", "author": "bwp91", "contributors": [ "gbro115", From 79a3058553ac1a0714afc27721f97b632bc5efe7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 11:04:01 +0100 Subject: [PATCH 0379/3183] Update fan.js --- lib/device/fan.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index d5b87fc1..3e12cc04 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -11,7 +11,7 @@ module.exports = class deviceFan { const fanLightService = accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb) fanService .getCharacteristic(Characteristic.Active) - .on('set', (value, callback) => this.internalUpdate(accessory, 'power', value, callback)) + .on('set', (value, callback) => callback()) fanService .getCharacteristic(Characteristic.RotationSpeed) .on('set', (value, callback) => this.internalUpdate(accessory, 'speed', value, callback)) @@ -33,16 +33,10 @@ module.exports = class deviceFan { const fanService = accessory.getService(Service.Fanv2) const params = { switches: cns.defaultMultiSwitchOff } switch (type) { - case 'power': - newPower = value - newSpeed = value ? 33 : 0 - newLight = lightService.getCharacteristic(Characteristic.On).value - break case 'speed': newPower = value >= 33 ? 1 : 0 newSpeed = value newLight = lightService.getCharacteristic(Characteristic.On).value - await utils.sleep(500) break case 'light': newPower = fanService.getCharacteristic(Characteristic.Active).value @@ -54,12 +48,13 @@ module.exports = class deviceFan { params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? 'on' : 'off' params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? 'on' : 'off' params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? 'on' : 'off' - await this.platform.sendDeviceUpdate(accessory, params) + lightService.updateCharacteristic(Characteristic.On, newLight) fanService .updateCharacteristic(Characteristic.Active, newPower) .updateCharacteristic(Characteristic.RotationSpeed, newSpeed) this.platform.log.error('**********************************************') + this.platform.log.error('updating %s characteristic', type) this.platform.log.error( 'INTERNAL FAN UPDATE: light [%s] power [%s] speed [%s%]', newLight ? 'on' : 'off', @@ -67,6 +62,7 @@ module.exports = class deviceFan { newSpeed ) this.platform.log.error('**********************************************') + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { this.platform.deviceUpdateError(accessory, err, true) } From 767d00c29ffd880622d35583dbf3be23a5d5d90e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 11:05:34 +0100 Subject: [PATCH 0380/3183] 3.4.0-10 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index b413d338..2d5bc597 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-9", + "version": "3.4.0-10", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 0bf49a57..9c647b74 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-9", + "version": "3.4.0-10", "author": "bwp91", "contributors": [ "gbro115", From ec916dc98d2d891e424b2d06418a379638cd665a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 11:33:39 +0100 Subject: [PATCH 0381/3183] Update fan.js --- lib/device/fan.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index 3e12cc04..80c56311 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -11,7 +11,13 @@ module.exports = class deviceFan { const fanLightService = accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb) fanService .getCharacteristic(Characteristic.Active) - .on('set', (value, callback) => callback()) + .on('set', async (value, callback) => { + callback() + if (value === 0) { + await utils.sleep(500) + fanService.setCharacteristic(Characteristic.RotationSpeed, 0) + } + }) fanService .getCharacteristic(Characteristic.RotationSpeed) .on('set', (value, callback) => this.internalUpdate(accessory, 'speed', value, callback)) From 2b987ae3b146dd09b5f750832fca2c4553d49a90 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 11:34:36 +0100 Subject: [PATCH 0382/3183] 3.4.0-11 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2d5bc597..7def0a7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-10", + "version": "3.4.0-11", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 9c647b74..4c0894c7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-10", + "version": "3.4.0-11", "author": "bwp91", "contributors": [ "gbro115", From 5ccc96f0d2f59cc0d94f117579309326b5af97bb Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 12:58:29 +0100 Subject: [PATCH 0383/3183] new utils function --- lib/device/blind.js | 2 +- lib/device/curtain.js | 3 ++- lib/device/fan.js | 2 +- lib/device/garage-eachen.js | 2 +- lib/device/garage.js | 2 +- lib/device/light.js | 18 +++++++++--------- lib/device/lock.js | 2 +- lib/device/outlet.js | 9 +++++---- lib/device/rf-bridge.js | 14 +++++++------- lib/device/scm.js | 3 ++- lib/device/sensor.js | 4 ++-- lib/device/switch.js | 5 +++-- lib/device/thermostat.js | 11 ++++++----- lib/device/usb.js | 3 ++- lib/device/valve.js | 3 ++- lib/device/zb-dev.js | 17 +++++++++-------- lib/utils.js | 3 +++ 17 files changed, 57 insertions(+), 46 deletions(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index 3259d21a..06e88c34 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -81,6 +81,6 @@ module.exports = class deviceBlind { } async externalUpdate (accessory, params) { - return true + return } } diff --git a/lib/device/curtain.js b/lib/device/curtain.js index 2f5f7c6c..6e16002c 100644 --- a/lib/device/curtain.js +++ b/lib/device/curtain.js @@ -1,5 +1,6 @@ 'use strict' let Characteristic, Service +const utils = require('./../utils') module.exports = class deviceCurtain { constructor (platform, accessory) { this.platform = platform @@ -49,7 +50,7 @@ module.exports = class deviceCurtain { async externalUpdate (accessory, params) { try { const cService = accessory.getService(Service.WindowCovering) - if (!Object.prototype.hasOwnProperty.call(params, 'switch') && !Object.prototype.hasOwnProperty.call(params, 'setclose')) { + if (!utils.hasProperty(params, 'switch') && !utils.hasProperty(params, 'setclose')) { return } const newPos = Math.abs(100 - parseInt(params.setclose)) diff --git a/lib/device/fan.js b/lib/device/fan.js index 80c56311..b3f35499 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -54,7 +54,7 @@ module.exports = class deviceFan { params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? 'on' : 'off' params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? 'on' : 'off' params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? 'on' : 'off' - + lightService.updateCharacteristic(Characteristic.On, newLight) fanService .updateCharacteristic(Characteristic.Active, newPower) diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 584319c2..1551541d 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -52,7 +52,7 @@ module.exports = class deviceGarageEachen { async externalUpdate (accessory, params) { try { - if (!Object.prototype.hasOwnProperty.call(params, 'switch') || accessory.context.inUse) { + if (!utils.hasProperty(params, 'switch') || accessory.context.inUse) { return } let garageConfig diff --git a/lib/device/garage.js b/lib/device/garage.js index 5341153c..d4f6a46c 100644 --- a/lib/device/garage.js +++ b/lib/device/garage.js @@ -86,7 +86,7 @@ module.exports = class deviceGarage { async externalUpdate (accessory, params) { try { - if (!Object.prototype.hasOwnProperty.call(params, 'switch') && !Object.prototype.hasOwnProperty.call(params, 'switches')) { + if (!utils.hasProperty(params, 'switch') && !utils.hasProperty(params, 'switches')) { return } let garageConfig diff --git a/lib/device/light.js b/lib/device/light.js index 066b0daf..6ee8f58b 100644 --- a/lib/device/light.js +++ b/lib/device/light.js @@ -216,9 +216,9 @@ module.exports = class deviceLight { let mode let isOn = false const lightService = accessory.getService(Service.Lightbulb) - if (accessory.context.eweUIID === 22 && Object.prototype.hasOwnProperty.call(params, 'state')) { + if (accessory.context.eweUIID === 22 && utils.hasProperty(params, 'state')) { isOn = params.state === 'on' - } else if (accessory.context.eweUIID !== 22 && Object.prototype.hasOwnProperty.call(params, 'switch')) { + } else if (accessory.context.eweUIID !== 22 && utils.hasProperty(params, 'switch')) { isOn = params.switch === 'on' } else { isOn = lightService.getCharacteristic(Characteristic.On).value @@ -227,20 +227,20 @@ module.exports = class deviceLight { lightService.updateCharacteristic(Characteristic.On, true) switch (accessory.context.eweUIID) { case 36: // KING-M4 - if (Object.prototype.hasOwnProperty.call(params, 'bright')) { + if (utils.hasProperty(params, 'bright')) { const nb = Math.round(((params.bright - 10) * 10) / 9) // eWeLink scale is 10-100 and HomeKit scale is 0-100. lightService.updateCharacteristic(Characteristic.Brightness, nb) } break case 44: // D1 - if (Object.prototype.hasOwnProperty.call(params, 'brightness')) { + if (utils.hasProperty(params, 'brightness')) { lightService.updateCharacteristic(Characteristic.Brightness, params.brightness) } break case 22: // B1 - if (Object.prototype.hasOwnProperty.call(params, 'zyx_mode')) { + if (utils.hasProperty(params, 'zyx_mode')) { mode = parseInt(params.zyx_mode) - } else if (Object.prototype.hasOwnProperty.call(params, 'channel0') && parseInt(params.channel0) + parseInt(params.channel1) > 0) { + } else if (utils.hasProperty(params, 'channel0') && parseInt(params.channel0) + parseInt(params.channel1) > 0) { mode = 1 } else { mode = 2 @@ -261,10 +261,10 @@ module.exports = class deviceLight { } break case 59: // L1 - if (Object.prototype.hasOwnProperty.call(params, 'bright')) { + if (utils.hasProperty(params, 'bright')) { lightService.updateCharacteristic(Characteristic.Brightness, params.bright) } - if (Object.prototype.hasOwnProperty.call(params, 'colorR')) { + if (utils.hasProperty(params, 'colorR')) { newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB) lightService .updateCharacteristic(Characteristic.Hue, newColour[0]) @@ -281,7 +281,7 @@ module.exports = class deviceLight { cns.devicesMultiSwitch.includes(accessory.context.eweUIID) && cns.devicesMultiSwitchLight.includes(accessory.context.eweModel) ) { - if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return + if (!utils.hasProperty(params, 'switches')) return const idToCheck = accessory.context.hbDeviceId.slice(0, -1) let primaryState = false for (let i = 1; i <= accessory.context.channelCount; i++) { diff --git a/lib/device/lock.js b/lib/device/lock.js index 6996f00b..eed6ef29 100644 --- a/lib/device/lock.js +++ b/lib/device/lock.js @@ -43,7 +43,7 @@ module.exports = class deviceLock { async externalUpdate (accessory, params) { try { - if (!Object.prototype.hasOwnProperty.call(params, 'switch')) return + if (!utils.hasProperty(params, 'switch')) return let lockConfig const lmService = accessory.getService(Service.LockMechanism) if (!(lockConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { diff --git a/lib/device/outlet.js b/lib/device/outlet.js index fe05aebe..ae2a1419 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -4,6 +4,7 @@ const cns = require('./../constants') const corrInterval = require('correcting-interval') const fakegato = require('fakegato-history') const hbLib = require('homebridge-lib') +const utils = require('./../utils') module.exports = class deviceOutlet { constructor (platform, accessory) { this.platform = platform @@ -125,13 +126,13 @@ module.exports = class deviceOutlet { async externalUpdate (accessory, params) { try { const outletService = accessory.getService(Service.Outlet) - if (Object.prototype.hasOwnProperty.call(params, 'switch')) { + if (utils.hasProperty(params, 'switch')) { outletService.updateCharacteristic(Characteristic.On, params.switch === 'on') if (cns.devicesSingleSwitchOutlet.includes(accessory.context.eweModel) || this.platform.config.disableEveLogging) { outletService.updateCharacteristic(Characteristic.OutletInUse, params.switch === 'on') } } - if (Object.prototype.hasOwnProperty.call(params, 'power')) { + if (utils.hasProperty(params, 'power')) { outletService.updateCharacteristic(EveService.Characteristics.CurrentConsumption, parseFloat(params.power)) if (!cns.devicesSingleSwitchOutlet.includes(accessory.context.eweModel) && !this.platform.config.disableEveLogging) { outletService.updateCharacteristic( @@ -145,10 +146,10 @@ module.exports = class deviceOutlet { }) } } - if (Object.prototype.hasOwnProperty.call(params, 'voltage')) { + if (utils.hasProperty(params, 'voltage')) { outletService.updateCharacteristic(EveService.Characteristics.Voltage, parseFloat(params.voltage)) } - if (Object.prototype.hasOwnProperty.call(params, 'current')) { + if (utils.hasProperty(params, 'current')) { outletService.updateCharacteristic(EveService.Characteristics.ElectricCurrent, parseFloat(params.current)) } } catch (err) { diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index a791b1ef..d1072925 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -61,15 +61,15 @@ module.exports = class deviceRFBridge { async externalUpdate (accessory, params) { try { - if (!Object.prototype.hasOwnProperty.call(params, 'updateSource')) return + if (!utils.hasProperty(params, 'updateSource')) return const timeNow = new Date() let oAccessory = false - if (Object.prototype.hasOwnProperty.call(params, 'cmd') && params.cmd === 'transmit' && Object.prototype.hasOwnProperty.call(params, 'rfChl')) { + if (utils.hasProperty(params, 'cmd') && params.cmd === 'transmit' && utils.hasProperty(params, 'rfChl')) { this.platform.devicesInHB.forEach(acc => { if ( acc.context.eweDeviceId === accessory.context.eweDeviceId && - Object.prototype.hasOwnProperty.call(acc.context, 'buttons') && - Object.prototype.hasOwnProperty.call(acc.context.buttons, params.rfChl.toString()) + utils.hasProperty(acc.context, 'buttons') && + utils.hasProperty(acc.context.buttons, params.rfChl.toString()) ) { oAccessory = acc } @@ -86,7 +86,7 @@ module.exports = class deviceRFBridge { } else { throw new Error('rf button not found in Homebridge') } - } else if (Object.prototype.hasOwnProperty.call(params, 'cmd') && params.cmd === 'trigger') { + } else if (utils.hasProperty(params, 'cmd') && params.cmd === 'trigger') { //* ** RF Sensor ***\\ Object.keys(params) .filter(name => /rfTrig/.test(name)) @@ -94,8 +94,8 @@ module.exports = class deviceRFBridge { this.platform.devicesInHB.forEach(acc => { if ( acc.context.eweDeviceId === accessory.context.eweDeviceId && - Object.prototype.hasOwnProperty.call(acc.context, 'buttons') && - Object.prototype.hasOwnProperty.call(acc.context.buttons, chan.substr(-1).toString()) + utils.hasProperty(acc.context, 'buttons') && + utils.hasProperty(acc.context.buttons, chan.substr(-1).toString()) ) { oAccessory = acc } diff --git a/lib/device/scm.js b/lib/device/scm.js index 8c62b37f..8f22a3e2 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -1,6 +1,7 @@ 'use strict' let Characteristic, Service const cns = require('./../constants') +const utils = require('./../utils') module.exports = class deviceSCM { constructor (platform, accessory) { this.platform = platform @@ -29,7 +30,7 @@ module.exports = class deviceSCM { async externalUpdate (accessory, params) { try { - if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return + if (!utils.hasProperty(params, 'switches')) return accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switches[0].switch === 'on') } catch (err) { this.platform.deviceUpdateError(accessory, err, false) diff --git a/lib/device/sensor.js b/lib/device/sensor.js index dac9afc2..f8eb9c6e 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -12,7 +12,7 @@ module.exports = class deviceSensor { async externalUpdate (accessory, params) { try { - if (Object.prototype.hasOwnProperty.call(params, 'battery')) { + if (utils.hasProperty(params, 'battery')) { const batteryService = accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService) const scaledBattery = Math.round(params.battery * 33.3) @@ -22,7 +22,7 @@ module.exports = class deviceSensor { scaledBattery < (this.platform.config.lowBattThreshold || 25) ) } - if (!Object.prototype.hasOwnProperty.call(params, 'switch')) return + if (!utils.hasProperty(params, 'switch')) return const newState = params.switch === 'on' ? 1 : 0 let oAccessory = false const contactService = accessory.getService(Service.ContactSensor) diff --git a/lib/device/switch.js b/lib/device/switch.js index 97ee0293..ceb5f110 100644 --- a/lib/device/switch.js +++ b/lib/device/switch.js @@ -1,6 +1,7 @@ 'use strict' let Characteristic, Service const cns = require('./../constants') +const utils = require('./../utils') module.exports = class deviceSwitch { constructor (platform, accessory) { this.platform = platform @@ -89,10 +90,10 @@ module.exports = class deviceSwitch { async externalUpdate (accessory, params) { try { if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID)) { - if (!Object.prototype.hasOwnProperty.call(params, 'switch')) return + if (!utils.hasProperty(params, 'switch')) return accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switch === 'on') } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID)) { - if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return + if (!utils.hasProperty(params, 'switches')) return const idToCheck = accessory.context.hbDeviceId.slice(0, -1) let primaryState = false for (let i = 1; i <= accessory.context.channelCount; i++) { diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index 5fd997ac..934314a8 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -2,6 +2,7 @@ let Characteristic, EveHistoryService, Service const corrInterval = require('correcting-interval') const fakegato = require('fakegato-history') +const utils = require('./../utils') module.exports = class deviceThermostat { constructor (platform, accessory) { this.platform = platform @@ -58,23 +59,23 @@ module.exports = class deviceThermostat { try { if ( !this.platform.config.hideTHSwitch && - (Object.prototype.hasOwnProperty.call(params, 'switch') || Object.prototype.hasOwnProperty.call(params, 'mainSwitch')) + (utils.hasProperty(params, 'switch') || utils.hasProperty(params, 'mainSwitch')) ) { - const newState = Object.prototype.hasOwnProperty.call(params, 'switch') ? params.switch === 'on' : params.mainSwitch === 'on' + const newState = utils.hasProperty(params, 'switch') ? params.switch === 'on' : params.mainSwitch === 'on' const switchService = accessory.getService(Service.Switch) switchService.updateCharacteristic(Characteristic.On, newState) } const eveLog = { time: Date.now() } - if (Object.prototype.hasOwnProperty.call(params, 'currentTemperature') && accessory.getService(Service.TemperatureSensor)) { + if (utils.hasProperty(params, 'currentTemperature') && accessory.getService(Service.TemperatureSensor)) { const currentTemp = parseFloat(params.currentTemperature !== 'unavailable' ? params.currentTemperature : 0) accessory .getService(Service.TemperatureSensor) .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp) eveLog.temp = currentTemp } - if (Object.prototype.hasOwnProperty.call(params, 'currentHumidity') && accessory.getService(Service.HumiditySensor)) { + if (utils.hasProperty(params, 'currentHumidity') && accessory.getService(Service.HumiditySensor)) { const currentHumi = parseFloat(params.currentHumidity !== 'unavailable' ? params.currentHumidity : 0) accessory .getService(Service.HumiditySensor) @@ -82,7 +83,7 @@ module.exports = class deviceThermostat { eveLog.humidity = currentHumi } if (!this.platform.config.disableEveLogging) { - if (Object.prototype.hasOwnProperty.call(eveLog, 'temp') || Object.prototype.hasOwnProperty.call(eveLog, 'humidity')) { + if (utils.hasProperty(eveLog, 'temp') || utils.hasProperty(eveLog, 'humidity')) { accessory.eveLogger.addEntry(eveLog) } } diff --git a/lib/device/usb.js b/lib/device/usb.js index 6c230010..eda32d7c 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -1,6 +1,7 @@ 'use strict' let Characteristic, Service const cns = require('./../constants') +const utils = require('./../utils') module.exports = class deviceUSB { constructor (platform, accessory) { this.platform = platform @@ -29,7 +30,7 @@ module.exports = class deviceUSB { async externalUpdate (accessory, params) { try { - if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return + if (!utils.hasProperty(params, 'switches')) return accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switches[0].switch === 'on') } catch (err) { this.platform.deviceUpdateError(accessory, err, false) diff --git a/lib/device/valve.js b/lib/device/valve.js index 67bf6d30..ee41f284 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -1,5 +1,6 @@ 'use strict' let Characteristic, Service +const utils = require('./../utils') module.exports = class deviceValve { constructor (platform, accessory) { this.platform = platform @@ -87,7 +88,7 @@ module.exports = class deviceValve { async externalUpdate (accessory, params) { try { - if (!Object.prototype.hasOwnProperty.call(params, 'switches')) return + if (!utils.hasProperty(params, 'switches')) return let valveConfig if (!(valveConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index 478544b1..e1ca5434 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -2,6 +2,7 @@ let Characteristic, Service, EveHistoryService const corrInterval = require('correcting-interval') const fakegato = require('fakegato-history') +const utils = require('./../utils') module.exports = class deviceZBDev { constructor (platform, accessory) { this.platform = platform @@ -54,7 +55,7 @@ module.exports = class deviceZBDev { async externalUpdate (accessory, params) { try { //* ** credit @tasict ***\\ - if (Object.prototype.hasOwnProperty.call(params, 'battery')) { + if (utils.hasProperty(params, 'battery')) { if (accessory.context.eweUIID === 3026 && this.platform.config.ZBDWBatt) { params.battery *= 10 } @@ -68,7 +69,7 @@ module.exports = class deviceZBDev { } switch (accessory.context.eweUIID) { case 1000: - if (Object.prototype.hasOwnProperty.call(params, 'key') && [0, 1, 2].includes(params.key)) { + if (utils.hasProperty(params, 'key') && [0, 1, 2].includes(params.key)) { accessory .getService(Service.StatelessProgrammableSwitch) .updateCharacteristic(Characteristic.ProgrammableSwitchEvent, params.key) @@ -78,34 +79,34 @@ module.exports = class deviceZBDev { const eveLog = { time: Date.now() } - if (Object.prototype.hasOwnProperty.call(params, 'temperature')) { + if (utils.hasProperty(params, 'temperature')) { const currentTemp = parseInt(params.temperature) / 100 accessory .getService(Service.TemperatureSensor) .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp) eveLog.temp = parseFloat(currentTemp) } - if (Object.prototype.hasOwnProperty.call(params, 'humidity')) { + if (utils.hasProperty(params, 'humidity')) { const currentHumi = parseInt(params.humidity) / 100 accessory .getService(Service.HumiditySensor) .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi) eveLog.humidity = parseFloat(currentHumi) } - if (Object.prototype.hasOwnProperty.call(eveLog, 'temp') || Object.prototype.hasOwnProperty.call(eveLog, 'humidity')) { + if (utils.hasProperty(eveLog, 'temp') || utils.hasProperty(eveLog, 'humidity')) { accessory.eveLogger.addEntry(eveLog) } break } case 2026: - if (Object.prototype.hasOwnProperty.call(params, 'motion') && Object.prototype.hasOwnProperty.call(params, 'trigTime')) { + if (utils.hasProperty(params, 'motion') && utils.hasProperty(params, 'trigTime')) { const timeNow = new Date() const diff = (timeNow.getTime() - params.trigTime) / 1000 accessory .getService(Service.MotionSensor) .updateCharacteristic( Characteristic.MotionDetected, - Object.prototype.hasOwnProperty.call(params, 'updateSource') && + utils.hasProperty(params, 'updateSource') && params.motion === 1 && diff < (this.platform.config.sensorTimeDifference || 120) ) @@ -113,7 +114,7 @@ module.exports = class deviceZBDev { } break case 3026: - if (Object.prototype.hasOwnProperty.call(params, 'lock') && [0, 1].includes(params.lock)) { + if (utils.hasProperty(params, 'lock') && [0, 1].includes(params.lock)) { accessory .getService(Service.ContactSensor) .updateCharacteristic(Characteristic.ContactSensorState, params.lock) diff --git a/lib/utils.js b/lib/utils.js index bf3698e8..eef849c6 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -2,5 +2,8 @@ module.exports = { sleep: ms => { return new Promise(resolve => setTimeout(resolve, ms)) + }, + hasProperty: (obj, prop) => { + return Object.prototype.hasOwnProperty.call(obj, prop) } } From cd9b5bd1f38ad1da2950d17cd78e155b1dd62b44 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 12:58:42 +0100 Subject: [PATCH 0384/3183] shorter line lengths --- lib/constants.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/constants.js b/lib/constants.js index 5418c20d..3f189523 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -8,7 +8,11 @@ module.exports = { devicesNonLAN: [22, 28, 34, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], - devicesSingleSwitchLight: ['T1 1C', 'L1', 'B1', 'B1_R2', 'TX1C', 'D1', 'D1R1', 'KING-M4', 'Slampher', 'GTTA59'], + devicesSingleSwitchLight: [ + 'T1 1C', 'L1', 'B1', + 'B1_R2', 'TX1C', 'D1', 'D1R1', + 'KING-M4', 'Slampher', 'GTTA59' + ], devicesMultiSwitchLight: ['T1 2C', 'T1 3C', 'TX2C', 'TX3C'], devicesSingleSwitchOutlet: ['Sonoff Pow', 'S20', 'S26', 'S55'], devicesBrightable: [36, 44], From 4a54669d3c677a72bce8b65a353c403f515a1bc2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 12:59:00 +0100 Subject: [PATCH 0385/3183] new utils function --- lib/eWeLink.js | 14 +++++++------- lib/eWeLinkHTTP.js | 30 +++++++++++++++--------------- lib/eWeLinkLAN.js | 27 ++++++++++++++------------- lib/eWeLinkWS.js | 18 +++++++++--------- 4 files changed, 45 insertions(+), 44 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 89c4a133..b7ce7233 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -63,13 +63,13 @@ class eWeLink { (() => { if (Object.keys(this.config.groups || []).length > 0) { this.config.groups - .filter(g => Object.prototype.hasOwnProperty.call(g, 'type') && cns.allowedGroups.includes(g.type)) - .filter(g => Object.prototype.hasOwnProperty.call(g, 'deviceId') && this.devicesInEW.has(g.deviceId)) + .filter(g => utils.hasProperty(g, 'type') && cns.allowedGroups.includes(g.type)) + .filter(g => utils.hasProperty(g, 'deviceId') && this.devicesInEW.has(g.deviceId)) .forEach(g => this.cusG.set(g.deviceId + 'SWX', g)) } if (Object.keys(this.config.bridgeSensors || []).length > 0) { this.config.bridgeSensors - .filter(s => Object.prototype.hasOwnProperty.call(s, 'deviceId') && this.devicesInEW.has(s.deviceId)) + .filter(s => utils.hasProperty(s, 'deviceId') && this.devicesInEW.has(s.deviceId)) .forEach(s => this.cusS.set(s.fullDeviceId, s)) } this.log('[%s] eWeLink devices loaded from the Homebridge cache.', this.devicesInHB.size) @@ -340,7 +340,7 @@ class eWeLink { *********************/ let rfChlCounter = 0 const rfMap = [] - if (Object.prototype.hasOwnProperty.call(device, 'tags') && Object.prototype.hasOwnProperty.call(device.tags, 'zyx_info')) { + if (utils.hasProperty(device, 'tags') && utils.hasProperty(device.tags, 'zyx_info')) { device.tags.zyx_info.forEach(remote => rfMap.push({ name: remote.name, @@ -444,7 +444,7 @@ class eWeLink { if (!accessory.context.reachableLAN) { if (cns.devicesNonLAN.includes(device.extra.uiid)) { str += "doesn't support it" - } else if (Object.prototype.hasOwnProperty.call(device, 'sharedBy') && Object.prototype.hasOwnProperty.call(device.sharedBy, 'email')) { + } else if (utils.hasProperty(device, 'sharedBy') && utils.hasProperty(device.sharedBy, 'email')) { str += 'is shared (' + device.sharedBy.email + ')' } else { str += 'is unreachable' @@ -454,7 +454,7 @@ class eWeLink { this.devicesInHB.set(accessory.context.hbDeviceId, accessory) this.log(' → [%s] initialised %s.', device.name, str) } catch (err) { - const deviceName = accessory && Object.prototype.hasOwnProperty.call(accessory, 'displayName') + const deviceName = accessory && utils.hasProperty(accessory, 'displayName') ? accessory.displayName : device.name this.log.warn('[%s] could not be initialised as %s.', deviceName, this.debug ? err : err.message) @@ -471,7 +471,7 @@ class eWeLink { if (['1', '2', '3', '4'].includes(switchNumber) && type !== 'rf_sub') { newDeviceName += ' SW' + switchNumber } - if (Object.prototype.hasOwnProperty.call(this.config.nameOverride || {}, hbDeviceId)) { + if (utils.hasProperty(this.config.nameOverride || {}, hbDeviceId)) { newDeviceName = this.config.nameOverride[hbDeviceId] } try { diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 0026d303..6f46e8cc 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -66,7 +66,7 @@ module.exports = class eWeLinkHTTP { } return this.httpHost } catch (err) { - if (Object.prototype.hasOwnProperty.call(err, 'code') && cns.httpRetryCodes.includes(err.code)) { + if (utils.hasProperty(err, 'code') && cns.httpRetryCodes.includes(err.code)) { if (this.debug) { this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') } @@ -102,10 +102,10 @@ module.exports = class eWeLinkHTTP { }) const body = res.data if ( - Object.prototype.hasOwnProperty.call(body, 'error') && + utils.hasProperty(body, 'error') && body.error === 10004 && - Object.prototype.hasOwnProperty.call(body, 'data') && - Object.prototype.hasOwnProperty.call(body.data, 'region') + utils.hasProperty(body, 'data') && + utils.hasProperty(body.data, 'region') ) { const givenRegion = body.data.region switch (givenRegion) { @@ -159,9 +159,9 @@ module.exports = class eWeLinkHTTP { }) const body = res.data if ( - !Object.prototype.hasOwnProperty.call(body, 'data') || - !Object.prototype.hasOwnProperty.call(body, 'error') || - (Object.prototype.hasOwnProperty.call(body, 'error') && body.error !== 0) + !utils.hasProperty(body, 'data') || + !utils.hasProperty(body, 'error') || + (utils.hasProperty(body, 'error') && body.error !== 0) ) { throw new Error(JSON.stringify(body, null, 2)) } @@ -169,9 +169,9 @@ module.exports = class eWeLinkHTTP { if (body.data.thingList && body.data.thingList.length > 0) { body.data.thingList.forEach(d => { if ( - Object.prototype.hasOwnProperty.call(d, 'itemData') && - Object.prototype.hasOwnProperty.call(d.itemData, 'extra') && - Object.prototype.hasOwnProperty.call(d.itemData.extra, 'uiid') && + utils.hasProperty(d, 'itemData') && + utils.hasProperty(d.itemData, 'extra') && + utils.hasProperty(d.itemData.extra, 'uiid') && !this.hideDevFromHB.includes(d.itemData.deviceid) ) { deviceList.push(d.itemData) @@ -180,7 +180,7 @@ module.exports = class eWeLinkHTTP { } return deviceList } catch (err) { - if (Object.prototype.hasOwnProperty.call(err, 'code') && cns.httpRetryCodes.includes(err.code)) { + if (utils.hasProperty(err, 'code') && cns.httpRetryCodes.includes(err.code)) { if (this.debug) { this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') } @@ -210,9 +210,9 @@ module.exports = class eWeLinkHTTP { }) const body = res.data if ( - !Object.prototype.hasOwnProperty.call(body, 'data') || - !Object.prototype.hasOwnProperty.call(body, 'error') || - (Object.prototype.hasOwnProperty.call(body, 'error') && body.error !== 0) + !utils.hasProperty(body, 'data') || + !utils.hasProperty(body, 'error') || + (utils.hasProperty(body, 'error') && body.error !== 0) ) { throw new Error(JSON.stringify(body, null, 2)) } @@ -222,7 +222,7 @@ module.exports = class eWeLinkHTTP { throw new Error('device not found in eWeLink') } } catch (err) { - if (Object.prototype.hasOwnProperty.call(err, 'code') && cns.httpRetryCodes.includes(err.code)) { + if (utils.hasProperty(err, 'code') && cns.httpRetryCodes.includes(err.code)) { if (this.debug) { this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') } diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index d0a043b0..2982f371 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -4,6 +4,7 @@ const cns = require('./constants') const crypto = require('crypto') const dns = require('node-dns-sd') const EventEmitter = require('events') +const utils = require('./utils') module.exports = class eWeLinkLAN { constructor (config, log, devices) { this.log = log @@ -17,8 +18,8 @@ module.exports = class eWeLinkLAN { devices.forEach(device => { this.deviceMap.set(device.deviceid, { apiKey: device.devicekey, - online: !!Object.prototype.hasOwnProperty.call(this.ipOverrides, device.deviceid), - ip: Object.prototype.hasOwnProperty.call(this.ipOverrides, device.deviceid) ? this.ipOverrides[device.deviceid] : null + online: !!utils.hasProperty(this.ipOverrides, device.deviceid), + ip: utils.hasProperty(this.ipOverrides, device.deviceid) ? this.ipOverrides[device.deviceid] : null }) }) } @@ -29,7 +30,7 @@ module.exports = class eWeLinkLAN { let d const deviceId = device.fqdn.replace('._ewelink._tcp.local', '').replace('eWeLink_', '') if ((d = this.deviceMap.get(deviceId))) { - if (!Object.prototype.hasOwnProperty.call(this.ipOverrides, deviceId)) { + if (!utils.hasProperty(this.ipOverrides, deviceId)) { this.deviceMap.set(deviceId, { apiKey: d.apiKey, online: true, @@ -53,14 +54,14 @@ module.exports = class eWeLinkLAN { const deviceInfo = this.deviceMap.get(rdata.id) const data = rdata.data1 + - (Object.prototype.hasOwnProperty.call(rdata, 'data2') ? rdata.data2 : '') + - (Object.prototype.hasOwnProperty.call(rdata, 'data3') ? rdata.data3 : '') + - (Object.prototype.hasOwnProperty.call(rdata, 'data4') ? rdata.data4 : '') + (utils.hasProperty(rdata, 'data2') ? rdata.data2 : '') + + (utils.hasProperty(rdata, 'data3') ? rdata.data3 : '') + + (utils.hasProperty(rdata, 'data4') ? rdata.data4 : '') const key = crypto.createHash('md5').update(Buffer.from(deviceInfo.apiKey, 'utf8')).digest() const dText = crypto.createDecipheriv('aes-128-cbc', key, Buffer.from(rdata.iv, 'base64')) const pText = Buffer.concat([dText.update(Buffer.from(data, 'base64')), dText.final()]).toString('utf8') let params - if (packet.address !== deviceInfo.ip && !Object.prototype.hasOwnProperty.call(this.ipOverrides, rdata.id)) { + if (packet.address !== deviceInfo.ip && !utils.hasProperty(this.ipOverrides, rdata.id)) { this.deviceMap.set(rdata.id, { apiKey: deviceInfo.apiKey, online: true, @@ -75,7 +76,7 @@ module.exports = class eWeLinkLAN { return } for (const param in params) { - if (Object.prototype.hasOwnProperty.call(params, param)) { + if (utils.hasProperty(params, param)) { if (!cns.paramsToKeep.includes(param.replace(/[0-9]/g, ''))) { delete params[param] } @@ -110,10 +111,10 @@ module.exports = class eWeLinkLAN { let apiKey let suffix const params = {} - if (Object.prototype.hasOwnProperty.call(json.params, 'switches')) { + if (utils.hasProperty(json.params, 'switches')) { params.switches = json.params.switches suffix = 'switches' - } else if (Object.prototype.hasOwnProperty.call(json.params, 'switch')) { + } else if (utils.hasProperty(json.params, 'switch')) { params.switch = json.params.switch suffix = 'switch' } else { @@ -148,7 +149,7 @@ module.exports = class eWeLinkLAN { }, data }) - if (!Object.prototype.hasOwnProperty.call(res.data, 'error') || res.data.error !== 0) { + if (!utils.hasProperty(res.data, 'error') || res.data.error !== 0) { throw new Error(res.data) } return 'ok' @@ -165,8 +166,8 @@ module.exports = class eWeLinkLAN { addDeviceToMap (device) { this.deviceMap.set(device.deviceid, { apiKey: device.devicekey, - online: !!Object.prototype.hasOwnProperty.call(this.ipOverrides, device.deviceid), - ip: Object.prototype.hasOwnProperty.call(this.ipOverrides, device.deviceid) ? this.ipOverrides[device.deviceid] : null + online: !!utils.hasProperty(this.ipOverrides, device.deviceid), + ip: utils.hasProperty(this.ipOverrides, device.deviceid) ? this.ipOverrides[device.deviceid] : null }) } diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 4a6ef090..670317ee 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -42,7 +42,7 @@ module.exports = class eWeLinkWS { this.wsHost = body.domain return body.domain } catch (err) { - if (Object.prototype.hasOwnProperty.call(err, 'code') && cns.httpRetryCodes.includes(err.code)) { + if (utils.hasProperty(err, 'code') && cns.httpRetryCodes.includes(err.code)) { if (this.debug) this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') await utils.sleep(30000) return this.getDevices() @@ -84,7 +84,7 @@ module.exports = class eWeLinkWS { } try { const res = await this.wsp.sendRequest(payload, { requestId: sequence }) - if (Object.prototype.hasOwnProperty.call(res, 'config') && res.config.hb && res.config.hbInterval && !this.hbInterval) { + if (utils.hasProperty(res, 'config') && res.config.hb && res.config.hbInterval && !this.hbInterval) { this.hbInterval = setInterval(() => { this.wsp.send('ping') }, (res.config.hbInterval + 7) * 1000) @@ -98,23 +98,23 @@ module.exports = class eWeLinkWS { this.wsp.onUnpackedMessage.addListener(device => { if (device === 'pong') return let onlineStatus = true - if (!Object.prototype.hasOwnProperty.call(device, 'params')) device.params = {} - if (Object.prototype.hasOwnProperty.call(device, 'deviceid') && Object.prototype.hasOwnProperty.call(device, 'error')) { + if (!utils.hasProperty(device, 'params')) device.params = {} + if (utils.hasProperty(device, 'deviceid') && utils.hasProperty(device, 'error')) { device.action = 'update' onlineStatus = device.error === 0 if (device.error !== 0 && this.debug) { this.log.warn('WS message received.\n%s', JSON.stringify(device, null, 2).replace(this.apiKey, '**hidden**')) } } - if (Object.prototype.hasOwnProperty.call(device, 'action')) { + if (utils.hasProperty(device, 'action')) { switch (device.action) { case 'update': case 'sysmsg': - if (device.action === 'sysmsg' && Object.prototype.hasOwnProperty.call(device.params, 'online')) { + if (device.action === 'sysmsg' && utils.hasProperty(device.params, 'online')) { onlineStatus = device.params.online } for (const param in device.params) { - if (Object.prototype.hasOwnProperty.call(device.params, param)) { + if (utils.hasProperty(device.params, param)) { if (!cns.paramsToKeep.includes(param.replace(/[0-9]/g, ''))) { delete device.params[param] } @@ -143,7 +143,7 @@ module.exports = class eWeLinkWS { this.log.warn('[%s] WS message has unknown action.\n' + JSON.stringify(device, null, 2), device.deviceid) } } - } else if (Object.prototype.hasOwnProperty.call(device, 'error') && device.error === 0) { + } else if (utils.hasProperty(device, 'error') && device.error === 0) { // *** Safe to ignore these messages *** \\ } else { if (this.debug) this.log.warn('WS unknown command received.\n' + JSON.stringify(device, null, 2)) @@ -200,7 +200,7 @@ module.exports = class eWeLinkWS { this.log('WS message sent.') } const device = await this.wsp.sendRequest(jsonToSend, { requestId: sequence }) - device.error = Object.prototype.hasOwnProperty.call(device, 'error') ? device.error : 504 + device.error = utils.hasProperty(device, 'error') ? device.error : 504 switch (device.error) { case 0: return From 72cf1d1ffcfb2637bebf432289d41a2684c52579 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 13:01:52 +0100 Subject: [PATCH 0386/3183] standard js --- lib/device/blind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index 06e88c34..fca991d9 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -81,6 +81,6 @@ module.exports = class deviceBlind { } async externalUpdate (accessory, params) { - return + } } From 9d0ea34c9d3e7f32722e8a3bc0525a667b29ccb7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 13:08:42 +0100 Subject: [PATCH 0387/3183] Update eWeLinkWS.js --- lib/eWeLinkWS.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 670317ee..9a2b5bcb 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -162,7 +162,7 @@ module.exports = class eWeLinkWS { this.log.warn('Web socket will try to reconnect in five seconds.') } await utils.sleep(5000) - await this.login() + return this.login() }) this.wsp.onError.addListener(async e => { this.wsIsOpen = false @@ -176,7 +176,7 @@ module.exports = class eWeLinkWS { this.log.warn('Web socket will try to reconnect in five seconds.') } await utils.sleep(5000) - await this.login() + return this.login() }) } From c48a61398d2f0d8ac9c858f64d3f1262d167a321 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 13:12:25 +0100 Subject: [PATCH 0388/3183] remove extra debugging --- lib/device/fan.js | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index b3f35499..3919cdc3 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -59,15 +59,6 @@ module.exports = class deviceFan { fanService .updateCharacteristic(Characteristic.Active, newPower) .updateCharacteristic(Characteristic.RotationSpeed, newSpeed) - this.platform.log.error('**********************************************') - this.platform.log.error('updating %s characteristic', type) - this.platform.log.error( - 'INTERNAL FAN UPDATE: light [%s] power [%s] speed [%s%]', - newLight ? 'on' : 'off', - newPower ? 'on' : 'off', - newSpeed - ) - this.platform.log.error('**********************************************') await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { this.platform.deviceUpdateError(accessory, err, true) @@ -103,15 +94,6 @@ module.exports = class deviceFan { fanService .updateCharacteristic(Characteristic.Active, status) .updateCharacteristic(Characteristic.RotationSpeed, speed) - - this.platform.log.error('**********************************************') - this.platform.log.error( - 'EXTERNAL FAN UPDATE: light [%s] power [%s] speed [%s%]', - light ? 'on' : 'off', - status ? 'on' : 'off', - speed - ) - this.platform.log.error('**********************************************') } } catch (err) { this.platform.deviceUpdateError(accessory, err, false) From 9aeaa3018305a5f4e0f738ca494493e0edf2751e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 13:18:01 +0100 Subject: [PATCH 0389/3183] 3.4.0-12 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7def0a7e..5def99ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-11", + "version": "3.4.0-12", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 4c0894c7..da59138e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-11", + "version": "3.4.0-12", "author": "bwp91", "contributors": [ "gbro115", From fe02e57c490c1d2852ce4b9fb43072308eb84897 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 13:52:54 +0100 Subject: [PATCH 0390/3183] try: ignore multiple updates --- lib/device/garage-eachen.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 1551541d..0d0c6dc0 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -43,6 +43,7 @@ module.exports = class deviceGarageEachen { await this.platform.sendDeviceUpdate(accessory, params) await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos) + await utils.sleep(2000) accessory.context.inUse = false } catch (err) { accessory.context.inUse = false From 95344cb46007a0089d44867cfadc0d34f3f1ec5c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 13:53:49 +0100 Subject: [PATCH 0391/3183] 3.4.0-13 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5def99ad..91832c12 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-12", + "version": "3.4.0-13", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index da59138e..7f0a4e71 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-12", + "version": "3.4.0-13", "author": "bwp91", "contributors": [ "gbro115", From db01c5b1e7d163a8746bfaac02b71e8a1660dcac Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 6 Oct 2020 22:23:24 +0100 Subject: [PATCH 0392/3183] 3.4.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 91832c12..c48f6a73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-13", + "version": "3.4.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 7f0a4e71..c70f6512 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0-13", + "version": "3.4.0", "author": "bwp91", "contributors": [ "gbro115", From 72122f6649bee36f5d2b322402e6ea08dec02e08 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 7 Oct 2020 08:30:05 +0100 Subject: [PATCH 0393/3183] new disable setting --- lib/eWeLink.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index b7ce7233..c0e172e7 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -48,6 +48,12 @@ class eWeLink { async eWeLinkSetup () { try { + if (this.config.disablePlugin) { + this.devicesInHB.forEach(a => this.removeAccessory(a)) + this.log.warn('******* Not loading homebridge-ewelink *******') + this.log.warn('*** To change this, set doNotLoad to false ***') + return + } this.log('Plugin has finished initialising. Syncing with eWeLink.') this.httpClient = new EWeLinkHTTP(this.config, this.log) await this.httpClient.getHost() From 34f786932e5498611ed1972391911b88d6470536 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 7 Oct 2020 10:23:50 +0100 Subject: [PATCH 0394/3183] hidden channels follow behaviour --- lib/device/light.js | 19 +++++++++---------- lib/device/switch.js | 19 +++++++++---------- lib/eWeLink.js | 42 ++++++++++++++++++++++-------------------- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/lib/device/light.js b/lib/device/light.js index 6ee8f58b..aead63ec 100644 --- a/lib/device/light.js +++ b/lib/device/light.js @@ -73,13 +73,11 @@ module.exports = class deviceLight { params.switches = cns.defaultMultiSwitchOff for (let i = 1; i <= 4; i++) { if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { - i === parseInt(accessory.context.switchNumber) - ? (params.switches[i - 1].switch = value ? 'on' : 'off') - : (params.switches[i - 1].switch = oAccessory - .getService(Service.Lightbulb) - .getCharacteristic(Characteristic.On).value - ? 'on' - : 'off') + if (i === parseInt(accessory.context.switchNumber)) { + params.switches[i - 1].switch = value ? 'on' : 'off' + } else { + params.switches[i - 1].switch = oAccessory.context.cacheOn ? 'on' : 'off' + } } else { params.switches[i - 1].switch = 'off' } @@ -285,14 +283,15 @@ module.exports = class deviceLight { const idToCheck = accessory.context.hbDeviceId.slice(0, -1) let primaryState = false for (let i = 1; i <= accessory.context.channelCount; i++) { + if (params.switches[i - 1].switch === 'on') { + primaryState = true + } if (this.platform.devicesInHB.has(idToCheck + i)) { const oAccessory = this.platform.devicesInHB.get(idToCheck + i) + oAccessory.context.cacheOn = params.switches[i - 1].switch === 'on' oAccessory .getService(Service.Lightbulb) .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === 'on') - if (params.switches[i - 1].switch === 'on') { - primaryState = true - } } } if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { diff --git a/lib/device/switch.js b/lib/device/switch.js index ceb5f110..45e150e9 100644 --- a/lib/device/switch.js +++ b/lib/device/switch.js @@ -37,13 +37,11 @@ module.exports = class deviceSwitch { params.switches = cns.defaultMultiSwitchOff for (let i = 1; i <= 4; i++) { if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { - i === parseInt(accessory.context.switchNumber) - ? (params.switches[i - 1].switch = value ? 'on' : 'off') - : (params.switches[i - 1].switch = oAccessory - .getService(Service.Switch) - .getCharacteristic(Characteristic.On).value - ? 'on' - : 'off') + if (i === parseInt(accessory.context.switchNumber)) { + params.switches[i - 1].switch = value ? 'on' : 'off' + } else { + params.switches[i - 1].switch = oAccessory.context.cacheOn ? 'on' : 'off' + } } else { params.switches[i - 1].switch = 'off' } @@ -97,14 +95,15 @@ module.exports = class deviceSwitch { const idToCheck = accessory.context.hbDeviceId.slice(0, -1) let primaryState = false for (let i = 1; i <= accessory.context.channelCount; i++) { + if (params.switches[i - 1].switch === 'on') { + primaryState = true + } if (this.platform.devicesInHB.has(idToCheck + i)) { const oAccessory = this.platform.devicesInHB.get(idToCheck + i) + oAccessory.context.cacheOn = params.switches[i - 1].switch === 'on' oAccessory .getService(Service.Switch) .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === 'on') - if (params.switches[i - 1].switch === 'on') { - primaryState = true - } } } if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { diff --git a/lib/eWeLink.js b/lib/eWeLink.js index c0e172e7..2a772c5b 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -132,6 +132,7 @@ class eWeLink { initialiseDevice (device) { let accessory + let oAccessory try { if (this.cusG.has(device.deviceid + 'SWX')) { ;['X', '0', '1', '2', '3', '4'].forEach(sw => { @@ -282,18 +283,19 @@ class eWeLink { if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + i)) } + oAccessory = this.addAccessory(device, device.deviceid + 'SW' + i, true) } else { - const oAccessory = this.devicesInHB.has(device.deviceid + 'SW' + i) + oAccessory = this.devicesInHB.has(device.deviceid + 'SW' + i) ? this.devicesInHB.get(device.deviceid + 'SW' + i) : this.addAccessory(device, device.deviceid + 'SW' + i) oAccessory .getService(Service.AccessoryInformation) .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) - oAccessory.context.reachableWAN = device.online - oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false - this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) - oAccessory.control = new DeviceLight(this, oAccessory) } + oAccessory.context.reachableWAN = device.online + oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) + oAccessory.control = new DeviceLight(this, oAccessory) } /********************/ } else if (cns.devicesSingleSwitch.includes(device.extra.uiid)) { @@ -326,18 +328,19 @@ class eWeLink { if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + i)) } + oAccessory = this.addAccessory(device, device.deviceid + 'SW' + i, true) } else { - const oAccessory = this.devicesInHB.has(device.deviceid + 'SW' + i) + oAccessory = this.devicesInHB.has(device.deviceid + 'SW' + i) ? this.devicesInHB.get(device.deviceid + 'SW' + i) : this.addAccessory(device, device.deviceid + 'SW' + i) oAccessory .getService(Service.AccessoryInformation) .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) - oAccessory.context.reachableWAN = device.online - oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false - this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) - oAccessory.control = new DeviceSwitch(this, oAccessory) } + oAccessory.context.reachableWAN = device.online + oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) + oAccessory.control = new DeviceLight(this, oAccessory) } /**********************/ } else if (cns.devicesRFBridge.includes(device.extra.uiid)) { @@ -364,7 +367,6 @@ class eWeLink { this.hiddenMasters.push(device.deviceid) rfMap.forEach(subDevice => { const swNumber = rfChlCounter + 1 - let subAccessory let subType let subExtraContext = {} if (['1', '2', '3', '4'].includes(subDevice.type)) { @@ -381,21 +383,21 @@ class eWeLink { subType, swNumber } - if ((subAccessory = this.devicesInHB.get(device.deviceid + 'SW' + swNumber))) { - if (subAccessory.context.subType !== subType || subAccessory.context.swNumber !== swNumber) { - this.removeAccessory(subAccessory) + if ((oAccessory = this.devicesInHB.get(device.deviceid + 'SW' + swNumber))) { + if (oAccessory.context.subType !== subType || oAccessory.context.swNumber !== swNumber) { + this.removeAccessory(oAccessory) } } - subAccessory = this.devicesInHB.has(device.deviceid + 'SW' + swNumber) + oAccessory = this.devicesInHB.has(device.deviceid + 'SW' + swNumber) ? this.devicesInHB.get(device.deviceid + 'SW' + swNumber) : this.addAccessory(device, device.deviceid + 'SW' + swNumber, false, subExtraContext, 'rf_sub') - subAccessory + oAccessory .getService(Service.AccessoryInformation) .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) - subAccessory.context.reachableWAN = device.online - subAccessory.context.reachableLAN = false - this.devicesInHB.set(subAccessory.context.hbDeviceId, subAccessory) - subAccessory.control = new DeviceRFBridge(this, subAccessory) + oAccessory.context.reachableWAN = device.online + oAccessory.context.reachableLAN = false + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) + oAccessory.control = new DeviceRFBridge(this, oAccessory) rfChlCounter += Object.keys(subDevice.buttons || {}).length }) accessory.context.channelCount = rfChlCounter From e0f2b132abeea0adf3e17a079fdf879db2d7194d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 7 Oct 2020 16:59:03 +0100 Subject: [PATCH 0395/3183] formatting --- lib/eWeLink.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 2a772c5b..a37f8724 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1,5 +1,5 @@ 'use strict' -let Characteristic, Service +let Accessory, Characteristic, Service const cns = require('./constants') const DeviceCurtain = require('./device/curtain') const DeviceBlind = require('./device/blind') @@ -50,8 +50,8 @@ class eWeLink { try { if (this.config.disablePlugin) { this.devicesInHB.forEach(a => this.removeAccessory(a)) - this.log.warn('******* Not loading homebridge-ewelink *******') - this.log.warn('*** To change this, set doNotLoad to false ***') + this.log.warn('********* Not loading homebridge-ewelink *********') + this.log.warn('*** To change this, set disablePlugin to false ***') return } this.log('Plugin has finished initialising. Syncing with eWeLink.') @@ -465,7 +465,7 @@ class eWeLink { const deviceName = accessory && utils.hasProperty(accessory, 'displayName') ? accessory.displayName : device.name - this.log.warn('[%s] could not be initialised as %s.', deviceName, this.debug ? err : err.message) + this.log.warn(' → [%s] could not be initialised as %s.', deviceName, this.debug ? err : err.message) } } @@ -483,7 +483,7 @@ class eWeLink { newDeviceName = this.config.nameOverride[hbDeviceId] } try { - const accessory = new this.api.platformAccessory(newDeviceName, this.api.hap.uuid.generate(hbDeviceId).toString()) + const accessory = new Accessory(newDeviceName, this.api.hap.uuid.generate(hbDeviceId).toString()) if (!hidden) { accessory .getService(Service.AccessoryInformation) @@ -636,6 +636,7 @@ class eWeLink { } } module.exports = function (homebridge) { + Accessory = homebridge.platformAccessory Characteristic = homebridge.hap.Characteristic Service = homebridge.hap.Service return eWeLink From c34168b90f33c08546be157d5cfa1ec3cba50c31 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 7 Oct 2020 17:00:06 +0100 Subject: [PATCH 0396/3183] 3.5.0-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index c48f6a73..204052b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0", + "version": "3.5.0-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index c70f6512..ed97b740 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.4.0", + "version": "3.5.0-0", "author": "bwp91", "contributors": [ "gbro115", From e06e2905ab69539f63a22e2bebf77edafa31af5b Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Wed, 7 Oct 2020 21:21:58 +0100 Subject: [PATCH 0397/3183] Update stale.yml --- .github/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/stale.yml b/.github/stale.yml index c75e5812..cd68e851 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,7 +1,7 @@ # Number of days of inactivity before an issue becomes stale daysUntilStale: 7 # Number of days of inactivity before a stale issue is closed -daysUntilClose: 7 +daysUntilClose: 3 # Issues with these labels will never be considered stale exemptLabels: - "feedback wanted" From 7d39c1de6030c8974a6f283a8c338581a93b1ecf Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Thu, 8 Oct 2020 14:37:50 +0100 Subject: [PATCH 0398/3183] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index af89e280..36b19707 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- Homebridge Verified + Homebridge Verified

From 4e9670d4be340b5897a8e4a770528f7bcd97e01a Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Thu, 8 Oct 2020 14:39:47 +0100 Subject: [PATCH 0399/3183] Update README.md --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 36b19707..cb40d4ab 100644 --- a/README.md +++ b/README.md @@ -5,14 +5,14 @@ # homebridge-ewelink - Homebridge plugin to control eWeLink devices with original firmware. +Homebridge plugin to control eWeLink devices with original firmware. - [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) - [![npm](https://img.shields.io/npm/v/homebridge-ewelink/latest?label=release)](https://www.npmjs.com/package/homebridge-ewelink) - [![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://www.npmjs.com/package/homebridge-ewelink) - [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) - [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) - [![Discord](https://img.shields.io/discord/432663330281226270?color=728ED5&logo=discord&label=discord)](https://discord.com/channels/432663330281226270/742733745743855627) +[![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) +[![npm](https://img.shields.io/npm/v/homebridge-ewelink/latest?label=release)](https://www.npmjs.com/package/homebridge-ewelink) +[![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://www.npmjs.com/package/homebridge-ewelink) +[![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) +[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) +[![Discord](https://img.shields.io/discord/432663330281226270?color=728ED5&logo=discord&label=discord)](https://discord.com/channels/432663330281226270/742733745743855627) From 5f0cb9870819f894f9e95d549f449ae00cb8d853 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Thu, 8 Oct 2020 14:41:00 +0100 Subject: [PATCH 0400/3183] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cb40d4ab..c1593981 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ # homebridge-ewelink Homebridge plugin to control eWeLink devices with original firmware. - + [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/latest?label=release)](https://www.npmjs.com/package/homebridge-ewelink) -[![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://www.npmjs.com/package/homebridge-ewelink) +[![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://github.com/bwp91/homebridge-ewelink/wiki/Beta-Version) [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Discord](https://img.shields.io/discord/432663330281226270?color=728ED5&logo=discord&label=discord)](https://discord.com/channels/432663330281226270/742733745743855627) From d6cf04150e7931353facebc4935f1215d4ccd967 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 8 Oct 2020 14:50:46 +0100 Subject: [PATCH 0401/3183] Update garage-eachen.js --- lib/device/garage-eachen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 0d0c6dc0..71ec2c5e 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -43,7 +43,6 @@ module.exports = class deviceGarageEachen { await this.platform.sendDeviceUpdate(accessory, params) await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos) - await utils.sleep(2000) accessory.context.inUse = false } catch (err) { accessory.context.inUse = false @@ -68,6 +67,7 @@ module.exports = class deviceGarageEachen { gdService.updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) gdService.updateCharacteristic(Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) + await utils.sleep(2500) accessory.context.inUse = false } catch (err) { accessory.context.inUse = false From 7e262a432d7db8161400a037ee1d7455bf51e37e Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Thu, 8 Oct 2020 14:59:14 +0100 Subject: [PATCH 0402/3183] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c1593981..1d7026bd 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Homebridge plugin to control eWeLink devices with original firmware. [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) -[![npm](https://img.shields.io/npm/v/homebridge-ewelink/latest?label=release)](https://www.npmjs.com/package/homebridge-ewelink) +[![npm](https://img.shields.io/npm/v/homebridge-ewelink/latest?label=latest)](https://www.npmjs.com/package/homebridge-ewelink) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://github.com/bwp91/homebridge-ewelink/wiki/Beta-Version) [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) From ca0a2deaa277f29251a218009bcc76ed4e587c5b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 9 Oct 2020 07:38:30 +0100 Subject: [PATCH 0403/3183] Update outlet.js --- lib/device/outlet.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/device/outlet.js b/lib/device/outlet.js index ae2a1419..26a8da12 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -78,6 +78,11 @@ module.exports = class deviceOutlet { time: Date.now(), power: currentWatt }) + + accessory.eveLogger.addEntry({ + time: Date.now(), + status: 1 + }) }, 300000) outletService .getCharacteristic(EveService.Characteristics.TotalConsumption) From f30b3dc59e9160b3870373dabb38b8b9f983b7b5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 9 Oct 2020 07:39:12 +0100 Subject: [PATCH 0404/3183] 3.5.0-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 204052b2..37cfbad5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-0", + "version": "3.5.0-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index ed97b740..41024cef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-0", + "version": "3.5.0-1", "author": "bwp91", "contributors": [ "gbro115", From 580a98c9df7c5e0c47ca2e868bed31659d4fdab3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 9 Oct 2020 08:04:30 +0100 Subject: [PATCH 0405/3183] Update outlet.js --- lib/device/outlet.js | 165 ++++++++++++++++++++++++------------------- 1 file changed, 92 insertions(+), 73 deletions(-) diff --git a/lib/device/outlet.js b/lib/device/outlet.js index 26a8da12..f5cfde80 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -39,79 +39,98 @@ module.exports = class deviceOutlet { outletService .getCharacteristic(Characteristic.On) .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) - if (!cns.devicesSingleSwitchOutlet.includes(accessory.context.eweModel) && !this.platform.config.disableEveLogging) { - accessory.log = this.platform.log - accessory.eveLogger = new EveHistoryService('energy', accessory, { - storage: 'fs', - minutes: 5, - path: this.platform.eveLogPath - }) - corrInterval.setCorrectingInterval(() => { - const isOn = outletService.getCharacteristic(Characteristic.On).value - const currentWatt = isOn - ? outletService.getCharacteristic(EveService.Characteristics.CurrentConsumption).value - : 0 - if (accessory.eveLogger.isHistoryLoaded()) { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalEnergy = - accessory.context.extraPersistedData.totalenergy + - accessory.context.totalEnergyTemp + - (currentWatt * 10) / 3600 / 1000 - accessory.eveLogger.setExtraPersistedData({ - totalenergy: accessory.context.totalEnergy, - lastReset: accessory.context.extraPersistedData.lastReset - }) - } else { - accessory.context.totalEnergy = accessory.context.totalEnergyTemp + (currentWatt * 10) / 3600 / 1000 - accessory.eveLogger.setExtraPersistedData({ - totalenergy: accessory.context.totalEnergy, - lastReset: 0 - }) - } - accessory.context.totalEnergytemp = 0 - } else { - accessory.context.totalEnergyTemp += (currentWatt * 10) / 3600 / 1000 - accessory.context.totalEnergy = accessory.context.totalEnergyTemp - } - accessory.eveLogger.addEntry({ - time: Date.now(), - power: currentWatt - }) - - accessory.eveLogger.addEntry({ - time: Date.now(), - status: 1 - }) - }, 300000) - outletService - .getCharacteristic(EveService.Characteristics.TotalConsumption) - .on('get', callback => { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower - } - callback(null, accessory.context.totalEnergy) - }) - outletService - .getCharacteristic(EveService.Characteristics.ResetTotal) - .on('set', (value, callback) => { - accessory.context.totalEnergy = 0 - accessory.context.lastReset = value - accessory.eveLogger.setExtraPersistedData({ - totalPower: 0, - lastReset: value - }) - callback() - }) - .on('get', callback => { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.lastReset = accessory.context.extraPersistedData.lastReset - } - callback(null, accessory.context.lastReset) - }) - } + if (!cns.devicesSingleSwitchOutlet.includes(accessory.context.eweModel) && !this.platform.config.disableEveLogging) { + accessory.log = this.platform.log + accessory.eveLogger = new EveHistoryService('energy', accessory, { + storage: 'fs', + minutes: 5, + path: this.platform.eveLogPath + }) + corrInterval.setCorrectingInterval(() => { + const isOn = outletService.getCharacteristic(Characteristic.On).value + const currentWatt = isOn + ? outletService.getCharacteristic(EveService.Characteristics.CurrentConsumption).value + : 0 + if (accessory.eveLogger.isHistoryLoaded()) { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.totalEnergy = + accessory.context.extraPersistedData.totalenergy + + accessory.context.totalEnergyTemp + + (currentWatt * 10) / 3600 / 1000 + accessory.eveLogger.setExtraPersistedData({ + totalenergy: accessory.context.totalEnergy, + lastReset: accessory.context.extraPersistedData.lastReset + }) + } else { + accessory.context.totalEnergy = accessory.context.totalEnergyTemp + (currentWatt * 10) / 3600 / 1000 + accessory.eveLogger.setExtraPersistedData({ + totalenergy: accessory.context.totalEnergy, + lastReset: 0 + }) + } + accessory.context.totalEnergytemp = 0 + } else { + accessory.context.totalEnergyTemp += (currentWatt * 10) / 3600 / 1000 + accessory.context.totalEnergy = accessory.context.totalEnergyTemp + } + accessory.eveLogger.addEntry({ + time: Date.now(), + power: currentWatt + }) + + accessory.eveLogger.addEntry({ + time: Date.now(), + status: 1 + }) + }, 300000) + outletService + .getCharacteristic(EveService.Characteristics.TotalConsumption) + .on('get', callback => { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower + } + callback(null, accessory.context.totalEnergy) + }) + outletService + .getCharacteristic(EveService.Characteristics.ResetTotal) + .on('set', (value, callback) => { + accessory.context.totalEnergy = 0 + accessory.context.lastReset = value + accessory.eveLogger.setExtraPersistedData({ + totalPower: 0, + lastReset: value + }) + callback() + }) + .on('get', callback => { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.lastReset = accessory.context.extraPersistedData.lastReset + } + callback(null, accessory.context.lastReset) + }) + } + + + + + if (cns.devicesSingleSwitchOutlet.includes(accessory.context.eweModel)) { + accessory.log = this.platform.log + accessory.eveLogger = new EveHistoryService('energy', accessory, { + storage: 'fs', + minutes: 5, + path: this.platform.eveLogPath + }) + corrInterval.setCorrectingInterval(() => { + accessory.eveLogger.addEntry({ + time: Date.now(), + status: 1 + }) + }, 30000) + } + } async internalUpdate (accessory, value, callback) { From deaa44f2b6baac5371fa4868f5f22b7b3a3a56fa Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 9 Oct 2020 08:05:34 +0100 Subject: [PATCH 0406/3183] 3.5.0-2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 37cfbad5..a7e3eab8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-1", + "version": "3.5.0-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 41024cef..cb674db7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-1", + "version": "3.5.0-2", "author": "bwp91", "contributors": [ "gbro115", From 39f4e5f9de4699fd12ecc0a0d7bbbc35d5db4fcf Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 9 Oct 2020 08:43:08 +0100 Subject: [PATCH 0407/3183] Update outlet.js --- lib/device/outlet.js | 160 ++++++++++++++++++------------------------- 1 file changed, 68 insertions(+), 92 deletions(-) diff --git a/lib/device/outlet.js b/lib/device/outlet.js index f5cfde80..ae2a1419 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -39,98 +39,74 @@ module.exports = class deviceOutlet { outletService .getCharacteristic(Characteristic.On) .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) - if (!cns.devicesSingleSwitchOutlet.includes(accessory.context.eweModel) && !this.platform.config.disableEveLogging) { - accessory.log = this.platform.log - accessory.eveLogger = new EveHistoryService('energy', accessory, { - storage: 'fs', - minutes: 5, - path: this.platform.eveLogPath - }) - corrInterval.setCorrectingInterval(() => { - const isOn = outletService.getCharacteristic(Characteristic.On).value - const currentWatt = isOn - ? outletService.getCharacteristic(EveService.Characteristics.CurrentConsumption).value - : 0 - if (accessory.eveLogger.isHistoryLoaded()) { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalEnergy = - accessory.context.extraPersistedData.totalenergy + - accessory.context.totalEnergyTemp + - (currentWatt * 10) / 3600 / 1000 - accessory.eveLogger.setExtraPersistedData({ - totalenergy: accessory.context.totalEnergy, - lastReset: accessory.context.extraPersistedData.lastReset - }) - } else { - accessory.context.totalEnergy = accessory.context.totalEnergyTemp + (currentWatt * 10) / 3600 / 1000 - accessory.eveLogger.setExtraPersistedData({ - totalenergy: accessory.context.totalEnergy, - lastReset: 0 - }) - } - accessory.context.totalEnergytemp = 0 - } else { - accessory.context.totalEnergyTemp += (currentWatt * 10) / 3600 / 1000 - accessory.context.totalEnergy = accessory.context.totalEnergyTemp - } - accessory.eveLogger.addEntry({ - time: Date.now(), - power: currentWatt - }) - - accessory.eveLogger.addEntry({ - time: Date.now(), - status: 1 - }) - }, 300000) - outletService - .getCharacteristic(EveService.Characteristics.TotalConsumption) - .on('get', callback => { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower - } - callback(null, accessory.context.totalEnergy) - }) - outletService - .getCharacteristic(EveService.Characteristics.ResetTotal) - .on('set', (value, callback) => { - accessory.context.totalEnergy = 0 - accessory.context.lastReset = value - accessory.eveLogger.setExtraPersistedData({ - totalPower: 0, - lastReset: value - }) - callback() - }) - .on('get', callback => { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.lastReset = accessory.context.extraPersistedData.lastReset - } - callback(null, accessory.context.lastReset) - }) - } - - - - - if (cns.devicesSingleSwitchOutlet.includes(accessory.context.eweModel)) { - accessory.log = this.platform.log - accessory.eveLogger = new EveHistoryService('energy', accessory, { - storage: 'fs', - minutes: 5, - path: this.platform.eveLogPath - }) - corrInterval.setCorrectingInterval(() => { - accessory.eveLogger.addEntry({ - time: Date.now(), - status: 1 - }) - }, 30000) - } - + if (!cns.devicesSingleSwitchOutlet.includes(accessory.context.eweModel) && !this.platform.config.disableEveLogging) { + accessory.log = this.platform.log + accessory.eveLogger = new EveHistoryService('energy', accessory, { + storage: 'fs', + minutes: 5, + path: this.platform.eveLogPath + }) + corrInterval.setCorrectingInterval(() => { + const isOn = outletService.getCharacteristic(Characteristic.On).value + const currentWatt = isOn + ? outletService.getCharacteristic(EveService.Characteristics.CurrentConsumption).value + : 0 + if (accessory.eveLogger.isHistoryLoaded()) { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.totalEnergy = + accessory.context.extraPersistedData.totalenergy + + accessory.context.totalEnergyTemp + + (currentWatt * 10) / 3600 / 1000 + accessory.eveLogger.setExtraPersistedData({ + totalenergy: accessory.context.totalEnergy, + lastReset: accessory.context.extraPersistedData.lastReset + }) + } else { + accessory.context.totalEnergy = accessory.context.totalEnergyTemp + (currentWatt * 10) / 3600 / 1000 + accessory.eveLogger.setExtraPersistedData({ + totalenergy: accessory.context.totalEnergy, + lastReset: 0 + }) + } + accessory.context.totalEnergytemp = 0 + } else { + accessory.context.totalEnergyTemp += (currentWatt * 10) / 3600 / 1000 + accessory.context.totalEnergy = accessory.context.totalEnergyTemp + } + accessory.eveLogger.addEntry({ + time: Date.now(), + power: currentWatt + }) + }, 300000) + outletService + .getCharacteristic(EveService.Characteristics.TotalConsumption) + .on('get', callback => { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower + } + callback(null, accessory.context.totalEnergy) + }) + outletService + .getCharacteristic(EveService.Characteristics.ResetTotal) + .on('set', (value, callback) => { + accessory.context.totalEnergy = 0 + accessory.context.lastReset = value + accessory.eveLogger.setExtraPersistedData({ + totalPower: 0, + lastReset: value + }) + callback() + }) + .on('get', callback => { + accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() + if (accessory.context.extraPersistedData !== undefined) { + accessory.context.lastReset = accessory.context.extraPersistedData.lastReset + } + callback(null, accessory.context.lastReset) + }) + } } async internalUpdate (accessory, value, callback) { From 9c9f198bab8440517693bc68bfe7acf7660ee36f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 9 Oct 2020 09:04:49 +0100 Subject: [PATCH 0408/3183] 3.5.0-3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a7e3eab8..86608c7a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-2", + "version": "3.5.0-3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index cb674db7..13337680 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-2", + "version": "3.5.0-3", "author": "bwp91", "contributors": [ "gbro115", From ef57e19b766f15ae1bc85c2918be719cc9f78901 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 9 Oct 2020 10:11:02 +0100 Subject: [PATCH 0409/3183] deps --- package-lock.json | 70 +++++++++++++++++++++++++++++++++++------------ package.json | 6 ++-- 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index 86608c7a..239bfb30 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,11 +4,6 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" - }, "abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -41,11 +36,10 @@ } }, "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "requires": { - "@types/color-name": "^1.1.1", "color-convert": "^2.0.1" } }, @@ -356,13 +350,13 @@ "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" }, "homebridge-lib": { - "version": "4.7.15", - "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-4.7.15.tgz", - "integrity": "sha512-654DQEwyhcHbZ1++1qv0k4lhoYWaZsHcriFRts4XHnGFQOgdO1G6VyP3hUjt/+y5FemoRVjqf6Tv0/IKNPDC4w==", + "version": "4.7.16", + "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-4.7.16.tgz", + "integrity": "sha512-+MYkMUUjP7mPdGT9fJU6ifjvg1SinCUlmdrzjPQZaoe119EN28d0bQSr1jpaVjWW1bqVo+KJT+ap5vnfAgFp1g==", "requires": { "bonjour": "^3.5.0", "chalk": "^4.1.0", - "debug": "^4.1.1", + "debug": "^4.2.0", "semver": "^7.3.2" }, "dependencies": { @@ -430,6 +424,11 @@ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" }, + "is-negative-zero": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", + "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=" + }, "is-regex": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", @@ -536,12 +535,49 @@ "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==" }, "object-is": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz", - "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.3.tgz", + "integrity": "sha512-teyqLvFWzLkq5B9ki8FVWA902UER2qkxmdA4nLf+wjOLAWgxzCWZNCxpDq9MvE8MmhWNr+I8w3BN49Vx36Y6Xg==", "requires": { "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" + "es-abstract": "^1.18.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "is-callable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==" + }, + "object.assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", + "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.0", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + } } }, "object-keys": { diff --git a/package.json b/package.json index 13337680..71c7d9b8 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,8 @@ "eachen" ], "engines": { - "node": ">=10.0.0", - "homebridge": ">=1.0.0" + "homebridge": "^1.1.0", + "node": "^12.19.0" }, "repository": { "type": "git", @@ -70,7 +70,7 @@ "color-temp": "0.0.2", "correcting-interval": "2.0.0", "fakegato-history": "0.5.6", - "homebridge-lib": "4.7.15", + "homebridge-lib": "4.7.16", "interval-promise": "1.4.0", "node-dns-sd": "0.4.2", "websocket-as-promised": "1.0.1", From 3b048dd69367ef0c8e5528cfe0b1dacd9f26fc40 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 9 Oct 2020 10:11:38 +0100 Subject: [PATCH 0410/3183] 3.5.0-4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 239bfb30..4999c061 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-3", + "version": "3.5.0-4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 71c7d9b8..6b5261bc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-3", + "version": "3.5.0-4", "author": "bwp91", "contributors": [ "gbro115", From 37606b05ee9af90a2eec9a00e8eb21f4ccf4bcb0 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 9 Oct 2020 10:18:49 +0100 Subject: [PATCH 0411/3183] remove dep --- package-lock.json | 5 ----- package.json | 1 - 2 files changed, 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4999c061..71f3dc33 100644 --- a/package-lock.json +++ b/package-lock.json @@ -121,11 +121,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "color-temp": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/color-temp/-/color-temp-0.0.2.tgz", - "integrity": "sha1-GxTzI9nLdq0fn1p140DWHW2WA/s=" - }, "correcting-interval": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/correcting-interval/-/correcting-interval-2.0.0.tgz", diff --git a/package.json b/package.json index 6b5261bc..260940ca 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,6 @@ "dependencies": { "axios": "0.20.0", "color-convert": "2.0.1", - "color-temp": "0.0.2", "correcting-interval": "2.0.0", "fakegato-history": "0.5.6", "homebridge-lib": "4.7.16", From 903f6ad77c92033206ec85ecf50786e1a5931008 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 9 Oct 2020 10:28:38 +0100 Subject: [PATCH 0412/3183] Update package.json --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 260940ca..2183f266 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,8 @@ "eachen" ], "engines": { - "homebridge": "^1.1.0", - "node": "^12.19.0" + "homebridge": ">=1.1.0", + "node": ">=12.19.0" }, "repository": { "type": "git", From eb177617d25cfcc5341fe0ec446e4c417d28dd63 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 9 Oct 2020 15:38:59 +0100 Subject: [PATCH 0413/3183] Update eWeLink.js --- lib/eWeLink.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index a37f8724..edec3e72 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -340,7 +340,7 @@ class eWeLink { oAccessory.context.reachableWAN = device.online oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) - oAccessory.control = new DeviceLight(this, oAccessory) + oAccessory.control = new DeviceSwitch(this, oAccessory) } /**********************/ } else if (cns.devicesRFBridge.includes(device.extra.uiid)) { From c8b049ec4c346ee588bd1e56c4de08c266f7e686 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 9 Oct 2020 15:39:37 +0100 Subject: [PATCH 0414/3183] 3.5.0-5 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 71f3dc33..a7c021dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-4", + "version": "3.5.0-5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 2183f266..0703ec51 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-4", + "version": "3.5.0-5", "author": "bwp91", "contributors": [ "gbro115", From cea1c79008e18599d421d31344c7a9d50847c3da Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 09:26:12 +0100 Subject: [PATCH 0415/3183] awaits --- lib/eWeLinkHTTP.js | 10 +++++----- lib/eWeLinkWS.js | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 6f46e8cc..9a05d605 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -71,7 +71,7 @@ module.exports = class eWeLinkHTTP { this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') } await utils.sleep(30000) - return this.getHost() + return await this.getHost() } else { return err } @@ -123,7 +123,7 @@ module.exports = class eWeLinkHTTP { if (this.debug) { this.log('New HTTP API host received [%s].', this.httpHost) } - return this.login() + return await this.login() } if (body.data.at) { this.aToken = body.data.at @@ -139,7 +139,7 @@ module.exports = class eWeLinkHTTP { this.log.warn('An eWeLink error [500] occured. Retrying in 30 seconds.') } await utils.sleep(30000) - return this.login() + return await this.login() } else { throw new Error('No auth token received.\n' + JSON.stringify(body, null, 2)) } @@ -185,7 +185,7 @@ module.exports = class eWeLinkHTTP { this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') } await utils.sleep(30000) - return this.getDevices() + return await this.getDevices() } else { return err } @@ -227,7 +227,7 @@ module.exports = class eWeLinkHTTP { this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') } await utils.sleep(30000) - return this.getDevice(deviceId) + return await this.getDevice(deviceId) } else { return err } diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 9a2b5bcb..f8f441ff 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -45,7 +45,7 @@ module.exports = class eWeLinkWS { if (utils.hasProperty(err, 'code') && cns.httpRetryCodes.includes(err.code)) { if (this.debug) this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') await utils.sleep(30000) - return this.getDevices() + return await this.getDevices() } else { return err } @@ -162,7 +162,7 @@ module.exports = class eWeLinkWS { this.log.warn('Web socket will try to reconnect in five seconds.') } await utils.sleep(5000) - return this.login() + return await this.login() }) this.wsp.onError.addListener(async e => { this.wsIsOpen = false @@ -176,7 +176,7 @@ module.exports = class eWeLinkWS { this.log.warn('Web socket will try to reconnect in five seconds.') } await utils.sleep(5000) - return this.login() + return await this.login() }) } @@ -216,7 +216,7 @@ module.exports = class eWeLinkWS { this.log.warn('Command will be resent when WS is reconnected.') } await utils.sleep(30000) - return this.sendUpdate(json) + return await this.sendUpdate(json) } } @@ -244,7 +244,7 @@ module.exports = class eWeLinkWS { } else { if (this.debug) this.log.warn('Command will be resent when WS is reconnected.') await utils.sleep(30000) - return this.requestUpdate(accessory) + return await this.requestUpdate(accessory) } } From 53c8f3de0025a82fdbd708404d31ae6871a74a08 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 09:27:19 +0100 Subject: [PATCH 0416/3183] 3.5.0-6 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a7c021dc..d02eadff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-5", + "version": "3.5.0-6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 0703ec51..03ca724f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-5", + "version": "3.5.0-6", "author": "bwp91", "contributors": [ "gbro115", From 58ffb962211a5795ea17db4f65cb9ead1ae4f139 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 09:29:50 +0100 Subject: [PATCH 0417/3183] catch error pinging --- lib/eWeLinkWS.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index f8f441ff..1ed8e157 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -86,7 +86,11 @@ module.exports = class eWeLinkWS { const res = await this.wsp.sendRequest(payload, { requestId: sequence }) if (utils.hasProperty(res, 'config') && res.config.hb && res.config.hbInterval && !this.hbInterval) { this.hbInterval = setInterval(() => { - this.wsp.send('ping') + try { + this.wsp.send('ping') + } catch (err) { + if (this.debug) this.log('Error sending ping - %.', err.message) + } }, (res.config.hbInterval + 7) * 1000) } else { throw new Error('Unknown parameters received\n' + res) From db4a260887c1e1b92c362e4bc88196a4acd76f09 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 09:30:41 +0100 Subject: [PATCH 0418/3183] 3.5.0-7 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index d02eadff..f6394443 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-6", + "version": "3.5.0-7", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 03ca724f..d15c0bd4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-6", + "version": "3.5.0-7", "author": "bwp91", "contributors": [ "gbro115", From 123c2ae9b4f3a201226b70d8d3ab098a4a73ee5f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 10:57:16 +0100 Subject: [PATCH 0419/3183] view ws error msg --- lib/eWeLinkWS.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 1ed8e157..d2ac5395 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -93,7 +93,7 @@ module.exports = class eWeLinkWS { } }, (res.config.hbInterval + 7) * 1000) } else { - throw new Error('Unknown parameters received\n' + res) + throw new Error('Unknown parameters received\n' + JSON.stringify(res, null, 2)) } } catch (err) { this.log.error('WS login failed [%s].', this.debug ? err : err.message) From b421cd90059424518c42b2da2122a38e3d4e2a89 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 10:57:51 +0100 Subject: [PATCH 0420/3183] 3.5.0-8 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f6394443..e027f127 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-7", + "version": "3.5.0-8", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index d15c0bd4..1844ed14 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-7", + "version": "3.5.0-8", "author": "bwp91", "contributors": [ "gbro115", From b29a3451fbc7103ca9d8610f30fbb52a7eb51e2f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 11:57:33 +0100 Subject: [PATCH 0421/3183] Update eWeLinkWS.js --- lib/eWeLinkWS.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index d2ac5395..0c595723 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -84,7 +84,8 @@ module.exports = class eWeLinkWS { } try { const res = await this.wsp.sendRequest(payload, { requestId: sequence }) - if (utils.hasProperty(res, 'config') && res.config.hb && res.config.hbInterval && !this.hbInterval) { + if (utils.hasProperty(res, 'config') && res.config.hb && res.config.hbInterval) { + if (this.hbInterval) clearInterval(this.hbInterval) this.hbInterval = setInterval(() => { try { this.wsp.send('ping') From 43619339a71f9bb1bccc8139e56047b2e41b6316 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 11:58:24 +0100 Subject: [PATCH 0422/3183] 3.5.0-9 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index e027f127..2a2ca5fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-8", + "version": "3.5.0-9", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1844ed14..7297a24e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-8", + "version": "3.5.0-9", "author": "bwp91", "contributors": [ "gbro115", From 290cce6be909ebd8b73b40f6f1473c5a04bd4bfa Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 12:41:37 +0100 Subject: [PATCH 0423/3183] correct function --- lib/eWeLinkWS.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 0c595723..88cfbb04 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -45,7 +45,7 @@ module.exports = class eWeLinkWS { if (utils.hasProperty(err, 'code') && cns.httpRetryCodes.includes(err.code)) { if (this.debug) this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') await utils.sleep(30000) - return await this.getDevices() + return await this.getHost() } else { return err } From 1c8801ae1d5f2a75b062fc5395d608b03f32545a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 12:41:44 +0100 Subject: [PATCH 0424/3183] ; placement --- lib/eWeLink.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index edec3e72..95cdcf35 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -65,8 +65,8 @@ class eWeLink { await this.wsClient.getHost() this.wsClient.login() this.lanDevices = await this.lanClient.getHosts() - await this.lanClient.startMonitor(); - (() => { + await this.lanClient.startMonitor() + ;(() => { if (Object.keys(this.config.groups || []).length > 0) { this.config.groups .filter(g => utils.hasProperty(g, 'type') && cns.allowedGroups.includes(g.type)) From e84e10e9efc37a872d79d671ecf87a7bbb917235 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 12:42:17 +0100 Subject: [PATCH 0425/3183] 3.5.0-10 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2a2ca5fc..dd31fa7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-9", + "version": "3.5.0-10", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 7297a24e..6002d4d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-9", + "version": "3.5.0-10", "author": "bwp91", "contributors": [ "gbro115", From 8a92e70850eeddce6c17a507b03a816f4d64266f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 15:24:05 +0100 Subject: [PATCH 0426/3183] revert extra sleep --- lib/device/garage-eachen.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 71ec2c5e..1551541d 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -67,7 +67,6 @@ module.exports = class deviceGarageEachen { gdService.updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) gdService.updateCharacteristic(Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) - await utils.sleep(2500) accessory.context.inUse = false } catch (err) { accessory.context.inUse = false From f09f776e9728fe405a50725350c731f8848fbbac Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 15:24:46 +0100 Subject: [PATCH 0427/3183] 3.5.0-11 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index dd31fa7e..cb6933b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-10", + "version": "3.5.0-11", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 6002d4d0..99060f29 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-10", + "version": "3.5.0-11", "author": "bwp91", "contributors": [ "gbro115", From 5c945546b7470b9797193686839231c01d5673c2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 15:28:07 +0100 Subject: [PATCH 0428/3183] Update garage-eachen.js --- lib/device/garage-eachen.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 1551541d..f7d7cc27 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -41,7 +41,7 @@ module.exports = class deviceGarageEachen { .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2) params.switch = value === 0 ? 'on' : 'off' await this.platform.sendDeviceUpdate(accessory, params) - await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) + await utils.sleep(garageConfig.operationTime * 100) gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos) accessory.context.inUse = false } catch (err) { @@ -65,7 +65,7 @@ module.exports = class deviceGarageEachen { accessory.context.inUse = true const gdService = accessory.getService(Service.GarageDoorOpener) gdService.updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) - await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) + await utils.sleep(garageConfig.operationTime * 100) gdService.updateCharacteristic(Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) accessory.context.inUse = false } catch (err) { From e8d57737915f6fc7295fd8229baae79551a27d3f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 15:28:53 +0100 Subject: [PATCH 0429/3183] 3.5.0-12 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index cb6933b4..a6c06f55 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-11", + "version": "3.5.0-12", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 99060f29..d9c73880 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-11", + "version": "3.5.0-12", "author": "bwp91", "contributors": [ "gbro115", From 33235e9f40cae3257682ee44c8f049918cd1b5a7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 16:12:43 +0100 Subject: [PATCH 0430/3183] Update garage-eachen.js --- lib/device/garage-eachen.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index f7d7cc27..b87ce171 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -41,8 +41,10 @@ module.exports = class deviceGarageEachen { .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2) params.switch = value === 0 ? 'on' : 'off' await this.platform.sendDeviceUpdate(accessory, params) - await utils.sleep(garageConfig.operationTime * 100) - gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos) + if (newPos === 0) { + await utils.sleep(garageConfig.operationTime * 100) + gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos) + } accessory.context.inUse = false } catch (err) { accessory.context.inUse = false From 84b4dcc5e2c7e956b0d1e97542a825c19f4263f4 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 16:32:46 +0100 Subject: [PATCH 0431/3183] Update garage-eachen.js --- lib/device/garage-eachen.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index b87ce171..832634ce 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -42,6 +42,7 @@ module.exports = class deviceGarageEachen { params.switch = value === 0 ? 'on' : 'off' await this.platform.sendDeviceUpdate(accessory, params) if (newPos === 0) { + // garage door to open. await utils.sleep(garageConfig.operationTime * 100) gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos) } @@ -64,10 +65,20 @@ module.exports = class deviceGarageEachen { if (garageConfig.type !== 'garage_eachen') { throw new Error('improper configuration') } - accessory.context.inUse = true const gdService = accessory.getService(Service.GarageDoorOpener) + + if (params.switch === 'off' && gdService.getCharacteristic(Characteristic.CurrentDoorState).value === 3) { + return + } + if (params.switch === 'on' && gdService.getCharacteristic(Characteristic.CurrentDoorState).value === 2) { + return + } + + accessory.context.inUse = true gdService.updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) - await utils.sleep(garageConfig.operationTime * 100) + if (params.switch === 'on') { + await utils.sleep(garageConfig.operationTime * 100) + } gdService.updateCharacteristic(Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) accessory.context.inUse = false } catch (err) { From 1b5daf21ac4ac7f666a4633257a59a84aee796fe Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 16:33:18 +0100 Subject: [PATCH 0432/3183] 3.5.0-13 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a6c06f55..65642fc9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-12", + "version": "3.5.0-13", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index d9c73880..14911228 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-12", + "version": "3.5.0-13", "author": "bwp91", "contributors": [ "gbro115", From 864bfe4e575ca99dcdbfdd1f7b8063eb97c0e50a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 16:55:45 +0100 Subject: [PATCH 0433/3183] Update garage-eachen.js --- lib/device/garage-eachen.js | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 832634ce..5c31e2c1 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -18,6 +18,8 @@ module.exports = class deviceGarageEachen { gdeService .getCharacteristic(Characteristic.TargetDoorState) .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + accessory.context.ignoreNextOffUpdate = false + accessory.context.ignoreNextOnUpdate = false } async internalUpdate (accessory, value, callback) { @@ -35,27 +37,24 @@ module.exports = class deviceGarageEachen { const gdService = accessory.getService(Service.GarageDoorOpener) const prevState = gdService.getCharacteristic(Characteristic.CurrentDoorState).value if (newPos === prevState % 2) return - accessory.context.inUse = true gdService .updateCharacteristic(Characteristic.TargetDoorState, newPos) .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2) params.switch = value === 0 ? 'on' : 'off' await this.platform.sendDeviceUpdate(accessory, params) - if (newPos === 0) { - // garage door to open. - await utils.sleep(garageConfig.operationTime * 100) - gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos) + if (newPos === 1) { + // garage door to close + accessory.context.ignoreNextOffUpdate = true + accessory.context.ignoreNextOnUpdate = true } - accessory.context.inUse = false } catch (err) { - accessory.context.inUse = false this.platform.deviceUpdateError(accessory, err, true) } } async externalUpdate (accessory, params) { try { - if (!utils.hasProperty(params, 'switch') || accessory.context.inUse) { + if (!utils.hasProperty(params, 'switch')) { return } let garageConfig @@ -67,22 +66,21 @@ module.exports = class deviceGarageEachen { } const gdService = accessory.getService(Service.GarageDoorOpener) - if (params.switch === 'off' && gdService.getCharacteristic(Characteristic.CurrentDoorState).value === 3) { + if (params.switch === 'off' && accessory.context.ignoreNextOffUpdate) { + accessory.context.ignoreNextOffUpdate = false return } - if (params.switch === 'on' && gdService.getCharacteristic(Characteristic.CurrentDoorState).value === 2) { + if (params.switch === 'on' && accessory.context.ignoreNextOnUpdate) { + accessory.context.ignoreNextOnUpdate = false return } - accessory.context.inUse = true gdService.updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) if (params.switch === 'on') { await utils.sleep(garageConfig.operationTime * 100) } gdService.updateCharacteristic(Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) - accessory.context.inUse = false } catch (err) { - accessory.context.inUse = false this.platform.deviceUpdateError(accessory, err, false) } } From 198f5f04b7cbdc381ac8b07040af07b35c596d1b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 16:56:28 +0100 Subject: [PATCH 0434/3183] 3.5.0-14 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 65642fc9..9227dd27 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-13", + "version": "3.5.0-14", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 14911228..d1dc5160 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-13", + "version": "3.5.0-14", "author": "bwp91", "contributors": [ "gbro115", From 1d6846c490c95cb162c1224ed2f812f18e705460 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 17:11:37 +0100 Subject: [PATCH 0435/3183] Revert "Update garage-eachen.js" This reverts commit 864bfe4e575ca99dcdbfdd1f7b8063eb97c0e50a. --- lib/device/garage-eachen.js | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 5c31e2c1..832634ce 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -18,8 +18,6 @@ module.exports = class deviceGarageEachen { gdeService .getCharacteristic(Characteristic.TargetDoorState) .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) - accessory.context.ignoreNextOffUpdate = false - accessory.context.ignoreNextOnUpdate = false } async internalUpdate (accessory, value, callback) { @@ -37,24 +35,27 @@ module.exports = class deviceGarageEachen { const gdService = accessory.getService(Service.GarageDoorOpener) const prevState = gdService.getCharacteristic(Characteristic.CurrentDoorState).value if (newPos === prevState % 2) return + accessory.context.inUse = true gdService .updateCharacteristic(Characteristic.TargetDoorState, newPos) .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2) params.switch = value === 0 ? 'on' : 'off' await this.platform.sendDeviceUpdate(accessory, params) - if (newPos === 1) { - // garage door to close - accessory.context.ignoreNextOffUpdate = true - accessory.context.ignoreNextOnUpdate = true + if (newPos === 0) { + // garage door to open. + await utils.sleep(garageConfig.operationTime * 100) + gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos) } + accessory.context.inUse = false } catch (err) { + accessory.context.inUse = false this.platform.deviceUpdateError(accessory, err, true) } } async externalUpdate (accessory, params) { try { - if (!utils.hasProperty(params, 'switch')) { + if (!utils.hasProperty(params, 'switch') || accessory.context.inUse) { return } let garageConfig @@ -66,21 +67,22 @@ module.exports = class deviceGarageEachen { } const gdService = accessory.getService(Service.GarageDoorOpener) - if (params.switch === 'off' && accessory.context.ignoreNextOffUpdate) { - accessory.context.ignoreNextOffUpdate = false + if (params.switch === 'off' && gdService.getCharacteristic(Characteristic.CurrentDoorState).value === 3) { return } - if (params.switch === 'on' && accessory.context.ignoreNextOnUpdate) { - accessory.context.ignoreNextOnUpdate = false + if (params.switch === 'on' && gdService.getCharacteristic(Characteristic.CurrentDoorState).value === 2) { return } + accessory.context.inUse = true gdService.updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) if (params.switch === 'on') { await utils.sleep(garageConfig.operationTime * 100) } gdService.updateCharacteristic(Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) + accessory.context.inUse = false } catch (err) { + accessory.context.inUse = false this.platform.deviceUpdateError(accessory, err, false) } } From eedb916626da65d2ac6c545243024b72d5b60880 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 17:31:49 +0100 Subject: [PATCH 0436/3183] Update garage-eachen.js --- lib/device/garage-eachen.js | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 832634ce..b97ed272 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -18,6 +18,7 @@ module.exports = class deviceGarageEachen { gdeService .getCharacteristic(Characteristic.TargetDoorState) .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + accessory.context.ignoreNextOff = false } async internalUpdate (accessory, value, callback) { @@ -35,20 +36,15 @@ module.exports = class deviceGarageEachen { const gdService = accessory.getService(Service.GarageDoorOpener) const prevState = gdService.getCharacteristic(Characteristic.CurrentDoorState).value if (newPos === prevState % 2) return - accessory.context.inUse = true gdService .updateCharacteristic(Characteristic.TargetDoorState, newPos) .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2) params.switch = value === 0 ? 'on' : 'off' - await this.platform.sendDeviceUpdate(accessory, params) - if (newPos === 0) { - // garage door to open. - await utils.sleep(garageConfig.operationTime * 100) - gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos) + if (newPos === 1) { + accessory.context.ignoreNextOff = true } - accessory.context.inUse = false + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { - accessory.context.inUse = false this.platform.deviceUpdateError(accessory, err, true) } } @@ -67,22 +63,29 @@ module.exports = class deviceGarageEachen { } const gdService = accessory.getService(Service.GarageDoorOpener) - if (params.switch === 'off' && gdService.getCharacteristic(Characteristic.CurrentDoorState).value === 3) { + if (params.switch === 'on' && gdService.getCharacteristic(Characteristic.CurrentDoorState).value === 2) { + // ON received when door is in fact closing (this is just the sensor behaviour) IGNORE return } - if (params.switch === 'on' && gdService.getCharacteristic(Characteristic.CurrentDoorState).value === 2) { + + // TWO CASES TO IGNORE THE OFF -> when HKContolled bool is true OR if controlled externally when G is open + + if ( + params.switch === 'off' && + (accessory.context.ignoreNextOff || gdService.getCharacteristic(Characteristic.CurrentDoorState).value === 0) + ) { + accessory.context.ignoreNextOff = false return } - accessory.context.inUse = true - gdService.updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) + if ([0, 1].includes(gdService.getCharacteristic(Characteristic.CurrentDoorState).value)) { + gdService.updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) + } if (params.switch === 'on') { await utils.sleep(garageConfig.operationTime * 100) } gdService.updateCharacteristic(Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) - accessory.context.inUse = false } catch (err) { - accessory.context.inUse = false this.platform.deviceUpdateError(accessory, err, false) } } From fd5c15414a189d8b67f7052b3b6e6e99bd230360 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 17:32:17 +0100 Subject: [PATCH 0437/3183] 3.5.0-15 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9227dd27..3c966f38 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-14", + "version": "3.5.0-15", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index d1dc5160..aae1cdd1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-14", + "version": "3.5.0-15", "author": "bwp91", "contributors": [ "gbro115", From 33c8dacd7b1980c44d6ffd1146aff580a7c7d207 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 18:02:17 +0100 Subject: [PATCH 0438/3183] Update garage-eachen.js --- lib/device/garage-eachen.js | 41 ++++++++++++++----------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index b97ed272..ee1f311e 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -18,7 +18,6 @@ module.exports = class deviceGarageEachen { gdeService .getCharacteristic(Characteristic.TargetDoorState) .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) - accessory.context.ignoreNextOff = false } async internalUpdate (accessory, value, callback) { @@ -36,15 +35,20 @@ module.exports = class deviceGarageEachen { const gdService = accessory.getService(Service.GarageDoorOpener) const prevState = gdService.getCharacteristic(Characteristic.CurrentDoorState).value if (newPos === prevState % 2) return + accessory.context.inUse = true + params.switch = value === 0 ? 'on' : 'off' + await this.platform.sendDeviceUpdate(accessory, params) gdService .updateCharacteristic(Characteristic.TargetDoorState, newPos) .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2) - params.switch = value === 0 ? 'on' : 'off' - if (newPos === 1) { - accessory.context.ignoreNextOff = true + await utils.sleep(3000) + accessory.context.inUse = false + if (newPos === 0) { + await utils.sleep(Math.max((garageConfig.operationTime - 30) * 100, 0)) + gdService.updateCharacteristic(Characteristic.CurrentDoorState, 1) } - await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { + accessory.context.inUse = false this.platform.deviceUpdateError(accessory, err, true) } } @@ -61,32 +65,17 @@ module.exports = class deviceGarageEachen { if (garageConfig.type !== 'garage_eachen') { throw new Error('improper configuration') } + accessory.context.inUse = true const gdService = accessory.getService(Service.GarageDoorOpener) - - if (params.switch === 'on' && gdService.getCharacteristic(Characteristic.CurrentDoorState).value === 2) { - // ON received when door is in fact closing (this is just the sensor behaviour) IGNORE - return - } - - // TWO CASES TO IGNORE THE OFF -> when HKContolled bool is true OR if controlled externally when G is open - - if ( - params.switch === 'off' && - (accessory.context.ignoreNextOff || gdService.getCharacteristic(Characteristic.CurrentDoorState).value === 0) - ) { - accessory.context.ignoreNextOff = false - return - } - - if ([0, 1].includes(gdService.getCharacteristic(Characteristic.CurrentDoorState).value)) { - gdService.updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) - } + gdService.updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) if (params.switch === 'on') { - await utils.sleep(garageConfig.operationTime * 100) + await utils.sleep(Math.max(garageConfig.operationTime * 100, 3000)) } gdService.updateCharacteristic(Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) + accessory.context.inUse = false } catch (err) { + accessory.context.inUse = false this.platform.deviceUpdateError(accessory, err, false) } } -} +} \ No newline at end of file From 187ed499d57383f056159bddd433c3d3478c23ae Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 18:03:10 +0100 Subject: [PATCH 0439/3183] 3.5.0-16 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3c966f38..f97191dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-15", + "version": "3.5.0-16", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index aae1cdd1..fc620267 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-15", + "version": "3.5.0-16", "author": "bwp91", "contributors": [ "gbro115", From b0fed467a2f89a05772f30883166345191991032 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 18:27:39 +0100 Subject: [PATCH 0440/3183] Update garage-eachen.js --- lib/device/garage-eachen.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index ee1f311e..3976104b 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -45,7 +45,7 @@ module.exports = class deviceGarageEachen { accessory.context.inUse = false if (newPos === 0) { await utils.sleep(Math.max((garageConfig.operationTime - 30) * 100, 0)) - gdService.updateCharacteristic(Characteristic.CurrentDoorState, 1) + gdService.updateCharacteristic(Characteristic.CurrentDoorState, 0) } } catch (err) { accessory.context.inUse = false @@ -67,15 +67,13 @@ module.exports = class deviceGarageEachen { } accessory.context.inUse = true const gdService = accessory.getService(Service.GarageDoorOpener) - gdService.updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) - if (params.switch === 'on') { - await utils.sleep(Math.max(garageConfig.operationTime * 100, 3000)) - } - gdService.updateCharacteristic(Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) + gdService + .updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) + .updateCharacteristic(Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) accessory.context.inUse = false } catch (err) { accessory.context.inUse = false this.platform.deviceUpdateError(accessory, err, false) } } -} \ No newline at end of file +} From 6914f44053593894689bbcdd04a093d5b7a7a285 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 18:28:20 +0100 Subject: [PATCH 0441/3183] 3.5.0-17 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f97191dd..4897cd01 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-16", + "version": "3.5.0-17", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index fc620267..cc67243b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-16", + "version": "3.5.0-17", "author": "bwp91", "contributors": [ "gbro115", From 0d43c869ee6b25d78c2cbe6a99eeaceb76ad662f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 18:58:48 +0100 Subject: [PATCH 0442/3183] change delay to 2 secs --- lib/device/garage-eachen.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 3976104b..00a5dc5f 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -41,10 +41,10 @@ module.exports = class deviceGarageEachen { gdService .updateCharacteristic(Characteristic.TargetDoorState, newPos) .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2) - await utils.sleep(3000) + await utils.sleep(2000) accessory.context.inUse = false if (newPos === 0) { - await utils.sleep(Math.max((garageConfig.operationTime - 30) * 100, 0)) + await utils.sleep(Math.max((garageConfig.operationTime - 20) * 100, 0)) gdService.updateCharacteristic(Characteristic.CurrentDoorState, 0) } } catch (err) { From 2b9a5f468dba8cba7ecbb65a5a6c2fbf88cf656e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 19:22:39 +0100 Subject: [PATCH 0443/3183] formatting --- lib/device/garage-eachen.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 00a5dc5f..7983fff2 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -30,20 +30,17 @@ module.exports = class deviceGarageEachen { if (garageConfig.type !== 'garage_eachen') { throw new Error('improper configuration') } - const params = {} - const newPos = value + const params = { switch: value === 0 ? 'on' : 'off' } const gdService = accessory.getService(Service.GarageDoorOpener) - const prevState = gdService.getCharacteristic(Characteristic.CurrentDoorState).value - if (newPos === prevState % 2) return + if (value === gdService.getCharacteristic(Characteristic.CurrentDoorState).value % 2) return accessory.context.inUse = true - params.switch = value === 0 ? 'on' : 'off' await this.platform.sendDeviceUpdate(accessory, params) gdService - .updateCharacteristic(Characteristic.TargetDoorState, newPos) - .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2) + .updateCharacteristic(Characteristic.TargetDoorState, value) + .updateCharacteristic(Characteristic.CurrentDoorState, value + 2) await utils.sleep(2000) accessory.context.inUse = false - if (newPos === 0) { + if (value === 0) { await utils.sleep(Math.max((garageConfig.operationTime - 20) * 100, 0)) gdService.updateCharacteristic(Characteristic.CurrentDoorState, 0) } From 9ea5c346332e192a62dd97edcb589f7350ff5f4e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 10 Oct 2020 19:23:38 +0100 Subject: [PATCH 0444/3183] 3.5.0-18 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4897cd01..92b7df67 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-17", + "version": "3.5.0-18", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index cc67243b..9ef1e846 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-17", + "version": "3.5.0-18", "author": "bwp91", "contributors": [ "gbro115", From cfb39a970c909cffdab4d12105ac9aa36254fc01 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 11 Oct 2020 09:17:50 +0100 Subject: [PATCH 0445/3183] 3.5.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 92b7df67..056b8787 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-18", + "version": "3.5.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 9ef1e846..b043e40a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0-18", + "version": "3.5.0", "author": "bwp91", "contributors": [ "gbro115", From cf823987d1d256d0230b75e5da222c69e7f6a335 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 11 Oct 2020 11:17:11 +0100 Subject: [PATCH 0446/3183] hide channels change --- config.schema.json | 15 ++++----------- lib/eWeLink.js | 12 ++++++++---- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/config.schema.json b/config.schema.json index 8d850422..a3c41c19 100644 --- a/config.schema.json +++ b/config.schema.json @@ -46,18 +46,12 @@ "description": "A list of eWeLink devices to hide from Homebridge. For example '10009553c8' or multiple separated with a comma '10009553c8,10009553c9'.", "default": "" }, - "hideMasters": { + "hideChanFromHB": { "type": "string", - "title": "Hide Master Lights/Switches", - "description": "A list of SW0 lights/switches to hide from Homebridge. For example '10009553c8' or multiple separated with a comma '10009553c8,10009553c9'.", + "title": "Hide Light/Switch Channels", + "description": "A list of light/switch channels to hide from Homebridge. For example '10009553c8SW0' or multiple separated with a comma '10009553c8SW0,10009553c9SW2'.", "default": false }, - "hideFromHB": { - "type": "string", - "title": "Hide Device Channels", - "description": "A list of SW1, SW2, SW3 and SW4 channels to hide from Homebridge. For example '10009553c8SW1' or multiple separated with a comma '10009553c8SW1,10009553c9SW2'.", - "default": "" - }, "disableHTTPRefresh": { "type": "boolean", "title": "Disable Initial Device Refresh", @@ -297,8 +291,6 @@ "debug", "debugReqRes", "hideDevFromHB", - "hideMasters", - "hideFromHB", "disableHTTPRefresh" ] }, @@ -308,6 +300,7 @@ "description": "A variety of optional settings for specific device types.", "expandable": true, "items": [ + "hideChanFromHB", "lowBattThreshold", "inUsePowerThreshold", "sensorTimeLength", diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 95cdcf35..32adccec 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -41,6 +41,10 @@ class eWeLink { this.hiddenMasters = [] this.eveLogPath = this.api.user.storagePath() + '/homebridge-ewelink/' this.wsRefreshFlag = true + + //*** UPGRADE **\\ + this.config.hideChanFromHB += this.config.hideMasters + ',' + this.config.hideFromHB + //**************\\ this.api .on('didFinishLaunching', () => this.eWeLinkSetup()) .on('shutdown', () => this.eWeLinkShutdown()) @@ -266,7 +270,7 @@ class eWeLink { /********************* LIGHTS [MULTI CHANNEL] *********************/ - if ((this.config.hideMasters || '').includes(device.deviceid)) { + if ((this.config.hideChanFromHB.split(',') || []).includes(device.deviceid)) { if (this.devicesInHB.has(device.deviceid + 'SW0')) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) } @@ -279,7 +283,7 @@ class eWeLink { } accessory.control = new DeviceLight(this, accessory) for (let i = 1; i <= cns.chansFromUiid[device.extra.uiid]; i++) { - if ((this.config.hideFromHB || '').includes(device.deviceid + 'SW' + i)) { + if ((this.config.hideChanFromHB.split(',') || []).includes(device.deviceid + 'SW' + i)) { if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + i)) } @@ -311,7 +315,7 @@ class eWeLink { /*********************** SWITCHES [MULTI CHANNEL] ***********************/ - if ((this.config.hideMasters || '').includes(device.deviceid)) { + if ((this.config.hideChanFromHB.split(',') || []).includes(device.deviceid)) { if (this.devicesInHB.has(device.deviceid + 'SW0')) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) } @@ -324,7 +328,7 @@ class eWeLink { } accessory.control = new DeviceSwitch(this, accessory) for (let i = 1; i <= cns.chansFromUiid[device.extra.uiid]; i++) { - if ((this.config.hideFromHB || '').includes(device.deviceid + 'SW' + i)) { + if ((this.config.hideChanFromHB.split(',') || []).includes(device.deviceid + 'SW' + i)) { if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + i)) } From 2c0da5be526e7eff39501abb608fc5fd7d3ed005 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 11 Oct 2020 11:24:52 +0100 Subject: [PATCH 0447/3183] reorganise settings --- config.schema.json | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/config.schema.json b/config.schema.json index a3c41c19..c79c591d 100644 --- a/config.schema.json +++ b/config.schema.json @@ -58,6 +58,20 @@ "description": "If enabled, devices will not be refreshed with their most recent status from eWeLink when Homebridge starts. This setting can be useful for users who block their devices from accessing the internet.", "default": false }, + "inUsePowerThreshold": { + "type": "integer", + "title": "Outlet 'In Use' Threshold", + "description": "Homebridge will set the 'In Use' status of outlet devices to true when the wattage is above this number.", + "default": 0, + "minimum": 0, + "maximum": 100 + }, + "hideTHSwitch": { + "title": "TH10/TH16 Hide Switch", + "type": "boolean", + "description": "If enabled, the switch for the TH10/TH16 devices will be hidden from Homebridge.", + "default": false + }, "lowBattThreshold": { "type": "integer", "title": "Low Battery Threshold", @@ -69,7 +83,7 @@ "sensorTimeLength": { "type": "integer", "title": "Sensor Length", - "description": "The number of seconds which the sensor tile in the Home app will light up for if a sensor detects something.", + "description": "The number of seconds which the sensor tile in the Home app will light up for if a sensor detects something. This setting applies to sensors connected to RF/Zigbee Bridges.", "default": 60, "minimum": 1, "maximum": 120 @@ -77,25 +91,11 @@ "sensorTimeDifference": { "type": "integer", "title": "Sensor Lag", - "description": "An offset in seconds to ignore any notifications if they is a delay between a sensor detecting something and Homebridge receiving the notification.", + "description": "An offset in seconds to ignore any notifications if they is a delay between a sensor detecting something and Homebridge receiving the notification. This setting applies to sensors connected to RF/Zigbee Bridges.", "default": 120, "minimum": 10, "maximum": 300 }, - "inUsePowerThreshold": { - "type": "integer", - "title": "Outlet 'In Use' Threshold", - "description": "Homebridge will set the 'In Use' status of outlet devices to true when the wattage is above this number.", - "default": 0, - "minimum": 0, - "maximum": 100 - }, - "hideTHSwitch": { - "title": "TH10/TH16 Hide Switch", - "type": "boolean", - "description": "If enabled, the switch for the TH10/TH16 devices will be hidden from Homebridge.", - "default": false - }, "hideZBLDPress": { "title": "Zigbee Button Hide Double/Long Press", "type": "boolean", @@ -204,12 +204,12 @@ "deviceId": { "type": "string", "title": "RF Bridge Device ID", - "description": "Device ID of your RF Bridge from your eWeLink app (10 digits normally in the format 1000******)." + "description": "Device ID of your RF Bridge from your eWeLink app (10 digits normally in the format 1000ab23cd)." }, "fullDeviceId": { "type": "string", "title": "Sensor Device ID", - "description": "Device ID of the sensor from Homebridge (13 digits normally in the format 1000******SW*)." + "description": "Device ID of the sensor from Homebridge (13 digits normally in the format 1000ab23cdSW2)." }, "type": { "type": "string", @@ -290,8 +290,8 @@ "items": [ "debug", "debugReqRes", - "hideDevFromHB", - "disableHTTPRefresh" + "disableHTTPRefresh", + "hideDevFromHB" ] }, { @@ -301,11 +301,11 @@ "expandable": true, "items": [ "hideChanFromHB", - "lowBattThreshold", "inUsePowerThreshold", + "hideTHSwitch", + "lowBattThreshold", "sensorTimeLength", "sensorTimeDifference", - "hideTHSwitch", "hideZBLDPress" ] }, From a3d0d76ffb469a1987c85b8ca868f64a5af8a314 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 11 Oct 2020 14:30:32 +0100 Subject: [PATCH 0448/3183] skeleton for 2 garage doors --- config.schema.json | 14 ++++++++++---- lib/constants.js | 8 +++++++- lib/device/garage-two.js | 42 ++++++++++++++++++++++++++++++++++++++++ lib/eWeLink.js | 12 +++++++++++- 4 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 lib/device/garage-two.js diff --git a/config.schema.json b/config.schema.json index c79c591d..806e073c 100644 --- a/config.schema.json +++ b/config.schema.json @@ -121,15 +121,21 @@ "description": "The new type for this device.", "oneOf": [ { - "title": "Garage Door (using Eachen GD-DC5)", + "title": "1 Garage Door (using single/multi-channel device)", "enum": [ - "garage_eachen" + "garage" ] }, { - "title": "Garage Door (using single/multi-channel device)", + "title": "2 Garage Doors (using multi-channel device)", "enum": [ - "garage" + "garage_two" + ] + }, + { + "title": "Garage Door (using Eachen GD-DC5)", + "enum": [ + "garage_eachen" ] }, { diff --git a/lib/constants.js b/lib/constants.js index 3f189523..c364dbb4 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -3,7 +3,7 @@ module.exports = { appId: 'oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq', appSecret: '6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM', httpRetryCodes: ['ENOTFOUND', 'ETIMEDOUT', 'EAI_AGAIN'], - allowedGroups: ['blind', 'garage', 'garage_eachen', 'lock', 'valve'], + allowedGroups: ['blind', 'garage', 'garage_two', 'garage_eachen', 'lock', 'valve'], devicesHideable: ['switch', 'light'], devicesNonLAN: [22, 28, 34, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], @@ -69,6 +69,12 @@ module.exports = { cacheCurrentDoorState: 1, cacheTargetDoorState: 1 }, + defaultGarageTwoCache: { + cacheOneCurrentDoorState: 1, + cacheOneTargetDoorState: 1, + cacheTwoCurrentDoorState: 1, + cacheTwoTargetDoorState: 1 + }, chansFromUiid: { 1: 1, // "SOCKET" \\ 20, MINI, BASIC, S26 2: 2, // "SOCKET_2" \\ diff --git a/lib/device/garage-two.js b/lib/device/garage-two.js new file mode 100644 index 00000000..a0a79b87 --- /dev/null +++ b/lib/device/garage-two.js @@ -0,0 +1,42 @@ +'use strict' +let Characteristic, Service +const utils = require('./../utils') +module.exports = class deviceGarageTwo { + constructor (platform, accessory) { + this.platform = platform + Service = platform.api.hap.Service + Characteristic = platform.api.hap.Characteristic + const arr = ['1', '2'] + arr.forEach(v => { + let gdService + if (!(gdService = accessory.getService('Garage ' + v))) { + accessory + .addService(Service.GarageDoorOpener, 'Garage ' + v, 'garage' + v) + .setCharacteristic(Characteristic.CurrentDoorState, 1) + .setCharacteristic(Characteristic.TargetDoorState, 1) + .setCharacteristic(Characteristic.ObstructionDetected, false) + gdService = accessory.getService('Garage ' + v)) + } + gdService + .getCharacteristic(Characteristic.TargetDoorState) + .on('set', (value, callback) => this.internalUpdate(accessory, 'Garage' + v, value, callback)) + }) + } + + async internalUpdate (accessory, garage, value, callback) { + callback() + try { + + } catch (err) { + this.platform.deviceUpdateError(accessory, err, true) + } + } + + async externalUpdate (accessory, params) { + try { + + } catch (err) { + this.platform.deviceUpdateError(accessory, err, false) + } + } +} diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 32adccec..b3144da5 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -4,6 +4,7 @@ const cns = require('./constants') const DeviceCurtain = require('./device/curtain') const DeviceBlind = require('./device/blind') const DeviceGarage = require('./device/garage') +const DeviceGarageTwo = require('./device/garage-two') const DeviceGarageEachen = require('./device/garage-eachen') const DeviceLock = require('./device/lock') const DeviceValve = require('./device/valve') @@ -167,13 +168,22 @@ class eWeLink { /***************************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage') { /********************************** - GARAGE DOORS [ACCESSORY SIMULATION] + GARAGE DOORS [ONE] [ACCESSORY SIMULATION] **********************************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX', false, cns.defaultGarageCache) accessory.control = new DeviceGarage(this, accessory) /*********************************/ + } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage_two') { + /********************************** + GARAGE DOORS [TWO] [ACCESSORY SIMULATION] + **********************************/ + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', false, cns.defaultGarageTwoCache) + accessory.control = new DeviceGarageTwo(this, accessory) + /*********************************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage_eachen') { /*************************** GARAGE DOORS [EACHEN GD-DC5] From 1369aac25241551404d4a466011339553b5ba597 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 11 Oct 2020 14:36:13 +0100 Subject: [PATCH 0449/3183] skeleton for 2 garage doors #2 --- config.schema.json | 4 ++-- lib/device/garage-two.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config.schema.json b/config.schema.json index 806e073c..aad99e26 100644 --- a/config.schema.json +++ b/config.schema.json @@ -133,7 +133,7 @@ ] }, { - "title": "Garage Door (using Eachen GD-DC5)", + "title": "1 Garage Door (using Eachen GD-DC5)", "enum": [ "garage_eachen" ] @@ -194,7 +194,7 @@ "title": "Sensor", "description": "A Sonoff DW2 sensor can optionally be used for garage doors. This is to determine the current open/closed state of the garage door. Please enter the 10 digit device ID (normally in the format 1000ab23cd). Otherwise leave this blank.", "condition": { - "functionBody": "return (model.groups[arrayIndices] && model.groups[arrayIndices].type==='garage')" + "functionBody": "return (model.groups[arrayIndices] && (model.groups[arrayIndices].type==='garage' || model.groups[arrayIndices].type==='garage_two'))" } } } diff --git a/lib/device/garage-two.js b/lib/device/garage-two.js index a0a79b87..adee0f0f 100644 --- a/lib/device/garage-two.js +++ b/lib/device/garage-two.js @@ -15,7 +15,7 @@ module.exports = class deviceGarageTwo { .setCharacteristic(Characteristic.CurrentDoorState, 1) .setCharacteristic(Characteristic.TargetDoorState, 1) .setCharacteristic(Characteristic.ObstructionDetected, false) - gdService = accessory.getService('Garage ' + v)) + gdService = accessory.getService('Garage ' + v) } gdService .getCharacteristic(Characteristic.TargetDoorState) From 35aeb1f5da80867be183660d3a680dc3ecd71129 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 11 Oct 2020 14:50:24 +0100 Subject: [PATCH 0450/3183] garage-two externalUpdate 1 --- lib/device/garage-two.js | 72 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/lib/device/garage-two.js b/lib/device/garage-two.js index adee0f0f..6605ec05 100644 --- a/lib/device/garage-two.js +++ b/lib/device/garage-two.js @@ -6,8 +6,7 @@ module.exports = class deviceGarageTwo { this.platform = platform Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic - const arr = ['1', '2'] - arr.forEach(v => { + ;['1', '2'].forEach(v => { let gdService if (!(gdService = accessory.getService('Garage ' + v))) { accessory @@ -34,7 +33,74 @@ module.exports = class deviceGarageTwo { async externalUpdate (accessory, params) { try { - + if (!utils.hasProperty(params, 'switches')) { + return + } + let garageConfig + if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + throw new Error('group config missing') + } + if (garageConfig.type !== 'garage_two') { + throw new Error('improper configuration') + } + if (accessory.context.inUse || garageConfig.sensorId) { + return + } + + ;['1', '2'].forEach((v, k) => { + const gcService = accessory.getService('Garage' + v) + const prevState = k === 0 + ? accessory.context.cacheOneCurrentDoorState + : accessory.context.cacheTwoCurrentDoorState + const newPos = [0, 2].includes(prevState) ? 3 : 2 + switch (v) { + case 'Garage 1': + if ( + params.switches[0].switch === params.switches[1].switch || + params.switches[prevState % 2].switch === 'on' + ) { + return + } + break + case 'Garage 2': + if ( + params.switches[2].switch === params.switches[3].switch || + params.switches[(prevState % 2) + 2].switch === 'on' + ) { + return + } + break + } + accessory.context.inUse = true + if (garageConfig.sensorId) { + await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) + } else { + gcService + .updateCharacteristic(Characteristic.TargetDoorState, newPos - 2) + .updateCharacteristic(Characteristic.CurrentDoorState, newPos) + switch (v) { + case 'Garage 1': + accessory.context.cacheOneCurrentDoorState = newPos + accessory.context.cacheTwoTargetDoorState = newPos - 2 + break + case 'Garage 2': + accessory.context.cacheTwoCurrentDoorState = newPos + accessory.context.cacheTwoTargetDoorState = newPos - 2 + break + } + await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) + gcService.updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2) + switch (v) { + case 'Garage 1': + accessory.context.cacheOneCurrentDoorState = newPos - 2 + break + case 'Garage 2': + accessory.context.cacheTwoCurrentDoorState = newPos - 2 + break + } + } + }) + accessory.context.inUse = false } catch (err) { this.platform.deviceUpdateError(accessory, err, false) } From 9ebec9c583620ca13663ce6b1f1b7905c7a52b44 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 11 Oct 2020 15:00:51 +0100 Subject: [PATCH 0451/3183] garage-two externalUpdate 2 --- lib/device/garage-two.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/device/garage-two.js b/lib/device/garage-two.js index 6605ec05..e57149c0 100644 --- a/lib/device/garage-two.js +++ b/lib/device/garage-two.js @@ -31,7 +31,7 @@ module.exports = class deviceGarageTwo { } } - async externalUpdate (accessory, params) { + externalUpdate (accessory, params) { try { if (!utils.hasProperty(params, 'switches')) { return @@ -46,8 +46,8 @@ module.exports = class deviceGarageTwo { if (accessory.context.inUse || garageConfig.sensorId) { return } - - ;['1', '2'].forEach((v, k) => { + + ;['1', '2'].forEach(async (v, k) => { const gcService = accessory.getService('Garage' + v) const prevState = k === 0 ? accessory.context.cacheOneCurrentDoorState From 5ae4bfbf9c5fa8e1ad78042a044ceb9513477be6 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 11 Oct 2020 15:00:58 +0100 Subject: [PATCH 0452/3183] formatting --- lib/eWeLink.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index b3144da5..10f03af3 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -42,10 +42,10 @@ class eWeLink { this.hiddenMasters = [] this.eveLogPath = this.api.user.storagePath() + '/homebridge-ewelink/' this.wsRefreshFlag = true - - //*** UPGRADE **\\ + + //* ** UPGRADE **\\ this.config.hideChanFromHB += this.config.hideMasters + ',' + this.config.hideFromHB - //**************\\ + //* *************\\ this.api .on('didFinishLaunching', () => this.eWeLinkSetup()) .on('shutdown', () => this.eWeLinkShutdown()) From de1e5ac6a461c19f5aec115c2ba24f544385d592 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 11 Oct 2020 15:03:43 +0100 Subject: [PATCH 0453/3183] 3.6.0-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 056b8787..7eeaa3d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0", + "version": "3.6.0-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index b043e40a..b09c0517 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.5.0", + "version": "3.6.0-0", "author": "bwp91", "contributors": [ "gbro115", From a12c2db9dc62298632f8a384b20fe35564456ecc Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 12 Oct 2020 04:35:52 +0100 Subject: [PATCH 0454/3183] garage-two internal update --- lib/device/garage-two.js | 79 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/lib/device/garage-two.js b/lib/device/garage-two.js index e57149c0..21fa2d4c 100644 --- a/lib/device/garage-two.js +++ b/lib/device/garage-two.js @@ -25,7 +25,82 @@ module.exports = class deviceGarageTwo { async internalUpdate (accessory, garage, value, callback) { callback() try { - + let garageConfig + if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + throw new Error('group config missing') + } + if (garageConfig.type !== 'garage_two') { + throw new Error('improper configuration') + } + let sensorDefinition = garageConfig.sensorId || false + if (sensorDefinition) { + const sensors = garageConfig.sensorId.split(',') + switch (garage) { + case 'Garage 1': { + sensorDefinition = sensors[0] || false + break + } + case 'Garage 2': { + sensorDefinition = sensors[1] || false + break + } + } + } + let sAccessory = false + const newPos = value + const params = {} + const gdService = accessory.getService(garage) + if (sensorDefinition && !(sAccessory = this.platform.devicesInHB.get(garageConfig.sensorId + 'SWX'))) { + throw new Error("defined DW2 sensor doesn't exist") + } + if (sensorDefinition && sAccessory.context.type !== 'sensor') { + throw new Error("defined DW2 sensor isn't a sensor") + } + const prevState = sAccessory + ? sAccessory.getService(Service.ContactSensor).getCharacteristic(Characteristic.ContactSensorState).value === 0 + ? 1 + : 0 + : garage === 'Garage 1' + ? accessory.context.cacheOneCurrentDoorState + : accessory.context.cacheTwoCurrentDoorState + if (newPos === prevState % 2) return + accessory.context.inUse = true + gdService + .updateCharacteristic(Characteristic.TargetDoorState, newPos) + .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2) + params.switches = accessory.context.switchState + switch (garage) { + case 'Garage 1': { + accessory.context.cacheOneTargetDoorState = newPos + accessory.context.cacheOneCurrentDoorState = newPos + 2 + params.switches[0].switch = newPos === 0 ? 'on' : 'off' + params.switches[1].switch = newPos === 1 ? 'on' : 'off' + break + } + case 'Garage 2': { + accessory.context.cacheTwoTargetDoorState = newPos + accessory.context.cacheTwoCurrentDoorState = newPos + 2 + params.switches[2].switch = newPos === 0 ? 'on' : 'off' + params.switches[3].switch = newPos === 1 ? 'on' : 'off' + break + } + } + await this.platform.sendDeviceUpdate(accessory, params) + await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) + if (!sAccessory) { + gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos) + switch (garage) { + case 'Garage 1': { + accessory.context.cacheOneCurrentDoorState = newPos + break + } + case 'Garage 2': { + accessory.context.cacheTwoCurrentDoorState = newPos + break + } + } + } + accessory.context.inUse = false } catch (err) { this.platform.deviceUpdateError(accessory, err, true) } @@ -46,7 +121,7 @@ module.exports = class deviceGarageTwo { if (accessory.context.inUse || garageConfig.sensorId) { return } - + accessory.context.switchState = params.switches ;['1', '2'].forEach(async (v, k) => { const gcService = accessory.getService('Garage' + v) const prevState = k === 0 From 31e9718f88d2172dc47d8c41dcdc2f11c9948551 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 12 Oct 2020 04:40:57 +0100 Subject: [PATCH 0455/3183] 3.6.0-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7eeaa3d0..fb31f9da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.0-0", + "version": "3.6.0-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index b09c0517..1d13b435 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.0-0", + "version": "3.6.0-1", "author": "bwp91", "contributors": [ "gbro115", From b14db31ca57ee4f17414b2614ec04897dbdef110 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 12 Oct 2020 10:11:05 +0100 Subject: [PATCH 0456/3183] garage-two externalUpdate 3 --- lib/device/garage-two.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/device/garage-two.js b/lib/device/garage-two.js index 21fa2d4c..c647f167 100644 --- a/lib/device/garage-two.js +++ b/lib/device/garage-two.js @@ -122,14 +122,15 @@ module.exports = class deviceGarageTwo { return } accessory.context.switchState = params.switches - ;['1', '2'].forEach(async (v, k) => { - const gcService = accessory.getService('Garage' + v) - const prevState = k === 0 + this.platform.log.warn(accessory.context.switchState) + ;['1', '2'].forEach(async v => { + const gcService = accessory.getService('Garage ' + v) + const prevState = v === '1' ? accessory.context.cacheOneCurrentDoorState : accessory.context.cacheTwoCurrentDoorState const newPos = [0, 2].includes(prevState) ? 3 : 2 switch (v) { - case 'Garage 1': + case '1': if ( params.switches[0].switch === params.switches[1].switch || params.switches[prevState % 2].switch === 'on' @@ -137,7 +138,7 @@ module.exports = class deviceGarageTwo { return } break - case 'Garage 2': + case '2': if ( params.switches[2].switch === params.switches[3].switch || params.switches[(prevState % 2) + 2].switch === 'on' @@ -154,11 +155,11 @@ module.exports = class deviceGarageTwo { .updateCharacteristic(Characteristic.TargetDoorState, newPos - 2) .updateCharacteristic(Characteristic.CurrentDoorState, newPos) switch (v) { - case 'Garage 1': + case '1': accessory.context.cacheOneCurrentDoorState = newPos accessory.context.cacheTwoTargetDoorState = newPos - 2 break - case 'Garage 2': + case '2': accessory.context.cacheTwoCurrentDoorState = newPos accessory.context.cacheTwoTargetDoorState = newPos - 2 break @@ -166,10 +167,10 @@ module.exports = class deviceGarageTwo { await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) gcService.updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2) switch (v) { - case 'Garage 1': + case '1': accessory.context.cacheOneCurrentDoorState = newPos - 2 break - case 'Garage 2': + case '2': accessory.context.cacheTwoCurrentDoorState = newPos - 2 break } From f491fb9916d92ab1d6d8f98009f15fe298c3807b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 12 Oct 2020 10:11:17 +0100 Subject: [PATCH 0457/3183] option to disable eve logging --- config.schema.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config.schema.json b/config.schema.json index aad99e26..b70ca21d 100644 --- a/config.schema.json +++ b/config.schema.json @@ -58,6 +58,12 @@ "description": "If enabled, devices will not be refreshed with their most recent status from eWeLink when Homebridge starts. This setting can be useful for users who block their devices from accessing the internet.", "default": false }, + "disableEveLogging": { + "type": "boolean", + "title": "Disable Eve Logging", + "description": "If enabled, switch, thermostat and power readings will not be logged to the Eve App.", + "default": false + }, "inUsePowerThreshold": { "type": "integer", "title": "Outlet 'In Use' Threshold", @@ -307,6 +313,7 @@ "expandable": true, "items": [ "hideChanFromHB", + "disableEveLogging", "inUsePowerThreshold", "hideTHSwitch", "lowBattThreshold", From 0dd560b29cbb48d432defc43db4a503398a9c497 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 12 Oct 2020 10:16:49 +0100 Subject: [PATCH 0458/3183] switch eve logging --- lib/device/switch.js | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/lib/device/switch.js b/lib/device/switch.js index 45e150e9..f287025f 100644 --- a/lib/device/switch.js +++ b/lib/device/switch.js @@ -1,16 +1,34 @@ 'use strict' -let Characteristic, Service +let Characteristic, EveHistoryService, Service const cns = require('./../constants') +const corrInterval = require('correcting-interval') +const fakegato = require('fakegato-history') const utils = require('./../utils') module.exports = class deviceSwitch { constructor (platform, accessory) { this.platform = platform Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic + EveHistoryService = fakegato(platform.api) const switchService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch) switchService .getCharacteristic(Characteristic.On) .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + if (!this.platform.config.disableEveLogging) { + accessory.log = this.platform.log + accessory.eveLogger = new EveHistoryService('energy', accessory, { + storage: 'fs', + minutes: 5, + path: this.platform.eveLogPath + }) + corrInterval.setCorrectingInterval(() => { + const isOn = switchService.getCharacteristic(Characteristic.On).value + accessory.eveLogger.addEntry({ + time: Date.now(), + status: isOn ? 1 : 0 + }) + }, 300000) + } } async internalUpdate (accessory, value, callback) { @@ -90,6 +108,12 @@ module.exports = class deviceSwitch { if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID)) { if (!utils.hasProperty(params, 'switch')) return accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switch === 'on') + if (!this.platform.config.disableEveLogging) { + accessory.eveLogger.addEntry({ + time: Date.now(), + status: params.switch === 'on' ? 1 : 0 + }) + } } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID)) { if (!utils.hasProperty(params, 'switches')) return const idToCheck = accessory.context.hbDeviceId.slice(0, -1) @@ -104,10 +128,22 @@ module.exports = class deviceSwitch { oAccessory .getService(Service.Switch) .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === 'on') + if (!this.platform.config.disableEveLogging) { + accessory.eveLogger.addEntry({ + time: Date.now(), + status: params.switches[i - 1].switch === 'on' ? 1 : 0 + }) + } } } if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState) + if (!this.platform.config.disableEveLogging) { + accessory.eveLogger.addEntry({ + time: Date.now(), + status: primaryState ? 1 : 0 + }) + } } } } catch (err) { From ad6a474b81d4412e3d53250cfed87617db4134bb Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 12 Oct 2020 13:42:08 +0100 Subject: [PATCH 0459/3183] update deps --- package-lock.json | 81 +++++++++++++++++++++++------------------------ package.json | 2 +- 2 files changed, 41 insertions(+), 42 deletions(-) diff --git a/package-lock.json b/package-lock.json index fb31f9da..fcf3e199 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,11 +21,11 @@ }, "dependencies": { "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "ms": { @@ -67,9 +67,9 @@ "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" }, "bignumber.js": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", - "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" }, "bonjour": { "version": "3.5.0", @@ -224,9 +224,8 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "fakegato-history": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/fakegato-history/-/fakegato-history-0.5.6.tgz", - "integrity": "sha512-LlsOkiw9LntVlRlBkssD5ozhEkQzYuEJUlvXk5YAgBQcWzk19PQ5g+NoKfs6SRY1qAeC1onb65hes4mCvY+JmA==", + "version": "github:simont77/fakegato-history#bc07b298838ec98a88ba07f519c4af53b9ce4230", + "from": "github:simont77/fakegato-history#Updated-Energy", "requires": { "debug": "^2.2.0", "googleapis": ">39.1.0", @@ -249,9 +248,9 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "gaxios": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.1.0.tgz", - "integrity": "sha512-DDTn3KXVJJigtz+g0J3vhcfbDbKtAroSTxauWsdnP57sM5KZ3d2c/3D9RKFJ86s43hfw6WULg6TXYw/AYiBlpA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.2.0.tgz", + "integrity": "sha512-+6WPeVzPvOshftpxJwRi2Ozez80tn/hdtOUag7+gajDHRJvAblKxTFSSMPtr2hmnLy7p0mvYz0rMXLBl8pSO7Q==", "requires": { "abort-controller": "^3.0.0", "extend": "^3.0.2", @@ -261,18 +260,18 @@ } }, "gcp-metadata": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.4.tgz", - "integrity": "sha512-5J/GIH0yWt/56R3dNaNWPGQ/zXsZOddYECfJaqxFWgrZ9HC2Kvc5vl9upOgUUHKzURjAVf2N+f6tEJiojqXUuA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.2.0.tgz", + "integrity": "sha512-vQZD57cQkqIA6YPGXM/zc+PIZfNRFdukWGsGZ5+LcJzesi5xp6Gn7a02wRJi4eXPyArNMIYpPET4QMxGqtlk6Q==", "requires": { "gaxios": "^3.0.0", "json-bigint": "^1.0.0" } }, "google-auth-library": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.6.tgz", - "integrity": "sha512-fWYdRdg55HSJoRq9k568jJA1lrhg9i2xgfhVIMJbskUmbDpJGHsbv9l41DGhCDXM21F9Kn4kUwdysgxSYBYJUw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.1.tgz", + "integrity": "sha512-0WfExOx3FrLYnY88RICQxvpaNzdwjz44OsHqHkIoAJfjY6Jck6CZRl1ASWadk+wbJ0LhkQ8rNY4zZebKml4Ghg==", "requires": { "arrify": "^2.0.0", "base64-js": "^1.3.0", @@ -280,7 +279,7 @@ "fast-text-encoding": "^1.0.0", "gaxios": "^3.0.0", "gcp-metadata": "^4.1.0", - "gtoken": "^5.0.0", + "gtoken": "^5.0.4", "jws": "^4.0.0", "lru-cache": "^6.0.0" } @@ -294,21 +293,21 @@ } }, "googleapis": { - "version": "59.0.0", - "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-59.0.0.tgz", - "integrity": "sha512-GV/E4KRN89a4GxSk7D7cwUfRYgcJHR05sOgm/WGdwc/u8dxNXG5lWmz9gF5ZwFGk2yKtVxL4VZNn4zBuZ6rmGg==", + "version": "61.0.0", + "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-61.0.0.tgz", + "integrity": "sha512-aXaNgWKaALiYrfwrJ0ZYhRo2abyIBcqUjyNMgkbghKJMiCeOwcktlaGseH6JbPlCxXYCE8ZDfvAQqVNsf+6/RA==", "requires": { "google-auth-library": "^6.0.0", "googleapis-common": "^4.4.0" } }, "googleapis-common": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-4.4.0.tgz", - "integrity": "sha512-Bgrs8/1OZQFFIfVuX38L9t48rPAkVUXttZy6NzhhXxFOEMSHgfFIjxou7RIXOkBHxmx2pVwct9WjKkbnqMYImQ==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-4.4.1.tgz", + "integrity": "sha512-F1QcH8oU7TOuZex9p+XW7TeyLY0332NwBwJ3dZoN+51pXZXB5JjrKswrpgbhuREuIe8xAy8J1rlmFqxeP2mFfA==", "requires": { "extend": "^3.0.2", - "gaxios": "^3.0.0", + "gaxios": "^3.2.0", "google-auth-library": "^6.0.0", "qs": "^6.7.0", "url-template": "^2.0.8", @@ -316,12 +315,12 @@ } }, "gtoken": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.3.tgz", - "integrity": "sha512-Nyd1wZCMRc2dj/mAD0LlfQLcAO06uKdpKJXvK85SGrF5+5+Bpfil9u/2aw35ltvEHjvl0h5FMKN5knEU+9JrOg==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.4.tgz", + "integrity": "sha512-U9wnSp4GZ7ov6zRdPuRHG4TuqEWqRRgT1gfXGNArhzBUn9byrPeH8uTmBWU/ZiWJJvTEmkjhDIC3mqHWdVi3xQ==", "requires": { "gaxios": "^3.0.0", - "google-p12-pem": "^3.0.0", + "google-p12-pem": "^3.0.3", "jws": "^4.0.0", "mime": "^2.2.0" } @@ -380,11 +379,11 @@ }, "dependencies": { "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "ms": { @@ -486,9 +485,9 @@ "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" }, "moment": { - "version": "2.27.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz", - "integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==" + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" }, "ms": { "version": "2.0.0", @@ -667,9 +666,9 @@ "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" }, "uuid": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.0.tgz", - "integrity": "sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==" + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", + "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==" }, "websocket-as-promised": { "version": "1.0.1", diff --git a/package.json b/package.json index 1d13b435..cc91d5b7 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "axios": "0.20.0", "color-convert": "2.0.1", "correcting-interval": "2.0.0", - "fakegato-history": "0.5.6", + "fakegato-history": "simont77/fakegato-history#Updated-Energy", "homebridge-lib": "4.7.16", "interval-promise": "1.4.0", "node-dns-sd": "0.4.2", From 0116834d729d05e902d3832cafc9a41f48df5cfc Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 12 Oct 2020 15:52:10 +0100 Subject: [PATCH 0460/3183] upgrade config --- config.schema.json | 28 ++++++++++++++++++++++++++++ lib/eWeLink.js | 8 +++++++- lib/eWeLinkLAN.js | 13 ++++++------- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/config.schema.json b/config.schema.json index b70ca21d..fa9d4669 100644 --- a/config.schema.json +++ b/config.schema.json @@ -108,6 +108,34 @@ "description": "If enabled, double and long press options will be hidden for the ZigBee button.", "default": false }, + "nameOverride": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fullDeviceId": { + "type": "string" + }, + "deviceName": { + "type": "string" + } + } + } + }, + "ipOverride": { + "type": "array", + "items": { + "type": "object", + "properties": { + "deviceId": { + "type": "string" + }, + "deviceIP": { + "type": "string" + } + } + } + }, "groups": { "type": "array", "title": "Accessory Simulations", diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 10f03af3..db82f375 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -45,6 +45,12 @@ class eWeLink { //* ** UPGRADE **\\ this.config.hideChanFromHB += this.config.hideMasters + ',' + this.config.hideFromHB + this.nameOverrideTmp = {} + this.ipOverrideTmp = {} + this.config.nameOverride.forEach(x => this.nameOverrideTmp[x.key] = x.value) + this.config.ipOverride.forEach(x => this.ipOverrideTmp[x.key] = x.value) + this.config.nameOverride = this.nameOverrideTmp + this.config.ipOverride = this.ipOverrideTmp //* *************\\ this.api .on('didFinishLaunching', () => this.eWeLinkSetup()) @@ -493,7 +499,7 @@ class eWeLink { if (['1', '2', '3', '4'].includes(switchNumber) && type !== 'rf_sub') { newDeviceName += ' SW' + switchNumber } - if (utils.hasProperty(this.config.nameOverride || {}, hbDeviceId)) { + if (utils.hasProperty(this.config.nameOverride, hbDeviceId)) { newDeviceName = this.config.nameOverride[hbDeviceId] } try { diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index 2982f371..b06e257a 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -11,15 +11,14 @@ module.exports = class eWeLinkLAN { this.config = config this.debug = this.config.debug || false this.debugReqRes = this.config.debugReqRes || false - this.ipOverrides = this.config.ipOverride || {} this.emitter = new EventEmitter() this.devices = devices this.deviceMap = new Map() devices.forEach(device => { this.deviceMap.set(device.deviceid, { apiKey: device.devicekey, - online: !!utils.hasProperty(this.ipOverrides, device.deviceid), - ip: utils.hasProperty(this.ipOverrides, device.deviceid) ? this.ipOverrides[device.deviceid] : null + online: utils.hasProperty(this.config.ipOverride, device.deviceid), + ip: utils.hasProperty(this.config.ipOverride, device.deviceid) ? this.config.ipOverride[device.deviceid] : null }) }) } @@ -30,7 +29,7 @@ module.exports = class eWeLinkLAN { let d const deviceId = device.fqdn.replace('._ewelink._tcp.local', '').replace('eWeLink_', '') if ((d = this.deviceMap.get(deviceId))) { - if (!utils.hasProperty(this.ipOverrides, deviceId)) { + if (!utils.hasProperty(this.config.ipOverride, deviceId)) { this.deviceMap.set(deviceId, { apiKey: d.apiKey, online: true, @@ -61,7 +60,7 @@ module.exports = class eWeLinkLAN { const dText = crypto.createDecipheriv('aes-128-cbc', key, Buffer.from(rdata.iv, 'base64')) const pText = Buffer.concat([dText.update(Buffer.from(data, 'base64')), dText.final()]).toString('utf8') let params - if (packet.address !== deviceInfo.ip && !utils.hasProperty(this.ipOverrides, rdata.id)) { + if (packet.address !== deviceInfo.ip && !utils.hasProperty(this.config.ipOverride, rdata.id)) { this.deviceMap.set(rdata.id, { apiKey: deviceInfo.apiKey, online: true, @@ -166,8 +165,8 @@ module.exports = class eWeLinkLAN { addDeviceToMap (device) { this.deviceMap.set(device.deviceid, { apiKey: device.devicekey, - online: !!utils.hasProperty(this.ipOverrides, device.deviceid), - ip: utils.hasProperty(this.ipOverrides, device.deviceid) ? this.ipOverrides[device.deviceid] : null + online: utils.hasProperty(this.config.ipOverride, device.deviceid), + ip: utils.hasProperty(this.config.ipOverride, device.deviceid) ? this.config.ipOverride[device.deviceid] : null }) } From 62df4f915d2929c8bceca325f50b7b9f12383344 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 12 Oct 2020 16:03:23 +0100 Subject: [PATCH 0461/3183] Update eWeLink.js --- lib/eWeLink.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index db82f375..7ca0c121 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -47,8 +47,8 @@ class eWeLink { this.config.hideChanFromHB += this.config.hideMasters + ',' + this.config.hideFromHB this.nameOverrideTmp = {} this.ipOverrideTmp = {} - this.config.nameOverride.forEach(x => this.nameOverrideTmp[x.key] = x.value) - this.config.ipOverride.forEach(x => this.ipOverrideTmp[x.key] = x.value) + this.config.nameOverride.forEach(x => (this.nameOverrideTmp[x.key] = x.value)) + this.config.ipOverride.forEach(x => (this.ipOverrideTmp[x.key] = x.value)) this.config.nameOverride = this.nameOverrideTmp this.config.ipOverride = this.ipOverrideTmp //* *************\\ From aa80dc2769ed2e658083eb70d633586fa4a7536f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 13 Oct 2020 06:06:48 +0100 Subject: [PATCH 0462/3183] Update config.schema.json --- config.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.schema.json b/config.schema.json index fa9d4669..31b651c1 100644 --- a/config.schema.json +++ b/config.schema.json @@ -50,7 +50,7 @@ "type": "string", "title": "Hide Light/Switch Channels", "description": "A list of light/switch channels to hide from Homebridge. For example '10009553c8SW0' or multiple separated with a comma '10009553c8SW0,10009553c9SW2'.", - "default": false + "default": "" }, "disableHTTPRefresh": { "type": "boolean", From 616db674a5561cf499c1f2906b3b3798ada24d2e Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Wed, 14 Oct 2020 08:16:42 +0100 Subject: [PATCH 0463/3183] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 1d7026bd..dbed106a 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,9 @@ Homebridge plugin to control eWeLink devices with original firmware. +### Homebridge +To use this plugin, you will need to already have Homebridge installed. Please refer to the [Homebridge website](https://homebridge.io) for more information and installation instructions. + ### Setup * [Installation (Homebridge)](https://github.com/bwp91/homebridge-ewelink/wiki/Installation-(Homebridge)) * [Installation (HOOBS)](https://github.com/bwp91/homebridge-ewelink/wiki/Installation-(HOOBS)) From f234aade28ca13d3d3bf583e819c95000e0d242d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 14 Oct 2020 14:47:11 +0100 Subject: [PATCH 0464/3183] jshint options --- index.js | 1 + lib/constants.js | 1 + lib/device/blind.js | 1 + lib/device/curtain.js | 1 + lib/device/fan.js | 1 + lib/device/garage-eachen.js | 1 + lib/device/garage-two.js | 1 + lib/device/garage.js | 1 + lib/device/light.js | 1 + lib/device/lock.js | 1 + lib/device/outlet.js | 1 + lib/device/rf-bridge.js | 24 ++++++++++++------------ lib/device/scm.js | 1 + lib/device/sensor.js | 5 +++-- lib/device/switch.js | 1 + lib/device/thermostat.js | 1 + lib/device/usb.js | 1 + lib/device/valve.js | 1 + lib/device/zb-dev.js | 7 ++++--- lib/eWeLink.js | 6 +++--- lib/eWeLinkHTTP.js | 7 ++++++- lib/eWeLinkLAN.js | 1 + lib/eWeLinkWS.js | 1 + lib/utils.js | 1 + 24 files changed, 47 insertions(+), 21 deletions(-) diff --git a/index.js b/index.js index bff9ae59..c815dcbd 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' module.exports = function (homebridge) { const eWeLink = require('./lib/eWeLink.js')(homebridge) diff --git a/lib/constants.js b/lib/constants.js index c364dbb4..1c92339c 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' module.exports = { appId: 'oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq', diff --git a/lib/device/blind.js b/lib/device/blind.js index fca991d9..ec90d22d 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' let Characteristic, Service const cns = require('./../constants') diff --git a/lib/device/curtain.js b/lib/device/curtain.js index 6e16002c..18ebcbb5 100644 --- a/lib/device/curtain.js +++ b/lib/device/curtain.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' let Characteristic, Service const utils = require('./../utils') diff --git a/lib/device/fan.js b/lib/device/fan.js index 3919cdc3..b84aed51 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' let Characteristic, Service const cns = require('./../constants') diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 7983fff2..42e5d085 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' let Characteristic, Service const utils = require('./../utils') diff --git a/lib/device/garage-two.js b/lib/device/garage-two.js index c647f167..931220f4 100644 --- a/lib/device/garage-two.js +++ b/lib/device/garage-two.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' let Characteristic, Service const utils = require('./../utils') diff --git a/lib/device/garage.js b/lib/device/garage.js index d4f6a46c..d11cccbf 100644 --- a/lib/device/garage.js +++ b/lib/device/garage.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' let Characteristic, Service const utils = require('./../utils') diff --git a/lib/device/light.js b/lib/device/light.js index aead63ec..14125bf1 100644 --- a/lib/device/light.js +++ b/lib/device/light.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' let Characteristic, Service const cns = require('./../constants') diff --git a/lib/device/lock.js b/lib/device/lock.js index eed6ef29..7ccb89ae 100644 --- a/lib/device/lock.js +++ b/lib/device/lock.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' let Characteristic, Service const utils = require('./../utils') diff --git a/lib/device/outlet.js b/lib/device/outlet.js index ae2a1419..ea799489 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' let Characteristic, EveHistoryService, EveService, Service const cns = require('./../constants') diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index d1072925..e52a6b60 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' let Characteristic, Service const utils = require('./../utils') @@ -8,43 +9,42 @@ module.exports = class deviceRFBridge { Characteristic = platform.api.hap.Characteristic switch (accessory.context.subType) { case 'water': - accessory.getService(Service.LeakSensor) || accessory.addService(Service.LeakSensor) + if (!accessory.getService(Service.LeakSensor)) accessory.addService(Service.LeakSensor) break case 'fire': case 'smoke': - accessory.getService(Service.SmokeSensor) || accessory.addService(Service.SmokeSensor) + if (!accessory.getService(Service.SmokeSensor)) accessory.addService(Service.SmokeSensor) break case 'co': - accessory.getService(Service.CarbonMonoxideSensor) || accessory.addService(Service.CarbonMonoxideSensor) + if (!accessory.getService(Service.CarbonMonoxideSensor)) accessory.addService(Service.CarbonMonoxideSensor) break case 'co2': - accessory.getService(Service.CarbonDioxideSensor) || accessory.addService(Service.CarbonDioxideSensor) + if (!accessory.getService(Service.CarbonDioxideSensor)) accessory.addService(Service.CarbonDioxideSensor) break case 'contact': - accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor) + if (!accessory.getService(Service.ContactSensor)) accessory.addService(Service.ContactSensor) break case 'occupancy': - accessory.getService(Service.OccupancySensor) || accessory.addService(Service.OccupancySensor) + if (!accessory.getService(Service.OccupancySensor)) accessory.addService(Service.OccupancySensor) break default: - accessory.getService(Service.MotionSensor) || accessory.addService(Service.MotionSensor) + if (!accessory.getService(Service.MotionSensor)) accessory.addService(Service.MotionSensor) break case 'button': Object.entries(accessory.context.buttons).forEach(([chan, name]) => { - accessory.getService(name) || accessory.addService(Service.Switch, name, 'switch' + chan) + if (!accessory.getService(name)) accessory.addService(Service.Switch, name, 'switch' + chan) accessory.getService(name).updateCharacteristic(Characteristic.On, false) accessory.getService(name).getCharacteristic(Characteristic.On) - .on('set', (value, callback) => { - value ? this.internalUpdate(accessory, chan, name, callback) : callback() - }) + .on('set', (value, callback) => this.internalUpdate(accessory, chan, name, value, callback)) }) break } } - async internalUpdate (accessory, rfChl, service, callback) { + async internalUpdate (accessory, rfChl, service, value, callback) { callback() try { + if (!value) return const params = { cmd: 'transmit', rfChl: parseInt(rfChl) diff --git a/lib/device/scm.js b/lib/device/scm.js index 8f22a3e2..9e4e1165 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' let Characteristic, Service const cns = require('./../constants') diff --git a/lib/device/sensor.js b/lib/device/sensor.js index f8eb9c6e..0ded5346 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' let Characteristic, Service const utils = require('./../utils') @@ -6,8 +7,8 @@ module.exports = class deviceSensor { this.platform = platform Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic - accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor) - accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService) + if (!accessory.getService(Service.ContactSensor)) accessory.addService(Service.ContactSensor) + if (!accessory.getService(Service.BatteryService)) accessory.addService(Service.BatteryService) } async externalUpdate (accessory, params) { diff --git a/lib/device/switch.js b/lib/device/switch.js index f287025f..c9371a79 100644 --- a/lib/device/switch.js +++ b/lib/device/switch.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' let Characteristic, EveHistoryService, Service const cns = require('./../constants') diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index 934314a8..92a81340 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' let Characteristic, EveHistoryService, Service const corrInterval = require('correcting-interval') diff --git a/lib/device/usb.js b/lib/device/usb.js index eda32d7c..7089bb03 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' let Characteristic, Service const cns = require('./../constants') diff --git a/lib/device/valve.js b/lib/device/valve.js index ee41f284..23e38061 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' let Characteristic, Service const utils = require('./../utils') diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index e1ca5434..83f70153 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' let Characteristic, Service, EveHistoryService const corrInterval = require('correcting-interval') @@ -9,7 +10,7 @@ module.exports = class deviceZBDev { Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic EveHistoryService = fakegato(platform.api) - accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService) + if (!accessory.getService(Service.BatteryService)) accessory.addService(Service.BatteryService) switch (accessory.context.eweUIID) { case 1000: { const zbspsService = @@ -44,10 +45,10 @@ module.exports = class deviceZBDev { break } case 2026: - accessory.getService(Service.MotionSensor) || accessory.addService(Service.MotionSensor) + if (!accessory.getService(Service.MotionSensor)) accessory.addService(Service.MotionSensor) break case 3026: - accessory.getService(Service.ContactSensor) || accessory.addService(Service.ContactSensor) + if (!accessory.getService(Service.ContactSensor)) accessory.addService(Service.ContactSensor) break } } diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 7ca0c121..3ca56137 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' let Accessory, Characteristic, Service const cns = require('./constants') @@ -42,15 +43,14 @@ class eWeLink { this.hiddenMasters = [] this.eveLogPath = this.api.user.storagePath() + '/homebridge-ewelink/' this.wsRefreshFlag = true - - //* ** UPGRADE **\\ - this.config.hideChanFromHB += this.config.hideMasters + ',' + this.config.hideFromHB this.nameOverrideTmp = {} this.ipOverrideTmp = {} this.config.nameOverride.forEach(x => (this.nameOverrideTmp[x.key] = x.value)) this.config.ipOverride.forEach(x => (this.ipOverrideTmp[x.key] = x.value)) this.config.nameOverride = this.nameOverrideTmp this.config.ipOverride = this.ipOverrideTmp + //* ** UPGRADE **\\ + this.config.hideChanFromHB += this.config.hideMasters + ',' + this.config.hideFromHB //* *************\\ this.api .on('didFinishLaunching', () => this.eWeLinkSetup()) diff --git a/lib/eWeLinkHTTP.js b/lib/eWeLinkHTTP.js index 9a05d605..e311f53b 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/eWeLinkHTTP.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' const axios = require('axios') const cns = require('./constants') @@ -83,7 +84,11 @@ module.exports = class eWeLinkHTTP { countryCode: this.cCode, password: this.password } - this.username.includes('@') ? (data.email = this.username) : (data.phoneNumber = this.username) + if (this.username.includes('@')) { + data.email = this.username + } else { + data.phoneNumber = this.username + } if (this.debugReqRes) { const msg = JSON.stringify(data, null, 2).replace(this.password, '**hidden**').replace(this.username, '**hidden**') this.log.warn('Sending HTTP login() request. This text is yellow for clarity.\n%s', msg) diff --git a/lib/eWeLinkLAN.js b/lib/eWeLinkLAN.js index b06e257a..a04cdbcd 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/eWeLinkLAN.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' const axios = require('axios') const cns = require('./constants') diff --git a/lib/eWeLinkWS.js b/lib/eWeLinkWS.js index 88cfbb04..50d0fe19 100644 --- a/lib/eWeLinkWS.js +++ b/lib/eWeLinkWS.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' const axios = require('axios') const cns = require('./constants') diff --git a/lib/utils.js b/lib/utils.js index eef849c6..4cd84223 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,3 +1,4 @@ +/* jshint -W014, -W033, esversion: 9 */ 'use strict' module.exports = { sleep: ms => { From 9e4e38ceee95bcbc85955328360d329c0c2668ae Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 14 Oct 2020 14:47:19 +0100 Subject: [PATCH 0465/3183] tidy up --- config.schema.json | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/config.schema.json b/config.schema.json index 31b651c1..e34e5776 100644 --- a/config.schema.json +++ b/config.schema.json @@ -14,43 +14,42 @@ "countryCode": { "type": "string", "title": "Country Code", + "required": true, "description": "The telephone country code linked to your eWeLink account (without the +)." }, "username": { "type": "string", "title": "Username", + "required": true, "description": "The phone number or email address linked to your eWeLink account. If you use a phone number please enter the country code (with the +), for example +8613185260282." }, "password": { "type": "string", "title": "Password", + "required": true, "description": "The password for your eWeLink account." }, "debug": { "title": "Debug Logging", "type": "boolean", - "required": true, "description": "If enabled, more information will be added to the Homebridge log.", "default": false }, "debugReqRes": { "title": "Request & Response Logging", "type": "boolean", - "required": true, "description": "If enabled, HTTP, web socket and LAN mode messages will be added to the log. Not recommended for long-term use.", "default": false }, "hideDevFromHB": { "type": "string", "title": "Hide Devices", - "description": "A list of eWeLink devices to hide from Homebridge. For example '10009553c8' or multiple separated with a comma '10009553c8,10009553c9'.", - "default": "" + "description": "A list of eWeLink devices to hide from Homebridge. For example '10009553c8' or multiple separated with a comma '10009553c8,10009553c9'." }, "hideChanFromHB": { "type": "string", "title": "Hide Light/Switch Channels", - "description": "A list of light/switch channels to hide from Homebridge. For example '10009553c8SW0' or multiple separated with a comma '10009553c8SW0,10009553c9SW2'.", - "default": "" + "description": "A list of light/switch channels to hide from Homebridge. For example '10009553c8SW0' or multiple separated with a comma '10009553c8SW0,10009553c9SW2'." }, "disableHTTPRefresh": { "type": "boolean", @@ -136,6 +135,9 @@ } } }, + "disablePlugin": { + "type": "boolean" + }, "groups": { "type": "array", "title": "Accessory Simulations", @@ -151,7 +153,6 @@ "type": { "type": "string", "title": "Type", - "default": "null", "description": "The new type for this device.", "oneOf": [ { @@ -195,7 +196,6 @@ "setup": { "type": "string", "title": "Device Setup", - "default": "null", "description": "The setup for your garage doors.", "condition": { "functionBody": "return (model.groups[arrayIndices] && model.groups[arrayIndices].type==='garage')" @@ -254,7 +254,6 @@ "type": { "type": "string", "title": "Sensor Type", - "default": "motion", "description": "Select the type of sensor you would like to expose this as in Homebridge.", "oneOf": [ { @@ -304,12 +303,7 @@ } } } - }, - "required": [ - "countryCode", - "username", - "password" - ] + } }, "layout": [ { From 733aaff29587d9c1bc8acb72db4816e101af8293 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 14 Oct 2020 14:47:26 +0100 Subject: [PATCH 0466/3183] Homebridge info --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 1d7026bd..dbed106a 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,9 @@ Homebridge plugin to control eWeLink devices with original firmware. +### Homebridge +To use this plugin, you will need to already have Homebridge installed. Please refer to the [Homebridge website](https://homebridge.io) for more information and installation instructions. + ### Setup * [Installation (Homebridge)](https://github.com/bwp91/homebridge-ewelink/wiki/Installation-(Homebridge)) * [Installation (HOOBS)](https://github.com/bwp91/homebridge-ewelink/wiki/Installation-(HOOBS)) From 8c504753187cba7da65f5e095d2917a041ca90ea Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 14 Oct 2020 15:28:43 +0100 Subject: [PATCH 0467/3183] revert switch logging (for now) --- lib/device/switch.js | 40 ++-------------------------------------- 1 file changed, 2 insertions(+), 38 deletions(-) diff --git a/lib/device/switch.js b/lib/device/switch.js index c9371a79..8ab31ae1 100644 --- a/lib/device/switch.js +++ b/lib/device/switch.js @@ -1,35 +1,17 @@ /* jshint -W014, -W033, esversion: 9 */ 'use strict' -let Characteristic, EveHistoryService, Service +let Characteristic, Service const cns = require('./../constants') -const corrInterval = require('correcting-interval') -const fakegato = require('fakegato-history') const utils = require('./../utils') module.exports = class deviceSwitch { constructor (platform, accessory) { this.platform = platform Service = platform.api.hap.Service Characteristic = platform.api.hap.Characteristic - EveHistoryService = fakegato(platform.api) const switchService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch) switchService .getCharacteristic(Characteristic.On) .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) - if (!this.platform.config.disableEveLogging) { - accessory.log = this.platform.log - accessory.eveLogger = new EveHistoryService('energy', accessory, { - storage: 'fs', - minutes: 5, - path: this.platform.eveLogPath - }) - corrInterval.setCorrectingInterval(() => { - const isOn = switchService.getCharacteristic(Characteristic.On).value - accessory.eveLogger.addEntry({ - time: Date.now(), - status: isOn ? 1 : 0 - }) - }, 300000) - } } async internalUpdate (accessory, value, callback) { @@ -109,12 +91,6 @@ module.exports = class deviceSwitch { if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID)) { if (!utils.hasProperty(params, 'switch')) return accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switch === 'on') - if (!this.platform.config.disableEveLogging) { - accessory.eveLogger.addEntry({ - time: Date.now(), - status: params.switch === 'on' ? 1 : 0 - }) - } } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID)) { if (!utils.hasProperty(params, 'switches')) return const idToCheck = accessory.context.hbDeviceId.slice(0, -1) @@ -129,26 +105,14 @@ module.exports = class deviceSwitch { oAccessory .getService(Service.Switch) .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === 'on') - if (!this.platform.config.disableEveLogging) { - accessory.eveLogger.addEntry({ - time: Date.now(), - status: params.switches[i - 1].switch === 'on' ? 1 : 0 - }) - } } } if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState) - if (!this.platform.config.disableEveLogging) { - accessory.eveLogger.addEntry({ - time: Date.now(), - status: primaryState ? 1 : 0 - }) - } } } } catch (err) { this.platform.deviceUpdateError(accessory, err, false) } } -} +} \ No newline at end of file From e65ed2ec15b8693949e73cb7db8af9183bca587b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 14 Oct 2020 15:28:50 +0100 Subject: [PATCH 0468/3183] versions --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cc91d5b7..1d13b435 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "axios": "0.20.0", "color-convert": "2.0.1", "correcting-interval": "2.0.0", - "fakegato-history": "simont77/fakegato-history#Updated-Energy", + "fakegato-history": "0.5.6", "homebridge-lib": "4.7.16", "interval-promise": "1.4.0", "node-dns-sd": "0.4.2", From f8babc9bb5156a084fe181b00dded5fb65f20078 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 14 Oct 2020 15:30:05 +0100 Subject: [PATCH 0469/3183] standard js formatting --- lib/device/rf-bridge.js | 2 +- lib/device/switch.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index e52a6b60..5a7ff260 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -16,7 +16,7 @@ module.exports = class deviceRFBridge { if (!accessory.getService(Service.SmokeSensor)) accessory.addService(Service.SmokeSensor) break case 'co': - if (!accessory.getService(Service.CarbonMonoxideSensor)) accessory.addService(Service.CarbonMonoxideSensor) + if (!accessory.getService(Service.CarbonMonoxideSensor)) accessory.addService(Service.CarbonMonoxideSensor) break case 'co2': if (!accessory.getService(Service.CarbonDioxideSensor)) accessory.addService(Service.CarbonDioxideSensor) diff --git a/lib/device/switch.js b/lib/device/switch.js index 8ab31ae1..095f2901 100644 --- a/lib/device/switch.js +++ b/lib/device/switch.js @@ -115,4 +115,4 @@ module.exports = class deviceSwitch { this.platform.deviceUpdateError(accessory, err, false) } } -} \ No newline at end of file +} From c1424499e14c2269fa1e23a6010e1fe73b338c4f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 14 Oct 2020 15:33:19 +0100 Subject: [PATCH 0470/3183] Update package-lock.json --- package-lock.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index fcf3e199..79f3a722 100644 --- a/package-lock.json +++ b/package-lock.json @@ -224,8 +224,9 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "fakegato-history": { - "version": "github:simont77/fakegato-history#bc07b298838ec98a88ba07f519c4af53b9ce4230", - "from": "github:simont77/fakegato-history#Updated-Energy", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/fakegato-history/-/fakegato-history-0.5.6.tgz", + "integrity": "sha512-LlsOkiw9LntVlRlBkssD5ozhEkQzYuEJUlvXk5YAgBQcWzk19PQ5g+NoKfs6SRY1qAeC1onb65hes4mCvY+JmA==", "requires": { "debug": "^2.2.0", "googleapis": ">39.1.0", From 8c3f72cfd92d5ba84a2103e5819ac2a6f996f2d2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 14 Oct 2020 15:42:12 +0100 Subject: [PATCH 0471/3183] prop names --- lib/eWeLink.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 3ca56137..64655c5d 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -45,8 +45,8 @@ class eWeLink { this.wsRefreshFlag = true this.nameOverrideTmp = {} this.ipOverrideTmp = {} - this.config.nameOverride.forEach(x => (this.nameOverrideTmp[x.key] = x.value)) - this.config.ipOverride.forEach(x => (this.ipOverrideTmp[x.key] = x.value)) + if (this.config.nameOverride) this.config.nameOverride.forEach(x => (this.nameOverrideTmp[x.fullDeviceId] = x.deviceName)) + if (this.config.ipOverride) this.config.ipOverride.forEach(x => (this.ipOverrideTmp[x.deviceId] = x.deviceIP)) this.config.nameOverride = this.nameOverrideTmp this.config.ipOverride = this.ipOverrideTmp //* ** UPGRADE **\\ From df729ebffdf0888207e525cc4d106df9d7518593 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 14 Oct 2020 15:47:05 +0100 Subject: [PATCH 0472/3183] check exists --- lib/eWeLink.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index 64655c5d..e585c259 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -286,7 +286,7 @@ class eWeLink { /********************* LIGHTS [MULTI CHANNEL] *********************/ - if ((this.config.hideChanFromHB.split(',') || []).includes(device.deviceid)) { + if ((this.config.hideChanFromHB || "").split(',').includes(device.deviceid)) { if (this.devicesInHB.has(device.deviceid + 'SW0')) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) } @@ -299,7 +299,7 @@ class eWeLink { } accessory.control = new DeviceLight(this, accessory) for (let i = 1; i <= cns.chansFromUiid[device.extra.uiid]; i++) { - if ((this.config.hideChanFromHB.split(',') || []).includes(device.deviceid + 'SW' + i)) { + if ((this.config.hideChanFromHB || "").split(',').includes(device.deviceid + 'SW' + i)) { if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + i)) } @@ -331,7 +331,7 @@ class eWeLink { /*********************** SWITCHES [MULTI CHANNEL] ***********************/ - if ((this.config.hideChanFromHB.split(',') || []).includes(device.deviceid)) { + if ((this.config.hideChanFromHB || "").split(',').includes(device.deviceid)) { if (this.devicesInHB.has(device.deviceid + 'SW0')) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) } @@ -344,7 +344,7 @@ class eWeLink { } accessory.control = new DeviceSwitch(this, accessory) for (let i = 1; i <= cns.chansFromUiid[device.extra.uiid]; i++) { - if ((this.config.hideChanFromHB.split(',') || []).includes(device.deviceid + 'SW' + i)) { + if ((this.config.hideChanFromHB || "").split(',').includes(device.deviceid + 'SW' + i)) { if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + i)) } From ef28194054eb096300fdc5da9c519a514f1638ff Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 14 Oct 2020 15:50:26 +0100 Subject: [PATCH 0473/3183] standard js formatting --- lib/eWeLink.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/eWeLink.js b/lib/eWeLink.js index e585c259..26aa3c9a 100644 --- a/lib/eWeLink.js +++ b/lib/eWeLink.js @@ -286,7 +286,7 @@ class eWeLink { /********************* LIGHTS [MULTI CHANNEL] *********************/ - if ((this.config.hideChanFromHB || "").split(',').includes(device.deviceid)) { + if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid)) { if (this.devicesInHB.has(device.deviceid + 'SW0')) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) } @@ -299,7 +299,7 @@ class eWeLink { } accessory.control = new DeviceLight(this, accessory) for (let i = 1; i <= cns.chansFromUiid[device.extra.uiid]; i++) { - if ((this.config.hideChanFromHB || "").split(',').includes(device.deviceid + 'SW' + i)) { + if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid + 'SW' + i)) { if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + i)) } @@ -331,7 +331,7 @@ class eWeLink { /*********************** SWITCHES [MULTI CHANNEL] ***********************/ - if ((this.config.hideChanFromHB || "").split(',').includes(device.deviceid)) { + if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid)) { if (this.devicesInHB.has(device.deviceid + 'SW0')) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) } @@ -344,7 +344,7 @@ class eWeLink { } accessory.control = new DeviceSwitch(this, accessory) for (let i = 1; i <= cns.chansFromUiid[device.extra.uiid]; i++) { - if ((this.config.hideChanFromHB || "").split(',').includes(device.deviceid + 'SW' + i)) { + if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid + 'SW' + i)) { if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + i)) } From 0879081a2158f7b28e5addc381f9c4459bf4c0bd Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 14 Oct 2020 15:51:09 +0100 Subject: [PATCH 0474/3183] 3.6.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 79f3a722..28a4db2c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.0-1", + "version": "3.6.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1d13b435..e093926d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.0-1", + "version": "3.6.0", "author": "bwp91", "contributors": [ "gbro115", From cb3f9bb6f2c97844f591cf76e04cd50d5c9a9f0a Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Wed, 14 Oct 2020 22:42:08 +0100 Subject: [PATCH 0475/3183] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index dbed106a..4fb13bae 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,6 @@ To use this plugin, you will need to already have Homebridge installed. Please r ### About * [About Me](https://github.com/sponsors/bwp91) * [Support Request](https://github.com/bwp91/homebridge-ewelink/issues/new/choose) -* [Roadmap](https://github.com/bwp91/homebridge-ewelink/wiki/Roadmap) * [Credits](https://github.com/bwp91/homebridge-ewelink/wiki/Credits) ### Disclaimer I am in no way affiliated with eWeLink nor any of the device brands (like Sonoff) and this plugin is a personal project that I maintain in my free time. From c429a5722fac3cad3a1f3d9ac2389750432974a9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 15 Oct 2020 11:09:35 +0100 Subject: [PATCH 0476/3183] file reorganisation 1 --- index.js | 7 +- lib/device/blind.js | 79 +++++----- lib/device/curtain.js | 56 +++---- lib/device/fan.js | 8 +- lib/device/garage-eachen.js | 9 +- lib/device/garage-two.js | 11 +- lib/device/garage.js | 13 +- lib/device/light.js | 190 ++++++++++++------------ lib/device/lock.js | 9 +- lib/device/outlet.js | 96 ++++++------ lib/device/rf-bridge.js | 21 +-- lib/device/scm.js | 8 +- lib/device/sensor.js | 9 +- lib/device/switch.js | 16 +- lib/device/thermostat.js | 13 +- lib/device/usb.js | 8 +- lib/device/valve.js | 5 +- lib/device/zb-dev.js | 19 +-- lib/{eWeLinkHTTP.js => ewelink-http.js} | 54 +++---- lib/{eWeLinkLAN.js => ewelink-lan.js} | 36 ++--- lib/{eWeLink.js => ewelink-platform.js} | 121 ++++++++------- lib/{eWeLinkWS.js => ewelink-ws.js} | 50 +++---- lib/{constants.js => helpers.js} | 7 + lib/utils.js | 10 -- 24 files changed, 428 insertions(+), 427 deletions(-) rename lib/{eWeLinkHTTP.js => ewelink-http.js} (81%) rename lib/{eWeLinkLAN.js => ewelink-lan.js} (81%) rename lib/{eWeLink.js => ewelink-platform.js} (86%) rename lib/{eWeLinkWS.js => ewelink-ws.js} (85%) rename lib/{constants.js => helpers.js} (97%) delete mode 100644 lib/utils.js diff --git a/index.js b/index.js index c815dcbd..11038152 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' -module.exports = function (homebridge) { - const eWeLink = require('./lib/eWeLink.js')(homebridge) - homebridge.registerPlatform('homebridge-ewelink', 'eWeLink', eWeLink, true) +const eWeLinkPlatform = require('./lib/ewelink-platform.js') +module.exports = (hb) => { + hb.registerPlatform('homebridge-ewelink', 'eWeLink', eWeLinkPlatform, true) } diff --git a/lib/device/blind.js b/lib/device/blind.js index ec90d22d..b65d9538 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -1,87 +1,86 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' -let Characteristic, Service -const cns = require('./../constants') -const utils = require('./../utils') +const helpers = require('./../helpers') module.exports = class deviceBlind { constructor (platform, accessory) { this.platform = platform - Service = platform.api.hap.Service - Characteristic = platform.api.hap.Characteristic + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic let wcService - if (!(wcService = accessory.getService(Service.WindowCovering))) { + if (!(wcService = accessory.getService(this.Service.WindowCovering))) { accessory - .addService(Service.WindowCovering) - .setCharacteristic(Characteristic.CurrentPosition, 0) - .setCharacteristic(Characteristic.TargetPosition, 0) - .setCharacteristic(Characteristic.PositionState, 2) - wcService = accessory.getService(Service.WindowCovering) + .addService(this.Service.WindowCovering) + .setCharacteristic(this.Characteristic.CurrentPosition, 0) + .setCharacteristic(this.Characteristic.TargetPosition, 0) + .setCharacteristic(this.Characteristic.PositionState, 2) + wcService = accessory.getService(this.Service.WindowCovering) } wcService - .getCharacteristic(Characteristic.TargetPosition) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .getCharacteristic(this.Characteristic.TargetPosition) + .on('set', (value, callback) => this.internalUpdate(value, callback)) } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { let blindConfig const params = {} - const wcService = accessory.getService(Service.WindowCovering) - const prevState = accessory.context.cachePositionState - let prevPosition = accessory.context.cacheCurrentPosition + const wcService = this.accessory.getService(this.Service.WindowCovering) + const prevState = this.accessory.context.cachePositionState + let prevPosition = this.accessory.context.cacheCurrentPosition const newTarget = value const updateKey = Math.random().toString(36).substr(2, 8) - if (!(blindConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + if (!(blindConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (blindConfig.type !== 'blind') { throw new Error('improper configuration') } if (newTarget === prevPosition) return - params.switches = cns.defaultMultiSwitchOff - accessory.context.updateKey = updateKey + params.switches = helpers.defaultMultiSwitchOff + this.accessory.context.updateKey = updateKey const percentStepPerDecisecond = blindConfig.operationTime / 100 if (prevState !== 2) { - await this.platform.sendDeviceUpdate(accessory, params) - let positionPercentChange = Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime + await this.platform.sendDeviceUpdate(this.accessory, params) + let positionPercentChange = Math.floor(Date.now() / 100) - this.accessory.context.cacheLastStartTime positionPercentChange = Math.floor(percentStepPerDecisecond * positionPercentChange) if (prevState === 0) { prevPosition -= positionPercentChange } else { prevPosition += positionPercentChange } - wcService.updateCharacteristic(Characteristic.CurrentPosition, prevPosition) - accessory.context.cacheCurrentPosition = prevPosition + wcService.updateCharacteristic(this.Characteristic.CurrentPosition, prevPosition) + this.accessory.context.cacheCurrentPosition = prevPosition } const diffPosition = newTarget - prevPosition const setToMoveUp = diffPosition > 0 const decisecondsToMove = Math.round(Math.abs(diffPosition) * percentStepPerDecisecond) params.switches[0].switch = setToMoveUp ? 'on' : 'off' params.switches[1].switch = setToMoveUp ? 'off' : 'on' - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) wcService - .updateCharacteristic(Characteristic.TargetPosition, newTarget) - .updateCharacteristic(Characteristic.PositionState, setToMoveUp) - accessory.context.cacheTargetPosition = newTarget - accessory.context.cachePositionState = setToMoveUp ? 1 : 0 - accessory.context.cacheLastStartTime = Math.floor(Date.now() / 100) - if (accessory.context.updateKey !== updateKey) return - await utils.sleep(decisecondsToMove * 100) - if (accessory.context.updateKey !== updateKey) return + .updateCharacteristic(this.Characteristic.TargetPosition, newTarget) + .updateCharacteristic(this.Characteristic.PositionState, setToMoveUp) + this.accessory.context.cacheTargetPosition = newTarget + this.accessory.context.cachePositionState = setToMoveUp ? 1 : 0 + this.accessory.context.cacheLastStartTime = Math.floor(Date.now() / 100) + if (this.accessory.context.updateKey !== updateKey) return + await helpers.sleep(decisecondsToMove * 100) + if (this.accessory.context.updateKey !== updateKey) return params.switches[0].switch = 'off' params.switches[1].switch = 'off' - await this.platform.sendDeviceUpdate(accessory, params) - wcService.updateCharacteristic(Characteristic.PositionState, 2) - wcService.updateCharacteristic(Characteristic.CurrentPosition, newTarget) - accessory.context.cachePositionState = 2 - accessory.context.cacheCurrentPosition = newTarget + await this.platform.sendDeviceUpdate(this.accessory, params) + wcService.updateCharacteristic(this.Characteristic.PositionState, 2) + wcService.updateCharacteristic(this.Characteristic.CurrentPosition, newTarget) + this.accessory.context.cachePositionState = 2 + this.accessory.context.cacheCurrentPosition = newTarget } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { } } diff --git a/lib/device/curtain.js b/lib/device/curtain.js index 18ebcbb5..49d45da4 100644 --- a/lib/device/curtain.js +++ b/lib/device/curtain.js @@ -1,32 +1,32 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' -let Characteristic, Service -const utils = require('./../utils') +const helpers = require('./../helpers') module.exports = class deviceCurtain { constructor (platform, accessory) { this.platform = platform - Service = platform.api.hap.Service - Characteristic = platform.api.hap.Characteristic + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic let cService - if (!(cService = accessory.getService(Service.WindowCovering))) { + if (!(cService = accessory.getService(this.Service.WindowCovering))) { accessory - .addService(Service.WindowCovering) - .setCharacteristic(Characteristic.CurrentPosition, 0) - .setCharacteristic(Characteristic.TargetPosition, 0) - .setCharacteristic(Characteristic.PositionState, 2) - cService = accessory.getService(Service.WindowCovering) + .addService(this.Service.WindowCovering) + .setCharacteristic(this.Characteristic.CurrentPosition, 0) + .setCharacteristic(this.Characteristic.TargetPosition, 0) + .setCharacteristic(this.Characteristic.PositionState, 2) + cService = accessory.getService(this.Service.WindowCovering) } cService - .getCharacteristic(Characteristic.TargetPosition) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .getCharacteristic(this.Characteristic.TargetPosition) + .on('set', (value, callback) => this.internalUpdate(value, callback)) } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { let params - const cService = accessory.getService(Service.WindowCovering) - const prevPos = accessory.context.cacheCurrentPosition + const cService = this.accessory.getService(this.Service.WindowCovering) + const prevPos = this.accessory.context.cacheCurrentPosition const newPos = value if (newPos === prevPos) return if (newPos === 0 || newPos === 100) { @@ -38,31 +38,31 @@ module.exports = class deviceCurtain { setclose: Math.abs(100 - newPos) } } - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) cService - .updateCharacteristic(Characteristic.TargetPosition, newPos) - .updateCharacteristic(Characteristic.PositionState, newPos > prevPos ? 1 : 0) - accessory.context.cacheCurrentPosition = newPos + .updateCharacteristic(this.Characteristic.TargetPosition, newPos) + .updateCharacteristic(this.Characteristic.PositionState, newPos > prevPos ? 1 : 0) + this.accessory.context.cacheCurrentPosition = newPos } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { - const cService = accessory.getService(Service.WindowCovering) - if (!utils.hasProperty(params, 'switch') && !utils.hasProperty(params, 'setclose')) { + const cService = this.accessory.getService(this.Service.WindowCovering) + if (!helpers.hasProperty(params, 'switch') && !helpers.hasProperty(params, 'setclose')) { return } const newPos = Math.abs(100 - parseInt(params.setclose)) cService - .updateCharacteristic(Characteristic.TargetPosition, newPos) - .updateCharacteristic(Characteristic.CurrentPosition, newPos) - .updateCharacteristic(Characteristic.PositionState, 2) - accessory.context.cacheCurrentPosition = newPos + .updateCharacteristic(this.Characteristic.TargetPosition, newPos) + .updateCharacteristic(this.Characteristic.CurrentPosition, newPos) + .updateCharacteristic(this.Characteristic.PositionState, 2) + this.accessory.context.cacheCurrentPosition = newPos return } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/fan.js b/lib/device/fan.js index b84aed51..c6f51864 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -1,8 +1,8 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' let Characteristic, Service -const cns = require('./../constants') -const utils = require('./../utils') +const helpers = require('./../helpers') module.exports = class deviceFan { constructor (platform, accessory) { this.platform = platform @@ -15,7 +15,7 @@ module.exports = class deviceFan { .on('set', async (value, callback) => { callback() if (value === 0) { - await utils.sleep(500) + await helpers.sleep(500) fanService.setCharacteristic(Characteristic.RotationSpeed, 0) } }) @@ -38,7 +38,7 @@ module.exports = class deviceFan { let newLight const lightService = accessory.getService(Service.Lightbulb) const fanService = accessory.getService(Service.Fanv2) - const params = { switches: cns.defaultMultiSwitchOff } + const params = { switches: helpers.defaultMultiSwitchOff } switch (type) { case 'speed': newPower = value >= 33 ? 1 : 0 diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 42e5d085..0f58b636 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -1,7 +1,8 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' let Characteristic, Service -const utils = require('./../utils') +const helpers = require('./../helpers') module.exports = class deviceGarageEachen { constructor (platform, accessory) { this.platform = platform @@ -39,10 +40,10 @@ module.exports = class deviceGarageEachen { gdService .updateCharacteristic(Characteristic.TargetDoorState, value) .updateCharacteristic(Characteristic.CurrentDoorState, value + 2) - await utils.sleep(2000) + await helpers.sleep(2000) accessory.context.inUse = false if (value === 0) { - await utils.sleep(Math.max((garageConfig.operationTime - 20) * 100, 0)) + await helpers.sleep(Math.max((garageConfig.operationTime - 20) * 100, 0)) gdService.updateCharacteristic(Characteristic.CurrentDoorState, 0) } } catch (err) { @@ -53,7 +54,7 @@ module.exports = class deviceGarageEachen { async externalUpdate (accessory, params) { try { - if (!utils.hasProperty(params, 'switch') || accessory.context.inUse) { + if (!helpers.hasProperty(params, 'switch') || accessory.context.inUse) { return } let garageConfig diff --git a/lib/device/garage-two.js b/lib/device/garage-two.js index 931220f4..36b18405 100644 --- a/lib/device/garage-two.js +++ b/lib/device/garage-two.js @@ -1,7 +1,8 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' let Characteristic, Service -const utils = require('./../utils') +const helpers = require('./../helpers') module.exports = class deviceGarageTwo { constructor (platform, accessory) { this.platform = platform @@ -87,7 +88,7 @@ module.exports = class deviceGarageTwo { } } await this.platform.sendDeviceUpdate(accessory, params) - await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) + await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) if (!sAccessory) { gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos) switch (garage) { @@ -109,7 +110,7 @@ module.exports = class deviceGarageTwo { externalUpdate (accessory, params) { try { - if (!utils.hasProperty(params, 'switches')) { + if (!helpers.hasProperty(params, 'switches')) { return } let garageConfig @@ -150,7 +151,7 @@ module.exports = class deviceGarageTwo { } accessory.context.inUse = true if (garageConfig.sensorId) { - await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) + await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) } else { gcService .updateCharacteristic(Characteristic.TargetDoorState, newPos - 2) @@ -165,7 +166,7 @@ module.exports = class deviceGarageTwo { accessory.context.cacheTwoTargetDoorState = newPos - 2 break } - await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) + await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) gcService.updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2) switch (v) { case '1': diff --git a/lib/device/garage.js b/lib/device/garage.js index d11cccbf..39eab6f3 100644 --- a/lib/device/garage.js +++ b/lib/device/garage.js @@ -1,7 +1,8 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' let Characteristic, Service -const utils = require('./../utils') +const helpers = require('./../helpers') module.exports = class deviceGarage { constructor (platform, accessory) { this.platform = platform @@ -57,7 +58,7 @@ module.exports = class deviceGarage { delay = 1500 } if (accessory.context.state !== newPos) return - await utils.sleep(delay) + await helpers.sleep(delay) gdService .updateCharacteristic(Characteristic.TargetDoorState, newPos) .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2) @@ -74,7 +75,7 @@ module.exports = class deviceGarage { break } await this.platform.sendDeviceUpdate(accessory, params) - await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) + await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) if (!sAccessory) { gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos) accessory.context.cacheCurrentDoorState = newPos @@ -87,7 +88,7 @@ module.exports = class deviceGarage { async externalUpdate (accessory, params) { try { - if (!utils.hasProperty(params, 'switch') && !utils.hasProperty(params, 'switches')) { + if (!helpers.hasProperty(params, 'switch') && !helpers.hasProperty(params, 'switches')) { return } let garageConfig @@ -120,14 +121,14 @@ module.exports = class deviceGarage { } accessory.context.inUse = true if (garageConfig.sensorId) { - await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) + await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) } else { gcService .updateCharacteristic(Characteristic.TargetDoorState, newPos - 2) .updateCharacteristic(Characteristic.CurrentDoorState, newPos) accessory.context.cacheCurrentDoorState = newPos accessory.context.cacheTargetDoorState = newPos - 2 - await utils.sleep(Math.max(garageConfig.operationTime * 100, 1000)) + await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) gcService.updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2) accessory.context.cacheCurrentDoorState = newPos - 2 } diff --git a/lib/device/light.js b/lib/device/light.js index 14125bf1..6d426caf 100644 --- a/lib/device/light.js +++ b/lib/device/light.js @@ -1,59 +1,59 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' -let Characteristic, Service -const cns = require('./../constants') const convert = require('color-convert') -const utils = require('./../utils') +const helpers = require('./../helpers') module.exports = class deviceLight { constructor (platform, accessory) { this.platform = platform - Service = platform.api.hap.Service - Characteristic = platform.api.hap.Characteristic - const lightService = accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb) + this.accessory = accessory + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + const lightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) lightService - .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, 'onoff', value, callback)) - if (cns.devicesBrightable.includes(accessory.context.eweUIID)) { - lightService.getCharacteristic(Characteristic.Brightness).on('set', (value, callback) => { + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalUpdate('onoff', value, callback)) + if (helpers.devicesBrightable.includes(accessory.context.eweUIID)) { + lightService.getCharacteristic(this.Characteristic.Brightness).on('set', (value, callback) => { if (value > 0) { - if (!lightService.getCharacteristic(Characteristic.On).value) { - this.internalUpdate(accessory, 'onoff', true, function () {}) + if (!lightService.getCharacteristic(this.Characteristic.On).value) { + this.internalUpdate('onoff', true, function () {}) } - this.internalUpdate(accessory, 'brightness', value, callback) + this.internalUpdate('brightness', value, callback) } else { - this.internalUpdate(accessory, 'onoff', false, callback) + this.internalUpdate('onoff', false, callback) } }) - } else if (cns.devicesColourable.includes(accessory.context.eweUIID)) { - lightService.getCharacteristic(Characteristic.Brightness).on('set', (value, callback) => { + } else if (helpers.devicesColourable.includes(accessory.context.eweUIID)) { + lightService.getCharacteristic(this.Characteristic.Brightness).on('set', (value, callback) => { if (value > 0) { - if (!lightService.getCharacteristic(Characteristic.On).value) { - this.internalUpdate(accessory, 'onoff', true, function () {}) + if (!lightService.getCharacteristic(this.Characteristic.On).value) { + this.internalUpdate('onoff', true, function () {}) } - this.internalUpdate(accessory, 'c_brightness', value, callback) + this.internalUpdate('c_brightness', value, callback) } else { - this.internalUpdate(accessory, 'onoff', false, callback) + this.internalUpdate('onoff', false, callback) } }) lightService - .getCharacteristic(Characteristic.Hue) - .on('set', (value, callback) => this.internalUpdate(accessory, 'c_hue', value, callback)) - lightService.getCharacteristic(Characteristic.Saturation).on('set', (value, callback) => callback()) + .getCharacteristic(this.Characteristic.Hue) + .on('set', (value, callback) => this.internalUpdate('c_hue', value, callback)) + lightService.getCharacteristic(this.Characteristic.Saturation).on('set', (value, callback) => callback()) } } - async internalUpdate (accessory, type, value, callback) { + async internalUpdate (type, value, callback) { callback() try { let oAccessory let newRGB let params = {} - const lightService = accessory.getService(Service.Lightbulb) + const lightService = this.accessory.getService(this.Service.Lightbulb) switch (type) { case 'onoff': - switch (accessory.context.switchNumber) { + switch (this.accessory.context.switchNumber) { case 'X': - if (accessory.context.eweUIID === 22) { + if (this.accessory.context.eweUIID === 22) { //* ** B1 ***\\ params.state = value ? 'on' : 'off' } else { @@ -61,7 +61,7 @@ module.exports = class deviceLight { } break case '0': - params.switches = cns.defaultMultiSwitchOff + params.switches = helpers.defaultMultiSwitchOff params.switches[0].switch = value ? 'on' : 'off' params.switches[1].switch = value ? 'on' : 'off' params.switches[2].switch = value ? 'on' : 'off' @@ -71,10 +71,10 @@ module.exports = class deviceLight { case '2': case '3': case '4': - params.switches = cns.defaultMultiSwitchOff + params.switches = helpers.defaultMultiSwitchOff for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { - if (i === parseInt(accessory.context.switchNumber)) { + if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { + if (i === parseInt(this.accessory.context.switchNumber)) { params.switches[i - 1].switch = value ? 'on' : 'off' } else { params.switches[i - 1].switch = oAccessory.context.cacheOn ? 'on' : 'off' @@ -85,15 +85,15 @@ module.exports = class deviceLight { } break } - await this.platform.sendDeviceUpdate(accessory, params) - switch (accessory.context.switchNumber) { + await this.platform.sendDeviceUpdate(this.accessory, params) + switch (this.accessory.context.switchNumber) { case 'X': - lightService.updateCharacteristic(Characteristic.On, value) + lightService.updateCharacteristic(this.Characteristic.On, value) break case '0': for (let i = 0; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { - oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, value) + if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { + oAccessory.getService(this.Service.Lightbulb).updateCharacteristic(this.Characteristic.On, value) } } break @@ -101,18 +101,18 @@ module.exports = class deviceLight { case '2': case '3': case '4': { - lightService.updateCharacteristic(Characteristic.On, value) + lightService.updateCharacteristic(this.Characteristic.On, value) let masterState = 'off' for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { - if (oAccessory.getService(Service.Lightbulb).getCharacteristic(Characteristic.On).value) { + if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { + if (oAccessory.getService(this.Service.Lightbulb).getCharacteristic(this.Characteristic.On).value) { masterState = 'on' } } } - if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { - oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW0') - oAccessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, masterState === 'on') + if (!this.platform.hiddenMasters.includes(this.accessory.context.eweDeviceId)) { + oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW0') + oAccessory.getService(this.Service.Lightbulb).updateCharacteristic(this.Characteristic.On, masterState === 'on') } break } @@ -122,10 +122,10 @@ module.exports = class deviceLight { if (value === 0) { params.switch = 'off' } else { - if (!lightService.getCharacteristic(Characteristic.On).value) { + if (!lightService.getCharacteristic(this.Characteristic.On).value) { params.switch = 'on' } - switch (accessory.context.eweUIID) { + switch (this.accessory.context.eweUIID) { case 36: //* ** KING-M4 ***\\ params.bright = Math.round((value * 9) / 10 + 10) break @@ -135,20 +135,20 @@ module.exports = class deviceLight { break } } - await utils.sleep(250) - await this.platform.sendDeviceUpdate(accessory, params) + await helpers.sleep(250) + await this.platform.sendDeviceUpdate(this.accessory, params) if (value === 0) { - lightService.updateCharacteristic(Characteristic.On, false) + lightService.updateCharacteristic(this.Characteristic.On, false) } else { - lightService.updateCharacteristic(Characteristic.Brightness, value) + lightService.updateCharacteristic(this.Characteristic.Brightness, value) } break case 'c_brightness': - switch (accessory.context.eweUIID) { + switch (this.accessory.context.eweUIID) { case 22: //* ** B1 ***\\ newRGB = convert.hsv.rgb( - lightService.getCharacteristic(Characteristic.Hue).value, - lightService.getCharacteristic(Characteristic.Saturation).value, + lightService.getCharacteristic(this.Characteristic.Hue).value, + lightService.getCharacteristic(this.Characteristic.Saturation).value, value ) params = { @@ -168,13 +168,13 @@ module.exports = class deviceLight { } break } - await utils.sleep(250) - await this.platform.sendDeviceUpdate(accessory, params) - lightService.updateCharacteristic(Characteristic.Brightness, value) + await helpers.sleep(250) + await this.platform.sendDeviceUpdate(this.accessory, params) + lightService.updateCharacteristic(this.Characteristic.Brightness, value) break case 'c_hue': - newRGB = convert.hsv.rgb(value, lightService.getCharacteristic(Characteristic.Saturation).value, 100) - switch (accessory.context.eweUIID) { + newRGB = convert.hsv.rgb(value, lightService.getCharacteristic(this.Characteristic.Saturation).value, 100) + switch (this.accessory.context.eweUIID) { case 22: //* ** B1 ***\\ params = { zyx_mode: 2, @@ -195,95 +195,95 @@ module.exports = class deviceLight { } break } - await utils.sleep(250) - await this.platform.sendDeviceUpdate(accessory, params) - lightService.updateCharacteristic(Characteristic.Hue, value) + await helpers.sleep(250) + await this.platform.sendDeviceUpdate(this.accessory, params) + lightService.updateCharacteristic(this.Characteristic.Hue, value) break } } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if ( - cns.devicesSingleSwitch.includes(accessory.context.eweUIID) && - cns.devicesSingleSwitchLight.includes(accessory.context.eweModel) + helpers.devicesSingleSwitch.includes(this.accessory.context.eweUIID) && + helpers.devicesSingleSwitchLight.includes(this.accessory.context.eweModel) ) { let newColour let mode let isOn = false - const lightService = accessory.getService(Service.Lightbulb) - if (accessory.context.eweUIID === 22 && utils.hasProperty(params, 'state')) { + const lightService = this.accessory.getService(this.Service.Lightbulb) + if (this.accessory.context.eweUIID === 22 && helpers.hasProperty(params, 'state')) { isOn = params.state === 'on' - } else if (accessory.context.eweUIID !== 22 && utils.hasProperty(params, 'switch')) { + } else if (this.accessory.context.eweUIID !== 22 && helpers.hasProperty(params, 'switch')) { isOn = params.switch === 'on' } else { - isOn = lightService.getCharacteristic(Characteristic.On).value + isOn = lightService.getCharacteristic(this.Characteristic.On).value } if (isOn) { - lightService.updateCharacteristic(Characteristic.On, true) - switch (accessory.context.eweUIID) { + lightService.updateCharacteristic(this.Characteristic.On, true) + switch (this.accessory.context.eweUIID) { case 36: // KING-M4 - if (utils.hasProperty(params, 'bright')) { + if (helpers.hasProperty(params, 'bright')) { const nb = Math.round(((params.bright - 10) * 10) / 9) // eWeLink scale is 10-100 and HomeKit scale is 0-100. - lightService.updateCharacteristic(Characteristic.Brightness, nb) + lightService.updateCharacteristic(this.Characteristic.Brightness, nb) } break case 44: // D1 - if (utils.hasProperty(params, 'brightness')) { - lightService.updateCharacteristic(Characteristic.Brightness, params.brightness) + if (helpers.hasProperty(params, 'brightness')) { + lightService.updateCharacteristic(this.Characteristic.Brightness, params.brightness) } break case 22: // B1 - if (utils.hasProperty(params, 'zyx_mode')) { + if (helpers.hasProperty(params, 'zyx_mode')) { mode = parseInt(params.zyx_mode) - } else if (utils.hasProperty(params, 'channel0') && parseInt(params.channel0) + parseInt(params.channel1) > 0) { + } else if (helpers.hasProperty(params, 'channel0') && parseInt(params.channel0) + parseInt(params.channel1) > 0) { mode = 1 } else { mode = 2 } if (mode === 2) { - lightService.updateCharacteristic(Characteristic.On, true) + lightService.updateCharacteristic(this.Characteristic.On, true) newColour = convert.rgb.hsv( parseInt(params.channel2), parseInt(params.channel3), parseInt(params.channel4) ) lightService - .updateCharacteristic(Characteristic.Hue, newColour[0]) - .updateCharacteristic(Characteristic.Saturation, 100) - .updateCharacteristic(Characteristic.Brightness, 100) + .updateCharacteristic(this.Characteristic.Hue, newColour[0]) + .updateCharacteristic(this.Characteristic.Saturation, 100) + .updateCharacteristic(this.Characteristic.Brightness, 100) } else if (mode === 1) { throw new Error('has been set to white mode which is not supported') } break case 59: // L1 - if (utils.hasProperty(params, 'bright')) { - lightService.updateCharacteristic(Characteristic.Brightness, params.bright) + if (helpers.hasProperty(params, 'bright')) { + lightService.updateCharacteristic(this.Characteristic.Brightness, params.bright) } - if (utils.hasProperty(params, 'colorR')) { + if (helpers.hasProperty(params, 'colorR')) { newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB) lightService - .updateCharacteristic(Characteristic.Hue, newColour[0]) - .updateCharacteristic(Characteristic.Saturation, newColour[1]) + .updateCharacteristic(this.Characteristic.Hue, newColour[0]) + .updateCharacteristic(this.Characteristic.Saturation, newColour[1]) } break default: return } } else { - lightService.updateCharacteristic(Characteristic.On, false) + lightService.updateCharacteristic(this.Characteristic.On, false) } } else if ( - cns.devicesMultiSwitch.includes(accessory.context.eweUIID) && - cns.devicesMultiSwitchLight.includes(accessory.context.eweModel) + helpers.devicesMultiSwitch.includes(this.accessory.context.eweUIID) && + helpers.devicesMultiSwitchLight.includes(this.accessory.context.eweModel) ) { - if (!utils.hasProperty(params, 'switches')) return - const idToCheck = accessory.context.hbDeviceId.slice(0, -1) + if (!helpers.hasProperty(params, 'switches')) return + const idToCheck = this.accessory.context.hbDeviceId.slice(0, -1) let primaryState = false - for (let i = 1; i <= accessory.context.channelCount; i++) { + for (let i = 1; i <= this.accessory.context.channelCount; i++) { if (params.switches[i - 1].switch === 'on') { primaryState = true } @@ -291,16 +291,16 @@ module.exports = class deviceLight { const oAccessory = this.platform.devicesInHB.get(idToCheck + i) oAccessory.context.cacheOn = params.switches[i - 1].switch === 'on' oAccessory - .getService(Service.Lightbulb) - .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === 'on') + .getService(this.Service.Lightbulb) + .updateCharacteristic(this.Characteristic.On, params.switches[i - 1].switch === 'on') } } - if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { - accessory.getService(Service.Lightbulb).updateCharacteristic(Characteristic.On, primaryState) + if (!this.platform.hiddenMasters.includes(this.accessory.context.eweDeviceId)) { + this.accessory.getService(this.Service.Lightbulb).updateCharacteristic(this.Characteristic.On, primaryState) } } } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/lock.js b/lib/device/lock.js index 7ccb89ae..614c4e68 100644 --- a/lib/device/lock.js +++ b/lib/device/lock.js @@ -1,7 +1,8 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' let Characteristic, Service -const utils = require('./../utils') +const helpers = require('./../helpers') module.exports = class deviceLock { constructor (platform, accessory) { this.platform = platform @@ -32,7 +33,7 @@ module.exports = class deviceLock { lmService .updateCharacteristic(Characteristic.LockTargetState, 0) .updateCharacteristic(Characteristic.LockCurrentState, 0) - await utils.sleep(Math.max(lockConfig.operationTime * 100, 1000)) + await helpers.sleep(Math.max(lockConfig.operationTime * 100, 1000)) lmService .updateCharacteristic(Characteristic.LockTargetState, 1) .updateCharacteristic(Characteristic.LockCurrentState, 1) @@ -44,7 +45,7 @@ module.exports = class deviceLock { async externalUpdate (accessory, params) { try { - if (!utils.hasProperty(params, 'switch')) return + if (!helpers.hasProperty(params, 'switch')) return let lockConfig const lmService = accessory.getService(Service.LockMechanism) if (!(lockConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { @@ -60,7 +61,7 @@ module.exports = class deviceLock { lmService .updateCharacteristic(Characteristic.LockCurrentState, 0) .updateCharacteristic(Characteristic.LockTargetState, 0) - await utils.sleep(Math.max(lockConfig.operationTime * 100, 1000)) + await helpers.sleep(Math.max(lockConfig.operationTime * 100, 1000)) lmService .updateCharacteristic(Characteristic.LockCurrentState, 1) .updateCharacteristic(Characteristic.LockTargetState, 1) diff --git a/lib/device/outlet.js b/lib/device/outlet.js index ea799489..9330cf65 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -1,31 +1,31 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' -let Characteristic, EveHistoryService, EveService, Service -const cns = require('./../constants') const corrInterval = require('correcting-interval') const fakegato = require('fakegato-history') const hbLib = require('homebridge-lib') -const utils = require('./../utils') +const helpers = require('./../helpers') module.exports = class deviceOutlet { constructor (platform, accessory) { this.platform = platform - Service = platform.api.hap.Service - Characteristic = platform.api.hap.Characteristic - EveService = new hbLib.EveHomeKitTypes(platform.api) - EveHistoryService = fakegato(platform.api) - if (accessory.getService(Service.Switch)) { - accessory.removeService(accessory.getService(Service.Switch)) + this.accessory = accessory + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + this.EveCharacteristics = new hbLib.EveHomeKitTypes(platform.api).Characteristics + this.EveHistoryService = fakegato(platform.api) + if (accessory.getService(this.Service.Switch)) { + accessory.removeService(accessory.getService(this.Service.Switch)) } let outletService - if (!(outletService = accessory.getService(Service.Outlet))) { - accessory.addService(Service.Outlet) - outletService = accessory.getService(Service.Outlet) - if (!cns.devicesSingleSwitchOutlet.includes(accessory.context.eweModel) && !this.platform.config.disableEveLogging) { - outletService.addCharacteristic(EveService.Characteristics.Voltage) - outletService.addCharacteristic(EveService.Characteristics.CurrentConsumption) - outletService.addCharacteristic(EveService.Characteristics.ElectricCurrent) - outletService.addCharacteristic(EveService.Characteristics.TotalConsumption) - outletService.addCharacteristic(EveService.Characteristics.ResetTotal) + if (!(outletService = accessory.getService(this.Service.Outlet))) { + accessory.addService(this.Service.Outlet) + outletService = accessory.getService(this.Service.Outlet) + if (!helpers.devicesSingleSwitchOutlet.includes(accessory.context.eweModel) && !this.platform.config.disableEveLogging) { + outletService.addCharacteristic(this.EveCharacteristics.Voltage) + outletService.addCharacteristic(this.EveCharacteristics.CurrentConsumption) + outletService.addCharacteristic(this.EveCharacteristics.ElectricCurrent) + outletService.addCharacteristic(this.EveCharacteristics.TotalConsumption) + outletService.addCharacteristic(this.EveCharacteristics.ResetTotal) accessory.context = { ...accessory.context, ...{ @@ -38,19 +38,19 @@ module.exports = class deviceOutlet { } } outletService - .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) - if (!cns.devicesSingleSwitchOutlet.includes(accessory.context.eweModel) && !this.platform.config.disableEveLogging) { + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(value, callback)) + if (!helpers.devicesSingleSwitchOutlet.includes(accessory.context.eweModel) && !this.platform.config.disableEveLogging) { accessory.log = this.platform.log - accessory.eveLogger = new EveHistoryService('energy', accessory, { + accessory.eveLogger = new this.EveHistoryService('energy', accessory, { storage: 'fs', minutes: 5, path: this.platform.eveLogPath }) corrInterval.setCorrectingInterval(() => { - const isOn = outletService.getCharacteristic(Characteristic.On).value + const isOn = outletService.getCharacteristic(this.Characteristic.On).value const currentWatt = isOn - ? outletService.getCharacteristic(EveService.Characteristics.CurrentConsumption).value + ? outletService.getCharacteristic(this.EveCharacteristics.CurrentConsumption).value : 0 if (accessory.eveLogger.isHistoryLoaded()) { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() @@ -81,7 +81,7 @@ module.exports = class deviceOutlet { }) }, 300000) outletService - .getCharacteristic(EveService.Characteristics.TotalConsumption) + .getCharacteristic(this.EveCharacteristics.TotalConsumption) .on('get', callback => { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() if (accessory.context.extraPersistedData !== undefined) { @@ -90,7 +90,7 @@ module.exports = class deviceOutlet { callback(null, accessory.context.totalEnergy) }) outletService - .getCharacteristic(EveService.Characteristics.ResetTotal) + .getCharacteristic(this.EveCharacteristics.ResetTotal) .on('set', (value, callback) => { accessory.context.totalEnergy = 0 accessory.context.lastReset = value @@ -110,51 +110,51 @@ module.exports = class deviceOutlet { } } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { const params = { switch: value ? 'on' : 'off' } - const outletService = accessory.getService(Service.Outlet) - await this.platform.sendDeviceUpdate(accessory, params) - outletService.updateCharacteristic(Characteristic.On, value) + const outletService = this.accessory.getService(this.Service.Outlet) + await this.platform.sendDeviceUpdate(this.accessory, params) + outletService.updateCharacteristic(this.Characteristic.On, value) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { - const outletService = accessory.getService(Service.Outlet) - if (utils.hasProperty(params, 'switch')) { - outletService.updateCharacteristic(Characteristic.On, params.switch === 'on') - if (cns.devicesSingleSwitchOutlet.includes(accessory.context.eweModel) || this.platform.config.disableEveLogging) { - outletService.updateCharacteristic(Characteristic.OutletInUse, params.switch === 'on') + const outletService = this.accessory.getService(this.Service.Outlet) + if (helpers.hasProperty(params, 'switch')) { + outletService.updateCharacteristic(this.Characteristic.On, params.switch === 'on') + if (helpers.devicesSingleSwitchOutlet.includes(this.accessory.context.eweModel) || this.platform.config.disableEveLogging) { + outletService.updateCharacteristic(this.Characteristic.OutletInUse, params.switch === 'on') } } - if (utils.hasProperty(params, 'power')) { - outletService.updateCharacteristic(EveService.Characteristics.CurrentConsumption, parseFloat(params.power)) - if (!cns.devicesSingleSwitchOutlet.includes(accessory.context.eweModel) && !this.platform.config.disableEveLogging) { + if (helpers.hasProperty(params, 'power')) { + outletService.updateCharacteristic(this.EveCharacteristics.CurrentConsumption, parseFloat(params.power)) + if (!helpers.devicesSingleSwitchOutlet.includes(this.accessory.context.eweModel) && !this.platform.config.disableEveLogging) { outletService.updateCharacteristic( - Characteristic.OutletInUse, + this.Characteristic.OutletInUse, parseFloat(params.power) > (this.platform.config.inUsePowerThreshold || 0) ) - const isOn = accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).value - accessory.eveLogger.addEntry({ + const isOn = this.accessory.getService(this.Service.Outlet).getCharacteristic(this.Characteristic.On).value + this.accessory.eveLogger.addEntry({ time: Date.now(), power: isOn ? parseFloat(params.power) : 0 }) } } - if (utils.hasProperty(params, 'voltage')) { - outletService.updateCharacteristic(EveService.Characteristics.Voltage, parseFloat(params.voltage)) + if (helpers.hasProperty(params, 'voltage')) { + outletService.updateCharacteristic(this.EveCharacteristics.Voltage, parseFloat(params.voltage)) } - if (utils.hasProperty(params, 'current')) { - outletService.updateCharacteristic(EveService.Characteristics.ElectricCurrent, parseFloat(params.current)) + if (helpers.hasProperty(params, 'current')) { + outletService.updateCharacteristic(this.EveCharacteristics.ElectricCurrent, parseFloat(params.current)) } } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index 5a7ff260..559e3a75 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -1,7 +1,8 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' let Characteristic, Service -const utils = require('./../utils') +const helpers = require('./../helpers') module.exports = class deviceRFBridge { constructor (platform, accessory) { this.platform = platform @@ -51,7 +52,7 @@ module.exports = class deviceRFBridge { } const rfService = accessory.getService(service) rfService.updateCharacteristic(Characteristic.On, true) - await utils.sleep(1000) + await helpers.sleep(1000) rfService.updateCharacteristic(Characteristic.On, false) await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { @@ -61,15 +62,15 @@ module.exports = class deviceRFBridge { async externalUpdate (accessory, params) { try { - if (!utils.hasProperty(params, 'updateSource')) return + if (!helpers.hasProperty(params, 'updateSource')) return const timeNow = new Date() let oAccessory = false - if (utils.hasProperty(params, 'cmd') && params.cmd === 'transmit' && utils.hasProperty(params, 'rfChl')) { + if (helpers.hasProperty(params, 'cmd') && params.cmd === 'transmit' && helpers.hasProperty(params, 'rfChl')) { this.platform.devicesInHB.forEach(acc => { if ( acc.context.eweDeviceId === accessory.context.eweDeviceId && - utils.hasProperty(acc.context, 'buttons') && - utils.hasProperty(acc.context.buttons, params.rfChl.toString()) + helpers.hasProperty(acc.context, 'buttons') && + helpers.hasProperty(acc.context.buttons, params.rfChl.toString()) ) { oAccessory = acc } @@ -86,7 +87,7 @@ module.exports = class deviceRFBridge { } else { throw new Error('rf button not found in Homebridge') } - } else if (utils.hasProperty(params, 'cmd') && params.cmd === 'trigger') { + } else if (helpers.hasProperty(params, 'cmd') && params.cmd === 'trigger') { //* ** RF Sensor ***\\ Object.keys(params) .filter(name => /rfTrig/.test(name)) @@ -94,8 +95,8 @@ module.exports = class deviceRFBridge { this.platform.devicesInHB.forEach(acc => { if ( acc.context.eweDeviceId === accessory.context.eweDeviceId && - utils.hasProperty(acc.context, 'buttons') && - utils.hasProperty(acc.context.buttons, chan.substr(-1).toString()) + helpers.hasProperty(acc.context, 'buttons') && + helpers.hasProperty(acc.context.buttons, chan.substr(-1).toString()) ) { oAccessory = acc } @@ -140,7 +141,7 @@ module.exports = class deviceRFBridge { break } oAccessory.getService(serv).updateCharacteristic(char, 1) - await utils.sleep((this.platform.config.sensorTimeLength || 2) * 1000) + await helpers.sleep((this.platform.config.sensorTimeLength || 2) * 1000) oAccessory.getService(serv).updateCharacteristic(char, 0) } } diff --git a/lib/device/scm.js b/lib/device/scm.js index 9e4e1165..b49d5915 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -1,8 +1,8 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' let Characteristic, Service -const cns = require('./../constants') -const utils = require('./../utils') +const helpers = require('./../helpers') module.exports = class deviceSCM { constructor (platform, accessory) { this.platform = platform @@ -18,7 +18,7 @@ module.exports = class deviceSCM { callback() try { const params = { - switches: cns.defaultMultiSwitchOff + switches: helpers.defaultMultiSwitchOff } const switchService = accessory.getService(Service.Switch) params.switches[0].switch = value ? 'on' : 'off' @@ -31,7 +31,7 @@ module.exports = class deviceSCM { async externalUpdate (accessory, params) { try { - if (!utils.hasProperty(params, 'switches')) return + if (!helpers.hasProperty(params, 'switches')) return accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switches[0].switch === 'on') } catch (err) { this.platform.deviceUpdateError(accessory, err, false) diff --git a/lib/device/sensor.js b/lib/device/sensor.js index 0ded5346..d0e3e273 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -1,7 +1,8 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' let Characteristic, Service -const utils = require('./../utils') +const helpers = require('./../helpers') module.exports = class deviceSensor { constructor (platform, accessory) { this.platform = platform @@ -13,7 +14,7 @@ module.exports = class deviceSensor { async externalUpdate (accessory, params) { try { - if (utils.hasProperty(params, 'battery')) { + if (helpers.hasProperty(params, 'battery')) { const batteryService = accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService) const scaledBattery = Math.round(params.battery * 33.3) @@ -23,7 +24,7 @@ module.exports = class deviceSensor { scaledBattery < (this.platform.config.lowBattThreshold || 25) ) } - if (!utils.hasProperty(params, 'switch')) return + if (!helpers.hasProperty(params, 'switch')) return const newState = params.switch === 'on' ? 1 : 0 let oAccessory = false const contactService = accessory.getService(Service.ContactSensor) @@ -39,7 +40,7 @@ module.exports = class deviceSensor { .updateCharacteristic(Characteristic.CurrentDoorState, 1) break case 1: - await utils.sleep(Math.max(group.operationTime * 100, 1000)) + await helpers.sleep(Math.max(group.operationTime * 100, 1000)) oAccessory .getService(Service.GarageDoorOpener) .updateCharacteristic(Characteristic.TargetDoorState, 0) diff --git a/lib/device/switch.js b/lib/device/switch.js index 095f2901..dc05d49f 100644 --- a/lib/device/switch.js +++ b/lib/device/switch.js @@ -1,8 +1,8 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' let Characteristic, Service -const cns = require('./../constants') -const utils = require('./../utils') +const helpers = require('./../helpers') module.exports = class deviceSwitch { constructor (platform, accessory) { this.platform = platform @@ -25,7 +25,7 @@ module.exports = class deviceSwitch { params.switch = value ? 'on' : 'off' break case '0': - params.switches = cns.defaultMultiSwitchOff + params.switches = helpers.defaultMultiSwitchOff params.switches[0].switch = value ? 'on' : 'off' params.switches[1].switch = value ? 'on' : 'off' params.switches[2].switch = value ? 'on' : 'off' @@ -35,7 +35,7 @@ module.exports = class deviceSwitch { case '2': case '3': case '4': - params.switches = cns.defaultMultiSwitchOff + params.switches = helpers.defaultMultiSwitchOff for (let i = 1; i <= 4; i++) { if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { if (i === parseInt(accessory.context.switchNumber)) { @@ -88,11 +88,11 @@ module.exports = class deviceSwitch { async externalUpdate (accessory, params) { try { - if (cns.devicesSingleSwitch.includes(accessory.context.eweUIID)) { - if (!utils.hasProperty(params, 'switch')) return + if (helpers.devicesSingleSwitch.includes(accessory.context.eweUIID)) { + if (!helpers.hasProperty(params, 'switch')) return accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switch === 'on') - } else if (cns.devicesMultiSwitch.includes(accessory.context.eweUIID)) { - if (!utils.hasProperty(params, 'switches')) return + } else if (helpers.devicesMultiSwitch.includes(accessory.context.eweUIID)) { + if (!helpers.hasProperty(params, 'switches')) return const idToCheck = accessory.context.hbDeviceId.slice(0, -1) let primaryState = false for (let i = 1; i <= accessory.context.channelCount; i++) { diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index 92a81340..14e412be 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -1,9 +1,10 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' let Characteristic, EveHistoryService, Service const corrInterval = require('correcting-interval') const fakegato = require('fakegato-history') -const utils = require('./../utils') +const helpers = require('./../helpers') module.exports = class deviceThermostat { constructor (platform, accessory) { this.platform = platform @@ -60,23 +61,23 @@ module.exports = class deviceThermostat { try { if ( !this.platform.config.hideTHSwitch && - (utils.hasProperty(params, 'switch') || utils.hasProperty(params, 'mainSwitch')) + (helpers.hasProperty(params, 'switch') || helpers.hasProperty(params, 'mainSwitch')) ) { - const newState = utils.hasProperty(params, 'switch') ? params.switch === 'on' : params.mainSwitch === 'on' + const newState = helpers.hasProperty(params, 'switch') ? params.switch === 'on' : params.mainSwitch === 'on' const switchService = accessory.getService(Service.Switch) switchService.updateCharacteristic(Characteristic.On, newState) } const eveLog = { time: Date.now() } - if (utils.hasProperty(params, 'currentTemperature') && accessory.getService(Service.TemperatureSensor)) { + if (helpers.hasProperty(params, 'currentTemperature') && accessory.getService(Service.TemperatureSensor)) { const currentTemp = parseFloat(params.currentTemperature !== 'unavailable' ? params.currentTemperature : 0) accessory .getService(Service.TemperatureSensor) .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp) eveLog.temp = currentTemp } - if (utils.hasProperty(params, 'currentHumidity') && accessory.getService(Service.HumiditySensor)) { + if (helpers.hasProperty(params, 'currentHumidity') && accessory.getService(Service.HumiditySensor)) { const currentHumi = parseFloat(params.currentHumidity !== 'unavailable' ? params.currentHumidity : 0) accessory .getService(Service.HumiditySensor) @@ -84,7 +85,7 @@ module.exports = class deviceThermostat { eveLog.humidity = currentHumi } if (!this.platform.config.disableEveLogging) { - if (utils.hasProperty(eveLog, 'temp') || utils.hasProperty(eveLog, 'humidity')) { + if (helpers.hasProperty(eveLog, 'temp') || helpers.hasProperty(eveLog, 'humidity')) { accessory.eveLogger.addEntry(eveLog) } } diff --git a/lib/device/usb.js b/lib/device/usb.js index 7089bb03..0600b2fd 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -1,8 +1,8 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' let Characteristic, Service -const cns = require('./../constants') -const utils = require('./../utils') +const helpers = require('./../helpers') module.exports = class deviceUSB { constructor (platform, accessory) { this.platform = platform @@ -18,7 +18,7 @@ module.exports = class deviceUSB { callback() try { const params = { - switches: cns.defaultMultiSwitchOff + switches: helpers.defaultMultiSwitchOff } const outletService = accessory.getService(Service.Outlet) params.switches[0].switch = value ? 'on' : 'off' @@ -31,7 +31,7 @@ module.exports = class deviceUSB { async externalUpdate (accessory, params) { try { - if (!utils.hasProperty(params, 'switches')) return + if (!helpers.hasProperty(params, 'switches')) return accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switches[0].switch === 'on') } catch (err) { this.platform.deviceUpdateError(accessory, err, false) diff --git a/lib/device/valve.js b/lib/device/valve.js index 23e38061..4995d267 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -1,7 +1,8 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' let Characteristic, Service -const utils = require('./../utils') +const helpers = require('./../helpers') module.exports = class deviceValve { constructor (platform, accessory) { this.platform = platform @@ -89,7 +90,7 @@ module.exports = class deviceValve { async externalUpdate (accessory, params) { try { - if (!utils.hasProperty(params, 'switches')) return + if (!helpers.hasProperty(params, 'switches')) return let valveConfig if (!(valveConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index 83f70153..1a9562c1 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -1,9 +1,10 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' let Characteristic, Service, EveHistoryService const corrInterval = require('correcting-interval') const fakegato = require('fakegato-history') -const utils = require('./../utils') +const helpers = require('./../helpers') module.exports = class deviceZBDev { constructor (platform, accessory) { this.platform = platform @@ -56,7 +57,7 @@ module.exports = class deviceZBDev { async externalUpdate (accessory, params) { try { //* ** credit @tasict ***\\ - if (utils.hasProperty(params, 'battery')) { + if (helpers.hasProperty(params, 'battery')) { if (accessory.context.eweUIID === 3026 && this.platform.config.ZBDWBatt) { params.battery *= 10 } @@ -70,7 +71,7 @@ module.exports = class deviceZBDev { } switch (accessory.context.eweUIID) { case 1000: - if (utils.hasProperty(params, 'key') && [0, 1, 2].includes(params.key)) { + if (helpers.hasProperty(params, 'key') && [0, 1, 2].includes(params.key)) { accessory .getService(Service.StatelessProgrammableSwitch) .updateCharacteristic(Characteristic.ProgrammableSwitchEvent, params.key) @@ -80,34 +81,34 @@ module.exports = class deviceZBDev { const eveLog = { time: Date.now() } - if (utils.hasProperty(params, 'temperature')) { + if (helpers.hasProperty(params, 'temperature')) { const currentTemp = parseInt(params.temperature) / 100 accessory .getService(Service.TemperatureSensor) .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp) eveLog.temp = parseFloat(currentTemp) } - if (utils.hasProperty(params, 'humidity')) { + if (helpers.hasProperty(params, 'humidity')) { const currentHumi = parseInt(params.humidity) / 100 accessory .getService(Service.HumiditySensor) .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi) eveLog.humidity = parseFloat(currentHumi) } - if (utils.hasProperty(eveLog, 'temp') || utils.hasProperty(eveLog, 'humidity')) { + if (helpers.hasProperty(eveLog, 'temp') || helpers.hasProperty(eveLog, 'humidity')) { accessory.eveLogger.addEntry(eveLog) } break } case 2026: - if (utils.hasProperty(params, 'motion') && utils.hasProperty(params, 'trigTime')) { + if (helpers.hasProperty(params, 'motion') && helpers.hasProperty(params, 'trigTime')) { const timeNow = new Date() const diff = (timeNow.getTime() - params.trigTime) / 1000 accessory .getService(Service.MotionSensor) .updateCharacteristic( Characteristic.MotionDetected, - utils.hasProperty(params, 'updateSource') && + helpers.hasProperty(params, 'updateSource') && params.motion === 1 && diff < (this.platform.config.sensorTimeDifference || 120) ) @@ -115,7 +116,7 @@ module.exports = class deviceZBDev { } break case 3026: - if (utils.hasProperty(params, 'lock') && [0, 1].includes(params.lock)) { + if (helpers.hasProperty(params, 'lock') && [0, 1].includes(params.lock)) { accessory .getService(Service.ContactSensor) .updateCharacteristic(Characteristic.ContactSensorState, params.lock) diff --git a/lib/eWeLinkHTTP.js b/lib/ewelink-http.js similarity index 81% rename from lib/eWeLinkHTTP.js rename to lib/ewelink-http.js index e311f53b..4ac13318 100644 --- a/lib/eWeLinkHTTP.js +++ b/lib/ewelink-http.js @@ -1,9 +1,9 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' const axios = require('axios') -const cns = require('./constants') const crypto = require('crypto') -const utils = require('./utils') +const helpers = require('./helpers') module.exports = class eWeLinkHTTP { constructor (config, log) { this.log = log @@ -17,7 +17,7 @@ module.exports = class eWeLinkHTTP { async getHost () { const params = { - appid: cns.appId, + appid: helpers.appId, country_code: this.cCode, nonce: Math.random().toString(36).substr(2, 8), ts: Math.floor(new Date().getTime() / 1000), @@ -33,7 +33,7 @@ module.exports = class eWeLinkHTTP { }) dataToSign.sort((a, b) => (a.key < b.key ? -1 : 1)) dataToSign = dataToSign.map(k => k.key + '=' + k.value).join('&') - dataToSign = crypto.createHmac('sha256', cns.appSecret).update(dataToSign).digest('base64') + dataToSign = crypto.createHmac('sha256', helpers.appSecret).update(dataToSign).digest('base64') if (this.debugReqRes) { this.log.warn('Sending HTTP getHost() request. This text is yellow for clarity.\n%s', JSON.stringify(params, null, 2)) } else if (this.debug) { @@ -67,11 +67,11 @@ module.exports = class eWeLinkHTTP { } return this.httpHost } catch (err) { - if (utils.hasProperty(err, 'code') && cns.httpRetryCodes.includes(err.code)) { + if (helpers.hasProperty(err, 'code') && helpers.httpRetryCodes.includes(err.code)) { if (this.debug) { this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') } - await utils.sleep(30000) + await helpers.sleep(30000) return await this.getHost() } else { return err @@ -95,22 +95,22 @@ module.exports = class eWeLinkHTTP { } else if (this.debug) { this.log('Sending HTTP login() request.') } - const dataToSign = crypto.createHmac('sha256', cns.appSecret).update(JSON.stringify(data)).digest('base64') + const dataToSign = crypto.createHmac('sha256', helpers.appSecret).update(JSON.stringify(data)).digest('base64') const res = await axios.post('https://' + this.httpHost + '/v2/user/login', data, { headers: { Authorization: 'Sign ' + dataToSign, 'Content-Type': 'application/json', Host: this.httpHost, - 'X-CK-Appid': cns.appId, + 'X-CK-Appid': helpers.appId, 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) } }) const body = res.data if ( - utils.hasProperty(body, 'error') && + helpers.hasProperty(body, 'error') && body.error === 10004 && - utils.hasProperty(body, 'data') && - utils.hasProperty(body.data, 'region') + helpers.hasProperty(body, 'data') && + helpers.hasProperty(body.data, 'region') ) { const givenRegion = body.data.region switch (givenRegion) { @@ -143,7 +143,7 @@ module.exports = class eWeLinkHTTP { if (this.debug) { this.log.warn('An eWeLink error [500] occured. Retrying in 30 seconds.') } - await utils.sleep(30000) + await helpers.sleep(30000) return await this.login() } else { throw new Error('No auth token received.\n' + JSON.stringify(body, null, 2)) @@ -158,15 +158,15 @@ module.exports = class eWeLinkHTTP { Authorization: 'Bearer ' + this.aToken, 'Content-Type': 'application/json', Host: this.httpHost, - 'X-CK-Appid': cns.appId, + 'X-CK-Appid': helpers.appId, 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) } }) const body = res.data if ( - !utils.hasProperty(body, 'data') || - !utils.hasProperty(body, 'error') || - (utils.hasProperty(body, 'error') && body.error !== 0) + !helpers.hasProperty(body, 'data') || + !helpers.hasProperty(body, 'error') || + (helpers.hasProperty(body, 'error') && body.error !== 0) ) { throw new Error(JSON.stringify(body, null, 2)) } @@ -174,9 +174,9 @@ module.exports = class eWeLinkHTTP { if (body.data.thingList && body.data.thingList.length > 0) { body.data.thingList.forEach(d => { if ( - utils.hasProperty(d, 'itemData') && - utils.hasProperty(d.itemData, 'extra') && - utils.hasProperty(d.itemData.extra, 'uiid') && + helpers.hasProperty(d, 'itemData') && + helpers.hasProperty(d.itemData, 'extra') && + helpers.hasProperty(d.itemData.extra, 'uiid') && !this.hideDevFromHB.includes(d.itemData.deviceid) ) { deviceList.push(d.itemData) @@ -185,11 +185,11 @@ module.exports = class eWeLinkHTTP { } return deviceList } catch (err) { - if (utils.hasProperty(err, 'code') && cns.httpRetryCodes.includes(err.code)) { + if (helpers.hasProperty(err, 'code') && helpers.httpRetryCodes.includes(err.code)) { if (this.debug) { this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') } - await utils.sleep(30000) + await helpers.sleep(30000) return await this.getDevices() } else { return err @@ -209,15 +209,15 @@ module.exports = class eWeLinkHTTP { Authorization: 'Bearer ' + this.aToken, 'Content-Type': 'application/json', Host: this.httpHost, - 'X-CK-Appid': cns.appId, + 'X-CK-Appid': helpers.appId, 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) } }) const body = res.data if ( - !utils.hasProperty(body, 'data') || - !utils.hasProperty(body, 'error') || - (utils.hasProperty(body, 'error') && body.error !== 0) + !helpers.hasProperty(body, 'data') || + !helpers.hasProperty(body, 'error') || + (helpers.hasProperty(body, 'error') && body.error !== 0) ) { throw new Error(JSON.stringify(body, null, 2)) } @@ -227,11 +227,11 @@ module.exports = class eWeLinkHTTP { throw new Error('device not found in eWeLink') } } catch (err) { - if (utils.hasProperty(err, 'code') && cns.httpRetryCodes.includes(err.code)) { + if (helpers.hasProperty(err, 'code') && helpers.httpRetryCodes.includes(err.code)) { if (this.debug) { this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') } - await utils.sleep(30000) + await helpers.sleep(30000) return await this.getDevice(deviceId) } else { return err diff --git a/lib/eWeLinkLAN.js b/lib/ewelink-lan.js similarity index 81% rename from lib/eWeLinkLAN.js rename to lib/ewelink-lan.js index a04cdbcd..41810271 100644 --- a/lib/eWeLinkLAN.js +++ b/lib/ewelink-lan.js @@ -1,25 +1,25 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' const axios = require('axios') -const cns = require('./constants') const crypto = require('crypto') const dns = require('node-dns-sd') -const EventEmitter = require('events') -const utils = require('./utils') +const eventEmitter = require('events') +const helpers = require('./helpers') module.exports = class eWeLinkLAN { constructor (config, log, devices) { this.log = log this.config = config this.debug = this.config.debug || false this.debugReqRes = this.config.debugReqRes || false - this.emitter = new EventEmitter() + this.emitter = new eventEmitter() this.devices = devices this.deviceMap = new Map() devices.forEach(device => { this.deviceMap.set(device.deviceid, { apiKey: device.devicekey, - online: utils.hasProperty(this.config.ipOverride, device.deviceid), - ip: utils.hasProperty(this.config.ipOverride, device.deviceid) ? this.config.ipOverride[device.deviceid] : null + online: helpers.hasProperty(this.config.ipOverride, device.deviceid), + ip: helpers.hasProperty(this.config.ipOverride, device.deviceid) ? this.config.ipOverride[device.deviceid] : null }) }) } @@ -30,7 +30,7 @@ module.exports = class eWeLinkLAN { let d const deviceId = device.fqdn.replace('._ewelink._tcp.local', '').replace('eWeLink_', '') if ((d = this.deviceMap.get(deviceId))) { - if (!utils.hasProperty(this.config.ipOverride, deviceId)) { + if (!helpers.hasProperty(this.config.ipOverride, deviceId)) { this.deviceMap.set(deviceId, { apiKey: d.apiKey, online: true, @@ -54,14 +54,14 @@ module.exports = class eWeLinkLAN { const deviceInfo = this.deviceMap.get(rdata.id) const data = rdata.data1 + - (utils.hasProperty(rdata, 'data2') ? rdata.data2 : '') + - (utils.hasProperty(rdata, 'data3') ? rdata.data3 : '') + - (utils.hasProperty(rdata, 'data4') ? rdata.data4 : '') + (helpers.hasProperty(rdata, 'data2') ? rdata.data2 : '') + + (helpers.hasProperty(rdata, 'data3') ? rdata.data3 : '') + + (helpers.hasProperty(rdata, 'data4') ? rdata.data4 : '') const key = crypto.createHash('md5').update(Buffer.from(deviceInfo.apiKey, 'utf8')).digest() const dText = crypto.createDecipheriv('aes-128-cbc', key, Buffer.from(rdata.iv, 'base64')) const pText = Buffer.concat([dText.update(Buffer.from(data, 'base64')), dText.final()]).toString('utf8') let params - if (packet.address !== deviceInfo.ip && !utils.hasProperty(this.config.ipOverride, rdata.id)) { + if (packet.address !== deviceInfo.ip && !helpers.hasProperty(this.config.ipOverride, rdata.id)) { this.deviceMap.set(rdata.id, { apiKey: deviceInfo.apiKey, online: true, @@ -76,8 +76,8 @@ module.exports = class eWeLinkLAN { return } for (const param in params) { - if (utils.hasProperty(params, param)) { - if (!cns.paramsToKeep.includes(param.replace(/[0-9]/g, ''))) { + if (helpers.hasProperty(params, param)) { + if (!helpers.paramsToKeep.includes(param.replace(/[0-9]/g, ''))) { delete params[param] } } @@ -111,10 +111,10 @@ module.exports = class eWeLinkLAN { let apiKey let suffix const params = {} - if (utils.hasProperty(json.params, 'switches')) { + if (helpers.hasProperty(json.params, 'switches')) { params.switches = json.params.switches suffix = 'switches' - } else if (utils.hasProperty(json.params, 'switch')) { + } else if (helpers.hasProperty(json.params, 'switch')) { params.switch = json.params.switch suffix = 'switch' } else { @@ -149,7 +149,7 @@ module.exports = class eWeLinkLAN { }, data }) - if (!utils.hasProperty(res.data, 'error') || res.data.error !== 0) { + if (!helpers.hasProperty(res.data, 'error') || res.data.error !== 0) { throw new Error(res.data) } return 'ok' @@ -166,8 +166,8 @@ module.exports = class eWeLinkLAN { addDeviceToMap (device) { this.deviceMap.set(device.deviceid, { apiKey: device.devicekey, - online: utils.hasProperty(this.config.ipOverride, device.deviceid), - ip: utils.hasProperty(this.config.ipOverride, device.deviceid) ? this.config.ipOverride[device.deviceid] : null + online: helpers.hasProperty(this.config.ipOverride, device.deviceid), + ip: helpers.hasProperty(this.config.ipOverride, device.deviceid) ? this.config.ipOverride[device.deviceid] : null }) } diff --git a/lib/eWeLink.js b/lib/ewelink-platform.js similarity index 86% rename from lib/eWeLink.js rename to lib/ewelink-platform.js index 26aa3c9a..54c9aef1 100644 --- a/lib/eWeLink.js +++ b/lib/ewelink-platform.js @@ -1,7 +1,6 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' -let Accessory, Characteristic, Service -const cns = require('./constants') const DeviceCurtain = require('./device/curtain') const DeviceBlind = require('./device/blind') const DeviceGarage = require('./device/garage') @@ -19,12 +18,12 @@ const DeviceLight = require('./device/light') const DeviceSwitch = require('./device/switch') const DeviceRFBridge = require('./device/rf-bridge') const DeviceZBDev = require('./device/zb-dev') -const EWeLinkHTTP = require('./eWeLinkHTTP') -const EWeLinkWS = require('./eWeLinkWS') -const EWeLinkLAN = require('./eWeLinkLAN') +const EWeLinkHTTP = require('./ewelink-http') +const EWeLinkLAN = require('./ewelink-lan') +const EWeLinkWS = require('./ewelink-ws') +const helpers = require('./helpers') const promInterval = require('interval-promise') -const utils = require('./utils') -class eWeLink { +module.exports = class eWeLinkPlatform { constructor (log, config, api) { if (!log || !api || !config) return if (!config.username || !config.password || !config.countryCode) { @@ -35,6 +34,8 @@ class eWeLink { this.log = log this.config = config this.api = api + this.Characteristic = api.hap.Characteristic + this.Service = api.hap.Service this.debug = this.config.debug || false this.devicesInHB = new Map() this.devicesInEW = new Map() @@ -80,13 +81,13 @@ class eWeLink { ;(() => { if (Object.keys(this.config.groups || []).length > 0) { this.config.groups - .filter(g => utils.hasProperty(g, 'type') && cns.allowedGroups.includes(g.type)) - .filter(g => utils.hasProperty(g, 'deviceId') && this.devicesInEW.has(g.deviceId)) + .filter(g => helpers.hasProperty(g, 'type') && helpers.allowedGroups.includes(g.type)) + .filter(g => helpers.hasProperty(g, 'deviceId') && this.devicesInEW.has(g.deviceId)) .forEach(g => this.cusG.set(g.deviceId + 'SWX', g)) } if (Object.keys(this.config.bridgeSensors || []).length > 0) { this.config.bridgeSensors - .filter(s => utils.hasProperty(s, 'deviceId') && this.devicesInEW.has(s.deviceId)) + .filter(s => helpers.hasProperty(s, 'deviceId') && this.devicesInEW.has(s.deviceId)) .forEach(s => this.cusS.set(s.fullDeviceId, s)) } this.log('[%s] eWeLink devices loaded from the Homebridge cache.', this.devicesInHB.size) @@ -104,7 +105,7 @@ class eWeLink { if (this.wsClient) { await this.wsClient.getHost() await this.wsClient.closeConnection() - await utils.sleep(250) + await helpers.sleep(250) await this.wsClient.login() } } catch (err) { @@ -148,19 +149,19 @@ class eWeLink { if (this.cusG.has(device.deviceid + 'SWX')) { ;['X', '0', '1', '2', '3', '4'].forEach(sw => { if (this.devicesInHB.has(device.deviceid + 'SW' + sw)) { - if (this.devicesInHB.get(device.deviceid + 'SW' + sw).getService(Service.Switch)) { + if (this.devicesInHB.get(device.deviceid + 'SW' + sw).getService(this.Service.Switch)) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + sw)) } } }) } - if (cns.devicesCurtain.includes(device.extra.uiid)) { + if (helpers.devicesCurtain.includes(device.extra.uiid)) { /*********************** BLINDS [EWELINK UIID 11] ***********************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', false, cns.defaultCurtainCache) + : this.addAccessory(device, device.deviceid + 'SWX', false, helpers.defaultCurtainCache) accessory.control = new DeviceCurtain(this, accessory) /**********************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'blind') { @@ -169,7 +170,7 @@ class eWeLink { ****************************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', false, cns.defaultBlindCache) + : this.addAccessory(device, device.deviceid + 'SWX', false, helpers.defaultBlindCache) accessory.control = new DeviceBlind(this, accessory) /***************************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage') { @@ -178,7 +179,7 @@ class eWeLink { **********************************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', false, cns.defaultGarageCache) + : this.addAccessory(device, device.deviceid + 'SWX', false, helpers.defaultGarageCache) accessory.control = new DeviceGarage(this, accessory) /*********************************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage_two') { @@ -187,7 +188,7 @@ class eWeLink { **********************************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX', false, cns.defaultGarageTwoCache) + : this.addAccessory(device, device.deviceid + 'SWX', false, helpers.defaultGarageTwoCache) accessory.control = new DeviceGarageTwo(this, accessory) /*********************************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage_eachen') { @@ -217,7 +218,7 @@ class eWeLink { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceValve(this, accessory) /***************************/ - } else if (cns.devicesSensor.includes(device.extra.uiid)) { + } else if (helpers.devicesSensor.includes(device.extra.uiid)) { /******************* SENSORS [SONOFF DW2] *******************/ @@ -226,7 +227,7 @@ class eWeLink { : this.addAccessory(device, device.deviceid + 'SWX', false, { type: 'sensor' }) accessory.control = new DeviceSensor(this, accessory) /******************/ - } else if (cns.devicesFan.includes(device.extra.uiid)) { + } else if (helpers.devicesFan.includes(device.extra.uiid)) { /*** FANS ***/ @@ -235,7 +236,7 @@ class eWeLink { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceFan(this, accessory) /**/ - } else if (cns.devicesThermostat.includes(device.extra.uiid)) { + } else if (helpers.devicesThermostat.includes(device.extra.uiid)) { /********** THERMOSTATS **********/ @@ -246,7 +247,7 @@ class eWeLink { }) accessory.control = new DeviceThermostat(this, accessory) /*********/ - } else if (cns.devicesOutlet.includes(device.extra.uiid) || (cns.devicesSingleSwitch.includes(device.extra.uiid) && cns.devicesSingleSwitchOutlet.includes(device.productModel))) { + } else if (helpers.devicesOutlet.includes(device.extra.uiid) || (helpers.devicesSingleSwitch.includes(device.extra.uiid) && helpers.devicesSingleSwitchOutlet.includes(device.productModel))) { /****** OUTLETS ******/ @@ -255,7 +256,7 @@ class eWeLink { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceOutlet(this, accessory) /*****/ - } else if (cns.devicesUSB.includes(device.extra.uiid)) { + } else if (helpers.devicesUSB.includes(device.extra.uiid)) { /********** USB OUTLETS **********/ @@ -264,7 +265,7 @@ class eWeLink { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceUSB(this, accessory) /*********/ - } else if (cns.devicesSCM.includes(device.extra.uiid)) { + } else if (helpers.devicesSCM.includes(device.extra.uiid)) { /********************************* SINGLE CHL [MULTIPLE CHL HARDWARE] *********************************/ @@ -273,7 +274,7 @@ class eWeLink { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceSCM(this, accessory) /********************************/ - } else if (cns.devicesSingleSwitch.includes(device.extra.uiid) && cns.devicesSingleSwitchLight.includes(device.productModel)) { + } else if (helpers.devicesSingleSwitch.includes(device.extra.uiid) && helpers.devicesSingleSwitchLight.includes(device.productModel)) { /********************** LIGHTS [SINGLE CHANNEL] **********************/ @@ -282,7 +283,7 @@ class eWeLink { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceLight(this, accessory) /*********************/ - } else if (cns.devicesMultiSwitch.includes(device.extra.uiid) && cns.devicesMultiSwitchLight.includes(device.productModel)) { + } else if (helpers.devicesMultiSwitch.includes(device.extra.uiid) && helpers.devicesMultiSwitchLight.includes(device.productModel)) { /********************* LIGHTS [MULTI CHANNEL] *********************/ @@ -298,7 +299,7 @@ class eWeLink { : this.addAccessory(device, device.deviceid + 'SW0') } accessory.control = new DeviceLight(this, accessory) - for (let i = 1; i <= cns.chansFromUiid[device.extra.uiid]; i++) { + for (let i = 1; i <= helpers.chansFromUiid[device.extra.uiid]; i++) { if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid + 'SW' + i)) { if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + i)) @@ -309,8 +310,8 @@ class eWeLink { ? this.devicesInHB.get(device.deviceid + 'SW' + i) : this.addAccessory(device, device.deviceid + 'SW' + i) oAccessory - .getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) + .getService(this.Service.AccessoryInformation) + .setCharacteristic(this.Characteristic.FirmwareRevision, device.params.fwVersion) } oAccessory.context.reachableWAN = device.online oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false @@ -318,7 +319,7 @@ class eWeLink { oAccessory.control = new DeviceLight(this, oAccessory) } /********************/ - } else if (cns.devicesSingleSwitch.includes(device.extra.uiid)) { + } else if (helpers.devicesSingleSwitch.includes(device.extra.uiid)) { /************************ SWITCHES [SINGLE CHANNEL] ************************/ @@ -327,7 +328,7 @@ class eWeLink { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceSwitch(this, accessory) /***********************/ - } else if (cns.devicesMultiSwitch.includes(device.extra.uiid)) { + } else if (helpers.devicesMultiSwitch.includes(device.extra.uiid)) { /*********************** SWITCHES [MULTI CHANNEL] ***********************/ @@ -343,7 +344,7 @@ class eWeLink { : this.addAccessory(device, device.deviceid + 'SW0') } accessory.control = new DeviceSwitch(this, accessory) - for (let i = 1; i <= cns.chansFromUiid[device.extra.uiid]; i++) { + for (let i = 1; i <= helpers.chansFromUiid[device.extra.uiid]; i++) { if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid + 'SW' + i)) { if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + i)) @@ -354,8 +355,8 @@ class eWeLink { ? this.devicesInHB.get(device.deviceid + 'SW' + i) : this.addAccessory(device, device.deviceid + 'SW' + i) oAccessory - .getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) + .getService(this.Service.AccessoryInformation) + .setCharacteristic(this.Characteristic.FirmwareRevision, device.params.fwVersion) } oAccessory.context.reachableWAN = device.online oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false @@ -363,13 +364,13 @@ class eWeLink { oAccessory.control = new DeviceSwitch(this, oAccessory) } /**********************/ - } else if (cns.devicesRFBridge.includes(device.extra.uiid)) { + } else if (helpers.devicesRFBridge.includes(device.extra.uiid)) { /********************* RF BRIDGE + SUBDEVICES *********************/ let rfChlCounter = 0 const rfMap = [] - if (utils.hasProperty(device, 'tags') && utils.hasProperty(device.tags, 'zyx_info')) { + if (helpers.hasProperty(device, 'tags') && helpers.hasProperty(device.tags, 'zyx_info')) { device.tags.zyx_info.forEach(remote => rfMap.push({ name: remote.name, @@ -412,8 +413,8 @@ class eWeLink { ? this.devicesInHB.get(device.deviceid + 'SW' + swNumber) : this.addAccessory(device, device.deviceid + 'SW' + swNumber, false, subExtraContext, 'rf_sub') oAccessory - .getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) + .getService(this.Service.AccessoryInformation) + .setCharacteristic(this.Characteristic.FirmwareRevision, device.params.fwVersion) oAccessory.context.reachableWAN = device.online oAccessory.context.reachableLAN = false this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) @@ -423,7 +424,7 @@ class eWeLink { accessory.context.channelCount = rfChlCounter this.devicesInHB.set(accessory.context.hbDeviceId, accessory) /********************/ - } else if (cns.devicesZBBridge.includes(device.extra.uiid)) { + } else if (helpers.devicesZBBridge.includes(device.extra.uiid)) { /************ ZIGBEE BRIDGE ************/ @@ -432,7 +433,7 @@ class eWeLink { } return /***********/ - } else if (cns.devicesZB.includes(device.extra.uiid)) { + } else if (helpers.devicesZB.includes(device.extra.uiid)) { /**************** ZIGBEE SUBDEVICES ****************/ @@ -441,7 +442,7 @@ class eWeLink { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new DeviceZBDev(this, accessory) /***************/ - } else if (cns.devicesCamera.includes(device.extra.uiid)) { + } else if (helpers.devicesCamera.includes(device.extra.uiid)) { /****** CAMERAS ******/ @@ -458,8 +459,8 @@ class eWeLink { } if (!this.hiddenMasters.includes(device.deviceid)) { accessory - .getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) + .getService(this.Service.AccessoryInformation) + .setCharacteristic(this.Characteristic.FirmwareRevision, device.params.fwVersion) } accessory.context.reachableWAN = device.online accessory.context.reachableLAN = this.lanDevices.has(device.deviceid) @@ -470,19 +471,19 @@ class eWeLink { ? 'and found locally with IP [' + this.lanDevices.get(device.deviceid).ip + ']' : 'but LAN mode unavailable as device ' if (!accessory.context.reachableLAN) { - if (cns.devicesNonLAN.includes(device.extra.uiid)) { + if (helpers.devicesNonLAN.includes(device.extra.uiid)) { str += "doesn't support it" - } else if (utils.hasProperty(device, 'sharedBy') && utils.hasProperty(device.sharedBy, 'email')) { + } else if (helpers.hasProperty(device, 'sharedBy') && helpers.hasProperty(device.sharedBy, 'email')) { str += 'is shared (' + device.sharedBy.email + ')' } else { str += 'is unreachable' } } - if (!this.config.disableHTTPRefresh) accessory.control.externalUpdate(accessory, device.params) + if (!this.config.disableHTTPRefresh) accessory.control.externalUpdate(device.params) this.devicesInHB.set(accessory.context.hbDeviceId, accessory) this.log(' → [%s] initialised %s.', device.name, str) } catch (err) { - const deviceName = accessory && utils.hasProperty(accessory, 'displayName') + const deviceName = accessory && helpers.hasProperty(accessory, 'displayName') ? accessory.displayName : device.name this.log.warn(' → [%s] could not be initialised as %s.', deviceName, this.debug ? err : err.message) @@ -495,23 +496,23 @@ class eWeLink { const channelCount = type === 'rf_pri' ? Object.keys((device.tags && device.tags.zyx_info) || []).length - : cns.chansFromUiid[device.extra.uiid] + : helpers.chansFromUiid[device.extra.uiid] if (['1', '2', '3', '4'].includes(switchNumber) && type !== 'rf_sub') { newDeviceName += ' SW' + switchNumber } - if (utils.hasProperty(this.config.nameOverride, hbDeviceId)) { + if (helpers.hasProperty(this.config.nameOverride, hbDeviceId)) { newDeviceName = this.config.nameOverride[hbDeviceId] } try { - const accessory = new Accessory(newDeviceName, this.api.hap.uuid.generate(hbDeviceId).toString()) + const accessory = new this.api.platformAccessory(newDeviceName, this.api.hap.uuid.generate(hbDeviceId).toString()) if (!hidden) { accessory - .getService(Service.AccessoryInformation) - .setCharacteristic(Characteristic.SerialNumber, hbDeviceId) - .setCharacteristic(Characteristic.Manufacturer, device.brandName) - .setCharacteristic(Characteristic.Model, device.productModel + ' (' + device.extra.model + ')') - .setCharacteristic(Characteristic.FirmwareRevision, device.params.fwVersion) - .setCharacteristic(Characteristic.Identify, false) + .getService(this.Service.AccessoryInformation) + .setCharacteristic(this.Characteristic.SerialNumber, hbDeviceId) + .setCharacteristic(this.Characteristic.Manufacturer, device.brandName) + .setCharacteristic(this.Characteristic.Model, device.productModel + ' (' + device.extra.model + ')') + .setCharacteristic(this.Characteristic.FirmwareRevision, device.params.fwVersion) + .setCharacteristic(this.Characteristic.Identify, false) } accessory.context = { ...{ @@ -543,7 +544,7 @@ class eWeLink { params } let res - if (cns.devicesNonLAN.includes(accessory.context.eweUIID)) { + if (helpers.devicesNonLAN.includes(accessory.context.eweUIID)) { res = "device doesn't support LAN mode" } else { res = await this.lanClient.sendUpdate(payload) @@ -608,7 +609,7 @@ class eWeLink { this.log('[%s] %s update received and will be refreshed.', accessory.displayName, device.params.updateSource) } try { - accessory.control.externalUpdate(accessory, device.params) + accessory.control.externalUpdate(device.params) } catch (err) { this.log.warn('[%s] could not be refreshed as %s.', accessory.displayName, this.debug ? err : err.message) } @@ -655,9 +656,3 @@ class eWeLink { } } } -module.exports = function (homebridge) { - Accessory = homebridge.platformAccessory - Characteristic = homebridge.hap.Characteristic - Service = homebridge.hap.Service - return eWeLink -} diff --git a/lib/eWeLinkWS.js b/lib/ewelink-ws.js similarity index 85% rename from lib/eWeLinkWS.js rename to lib/ewelink-ws.js index 50d0fe19..04f4a0d4 100644 --- a/lib/eWeLinkWS.js +++ b/lib/ewelink-ws.js @@ -1,11 +1,11 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' const axios = require('axios') -const cns = require('./constants') -const EventEmitter = require('events') -const utils = require('./utils') -const WS = require('ws') -const WSP = require('websocket-as-promised') +const eventEmitter = require('events') +const helpers = require('./helpers') +const ws = require('ws') +const wsp = require('websocket-as-promised') module.exports = class eWeLinkWS { constructor (config, log, res) { this.config = config @@ -16,7 +16,7 @@ module.exports = class eWeLinkWS { this.aToken = res.aToken this.apiKey = res.apiKey this.wsIsOpen = false - this.emitter = new EventEmitter() + this.emitter = new eventEmitter() } async getHost () { @@ -29,7 +29,7 @@ module.exports = class eWeLinkWS { 'Content-Type': 'application/json' }, data: { - appid: cns.appId, + appid: helpers.appId, nonce: Math.random().toString(36).substr(2, 8), ts: Math.floor(new Date().getTime() / 1000), version: 8 @@ -43,9 +43,9 @@ module.exports = class eWeLinkWS { this.wsHost = body.domain return body.domain } catch (err) { - if (utils.hasProperty(err, 'code') && cns.httpRetryCodes.includes(err.code)) { + if (helpers.hasProperty(err, 'code') && helpers.httpRetryCodes.includes(err.code)) { if (this.debug) this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') - await utils.sleep(30000) + await helpers.sleep(30000) return await this.getHost() } else { return err @@ -54,8 +54,8 @@ module.exports = class eWeLinkWS { } login () { - this.wsp = new WSP('wss://' + this.wsHost + ':8080/api/ws', { - createWebSocket: url => new WS(url), + this.wsp = new wsp('wss://' + this.wsHost + ':8080/api/ws', { + createWebSocket: url => new ws(url), extractMessageData: event => event, attachRequestId: (data, requestId) => Object.assign({ sequence: requestId }, data), extractRequestId: data => data && data.sequence, @@ -69,7 +69,7 @@ module.exports = class eWeLinkWS { const payload = { action: 'userOnline', apikey: this.apiKey, - appid: cns.appId, + appid: helpers.appId, at: this.aToken, nonce: Math.random().toString(36).substr(2, 8), sequence, @@ -85,7 +85,7 @@ module.exports = class eWeLinkWS { } try { const res = await this.wsp.sendRequest(payload, { requestId: sequence }) - if (utils.hasProperty(res, 'config') && res.config.hb && res.config.hbInterval) { + if (helpers.hasProperty(res, 'config') && res.config.hb && res.config.hbInterval) { if (this.hbInterval) clearInterval(this.hbInterval) this.hbInterval = setInterval(() => { try { @@ -104,24 +104,24 @@ module.exports = class eWeLinkWS { this.wsp.onUnpackedMessage.addListener(device => { if (device === 'pong') return let onlineStatus = true - if (!utils.hasProperty(device, 'params')) device.params = {} - if (utils.hasProperty(device, 'deviceid') && utils.hasProperty(device, 'error')) { + if (!helpers.hasProperty(device, 'params')) device.params = {} + if (helpers.hasProperty(device, 'deviceid') && helpers.hasProperty(device, 'error')) { device.action = 'update' onlineStatus = device.error === 0 if (device.error !== 0 && this.debug) { this.log.warn('WS message received.\n%s', JSON.stringify(device, null, 2).replace(this.apiKey, '**hidden**')) } } - if (utils.hasProperty(device, 'action')) { + if (helpers.hasProperty(device, 'action')) { switch (device.action) { case 'update': case 'sysmsg': - if (device.action === 'sysmsg' && utils.hasProperty(device.params, 'online')) { + if (device.action === 'sysmsg' && helpers.hasProperty(device.params, 'online')) { onlineStatus = device.params.online } for (const param in device.params) { - if (utils.hasProperty(device.params, param)) { - if (!cns.paramsToKeep.includes(param.replace(/[0-9]/g, ''))) { + if (helpers.hasProperty(device.params, param)) { + if (!helpers.paramsToKeep.includes(param.replace(/[0-9]/g, ''))) { delete device.params[param] } } @@ -149,7 +149,7 @@ module.exports = class eWeLinkWS { this.log.warn('[%s] WS message has unknown action.\n' + JSON.stringify(device, null, 2), device.deviceid) } } - } else if (utils.hasProperty(device, 'error') && device.error === 0) { + } else if (helpers.hasProperty(device, 'error') && device.error === 0) { // *** Safe to ignore these messages *** \\ } else { if (this.debug) this.log.warn('WS unknown command received.\n' + JSON.stringify(device, null, 2)) @@ -167,7 +167,7 @@ module.exports = class eWeLinkWS { this.log.warn('Web socket closed - [%s].', e) this.log.warn('Web socket will try to reconnect in five seconds.') } - await utils.sleep(5000) + await helpers.sleep(5000) return await this.login() }) this.wsp.onError.addListener(async e => { @@ -181,7 +181,7 @@ module.exports = class eWeLinkWS { this.log.warn('Web socket error - [%s].', e) this.log.warn('Web socket will try to reconnect in five seconds.') } - await utils.sleep(5000) + await helpers.sleep(5000) return await this.login() }) } @@ -206,7 +206,7 @@ module.exports = class eWeLinkWS { this.log('WS message sent.') } const device = await this.wsp.sendRequest(jsonToSend, { requestId: sequence }) - device.error = utils.hasProperty(device, 'error') ? device.error : 504 + device.error = helpers.hasProperty(device, 'error') ? device.error : 504 switch (device.error) { case 0: return @@ -221,7 +221,7 @@ module.exports = class eWeLinkWS { if (this.debug) { this.log.warn('Command will be resent when WS is reconnected.') } - await utils.sleep(30000) + await helpers.sleep(30000) return await this.sendUpdate(json) } } @@ -249,7 +249,7 @@ module.exports = class eWeLinkWS { } } else { if (this.debug) this.log.warn('Command will be resent when WS is reconnected.') - await utils.sleep(30000) + await helpers.sleep(30000) return await this.requestUpdate(accessory) } } diff --git a/lib/constants.js b/lib/helpers.js similarity index 97% rename from lib/constants.js rename to lib/helpers.js index 1c92339c..b88b9be5 100644 --- a/lib/constants.js +++ b/lib/helpers.js @@ -1,6 +1,13 @@ /* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ 'use strict' module.exports = { + sleep: ms => { + return new Promise(resolve => setTimeout(resolve, ms)) + }, + hasProperty: (obj, prop) => { + return Object.prototype.hasOwnProperty.call(obj, prop) + }, appId: 'oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq', appSecret: '6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM', httpRetryCodes: ['ENOTFOUND', 'ETIMEDOUT', 'EAI_AGAIN'], diff --git a/lib/utils.js b/lib/utils.js deleted file mode 100644 index 4cd84223..00000000 --- a/lib/utils.js +++ /dev/null @@ -1,10 +0,0 @@ -/* jshint -W014, -W033, esversion: 9 */ -'use strict' -module.exports = { - sleep: ms => { - return new Promise(resolve => setTimeout(resolve, ms)) - }, - hasProperty: (obj, prop) => { - return Object.prototype.hasOwnProperty.call(obj, prop) - } -} From c4e14f5fbafdbc3945b9c64009849df0d888047c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 15 Oct 2020 11:45:23 +0100 Subject: [PATCH 0477/3183] file reorganisation 2 --- lib/device/fan.js | 58 ++++++++++----------- lib/device/garage-eachen.js | 68 ++++++++++++------------ lib/device/garage-two.js | 100 +++++++++++++++++------------------- lib/device/garage.js | 94 +++++++++++++++++---------------- lib/device/lock.js | 62 +++++++++++----------- lib/device/rf-bridge.js | 87 +++++++++++++++---------------- lib/device/scm.js | 32 ++++++------ lib/device/sensor.js | 38 +++++++------- 8 files changed, 261 insertions(+), 278 deletions(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index c6f51864..dd72b1a4 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -1,53 +1,53 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -let Characteristic, Service const helpers = require('./../helpers') module.exports = class deviceFan { constructor (platform, accessory) { this.platform = platform - Service = platform.api.hap.Service - Characteristic = platform.api.hap.Characteristic - const fanService = accessory.getService(Service.Fanv2) || accessory.addService(Service.Fanv2) - const fanLightService = accessory.getService(Service.Lightbulb) || accessory.addService(Service.Lightbulb) + this.accessory = accessory + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + const fanService = accessory.getService(this.Service.Fanv2) || accessory.addService(this.Service.Fanv2) + const fanLightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) fanService - .getCharacteristic(Characteristic.Active) + .getCharacteristic(this.Characteristic.Active) .on('set', async (value, callback) => { callback() if (value === 0) { await helpers.sleep(500) - fanService.setCharacteristic(Characteristic.RotationSpeed, 0) + fanService.setCharacteristic(this.Characteristic.RotationSpeed, 0) } }) fanService - .getCharacteristic(Characteristic.RotationSpeed) - .on('set', (value, callback) => this.internalUpdate(accessory, 'speed', value, callback)) + .getCharacteristic(this.Characteristic.RotationSpeed) + .on('set', (value, callback) => this.internalUpdate('speed', value, callback)) .setProps({ minStep: 33 }) fanLightService - .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, 'light', value, callback)) + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalUpdate('light', value, callback)) } - async internalUpdate (accessory, type, value, callback) { + async internalUpdate (type, value, callback) { callback() try { let newPower let newSpeed let newLight - const lightService = accessory.getService(Service.Lightbulb) - const fanService = accessory.getService(Service.Fanv2) + const lightService = this.accessory.getService(this.Service.Lightbulb) + const fanService = this.accessory.getService(this.Service.Fanv2) const params = { switches: helpers.defaultMultiSwitchOff } switch (type) { case 'speed': newPower = value >= 33 ? 1 : 0 newSpeed = value - newLight = lightService.getCharacteristic(Characteristic.On).value + newLight = lightService.getCharacteristic(this.Characteristic.On).value break case 'light': - newPower = fanService.getCharacteristic(Characteristic.Active).value - newSpeed = fanService.getCharacteristic(Characteristic.RotationSpeed).value + newPower = fanService.getCharacteristic(this.Characteristic.Active).value + newSpeed = fanService.getCharacteristic(this.Characteristic.RotationSpeed).value newLight = value break } @@ -56,21 +56,21 @@ module.exports = class deviceFan { params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? 'on' : 'off' params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? 'on' : 'off' - lightService.updateCharacteristic(Characteristic.On, newLight) + lightService.updateCharacteristic(this.Characteristic.On, newLight) fanService - .updateCharacteristic(Characteristic.Active, newPower) - .updateCharacteristic(Characteristic.RotationSpeed, newSpeed) - await this.platform.sendDeviceUpdate(accessory, params) + .updateCharacteristic(this.Characteristic.Active, newPower) + .updateCharacteristic(this.Characteristic.RotationSpeed, newSpeed) + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (params.switches && Array.isArray(params.switches)) { - const lightService = accessory.getService(Service.Lightbulb) - const fanService = accessory.getService(Service.Fanv2) + const lightService = this.accessory.getService(this.Service.Lightbulb) + const fanService = this.accessory.getService(this.Service.Fanv2) const light = params.switches[0].switch === 'on' let status let speed @@ -91,13 +91,13 @@ module.exports = class deviceFan { status = 1 speed = 99 } - lightService.updateCharacteristic(Characteristic.On, light) + lightService.updateCharacteristic(this.Characteristic.On, light) fanService - .updateCharacteristic(Characteristic.Active, status) - .updateCharacteristic(Characteristic.RotationSpeed, speed) + .updateCharacteristic(this.Characteristic.Active, status) + .updateCharacteristic(this.Characteristic.RotationSpeed, speed) } } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 0f58b636..3dc5fa7d 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -1,78 +1,76 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -let Characteristic, Service const helpers = require('./../helpers') module.exports = class deviceGarageEachen { constructor (platform, accessory) { this.platform = platform - Service = platform.api.hap.Service - Characteristic = platform.api.hap.Characteristic + this.accessory = accessory + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic let gdeService - if (!(gdeService = accessory.getService(Service.GarageDoorOpener))) { + if (!(gdeService = accessory.getService(this.Service.GarageDoorOpener))) { accessory - .addService(Service.GarageDoorOpener) - .setCharacteristic(Characteristic.CurrentDoorState, 1) - .setCharacteristic(Characteristic.TargetDoorState, 1) - .setCharacteristic(Characteristic.ObstructionDetected, false) - gdeService = accessory.getService(Service.GarageDoorOpener) + .addService(this.Service.GarageDoorOpener) + .setCharacteristic(this.Characteristic.CurrentDoorState, 1) + .setCharacteristic(this.Characteristic.TargetDoorState, 1) + .setCharacteristic(this.Characteristic.ObstructionDetected, false) + gdeService = accessory.getService(this.Service.GarageDoorOpener) } gdeService - .getCharacteristic(Characteristic.TargetDoorState) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .getCharacteristic(this.Characteristic.TargetDoorState) + .on('set', (value, callback) => this.internalUpdate(value, callback)) } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { let garageConfig - if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage_eachen') { throw new Error('improper configuration') } const params = { switch: value === 0 ? 'on' : 'off' } - const gdService = accessory.getService(Service.GarageDoorOpener) - if (value === gdService.getCharacteristic(Characteristic.CurrentDoorState).value % 2) return - accessory.context.inUse = true - await this.platform.sendDeviceUpdate(accessory, params) + const gdService = this.accessory.getService(this.Service.GarageDoorOpener) + if (value === gdService.getCharacteristic(this.Characteristic.CurrentDoorState).value % 2) return + this.accessory.context.inUse = true + await this.platform.sendDeviceUpdate(this.accessory, params) gdService - .updateCharacteristic(Characteristic.TargetDoorState, value) - .updateCharacteristic(Characteristic.CurrentDoorState, value + 2) + .updateCharacteristic(this.Characteristic.TargetDoorState, value) + .updateCharacteristic(this.Characteristic.CurrentDoorState, value + 2) await helpers.sleep(2000) - accessory.context.inUse = false + this.accessory.context.inUse = false if (value === 0) { await helpers.sleep(Math.max((garageConfig.operationTime - 20) * 100, 0)) - gdService.updateCharacteristic(Characteristic.CurrentDoorState, 0) + gdService.updateCharacteristic(this.Characteristic.CurrentDoorState, 0) } } catch (err) { - accessory.context.inUse = false - this.platform.deviceUpdateError(accessory, err, true) + this.accessory.context.inUse = false + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { - if (!helpers.hasProperty(params, 'switch') || accessory.context.inUse) { - return - } + if (!helpers.hasProperty(params, 'switch') || this.accessory.context.inUse) return let garageConfig - if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage_eachen') { throw new Error('improper configuration') } - accessory.context.inUse = true - const gdService = accessory.getService(Service.GarageDoorOpener) + this.accessory.context.inUse = true + const gdService = this.accessory.getService(this.Service.GarageDoorOpener) gdService - .updateCharacteristic(Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) - .updateCharacteristic(Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) - accessory.context.inUse = false + .updateCharacteristic(this.Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) + .updateCharacteristic(this.Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) + this.accessory.context.inUse = false } catch (err) { - accessory.context.inUse = false - this.platform.deviceUpdateError(accessory, err, false) + this.accessory.context.inUse = false + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/garage-two.js b/lib/device/garage-two.js index 36b18405..6e456abe 100644 --- a/lib/device/garage-two.js +++ b/lib/device/garage-two.js @@ -1,34 +1,34 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -let Characteristic, Service const helpers = require('./../helpers') module.exports = class deviceGarageTwo { constructor (platform, accessory) { this.platform = platform - Service = platform.api.hap.Service - Characteristic = platform.api.hap.Characteristic + this.accessory = accessory + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic ;['1', '2'].forEach(v => { let gdService if (!(gdService = accessory.getService('Garage ' + v))) { accessory - .addService(Service.GarageDoorOpener, 'Garage ' + v, 'garage' + v) - .setCharacteristic(Characteristic.CurrentDoorState, 1) - .setCharacteristic(Characteristic.TargetDoorState, 1) - .setCharacteristic(Characteristic.ObstructionDetected, false) + .addService(this.Service.GarageDoorOpener, 'Garage ' + v, 'garage' + v) + .setCharacteristic(this.Characteristic.CurrentDoorState, 1) + .setCharacteristic(this.Characteristic.TargetDoorState, 1) + .setCharacteristic(this.Characteristic.ObstructionDetected, false) gdService = accessory.getService('Garage ' + v) } gdService - .getCharacteristic(Characteristic.TargetDoorState) - .on('set', (value, callback) => this.internalUpdate(accessory, 'Garage' + v, value, callback)) + .getCharacteristic(this.Characteristic.TargetDoorState) + .on('set', (value, callback) => this.internalUpdate('Garage' + v, value, callback)) }) } - async internalUpdate (accessory, garage, value, callback) { + async internalUpdate (garage, value, callback) { callback() try { let garageConfig - if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage_two') { @@ -50,8 +50,8 @@ module.exports = class deviceGarageTwo { } let sAccessory = false const newPos = value - const params = {} - const gdService = accessory.getService(garage) + const params = { switches: this.accessory.context.switchState } + const gdService = this.accessory.getService(garage) if (sensorDefinition && !(sAccessory = this.platform.devicesInHB.get(garageConfig.sensorId + 'SWX'))) { throw new Error("defined DW2 sensor doesn't exist") } @@ -59,77 +59,73 @@ module.exports = class deviceGarageTwo { throw new Error("defined DW2 sensor isn't a sensor") } const prevState = sAccessory - ? sAccessory.getService(Service.ContactSensor).getCharacteristic(Characteristic.ContactSensorState).value === 0 + ? sAccessory.getService(this.Service.ContactSensor).getCharacteristic(this.Characteristic.ContactSensorState).value === 0 ? 1 : 0 : garage === 'Garage 1' - ? accessory.context.cacheOneCurrentDoorState - : accessory.context.cacheTwoCurrentDoorState + ? this.accessory.context.cacheOneCurrentDoorState + : this.accessory.context.cacheTwoCurrentDoorState if (newPos === prevState % 2) return - accessory.context.inUse = true + this.accessory.context.inUse = true gdService - .updateCharacteristic(Characteristic.TargetDoorState, newPos) - .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2) - params.switches = accessory.context.switchState + .updateCharacteristic(this.Characteristic.TargetDoorState, newPos) + .updateCharacteristic(this.Characteristic.CurrentDoorState, newPos + 2) switch (garage) { case 'Garage 1': { - accessory.context.cacheOneTargetDoorState = newPos - accessory.context.cacheOneCurrentDoorState = newPos + 2 + this.accessory.context.cacheOneTargetDoorState = newPos + this.accessory.context.cacheOneCurrentDoorState = newPos + 2 params.switches[0].switch = newPos === 0 ? 'on' : 'off' params.switches[1].switch = newPos === 1 ? 'on' : 'off' break } case 'Garage 2': { - accessory.context.cacheTwoTargetDoorState = newPos - accessory.context.cacheTwoCurrentDoorState = newPos + 2 + this.accessory.context.cacheTwoTargetDoorState = newPos + this.accessory.context.cacheTwoCurrentDoorState = newPos + 2 params.switches[2].switch = newPos === 0 ? 'on' : 'off' params.switches[3].switch = newPos === 1 ? 'on' : 'off' break } } - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) if (!sAccessory) { - gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos) + gdService.updateCharacteristic(this.Characteristic.CurrentDoorState, newPos) switch (garage) { case 'Garage 1': { - accessory.context.cacheOneCurrentDoorState = newPos + this.accessory.context.cacheOneCurrentDoorState = newPos break } case 'Garage 2': { - accessory.context.cacheTwoCurrentDoorState = newPos + this.accessory.context.cacheTwoCurrentDoorState = newPos break } } } - accessory.context.inUse = false + this.accessory.context.inUse = false } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - externalUpdate (accessory, params) { + externalUpdate (params) { try { if (!helpers.hasProperty(params, 'switches')) { return } let garageConfig - if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage_two') { throw new Error('improper configuration') } - if (accessory.context.inUse || garageConfig.sensorId) { - return - } - accessory.context.switchState = params.switches - this.platform.log.warn(accessory.context.switchState) + if (this.accessory.context.inUse || garageConfig.sensorId) return + this.accessory.context.switchState = params.switches ;['1', '2'].forEach(async v => { - const gcService = accessory.getService('Garage ' + v) + const gcService = this.accessory.getService('Garage ' + v) const prevState = v === '1' - ? accessory.context.cacheOneCurrentDoorState - : accessory.context.cacheTwoCurrentDoorState + ? this.accessory.context.cacheOneCurrentDoorState + : this.accessory.context.cacheTwoCurrentDoorState const newPos = [0, 2].includes(prevState) ? 3 : 2 switch (v) { case '1': @@ -149,38 +145,38 @@ module.exports = class deviceGarageTwo { } break } - accessory.context.inUse = true + this.accessory.context.inUse = true if (garageConfig.sensorId) { await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) } else { gcService - .updateCharacteristic(Characteristic.TargetDoorState, newPos - 2) - .updateCharacteristic(Characteristic.CurrentDoorState, newPos) + .updateCharacteristic(this.Characteristic.TargetDoorState, newPos - 2) + .updateCharacteristic(this.Characteristic.CurrentDoorState, newPos) switch (v) { case '1': - accessory.context.cacheOneCurrentDoorState = newPos - accessory.context.cacheTwoTargetDoorState = newPos - 2 + this.accessory.context.cacheOneCurrentDoorState = newPos + this.accessory.context.cacheTwoTargetDoorState = newPos - 2 break case '2': - accessory.context.cacheTwoCurrentDoorState = newPos - accessory.context.cacheTwoTargetDoorState = newPos - 2 + this.accessory.context.cacheTwoCurrentDoorState = newPos + this.accessory.context.cacheTwoTargetDoorState = newPos - 2 break } await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) - gcService.updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2) + gcService.updateCharacteristic(this.Characteristic.CurrentDoorState, newPos - 2) switch (v) { case '1': - accessory.context.cacheOneCurrentDoorState = newPos - 2 + this.accessory.context.cacheOneCurrentDoorState = newPos - 2 break case '2': - accessory.context.cacheTwoCurrentDoorState = newPos - 2 + this.accessory.context.cacheTwoCurrentDoorState = newPos - 2 break } } }) - accessory.context.inUse = false + this.accessory.context.inUse = false } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/garage.js b/lib/device/garage.js index 39eab6f3..ad5f3945 100644 --- a/lib/device/garage.js +++ b/lib/device/garage.js @@ -1,32 +1,32 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -let Characteristic, Service const helpers = require('./../helpers') module.exports = class deviceGarage { constructor (platform, accessory) { this.platform = platform - Service = platform.api.hap.Service - Characteristic = platform.api.hap.Characteristic + this.accessory = accessory + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic let gdService - if (!(gdService = accessory.getService(Service.GarageDoorOpener))) { + if (!(gdService = accessory.getService(this.Service.GarageDoorOpener))) { accessory - .addService(Service.GarageDoorOpener) - .setCharacteristic(Characteristic.CurrentDoorState, 1) - .setCharacteristic(Characteristic.TargetDoorState, 1) - .setCharacteristic(Characteristic.ObstructionDetected, false) - gdService = accessory.getService(Service.GarageDoorOpener) + .addService(this.Service.GarageDoorOpener) + .setCharacteristic(this.Characteristic.CurrentDoorState, 1) + .setCharacteristic(this.Characteristic.TargetDoorState, 1) + .setCharacteristic(this.Characteristic.ObstructionDetected, false) + gdService = accessory.getService(this.Service.GarageDoorOpener) } gdService - .getCharacteristic(Characteristic.TargetDoorState) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .getCharacteristic(this.Characteristic.TargetDoorState) + .on('set', (value, callback) => this.internalUpdate(value, callback)) } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { let garageConfig - if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage' || !['oneSwitch', 'twoSwitch'].includes(garageConfig.setup)) { @@ -37,7 +37,7 @@ module.exports = class deviceGarage { const newPos = value const params = {} let delay = 0 - const gdService = accessory.getService(Service.GarageDoorOpener) + const gdService = this.accessory.getService(this.Service.GarageDoorOpener) if (sensorDefinition && !(sAccessory = this.platform.devicesInHB.get(garageConfig.sensorId + 'SWX'))) { throw new Error("defined DW2 sensor doesn't exist") } @@ -45,65 +45,63 @@ module.exports = class deviceGarage { throw new Error("defined DW2 sensor isn't a sensor") } const prevState = sAccessory - ? sAccessory.getService(Service.ContactSensor).getCharacteristic(Characteristic.ContactSensorState).value === 0 + ? sAccessory.getService(this.Service.ContactSensor).getCharacteristic(this.Characteristic.ContactSensorState).value === 0 ? 1 : 0 - : accessory.context.cacheCurrentDoorState + : this.accessory.context.cacheCurrentDoorState if (newPos === prevState % 2) return - accessory.context.inUse = true - accessory.context.state = value + this.accessory.context.inUse = true + this.accessory.context.state = value if (garageConfig.setup === 'oneSwitch' && [2, 3].includes(prevState)) { - gdService.updateCharacteristic(Characteristic.CurrentDoorState, ((prevState * 2) % 3) + 2) - accessory.context.cacheCurrentDoorState = ((prevState * 2) % 3) + 2 + gdService.updateCharacteristic(this.Characteristic.CurrentDoorState, ((prevState * 2) % 3) + 2) + this.accessory.context.cacheCurrentDoorState = ((prevState * 2) % 3) + 2 delay = 1500 } - if (accessory.context.state !== newPos) return + if (this.accessory.context.state !== newPos) return await helpers.sleep(delay) gdService - .updateCharacteristic(Characteristic.TargetDoorState, newPos) - .updateCharacteristic(Characteristic.CurrentDoorState, newPos + 2) - accessory.context.cacheTargetDoorState = newPos - accessory.context.cacheCurrentDoorState = newPos + 2 + .updateCharacteristic(this.Characteristic.TargetDoorState, newPos) + .updateCharacteristic(this.Characteristic.CurrentDoorState, newPos + 2) + this.accessory.context.cacheTargetDoorState = newPos + this.accessory.context.cacheCurrentDoorState = newPos + 2 switch (garageConfig.setup) { case 'oneSwitch': params.switch = 'on' break case 'twoSwitch': - params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches + params.switches = helpers.defaultMultiSwitchOff params.switches[0].switch = newPos === 0 ? 'on' : 'off' params.switches[1].switch = newPos === 1 ? 'on' : 'off' break } - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) if (!sAccessory) { - gdService.updateCharacteristic(Characteristic.CurrentDoorState, newPos) - accessory.context.cacheCurrentDoorState = newPos + gdService.updateCharacteristic(this.Characteristic.CurrentDoorState, newPos) + this.accessory.context.cacheCurrentDoorState = newPos } - accessory.context.inUse = false + this.accessory.context.inUse = false } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (!helpers.hasProperty(params, 'switch') && !helpers.hasProperty(params, 'switches')) { return } let garageConfig - const gcService = accessory.getService(Service.GarageDoorOpener) - const prevState = accessory.context.cacheCurrentDoorState + const gcService = this.accessory.getService(this.Service.GarageDoorOpener) + const prevState = this.accessory.context.cacheCurrentDoorState const newPos = [0, 2].includes(prevState) ? 3 : 2 - if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage' || !['oneSwitch', 'twoSwitch'].includes(garageConfig.setup)) { throw new Error('improper configuration') } - if (accessory.context.inUse || garageConfig.sensorId) { - return - } + if (this.accessory.context.inUse || garageConfig.sensorId) return switch (garageConfig.setup) { case 'oneSwitch': if (params.switch === 'off') { @@ -119,23 +117,23 @@ module.exports = class deviceGarage { } break } - accessory.context.inUse = true + this.accessory.context.inUse = true if (garageConfig.sensorId) { await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) } else { gcService - .updateCharacteristic(Characteristic.TargetDoorState, newPos - 2) - .updateCharacteristic(Characteristic.CurrentDoorState, newPos) - accessory.context.cacheCurrentDoorState = newPos - accessory.context.cacheTargetDoorState = newPos - 2 + .updateCharacteristic(this.Characteristic.TargetDoorState, newPos - 2) + .updateCharacteristic(this.Characteristic.CurrentDoorState, newPos) + this.accessory.context.cacheCurrentDoorState = newPos + this.accessory.context.cacheTargetDoorState = newPos - 2 await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) - gcService.updateCharacteristic(Characteristic.CurrentDoorState, newPos - 2) - accessory.context.cacheCurrentDoorState = newPos - 2 + gcService.updateCharacteristic(this.Characteristic.CurrentDoorState, newPos - 2) + this.accessory.context.cacheCurrentDoorState = newPos - 2 } - accessory.context.inUse = false + this.accessory.context.inUse = false } catch (err) { - accessory.context.inUse = false - this.platform.deviceUpdateError(accessory, err, false) + this.accessory.context.inUse = false + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/lock.js b/lib/device/lock.js index 614c4e68..8114e730 100644 --- a/lib/device/lock.js +++ b/lib/device/lock.js @@ -1,74 +1,72 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -let Characteristic, Service const helpers = require('./../helpers') module.exports = class deviceLock { constructor (platform, accessory) { this.platform = platform - Service = platform.api.hap.Service - Characteristic = platform.api.hap.Characteristic - const lmService = accessory.getService(Service.LockMechanism) || accessory.addService(Service.LockMechanism) + this.accessory = accessory + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + const lmService = accessory.getService(this.Service.LockMechanism) || accessory.addService(this.Service.LockMechanism) lmService - .getCharacteristic(Characteristic.LockTargetState) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .getCharacteristic(this.Characteristic.LockTargetState) + .on('set', (value, callback) => this.internalUpdate(value, callback)) } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { let lockConfig - const params = { - switch: 'on' - } - const lmService = accessory.getService(Service.LockMechanism) - if (!(lockConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + const params = { switch: 'on' } + const lmService = this.accessory.getService(this.Service.LockMechanism) + if (!(lockConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (lockConfig.type !== 'lock') { throw new Error('improper configuration') } - accessory.context.inUse = true - await this.platform.sendDeviceUpdate(accessory, params) + this.accessory.context.inUse = true + await this.platform.sendDeviceUpdate(this.accessory, params) lmService - .updateCharacteristic(Characteristic.LockTargetState, 0) - .updateCharacteristic(Characteristic.LockCurrentState, 0) + .updateCharacteristic(this.Characteristic.LockTargetState, 0) + .updateCharacteristic(this.Characteristic.LockCurrentState, 0) await helpers.sleep(Math.max(lockConfig.operationTime * 100, 1000)) lmService - .updateCharacteristic(Characteristic.LockTargetState, 1) - .updateCharacteristic(Characteristic.LockCurrentState, 1) - accessory.context.inUse = false + .updateCharacteristic(this.Characteristic.LockTargetState, 1) + .updateCharacteristic(this.Characteristic.LockCurrentState, 1) + this.accessory.context.inUse = false } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (!helpers.hasProperty(params, 'switch')) return let lockConfig - const lmService = accessory.getService(Service.LockMechanism) - if (!(lockConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + const lmService = this.accessory.getService(this.Service.LockMechanism) + if (!(lockConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (lockConfig.type !== 'lock') { throw new Error('improper configuration') } - if (params.switch === 'off' || accessory.context.inUse) { + if (params.switch === 'off' || this.accessory.context.inUse) { return } - accessory.context.inUse = true + this.accessory.context.inUse = true lmService - .updateCharacteristic(Characteristic.LockCurrentState, 0) - .updateCharacteristic(Characteristic.LockTargetState, 0) + .updateCharacteristic(this.Characteristic.LockCurrentState, 0) + .updateCharacteristic(this.Characteristic.LockTargetState, 0) await helpers.sleep(Math.max(lockConfig.operationTime * 100, 1000)) lmService - .updateCharacteristic(Characteristic.LockCurrentState, 1) - .updateCharacteristic(Characteristic.LockTargetState, 1) - accessory.context.inUse = false + .updateCharacteristic(this.Characteristic.LockCurrentState, 1) + .updateCharacteristic(this.Characteristic.LockTargetState, 1) + this.accessory.context.inUse = false } catch (err) { - accessory.context.inUse = false - this.platform.deviceUpdateError(accessory, err, false) + this.accessory.context.inUse = false + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index 559e3a75..fe821fbb 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -1,48 +1,48 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -let Characteristic, Service const helpers = require('./../helpers') module.exports = class deviceRFBridge { constructor (platform, accessory) { this.platform = platform - Service = platform.api.hap.Service - Characteristic = platform.api.hap.Characteristic + this.accessory = accessory + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic switch (accessory.context.subType) { case 'water': - if (!accessory.getService(Service.LeakSensor)) accessory.addService(Service.LeakSensor) + if (!accessory.getService(this.Service.LeakSensor)) accessory.addService(this.Service.LeakSensor) break case 'fire': case 'smoke': - if (!accessory.getService(Service.SmokeSensor)) accessory.addService(Service.SmokeSensor) + if (!accessory.getService(this.Service.SmokeSensor)) accessory.addService(this.Service.SmokeSensor) break case 'co': - if (!accessory.getService(Service.CarbonMonoxideSensor)) accessory.addService(Service.CarbonMonoxideSensor) + if (!accessory.getService(this.Service.CarbonMonoxideSensor)) accessory.addService(this.Service.CarbonMonoxideSensor) break case 'co2': - if (!accessory.getService(Service.CarbonDioxideSensor)) accessory.addService(Service.CarbonDioxideSensor) + if (!accessory.getService(this.Service.CarbonDioxideSensor)) accessory.addService(this.Service.CarbonDioxideSensor) break case 'contact': - if (!accessory.getService(Service.ContactSensor)) accessory.addService(Service.ContactSensor) + if (!accessory.getService(this.Service.ContactSensor)) accessory.addService(this.Service.ContactSensor) break case 'occupancy': - if (!accessory.getService(Service.OccupancySensor)) accessory.addService(Service.OccupancySensor) + if (!accessory.getService(this.Service.OccupancySensor)) accessory.addService(this.Service.OccupancySensor) break default: - if (!accessory.getService(Service.MotionSensor)) accessory.addService(Service.MotionSensor) + if (!accessory.getService(this.Service.MotionSensor)) accessory.addService(this.Service.MotionSensor) break case 'button': Object.entries(accessory.context.buttons).forEach(([chan, name]) => { - if (!accessory.getService(name)) accessory.addService(Service.Switch, name, 'switch' + chan) - accessory.getService(name).updateCharacteristic(Characteristic.On, false) - accessory.getService(name).getCharacteristic(Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, chan, name, value, callback)) + if (!accessory.getService(name)) accessory.addService(this.Service.Switch, name, 'switch' + chan) + accessory.getService(name).updateCharacteristic(this.Characteristic.On, false) + accessory.getService(name).getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(chan, name, value, callback)) }) break } } - async internalUpdate (accessory, rfChl, service, value, callback) { + async internalUpdate (rfChl, service, value, callback) { callback() try { if (!value) return @@ -50,17 +50,17 @@ module.exports = class deviceRFBridge { cmd: 'transmit', rfChl: parseInt(rfChl) } - const rfService = accessory.getService(service) - rfService.updateCharacteristic(Characteristic.On, true) + const rfService = this.accessory.getService(service) + rfService.updateCharacteristic(this.Characteristic.On, true) await helpers.sleep(1000) - rfService.updateCharacteristic(Characteristic.On, false) - await this.platform.sendDeviceUpdate(accessory, params) + rfService.updateCharacteristic(this.Characteristic.On, false) + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (!helpers.hasProperty(params, 'updateSource')) return const timeNow = new Date() @@ -68,7 +68,7 @@ module.exports = class deviceRFBridge { if (helpers.hasProperty(params, 'cmd') && params.cmd === 'transmit' && helpers.hasProperty(params, 'rfChl')) { this.platform.devicesInHB.forEach(acc => { if ( - acc.context.eweDeviceId === accessory.context.eweDeviceId && + acc.context.eweDeviceId === this.accessory.context.eweDeviceId && helpers.hasProperty(acc.context, 'buttons') && helpers.hasProperty(acc.context.buttons, params.rfChl.toString()) ) { @@ -76,14 +76,9 @@ module.exports = class deviceRFBridge { } }) if (oAccessory) { - oAccessory.getService(oAccessory.context.buttons[params.rfChl]).updateCharacteristic(Characteristic.On, 1) - setTimeout( - () => - oAccessory - .getService(oAccessory.context.buttons[params.rfChl]) - .updateCharacteristic(Characteristic.On, 0), - 3000 - ) + oAccessory.getService(oAccessory.context.buttons[params.rfChl]).updateCharacteristic(this.Characteristic.On, 1) + helpers.sleep(3000) + oAccessory.getService(oAccessory.context.buttons[params.rfChl]).updateCharacteristic(this.Characteristic.On, 0) } else { throw new Error('rf button not found in Homebridge') } @@ -94,7 +89,7 @@ module.exports = class deviceRFBridge { .forEach(async chan => { this.platform.devicesInHB.forEach(acc => { if ( - acc.context.eweDeviceId === accessory.context.eweDeviceId && + acc.context.eweDeviceId === this.accessory.context.eweDeviceId && helpers.hasProperty(acc.context, 'buttons') && helpers.hasProperty(acc.context.buttons, chan.substr(-1).toString()) ) { @@ -111,33 +106,33 @@ module.exports = class deviceRFBridge { case 'button': return case 'water': - serv = Service.LeakSensor - char = Characteristic.LeakDetected + serv = this.Service.LeakSensor + char = this.Characteristic.LeakDetected break case 'fire': case 'smoke': - serv = Service.SmokeSensor - char = Characteristic.LeakDetected + serv = this.Service.SmokeSensor + char = this.Characteristic.LeakDetected break case 'co': - serv = Service.CarbonMonoxideSensor - char = Characteristic.CarbonMonoxideDetected + serv = this.Service.CarbonMonoxideSensor + char = this.Characteristic.CarbonMonoxideDetected break case 'co2': - serv = Service.CarbonDioxideSensor - char = Characteristic.CarbonDioxideDetected + serv = this.Service.CarbonDioxideSensor + char = this.Characteristic.CarbonDioxideDetected break case 'contact': - serv = Service.ContactSensor - char = Characteristic.ContactSensorState + serv = this.Service.ContactSensor + char = this.Characteristic.ContactSensorState break case 'occupancy': - serv = Service.OccupancySensor - char = Characteristic.OccupancyDetected + serv = this.Service.OccupancySensor + char = this.Characteristic.OccupancyDetected break default: - serv = Service.MotionSensor - char = Characteristic.MotionDetected + serv = this.Service.MotionSensor + char = this.Characteristic.MotionDetected break } oAccessory.getService(serv).updateCharacteristic(char, 1) @@ -148,7 +143,7 @@ module.exports = class deviceRFBridge { }) } } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/scm.js b/lib/device/scm.js index b49d5915..9c7d809d 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -1,40 +1,38 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -let Characteristic, Service const helpers = require('./../helpers') module.exports = class deviceSCM { constructor (platform, accessory) { this.platform = platform - Service = platform.api.hap.Service - Characteristic = platform.api.hap.Characteristic - const scmService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch) + this.accessory = accessory + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + const scmService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) scmService - .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(value, callback)) } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { - const params = { - switches: helpers.defaultMultiSwitchOff - } - const switchService = accessory.getService(Service.Switch) + const params = { switches: helpers.defaultMultiSwitchOff } + const switchService = this.accessory.getService(this.Service.Switch) params.switches[0].switch = value ? 'on' : 'off' - await this.platform.sendDeviceUpdate(accessory, params) - switchService.updateCharacteristic(Characteristic.On, value) + await this.platform.sendDeviceUpdate(this.accessory, params) + switchService.updateCharacteristic(this.Characteristic.On, value) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (!helpers.hasProperty(params, 'switches')) return - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switches[0].switch === 'on') + this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, params.switches[0].switch === 'on') } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/sensor.js b/lib/device/sensor.js index d0e3e273..488de3e5 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -1,57 +1,57 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -let Characteristic, Service const helpers = require('./../helpers') module.exports = class deviceSensor { constructor (platform, accessory) { this.platform = platform - Service = platform.api.hap.Service - Characteristic = platform.api.hap.Characteristic - if (!accessory.getService(Service.ContactSensor)) accessory.addService(Service.ContactSensor) - if (!accessory.getService(Service.BatteryService)) accessory.addService(Service.BatteryService) + this.accessory = accessory + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + if (!accessory.getService(this.Service.ContactSensor)) accessory.addService(this.Service.ContactSensor) + if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (helpers.hasProperty(params, 'battery')) { const batteryService = - accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService) + this.accessory.getService(this.Service.BatteryService) || this.accessory.addService(this.Service.BatteryService) const scaledBattery = Math.round(params.battery * 33.3) - batteryService.updateCharacteristic(Characteristic.BatteryLevel, scaledBattery) + batteryService.updateCharacteristic(this.Characteristic.BatteryLevel, scaledBattery) batteryService.updateCharacteristic( - Characteristic.StatusLowBattery, + this.Characteristic.StatusLowBattery, scaledBattery < (this.platform.config.lowBattThreshold || 25) ) } if (!helpers.hasProperty(params, 'switch')) return const newState = params.switch === 'on' ? 1 : 0 let oAccessory = false - const contactService = accessory.getService(Service.ContactSensor) - contactService.updateCharacteristic(Characteristic.ContactSensorState, newState) + const contactService = this.accessory.getService(this.Service.ContactSensor) + contactService.updateCharacteristic(this.Characteristic.ContactSensorState, newState) this.platform.cusG.forEach(async group => { - if (group.sensorId === accessory.context.eweDeviceId && group.type === 'garage') { + if (group.sensorId === this.accessory.context.eweDeviceId && group.type === 'garage') { if ((oAccessory = this.platform.devicesInHB.get(group.deviceId + 'SWX'))) { switch (newState) { case 0: oAccessory - .getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.TargetDoorState, 1) - .updateCharacteristic(Characteristic.CurrentDoorState, 1) + .getService(this.Service.GarageDoorOpener) + .updateCharacteristic(this.Characteristic.TargetDoorState, 1) + .updateCharacteristic(this.Characteristic.CurrentDoorState, 1) break case 1: await helpers.sleep(Math.max(group.operationTime * 100, 1000)) oAccessory - .getService(Service.GarageDoorOpener) - .updateCharacteristic(Characteristic.TargetDoorState, 0) - .updateCharacteristic(Characteristic.CurrentDoorState, 0) + .getService(this.Service.GarageDoorOpener) + .updateCharacteristic(this.Characteristic.TargetDoorState, 0) + .updateCharacteristic(this.Characteristic.CurrentDoorState, 0) break } } } }) } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } From df69c8f746338bed1c60bb63ea13c5d2e03caf80 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 15 Oct 2020 13:00:44 +0100 Subject: [PATCH 0478/3183] file reorganisation 3 --- lib/device/switch.js | 68 +++++++++++------------ lib/device/thermostat.js | 64 +++++++++++----------- lib/device/usb.js | 32 +++++------ lib/device/valve.js | 115 +++++++++++++++++++-------------------- lib/device/zb-dev.js | 111 +++++++++++++++++++------------------ 5 files changed, 192 insertions(+), 198 deletions(-) diff --git a/lib/device/switch.js b/lib/device/switch.js index dc05d49f..a18c6fea 100644 --- a/lib/device/switch.js +++ b/lib/device/switch.js @@ -1,26 +1,26 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -let Characteristic, Service const helpers = require('./../helpers') module.exports = class deviceSwitch { constructor (platform, accessory) { this.platform = platform - Service = platform.api.hap.Service - Characteristic = platform.api.hap.Characteristic - const switchService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch) + this.accessory = accessory + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + const switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) switchService - .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(value, callback)) } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { let oAccessory const params = {} - const switchService = accessory.getService(Service.Switch) - switch (accessory.context.switchNumber) { + const switchService = this.accessory.getService(this.Service.Switch) + switch (this.accessory.context.switchNumber) { case 'X': params.switch = value ? 'on' : 'off' break @@ -37,8 +37,8 @@ module.exports = class deviceSwitch { case '4': params.switches = helpers.defaultMultiSwitchOff for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { - if (i === parseInt(accessory.context.switchNumber)) { + if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { + if (i === parseInt(this.accessory.context.switchNumber)) { params.switches[i - 1].switch = value ? 'on' : 'off' } else { params.switches[i - 1].switch = oAccessory.context.cacheOn ? 'on' : 'off' @@ -49,15 +49,15 @@ module.exports = class deviceSwitch { } break } - await this.platform.sendDeviceUpdate(accessory, params) - switch (accessory.context.switchNumber) { + await this.platform.sendDeviceUpdate(this.accessory, params) + switch (this.accessory.context.switchNumber) { case 'X': - switchService.updateCharacteristic(Characteristic.On, value) + switchService.updateCharacteristic(this.Characteristic.On, value) break case '0': for (let i = 0; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { - oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, value) + if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { + oAccessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, value) } } break @@ -65,37 +65,37 @@ module.exports = class deviceSwitch { case '2': case '3': case '4': { - switchService.updateCharacteristic(Characteristic.On, value) + switchService.updateCharacteristic(this.Characteristic.On, value) let masterState = 'off' for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { - if (oAccessory.getService(Service.Switch).getCharacteristic(Characteristic.On).value) { + if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { + if (oAccessory.getService(this.Service.Switch).getCharacteristic(this.Characteristic.On).value) { masterState = 'on' } } } - if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { - oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW0') - oAccessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, masterState === 'on') + if (!this.platform.hiddenMasters.includes(this.accessory.context.eweDeviceId)) { + oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW0') + oAccessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, masterState === 'on') } break } } } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { - if (helpers.devicesSingleSwitch.includes(accessory.context.eweUIID)) { + if (helpers.devicesSingleSwitch.includes(this.accessory.context.eweUIID)) { if (!helpers.hasProperty(params, 'switch')) return - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, params.switch === 'on') - } else if (helpers.devicesMultiSwitch.includes(accessory.context.eweUIID)) { + this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, params.switch === 'on') + } else if (helpers.devicesMultiSwitch.includes(this.accessory.context.eweUIID)) { if (!helpers.hasProperty(params, 'switches')) return - const idToCheck = accessory.context.hbDeviceId.slice(0, -1) + const idToCheck = this.accessory.context.hbDeviceId.slice(0, -1) let primaryState = false - for (let i = 1; i <= accessory.context.channelCount; i++) { + for (let i = 1; i <= this.accessory.context.channelCount; i++) { if (params.switches[i - 1].switch === 'on') { primaryState = true } @@ -103,16 +103,16 @@ module.exports = class deviceSwitch { const oAccessory = this.platform.devicesInHB.get(idToCheck + i) oAccessory.context.cacheOn = params.switches[i - 1].switch === 'on' oAccessory - .getService(Service.Switch) - .updateCharacteristic(Characteristic.On, params.switches[i - 1].switch === 'on') + .getService(this.Service.Switch) + .updateCharacteristic(this.Characteristic.On, params.switches[i - 1].switch === 'on') } } - if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { - accessory.getService(Service.Switch).updateCharacteristic(Characteristic.On, primaryState) + if (!this.platform.hiddenMasters.includes(this.accessory.context.eweDeviceId)) { + this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, primaryState) } } } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index 14e412be..bea10d51 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -1,30 +1,30 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -let Characteristic, EveHistoryService, Service const corrInterval = require('correcting-interval') const fakegato = require('fakegato-history') const helpers = require('./../helpers') module.exports = class deviceThermostat { constructor (platform, accessory) { this.platform = platform - Service = platform.api.hap.Service - Characteristic = platform.api.hap.Characteristic - EveHistoryService = fakegato(platform.api) - const tempService = accessory.getService(Service.TemperatureSensor) || accessory.addService(Service.TemperatureSensor) + this.accessory = accessory + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + this.EveHistoryService = fakegato(platform.api) + const tempService = accessory.getService(this.Service.TemperatureSensor) || accessory.addService(this.Service.TemperatureSensor) let humiService = false if (accessory.context.sensorType !== 'DS18B20') { - humiService = accessory.getService(Service.HumiditySensor) || accessory.addService(Service.HumiditySensor) + humiService = accessory.getService(this.Service.HumiditySensor) || accessory.addService(this.Service.HumiditySensor) } if (!this.platform.config.hideTHSwitch) { - const switchService = accessory.getService(Service.Switch) || accessory.addService(Service.Switch) + const switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) switchService - .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(value, callback)) } if (!this.platform.config.disableEveLogging) { accessory.log = this.platform.log - accessory.eveLogger = new EveHistoryService('weather', accessory, { + accessory.eveLogger = new this.EveHistoryService('weather', accessory, { storage: 'fs', minutes: 5, path: this.platform.eveLogPath @@ -32,65 +32,63 @@ module.exports = class deviceThermostat { corrInterval.setCorrectingInterval(() => { const dataToAdd = { time: Date.now(), - temp: tempService.getCharacteristic(Characteristic.CurrentTemperature).value + temp: tempService.getCharacteristic(this.Characteristic.CurrentTemperature).value } if (humiService) { - dataToAdd.humidity = humiService.getCharacteristic(Characteristic.CurrentRelativeHumidity).value + dataToAdd.humidity = humiService.getCharacteristic(this.Characteristic.CurrentRelativeHumidity).value } accessory.eveLogger.addEntry(dataToAdd) }, 300000) } } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { const params = { switch: value ? 'on' : 'off', mainSwitch: value ? 'on' : 'off' } - const switchService = accessory.getService(Service.Switch) - await this.platform.sendDeviceUpdate(accessory, params) - switchService.updateCharacteristic(Characteristic.On, value) + const switchService = this.accessory.getService(this.Service.Switch) + await this.platform.sendDeviceUpdate(this.accessory, params) + switchService.updateCharacteristic(this.Characteristic.On, value) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if ( !this.platform.config.hideTHSwitch && (helpers.hasProperty(params, 'switch') || helpers.hasProperty(params, 'mainSwitch')) ) { const newState = helpers.hasProperty(params, 'switch') ? params.switch === 'on' : params.mainSwitch === 'on' - const switchService = accessory.getService(Service.Switch) - switchService.updateCharacteristic(Characteristic.On, newState) + const switchService = this.accessory.getService(this.Service.Switch) + switchService.updateCharacteristic(this.Characteristic.On, newState) } - const eveLog = { - time: Date.now() - } - if (helpers.hasProperty(params, 'currentTemperature') && accessory.getService(Service.TemperatureSensor)) { + const eveLog = { time: Date.now() } + if (helpers.hasProperty(params, 'currentTemperature') && this.accessory.getService(this.Service.TemperatureSensor)) { const currentTemp = parseFloat(params.currentTemperature !== 'unavailable' ? params.currentTemperature : 0) - accessory - .getService(Service.TemperatureSensor) - .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp) + this.accessory + .getService(this.Service.TemperatureSensor) + .updateCharacteristic(this.Characteristic.CurrentTemperature, currentTemp) eveLog.temp = currentTemp } - if (helpers.hasProperty(params, 'currentHumidity') && accessory.getService(Service.HumiditySensor)) { + if (helpers.hasProperty(params, 'currentHumidity') && this.accessory.getService(this.Service.HumiditySensor)) { const currentHumi = parseFloat(params.currentHumidity !== 'unavailable' ? params.currentHumidity : 0) - accessory - .getService(Service.HumiditySensor) - .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi) + this.accessory + .getService(this.Service.HumiditySensor) + .updateCharacteristic(this.Characteristic.CurrentRelativeHumidity, currentHumi) eveLog.humidity = currentHumi } if (!this.platform.config.disableEveLogging) { if (helpers.hasProperty(eveLog, 'temp') || helpers.hasProperty(eveLog, 'humidity')) { - accessory.eveLogger.addEntry(eveLog) + this.accessory.eveLogger.addEntry(eveLog) } } } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/usb.js b/lib/device/usb.js index 0600b2fd..9274407d 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -1,40 +1,38 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -let Characteristic, Service const helpers = require('./../helpers') module.exports = class deviceUSB { constructor (platform, accessory) { this.platform = platform - Service = platform.api.hap.Service - Characteristic = platform.api.hap.Characteristic - const usbService = accessory.getService(Service.Outlet) || accessory.addService(Service.Outlet) + this.accessory = accessory + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + const usbService = accessory.getService(this.Service.Outlet) || accessory.addService(this.Service.Outlet) usbService - .getCharacteristic(Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(value, callback)) } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { - const params = { - switches: helpers.defaultMultiSwitchOff - } - const outletService = accessory.getService(Service.Outlet) + const params = { switches: helpers.defaultMultiSwitchOff } + const outletService = this.accessory.getService(this.Service.Outlet) params.switches[0].switch = value ? 'on' : 'off' - await this.platform.sendDeviceUpdate(accessory, params) - outletService.updateCharacteristic(Characteristic.On, value) + await this.platform.sendDeviceUpdate(this.accessory, params) + outletService.updateCharacteristic(this.Characteristic.On, value) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (!helpers.hasProperty(params, 'switches')) return - accessory.getService(Service.Outlet).updateCharacteristic(Characteristic.On, params.switches[0].switch === 'on') + this.accessory.getService(this.Service.Outlet).updateCharacteristic(this.Characteristic.On, params.switches[0].switch === 'on') } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/valve.js b/lib/device/valve.js index 4995d267..a1ff0f05 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -1,122 +1,117 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -let Characteristic, Service const helpers = require('./../helpers') module.exports = class deviceValve { constructor (platform, accessory) { this.platform = platform - Service = platform.api.hap.Service - Characteristic = platform.api.hap.Characteristic - const arr = ['A', 'B'] - arr.forEach(v => { + this.accessory = accessory + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + ;['A', 'B'].forEach(v => { let valveService - const valveConfig = this.platform.cusG.get(accessory.context.hbDeviceId) - if (!(valveService = accessory.getService('Valve ' + v))) { - accessory - .addService(Service.Valve, 'Valve ' + v, 'valve' + v.toLowerCase()) - .setCharacteristic(Characteristic.Active, 0) - .setCharacteristic(Characteristic.InUse, 0) - .setCharacteristic(Characteristic.ValveType, 1) - .setCharacteristic(Characteristic.SetDuration, Math.round((valveConfig.operationTime || 1200) / 10)) - .addCharacteristic(Characteristic.RemainingDuration) - valveService = accessory.getService('Valve ' + v) + const valveConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId) + if (!(valveService = this.accessory.getService('Valve ' + v))) { + this.accessory + .addService(this.Service.Valve, 'Valve ' + v, 'valve' + v.toLowerCase()) + .setCharacteristic(this.Characteristic.Active, 0) + .setCharacteristic(this.Characteristic.InUse, 0) + .setCharacteristic(this.Characteristic.ValveType, 1) + .setCharacteristic(this.Characteristic.SetDuration, Math.round((valveConfig.operationTime || 1200) / 10)) + .addCharacteristic(this.Characteristic.RemainingDuration) + valveService = this.accessory.getService('Valve ' + v) } valveService - .getCharacteristic(Characteristic.Active) - .on('set', (value, callback) => - this.internalUpdate(accessory, 'Valve ' + v, value, callback) - ) - valveService.getCharacteristic(Characteristic.SetDuration).on('set', (value, callback) => { - if (valveService.getCharacteristic(Characteristic.InUse).value) { - valveService.updateCharacteristic(Characteristic.RemainingDuration, value) - clearTimeout(valveService.timer) - valveService.timer = setTimeout(() => { - valveService.setCharacteristic(Characteristic.Active, 0) - }, value * 1000) - } - callback() - }) + .getCharacteristic(this.Characteristic.Active) + .on('set', (value, callback) => this.internalUpdate('Valve ' + v, value, callback)) + valveService + .getCharacteristic(this.Characteristic.SetDuration) + .on('set', (value, callback) => { + if (valveService.getCharacteristic(this.Characteristic.InUse).value) { + valveService.updateCharacteristic(this.Characteristic.RemainingDuration, value) + clearTimeout(valveService.timer) + valveService.timer = setTimeout(() => { + valveService.setCharacteristic(this.Characteristic.Active, 0) + }, value * 1000) + } + callback() + }) }) } - async internalUpdate (accessory, valve, value, callback) { + async internalUpdate (valve, value, callback) { callback() try { let valveConfig - const params = {} - if (!(valveConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + const params = { switches: helpers.defaultMultiSwitchOff } + if (!(valveConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (valveConfig.type !== 'valve') { throw new Error('improper configuration') } - const serviceValve = accessory.getService(valve) - params.switches = this.platform.devicesInEW.get(accessory.context.eweDeviceId).params.switches + const serviceValve = this.accessory.getService(valve) switch (valve) { case 'Valve A': params.switches[0].switch = value ? 'on' : 'off' - params.switches[1].switch = accessory.getService('Valve B').getCharacteristic(Characteristic.Active).value + params.switches[1].switch = this.accessory.getService('Valve B').getCharacteristic(this.Characteristic.Active).value ? 'on' : 'off' break case 'Valve B': - params.switches[0].switch = accessory.getService('Valve A').getCharacteristic(Characteristic.Active).value + params.switches[0].switch = this.accessory.getService('Valve A').getCharacteristic(this.Characteristic.Active).value ? 'on' : 'off' params.switches[1].switch = value ? 'on' : 'off' break } - params.switches[2].switch = 'off' - params.switches[3].switch = 'off' - await this.platform.sendDeviceUpdate(accessory, params) - serviceValve.updateCharacteristic(Characteristic.Active, value).updateCharacteristic(Characteristic.InUse, value) + await this.platform.sendDeviceUpdate(this.accessory, params) + serviceValve + .updateCharacteristic(this.Characteristic.Active, value) + .updateCharacteristic(this.Characteristic.InUse, value) switch (value) { case 0: - serviceValve.updateCharacteristic(Characteristic.RemainingDuration, 0) - clearTimeout(accessory.getService(valve).timer) + serviceValve.updateCharacteristic(this.Characteristic.RemainingDuration, 0) + clearTimeout(this.accessory.getService(valve).timer) break case 1: { - const timer = serviceValve.getCharacteristic(Characteristic.SetDuration).value - serviceValve.updateCharacteristic(Characteristic.RemainingDuration, timer) - serviceValve.timer = setTimeout(() => serviceValve.setCharacteristic(Characteristic.Active, 0), timer * 1000) + const timer = serviceValve.getCharacteristic(this.Characteristic.SetDuration).value + serviceValve.updateCharacteristic(this.Characteristic.RemainingDuration, timer) + serviceValve.timer = setTimeout(() => serviceValve.setCharacteristic(this.Characteristic.Active, 0), timer * 1000) break } } } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (!helpers.hasProperty(params, 'switches')) return let valveConfig - if (!(valveConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + if (!(valveConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (valveConfig.type !== 'valve') { throw new Error('improper configuration') } - const arr = ['A', 'B'] - arr.forEach((v, k) => { - const valveService = accessory.getService('Valve ' + v) + ;['A', 'B'].forEach((v, k) => { + const valveService = this.accessory.getService('Valve ' + v) valveService - .updateCharacteristic(Characteristic.Active, params.switches[k].switch === 'on') - .updateCharacteristic(Characteristic.InUse, params.switches[k].switch === 'on') + .updateCharacteristic(this.Characteristic.Active, params.switches[k].switch === 'on') + .updateCharacteristic(this.Characteristic.InUse, params.switches[k].switch === 'on') if (params.switches[k].switch === 'on') { - const timer = valveService.getCharacteristic(Characteristic.SetDuration).value - valveService.updateCharacteristic(Characteristic.RemainingDuration, timer) - valveService.timer = setTimeout(() => { - valveService.setCharacteristic(Characteristic.Active, 0) - }, timer * 1000) + const timer = valveService.getCharacteristic(this.Characteristic.SetDuration).value + valveService.updateCharacteristic(this.Characteristic.RemainingDuration, timer) + valveService.timer = setTimeout(() => valveService.setCharacteristic(this.Characteristic.Active, 0), timer * 1000) } else { - valveService.updateCharacteristic(Characteristic.RemainingDuration, 0) + valveService.updateCharacteristic(this.Characteristic.RemainingDuration, 0) clearTimeout(valveService.timer) } }) } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index 1a9562c1..bbd171ad 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -1,24 +1,24 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -let Characteristic, Service, EveHistoryService const corrInterval = require('correcting-interval') const fakegato = require('fakegato-history') const helpers = require('./../helpers') module.exports = class deviceZBDev { constructor (platform, accessory) { this.platform = platform - Service = platform.api.hap.Service - Characteristic = platform.api.hap.Characteristic - EveHistoryService = fakegato(platform.api) - if (!accessory.getService(Service.BatteryService)) accessory.addService(Service.BatteryService) + this.accessory = accessory + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + this.EveHistoryService = fakegato(platform.api) + if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) switch (accessory.context.eweUIID) { case 1000: { const zbspsService = - accessory.getService(Service.StatelessProgrammableSwitch) || - accessory.addService(Service.StatelessProgrammableSwitch) + accessory.getService(this.Service.StatelessProgrammableSwitch) || + accessory.addService(this.Service.StatelessProgrammableSwitch) if (this.platform.config.hideZBLDPress) { - zbspsService.getCharacteristic(Characteristic.ProgrammableSwitchEvent).setProps({ + zbspsService.getCharacteristic(this.Characteristic.ProgrammableSwitchEvent).setProps({ validValues: [0] }) } @@ -26,77 +26,80 @@ module.exports = class deviceZBDev { } case 1770: { const zbTempService = - accessory.getService(Service.TemperatureSensor) || accessory.addService(Service.TemperatureSensor) + accessory.getService(this.Service.TemperatureSensor) || accessory.addService(this.Service.TemperatureSensor) const zbHumiService = - accessory.getService(Service.HumiditySensor) || accessory.addService(Service.HumiditySensor) - accessory.log = this.platform.log - accessory.eveLogger = new EveHistoryService('weather', accessory, { - storage: 'fs', - minutes: 5, - path: this.platform.eveLogPath - }) - corrInterval.setCorrectingInterval(() => { - const dataToAdd = { - time: Date.now(), - temp: zbTempService.getCharacteristic(Characteristic.CurrentTemperature).value, - humidity: zbHumiService.getCharacteristic(Characteristic.CurrentRelativeHumidity).value - } - accessory.eveLogger.addEntry(dataToAdd) - }, 300000) + accessory.getService(this.Service.HumiditySensor) || accessory.addService(this.Service.HumiditySensor) + if (!this.platform.config.disableEveLogging) { + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('weather', accessory, { + storage: 'fs', + minutes: 5, + path: this.platform.eveLogPath + }) + corrInterval.setCorrectingInterval(() => { + const dataToAdd = { + time: Date.now(), + temp: zbTempService.getCharacteristic(this.Characteristic.CurrentTemperature).value, + humidity: zbHumiService.getCharacteristic(this.Characteristic.CurrentRelativeHumidity).value + } + accessory.eveLogger.addEntry(dataToAdd) + }, 300000) + } break } case 2026: - if (!accessory.getService(Service.MotionSensor)) accessory.addService(Service.MotionSensor) + if (!accessory.getService(this.Service.MotionSensor)) accessory.addService(this.Service.MotionSensor) break case 3026: - if (!accessory.getService(Service.ContactSensor)) accessory.addService(Service.ContactSensor) + if (!accessory.getService(this.Service.ContactSensor)) accessory.addService(this.Service.ContactSensor) break } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { //* ** credit @tasict ***\\ if (helpers.hasProperty(params, 'battery')) { - if (accessory.context.eweUIID === 3026 && this.platform.config.ZBDWBatt) { + if (this.accessory.context.eweUIID === 3026 && this.platform.config.ZBDWBatt) { params.battery *= 10 } const batteryService = - accessory.getService(Service.BatteryService) || accessory.addService(Service.BatteryService) - batteryService.updateCharacteristic(Characteristic.BatteryLevel, params.battery) + this.accessory.getService(this.Service.BatteryService) || this.accessory.addService(this.Service.BatteryService) + batteryService.updateCharacteristic(this.Characteristic.BatteryLevel, params.battery) batteryService.updateCharacteristic( - Characteristic.StatusLowBattery, + this.Characteristic.StatusLowBattery, params.battery < (this.platform.config.lowBattThreshold || 25) ) } - switch (accessory.context.eweUIID) { + switch (this.accessory.context.eweUIID) { case 1000: if (helpers.hasProperty(params, 'key') && [0, 1, 2].includes(params.key)) { - accessory - .getService(Service.StatelessProgrammableSwitch) - .updateCharacteristic(Characteristic.ProgrammableSwitchEvent, params.key) + this.accessory + .getService(this.Service.StatelessProgrammableSwitch) + .updateCharacteristic(this.Characteristic.ProgrammableSwitchEvent, params.key) } break case 1770: { - const eveLog = { - time: Date.now() - } + const eveLog = { time: Date.now() } if (helpers.hasProperty(params, 'temperature')) { const currentTemp = parseInt(params.temperature) / 100 - accessory - .getService(Service.TemperatureSensor) - .updateCharacteristic(Characteristic.CurrentTemperature, currentTemp) + this.accessory + .getService(this.Service.TemperatureSensor) + .updateCharacteristic(this.Characteristic.CurrentTemperature, currentTemp) eveLog.temp = parseFloat(currentTemp) } if (helpers.hasProperty(params, 'humidity')) { const currentHumi = parseInt(params.humidity) / 100 - accessory - .getService(Service.HumiditySensor) - .updateCharacteristic(Characteristic.CurrentRelativeHumidity, currentHumi) + this.accessory + .getService(this.Service.HumiditySensor) + .updateCharacteristic(this.Characteristic.CurrentRelativeHumidity, currentHumi) eveLog.humidity = parseFloat(currentHumi) } - if (helpers.hasProperty(eveLog, 'temp') || helpers.hasProperty(eveLog, 'humidity')) { - accessory.eveLogger.addEntry(eveLog) + if ( + !this.platform.config.disableEveLogging && + (helpers.hasProperty(eveLog, 'temp') || helpers.hasProperty(eveLog, 'humidity')) + ) { + this.accessory.eveLogger.addEntry(eveLog) } break } @@ -104,10 +107,10 @@ module.exports = class deviceZBDev { if (helpers.hasProperty(params, 'motion') && helpers.hasProperty(params, 'trigTime')) { const timeNow = new Date() const diff = (timeNow.getTime() - params.trigTime) / 1000 - accessory - .getService(Service.MotionSensor) + this.accessory + .getService(this.Service.MotionSensor) .updateCharacteristic( - Characteristic.MotionDetected, + this.Characteristic.MotionDetected, helpers.hasProperty(params, 'updateSource') && params.motion === 1 && diff < (this.platform.config.sensorTimeDifference || 120) @@ -117,16 +120,16 @@ module.exports = class deviceZBDev { break case 3026: if (helpers.hasProperty(params, 'lock') && [0, 1].includes(params.lock)) { - accessory - .getService(Service.ContactSensor) - .updateCharacteristic(Characteristic.ContactSensorState, params.lock) + this.accessory + .getService(this.Service.ContactSensor) + .updateCharacteristic(this.Characteristic.ContactSensorState, params.lock) } break default: - throw new Error('Zigbee device type not supported [uiid ' + accessory.context.eweUIID + ']') + throw new Error('Zigbee device type not supported [uiid ' + this.accessory.context.eweUIID + ']') } } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } From c5a0f0eb9e6f943d6131176727280906497c256a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 15 Oct 2020 13:01:55 +0100 Subject: [PATCH 0479/3183] 3.6.1-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 28a4db2c..bc68f03f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.0", + "version": "3.6.1-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index e093926d..91e99bb0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.0", + "version": "3.6.1-0", "author": "bwp91", "contributors": [ "gbro115", From 2099e93b424e11dfa701c9de27c85a0eca4b6161 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 15 Oct 2020 13:49:30 +0100 Subject: [PATCH 0480/3183] move line --- lib/device/blind.js | 1 + lib/device/curtain.js | 1 + lib/device/fan.js | 2 +- lib/device/garage-eachen.js | 2 +- lib/device/garage-two.js | 2 +- lib/device/garage.js | 2 +- lib/device/light.js | 2 +- lib/device/lock.js | 2 +- lib/device/outlet.js | 2 +- lib/device/rf-bridge.js | 2 +- lib/device/scm.js | 2 +- lib/device/sensor.js | 2 +- lib/device/switch.js | 2 +- lib/device/thermostat.js | 2 +- lib/device/usb.js | 2 +- lib/device/valve.js | 2 +- lib/device/zb-dev.js | 2 +- 17 files changed, 17 insertions(+), 15 deletions(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index b65d9538..31e7bc82 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -19,6 +19,7 @@ module.exports = class deviceBlind { wcService .getCharacteristic(this.Characteristic.TargetPosition) .on('set', (value, callback) => this.internalUpdate(value, callback)) + this.accessory = accessory } async internalUpdate (value, callback) { diff --git a/lib/device/curtain.js b/lib/device/curtain.js index 49d45da4..645a38f8 100644 --- a/lib/device/curtain.js +++ b/lib/device/curtain.js @@ -19,6 +19,7 @@ module.exports = class deviceCurtain { cService .getCharacteristic(this.Characteristic.TargetPosition) .on('set', (value, callback) => this.internalUpdate(value, callback)) + this.accessory = accessory } async internalUpdate (value, callback) { diff --git a/lib/device/fan.js b/lib/device/fan.js index dd72b1a4..48037085 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -5,7 +5,6 @@ const helpers = require('./../helpers') module.exports = class deviceFan { constructor (platform, accessory) { this.platform = platform - this.accessory = accessory this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic const fanService = accessory.getService(this.Service.Fanv2) || accessory.addService(this.Service.Fanv2) @@ -28,6 +27,7 @@ module.exports = class deviceFan { fanLightService .getCharacteristic(this.Characteristic.On) .on('set', (value, callback) => this.internalUpdate('light', value, callback)) + this.accessory = accessory } async internalUpdate (type, value, callback) { diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 3dc5fa7d..1c7fb8bf 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -5,7 +5,6 @@ const helpers = require('./../helpers') module.exports = class deviceGarageEachen { constructor (platform, accessory) { this.platform = platform - this.accessory = accessory this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic let gdeService @@ -20,6 +19,7 @@ module.exports = class deviceGarageEachen { gdeService .getCharacteristic(this.Characteristic.TargetDoorState) .on('set', (value, callback) => this.internalUpdate(value, callback)) + this.accessory = accessory } async internalUpdate (value, callback) { diff --git a/lib/device/garage-two.js b/lib/device/garage-two.js index 6e456abe..fa02653c 100644 --- a/lib/device/garage-two.js +++ b/lib/device/garage-two.js @@ -5,7 +5,6 @@ const helpers = require('./../helpers') module.exports = class deviceGarageTwo { constructor (platform, accessory) { this.platform = platform - this.accessory = accessory this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic ;['1', '2'].forEach(v => { @@ -22,6 +21,7 @@ module.exports = class deviceGarageTwo { .getCharacteristic(this.Characteristic.TargetDoorState) .on('set', (value, callback) => this.internalUpdate('Garage' + v, value, callback)) }) + this.accessory = accessory } async internalUpdate (garage, value, callback) { diff --git a/lib/device/garage.js b/lib/device/garage.js index ad5f3945..38d31896 100644 --- a/lib/device/garage.js +++ b/lib/device/garage.js @@ -5,7 +5,6 @@ const helpers = require('./../helpers') module.exports = class deviceGarage { constructor (platform, accessory) { this.platform = platform - this.accessory = accessory this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic let gdService @@ -20,6 +19,7 @@ module.exports = class deviceGarage { gdService .getCharacteristic(this.Characteristic.TargetDoorState) .on('set', (value, callback) => this.internalUpdate(value, callback)) + this.accessory = accessory } async internalUpdate (value, callback) { diff --git a/lib/device/light.js b/lib/device/light.js index 6d426caf..6a1ba5de 100644 --- a/lib/device/light.js +++ b/lib/device/light.js @@ -6,7 +6,6 @@ const helpers = require('./../helpers') module.exports = class deviceLight { constructor (platform, accessory) { this.platform = platform - this.accessory = accessory this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic const lightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) @@ -40,6 +39,7 @@ module.exports = class deviceLight { .on('set', (value, callback) => this.internalUpdate('c_hue', value, callback)) lightService.getCharacteristic(this.Characteristic.Saturation).on('set', (value, callback) => callback()) } + this.accessory = accessory } async internalUpdate (type, value, callback) { diff --git a/lib/device/lock.js b/lib/device/lock.js index 8114e730..24c8c6ec 100644 --- a/lib/device/lock.js +++ b/lib/device/lock.js @@ -5,13 +5,13 @@ const helpers = require('./../helpers') module.exports = class deviceLock { constructor (platform, accessory) { this.platform = platform - this.accessory = accessory this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic const lmService = accessory.getService(this.Service.LockMechanism) || accessory.addService(this.Service.LockMechanism) lmService .getCharacteristic(this.Characteristic.LockTargetState) .on('set', (value, callback) => this.internalUpdate(value, callback)) + this.accessory = accessory } async internalUpdate (value, callback) { diff --git a/lib/device/outlet.js b/lib/device/outlet.js index 9330cf65..ae80e022 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -8,7 +8,6 @@ const helpers = require('./../helpers') module.exports = class deviceOutlet { constructor (platform, accessory) { this.platform = platform - this.accessory = accessory this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic this.EveCharacteristics = new hbLib.EveHomeKitTypes(platform.api).Characteristics @@ -108,6 +107,7 @@ module.exports = class deviceOutlet { callback(null, accessory.context.lastReset) }) } + this.accessory = accessory } async internalUpdate (value, callback) { diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index fe821fbb..9270cd89 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -5,7 +5,6 @@ const helpers = require('./../helpers') module.exports = class deviceRFBridge { constructor (platform, accessory) { this.platform = platform - this.accessory = accessory this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic switch (accessory.context.subType) { @@ -40,6 +39,7 @@ module.exports = class deviceRFBridge { }) break } + this.accessory = accessory } async internalUpdate (rfChl, service, value, callback) { diff --git a/lib/device/scm.js b/lib/device/scm.js index 9c7d809d..961b1b83 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -5,13 +5,13 @@ const helpers = require('./../helpers') module.exports = class deviceSCM { constructor (platform, accessory) { this.platform = platform - this.accessory = accessory this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic const scmService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) scmService .getCharacteristic(this.Characteristic.On) .on('set', (value, callback) => this.internalUpdate(value, callback)) + this.accessory = accessory } async internalUpdate (value, callback) { diff --git a/lib/device/sensor.js b/lib/device/sensor.js index 488de3e5..ee5ae854 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -5,11 +5,11 @@ const helpers = require('./../helpers') module.exports = class deviceSensor { constructor (platform, accessory) { this.platform = platform - this.accessory = accessory this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic if (!accessory.getService(this.Service.ContactSensor)) accessory.addService(this.Service.ContactSensor) if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) + this.accessory = accessory } async externalUpdate (params) { diff --git a/lib/device/switch.js b/lib/device/switch.js index a18c6fea..9cea49b7 100644 --- a/lib/device/switch.js +++ b/lib/device/switch.js @@ -5,13 +5,13 @@ const helpers = require('./../helpers') module.exports = class deviceSwitch { constructor (platform, accessory) { this.platform = platform - this.accessory = accessory this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic const switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) switchService .getCharacteristic(this.Characteristic.On) .on('set', (value, callback) => this.internalUpdate(value, callback)) + this.accessory = accessory } async internalUpdate (value, callback) { diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index bea10d51..eed8ccba 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -7,7 +7,6 @@ const helpers = require('./../helpers') module.exports = class deviceThermostat { constructor (platform, accessory) { this.platform = platform - this.accessory = accessory this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic this.EveHistoryService = fakegato(platform.api) @@ -40,6 +39,7 @@ module.exports = class deviceThermostat { accessory.eveLogger.addEntry(dataToAdd) }, 300000) } + this.accessory = accessory } async internalUpdate (value, callback) { diff --git a/lib/device/usb.js b/lib/device/usb.js index 9274407d..695d0391 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -5,13 +5,13 @@ const helpers = require('./../helpers') module.exports = class deviceUSB { constructor (platform, accessory) { this.platform = platform - this.accessory = accessory this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic const usbService = accessory.getService(this.Service.Outlet) || accessory.addService(this.Service.Outlet) usbService .getCharacteristic(this.Characteristic.On) .on('set', (value, callback) => this.internalUpdate(value, callback)) + this.accessory = accessory } async internalUpdate (value, callback) { diff --git a/lib/device/valve.js b/lib/device/valve.js index a1ff0f05..d5993430 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -5,7 +5,6 @@ const helpers = require('./../helpers') module.exports = class deviceValve { constructor (platform, accessory) { this.platform = platform - this.accessory = accessory this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic ;['A', 'B'].forEach(v => { @@ -37,6 +36,7 @@ module.exports = class deviceValve { callback() }) }) + this.accessory = accessory } async internalUpdate (valve, value, callback) { diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index bbd171ad..bda0352e 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -7,7 +7,6 @@ const helpers = require('./../helpers') module.exports = class deviceZBDev { constructor (platform, accessory) { this.platform = platform - this.accessory = accessory this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic this.EveHistoryService = fakegato(platform.api) @@ -54,6 +53,7 @@ module.exports = class deviceZBDev { if (!accessory.getService(this.Service.ContactSensor)) accessory.addService(this.Service.ContactSensor) break } + this.accessory = accessory } async externalUpdate (params) { From 122ee3e38e4fe4b902bfdd54549212756b400b17 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 15 Oct 2020 13:57:29 +0100 Subject: [PATCH 0481/3183] 3.6.1-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index bc68f03f..52248ae4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.1-0", + "version": "3.6.1-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 91e99bb0..a2511d6b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.1-0", + "version": "3.6.1-1", "author": "bwp91", "contributors": [ "gbro115", From 2410609334d68bade5d1de59cb1e0bf0fa2c4e70 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 15 Oct 2020 15:28:07 +0100 Subject: [PATCH 0482/3183] master switch hide --- lib/ewelink-platform.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 54c9aef1..6e14c89e 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -287,7 +287,7 @@ module.exports = class eWeLinkPlatform { /********************* LIGHTS [MULTI CHANNEL] *********************/ - if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid)) { + if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid + 'SW0')) { if (this.devicesInHB.has(device.deviceid + 'SW0')) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) } @@ -332,7 +332,7 @@ module.exports = class eWeLinkPlatform { /*********************** SWITCHES [MULTI CHANNEL] ***********************/ - if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid)) { + if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid + 'SW0')) { if (this.devicesInHB.has(device.deviceid + 'SW0')) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) } From 52f90f4ed6b607eea374e5fd67de0bab6b51987f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 15 Oct 2020 15:28:58 +0100 Subject: [PATCH 0483/3183] 3.6.1-2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 52248ae4..b60b8144 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.1-1", + "version": "3.6.1-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a2511d6b..6d138e57 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.1-1", + "version": "3.6.1-2", "author": "bwp91", "contributors": [ "gbro115", From 441917f076ab68b8c18deb0d1c0bc8b538f56bc0 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 15 Oct 2020 15:34:58 +0100 Subject: [PATCH 0484/3183] Update ewelink-platform.js --- lib/ewelink-platform.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 6e14c89e..39833c3e 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -51,7 +51,7 @@ module.exports = class eWeLinkPlatform { this.config.nameOverride = this.nameOverrideTmp this.config.ipOverride = this.ipOverrideTmp //* ** UPGRADE **\\ - this.config.hideChanFromHB += this.config.hideMasters + ',' + this.config.hideFromHB + this.config.hideChanFromHB += ',' + this.config.hideMasters + ',' + this.config.hideFromHB //* *************\\ this.api .on('didFinishLaunching', () => this.eWeLinkSetup()) From 31d342ecc69a63191d08d058f1058ec97159f7e7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 15 Oct 2020 15:36:03 +0100 Subject: [PATCH 0485/3183] 3.6.1-3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index b60b8144..3efa271b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.1-2", + "version": "3.6.1-3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 6d138e57..9c7b027d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.1-2", + "version": "3.6.1-3", "author": "bwp91", "contributors": [ "gbro115", From 30e2188f9083e75081b1ce8ec99cde1fd6e13a2b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 15 Oct 2020 15:39:21 +0100 Subject: [PATCH 0486/3183] 3.6.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3efa271b..badac319 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.1-3", + "version": "3.6.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 9c7b027d..ea4bf74c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.1-3", + "version": "3.6.1", "author": "bwp91", "contributors": [ "gbro115", From d9a99940f5743e21a8e67599832001658727e06e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 16 Oct 2020 07:44:51 +0100 Subject: [PATCH 0487/3183] update wsp dep --- package-lock.json | 10 +++++----- package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index badac319..b046aa00 100644 --- a/package-lock.json +++ b/package-lock.json @@ -672,13 +672,13 @@ "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==" }, "websocket-as-promised": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/websocket-as-promised/-/websocket-as-promised-1.0.1.tgz", - "integrity": "sha512-+gBevna4yxisb8cigL8NxcS8s241cvfMeyy1fNFcFgBcX/6vknMT84MwMmBNLYmsYH2giVoxOSEiAeeb7txFOw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/websocket-as-promised/-/websocket-as-promised-1.1.0.tgz", + "integrity": "sha512-agq8bPsPFKBWinKQkoXwY7LoBYe+2fQ7Gnuxx964+BTIiyAdL130FnB60bXuVQdUCdaS17R/MyRaaO4WIqtl4Q==", "requires": { - "chnl": "^1.0.0", + "chnl": "^1.2.0", "promise-controller": "^1.0.0", - "promise.prototype.finally": "^3.1.1" + "promise.prototype.finally": "^3.1.2" } }, "ws": { diff --git a/package.json b/package.json index ea4bf74c..9fdbb103 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "homebridge-lib": "4.7.16", "interval-promise": "1.4.0", "node-dns-sd": "0.4.2", - "websocket-as-promised": "1.0.1", + "websocket-as-promised": "1.1.0", "ws": "7.3.1" } } From d8a30f98c7bea1405d47ba06ab70623fb8e9eb58 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 16 Oct 2020 07:45:03 +0100 Subject: [PATCH 0488/3183] add reason for ws closure --- lib/ewelink-ws.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ewelink-ws.js b/lib/ewelink-ws.js index 04f4a0d4..d49f5d0f 100644 --- a/lib/ewelink-ws.js +++ b/lib/ewelink-ws.js @@ -260,7 +260,7 @@ module.exports = class eWeLinkWS { async closeConnection () { if (this.wsp && this.wsIsOpen) { - await this.wsp.close() + await this.wsp.close(1005, 'Normal Closure') if (this.debug) this.log('Web socket gracefully closed.') } } From 5d7a19680b44e4164b0e0d6c8c1871e05dc01ae0 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 16 Oct 2020 12:09:05 +0100 Subject: [PATCH 0489/3183] identify --- lib/ewelink-platform.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 39833c3e..c785b80e 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -512,7 +512,10 @@ module.exports = class eWeLinkPlatform { .setCharacteristic(this.Characteristic.Manufacturer, device.brandName) .setCharacteristic(this.Characteristic.Model, device.productModel + ' (' + device.extra.model + ')') .setCharacteristic(this.Characteristic.FirmwareRevision, device.params.fwVersion) - .setCharacteristic(this.Characteristic.Identify, false) + accessory.on('identify', (paired, callback) => { + this.log('[%s] - identify button pressed.', accessory.displayName) + callback() + }) } accessory.context = { ...{ From 2f638f6442438203f6394c5662ca531c07ba4845 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 16 Oct 2020 12:34:21 +0100 Subject: [PATCH 0490/3183] identify better --- lib/ewelink-platform.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index c785b80e..40740666 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -512,6 +512,7 @@ module.exports = class eWeLinkPlatform { .setCharacteristic(this.Characteristic.Manufacturer, device.brandName) .setCharacteristic(this.Characteristic.Model, device.productModel + ' (' + device.extra.model + ')') .setCharacteristic(this.Characteristic.FirmwareRevision, device.params.fwVersion) + .setCharacteristic(this.Characteristic.Identify, true) accessory.on('identify', (paired, callback) => { this.log('[%s] - identify button pressed.', accessory.displayName) callback() From bb3fcdf050bc5ff86236243acf304a74ca8ed907 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 16 Oct 2020 13:36:18 +0100 Subject: [PATCH 0491/3183] Update ewelink-ws.js --- lib/ewelink-ws.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ewelink-ws.js b/lib/ewelink-ws.js index d49f5d0f..04f4a0d4 100644 --- a/lib/ewelink-ws.js +++ b/lib/ewelink-ws.js @@ -260,7 +260,7 @@ module.exports = class eWeLinkWS { async closeConnection () { if (this.wsp && this.wsIsOpen) { - await this.wsp.close(1005, 'Normal Closure') + await this.wsp.close() if (this.debug) this.log('Web socket gracefully closed.') } } From b2d21b612aadc813dc4764c59059e729259d9d8f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 16 Oct 2020 13:40:42 +0100 Subject: [PATCH 0492/3183] lower case --- lib/ewelink-platform.js | 90 ++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 40740666..13dba7ba 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -1,26 +1,26 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const DeviceCurtain = require('./device/curtain') -const DeviceBlind = require('./device/blind') -const DeviceGarage = require('./device/garage') -const DeviceGarageTwo = require('./device/garage-two') -const DeviceGarageEachen = require('./device/garage-eachen') -const DeviceLock = require('./device/lock') -const DeviceValve = require('./device/valve') -const DeviceSensor = require('./device/sensor') -const DeviceFan = require('./device/fan') -const DeviceThermostat = require('./device/thermostat') -const DeviceOutlet = require('./device/outlet') -const DeviceUSB = require('./device/usb') -const DeviceSCM = require('./device/scm') -const DeviceLight = require('./device/light') -const DeviceSwitch = require('./device/switch') -const DeviceRFBridge = require('./device/rf-bridge') -const DeviceZBDev = require('./device/zb-dev') -const EWeLinkHTTP = require('./ewelink-http') -const EWeLinkLAN = require('./ewelink-lan') -const EWeLinkWS = require('./ewelink-ws') +const deviceCurtain = require('./device/curtain') +const deviceBlind = require('./device/blind') +const deviceGarage = require('./device/garage') +const deviceGarageTwo = require('./device/garage-two') +const deviceGarageEachen = require('./device/garage-eachen') +const deviceLock = require('./device/lock') +const deviceValve = require('./device/valve') +const deviceSensor = require('./device/sensor') +const deviceFan = require('./device/fan') +const deviceThermostat = require('./device/thermostat') +const deviceOutlet = require('./device/outlet') +const deviceUSB = require('./device/usb') +const deviceSCM = require('./device/scm') +const deviceLight = require('./device/light') +const deviceSwitch = require('./device/switch') +const deviceRFBridge = require('./device/rf-bridge') +const deviceZBDev = require('./device/zb-dev') +const eWeLinkHTTP = require('./ewelink-http') +const eWeLinkLAN = require('./ewelink-lan') +const eWeLinkWS = require('./ewelink-ws') const helpers = require('./helpers') const promInterval = require('interval-promise') module.exports = class eWeLinkPlatform { @@ -67,13 +67,13 @@ module.exports = class eWeLinkPlatform { return } this.log('Plugin has finished initialising. Syncing with eWeLink.') - this.httpClient = new EWeLinkHTTP(this.config, this.log) + this.httpClient = new eWeLinkHTTP(this.config, this.log) await this.httpClient.getHost() this.authData = await this.httpClient.login() const deviceList = await this.httpClient.getDevices() deviceList.forEach(device => this.devicesInEW.set(device.deviceid, device)) - this.wsClient = new EWeLinkWS(this.config, this.log, this.authData) - this.lanClient = new EWeLinkLAN(this.config, this.log, deviceList) + this.wsClient = new eWeLinkWS(this.config, this.log, this.authData) + this.lanClient = new eWeLinkLAN(this.config, this.log, deviceList) await this.wsClient.getHost() this.wsClient.login() this.lanDevices = await this.lanClient.getHosts() @@ -162,7 +162,7 @@ module.exports = class eWeLinkPlatform { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX', false, helpers.defaultCurtainCache) - accessory.control = new DeviceCurtain(this, accessory) + accessory.control = new deviceCurtain(this, accessory) /**********************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'blind') { /**************************** @@ -171,7 +171,7 @@ module.exports = class eWeLinkPlatform { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX', false, helpers.defaultBlindCache) - accessory.control = new DeviceBlind(this, accessory) + accessory.control = new deviceBlind(this, accessory) /***************************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage') { /********************************** @@ -180,7 +180,7 @@ module.exports = class eWeLinkPlatform { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX', false, helpers.defaultGarageCache) - accessory.control = new DeviceGarage(this, accessory) + accessory.control = new deviceGarage(this, accessory) /*********************************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage_two') { /********************************** @@ -189,7 +189,7 @@ module.exports = class eWeLinkPlatform { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX', false, helpers.defaultGarageTwoCache) - accessory.control = new DeviceGarageTwo(this, accessory) + accessory.control = new deviceGarageTwo(this, accessory) /*********************************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage_eachen') { /*************************** @@ -198,7 +198,7 @@ module.exports = class eWeLinkPlatform { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new DeviceGarageEachen(this, accessory) + accessory.control = new deviceGarageEachen(this, accessory) /**************************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'lock') { /*************************** @@ -207,7 +207,7 @@ module.exports = class eWeLinkPlatform { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new DeviceLock(this, accessory) + accessory.control = new deviceLock(this, accessory) /**************************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'valve') { /**************************** @@ -216,7 +216,7 @@ module.exports = class eWeLinkPlatform { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new DeviceValve(this, accessory) + accessory.control = new deviceValve(this, accessory) /***************************/ } else if (helpers.devicesSensor.includes(device.extra.uiid)) { /******************* @@ -225,7 +225,7 @@ module.exports = class eWeLinkPlatform { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX', false, { type: 'sensor' }) - accessory.control = new DeviceSensor(this, accessory) + accessory.control = new deviceSensor(this, accessory) /******************/ } else if (helpers.devicesFan.includes(device.extra.uiid)) { /*** @@ -234,7 +234,7 @@ module.exports = class eWeLinkPlatform { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new DeviceFan(this, accessory) + accessory.control = new deviceFan(this, accessory) /**/ } else if (helpers.devicesThermostat.includes(device.extra.uiid)) { /********** @@ -245,7 +245,7 @@ module.exports = class eWeLinkPlatform { : this.addAccessory(device, device.deviceid + 'SWX', false, { sensorType: device.params.sensorType }) - accessory.control = new DeviceThermostat(this, accessory) + accessory.control = new deviceThermostat(this, accessory) /*********/ } else if (helpers.devicesOutlet.includes(device.extra.uiid) || (helpers.devicesSingleSwitch.includes(device.extra.uiid) && helpers.devicesSingleSwitchOutlet.includes(device.productModel))) { /****** @@ -254,7 +254,7 @@ module.exports = class eWeLinkPlatform { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new DeviceOutlet(this, accessory) + accessory.control = new deviceOutlet(this, accessory) /*****/ } else if (helpers.devicesUSB.includes(device.extra.uiid)) { /********** @@ -263,7 +263,7 @@ module.exports = class eWeLinkPlatform { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new DeviceUSB(this, accessory) + accessory.control = new deviceUSB(this, accessory) /*********/ } else if (helpers.devicesSCM.includes(device.extra.uiid)) { /********************************* @@ -272,7 +272,7 @@ module.exports = class eWeLinkPlatform { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new DeviceSCM(this, accessory) + accessory.control = new deviceSCM(this, accessory) /********************************/ } else if (helpers.devicesSingleSwitch.includes(device.extra.uiid) && helpers.devicesSingleSwitchLight.includes(device.productModel)) { /********************** @@ -281,7 +281,7 @@ module.exports = class eWeLinkPlatform { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new DeviceLight(this, accessory) + accessory.control = new deviceLight(this, accessory) /*********************/ } else if (helpers.devicesMultiSwitch.includes(device.extra.uiid) && helpers.devicesMultiSwitchLight.includes(device.productModel)) { /********************* @@ -298,7 +298,7 @@ module.exports = class eWeLinkPlatform { ? this.devicesInHB.get(device.deviceid + 'SW0') : this.addAccessory(device, device.deviceid + 'SW0') } - accessory.control = new DeviceLight(this, accessory) + accessory.control = new deviceLight(this, accessory) for (let i = 1; i <= helpers.chansFromUiid[device.extra.uiid]; i++) { if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid + 'SW' + i)) { if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { @@ -316,7 +316,7 @@ module.exports = class eWeLinkPlatform { oAccessory.context.reachableWAN = device.online oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) - oAccessory.control = new DeviceLight(this, oAccessory) + oAccessory.control = new deviceLight(this, oAccessory) } /********************/ } else if (helpers.devicesSingleSwitch.includes(device.extra.uiid)) { @@ -326,7 +326,7 @@ module.exports = class eWeLinkPlatform { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new DeviceSwitch(this, accessory) + accessory.control = new deviceSwitch(this, accessory) /***********************/ } else if (helpers.devicesMultiSwitch.includes(device.extra.uiid)) { /*********************** @@ -343,7 +343,7 @@ module.exports = class eWeLinkPlatform { ? this.devicesInHB.get(device.deviceid + 'SW0') : this.addAccessory(device, device.deviceid + 'SW0') } - accessory.control = new DeviceSwitch(this, accessory) + accessory.control = new deviceSwitch(this, accessory) for (let i = 1; i <= helpers.chansFromUiid[device.extra.uiid]; i++) { if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid + 'SW' + i)) { if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { @@ -361,7 +361,7 @@ module.exports = class eWeLinkPlatform { oAccessory.context.reachableWAN = device.online oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) - oAccessory.control = new DeviceSwitch(this, oAccessory) + oAccessory.control = new deviceSwitch(this, oAccessory) } /**********************/ } else if (helpers.devicesRFBridge.includes(device.extra.uiid)) { @@ -384,7 +384,7 @@ module.exports = class eWeLinkPlatform { : this.addAccessory(device, device.deviceid + 'SW0', true, { rfMap }, 'rf_pri') - accessory.control = new DeviceRFBridge(this, accessory) + accessory.control = new deviceRFBridge(this, accessory) this.hiddenMasters.push(device.deviceid) rfMap.forEach(subDevice => { const swNumber = rfChlCounter + 1 @@ -418,7 +418,7 @@ module.exports = class eWeLinkPlatform { oAccessory.context.reachableWAN = device.online oAccessory.context.reachableLAN = false this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) - oAccessory.control = new DeviceRFBridge(this, oAccessory) + oAccessory.control = new deviceRFBridge(this, oAccessory) rfChlCounter += Object.keys(subDevice.buttons || {}).length }) accessory.context.channelCount = rfChlCounter @@ -440,7 +440,7 @@ module.exports = class eWeLinkPlatform { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new DeviceZBDev(this, accessory) + accessory.control = new deviceZBDev(this, accessory) /***************/ } else if (helpers.devicesCamera.includes(device.extra.uiid)) { /****** From ddd53f34e2a40362d5220c27f5b53b23437752f6 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 16 Oct 2020 13:41:44 +0100 Subject: [PATCH 0493/3183] 3.6.2-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index b046aa00..34b8bf76 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.1", + "version": "3.6.2-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 9fdbb103..996c9e66 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.1", + "version": "3.6.2-0", "author": "bwp91", "contributors": [ "gbro115", From aef497db1aebcdd90f556cdf66fc9b9ef21b27c1 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 16 Oct 2020 13:46:28 +0100 Subject: [PATCH 0494/3183] Update index.js --- index.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/index.js b/index.js index 11038152..731ea97a 100644 --- a/index.js +++ b/index.js @@ -2,6 +2,4 @@ /* eslint-disable new-cap */ 'use strict' const eWeLinkPlatform = require('./lib/ewelink-platform.js') -module.exports = (hb) => { - hb.registerPlatform('homebridge-ewelink', 'eWeLink', eWeLinkPlatform, true) -} +module.exports = hb => hb.registerPlatform('eWeLink', eWeLinkPlatform) From 1b0b8ae5056a6517fbc554c8b8adfbfd62a077d8 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 16 Oct 2020 15:39:50 +0100 Subject: [PATCH 0495/3183] ignore duplicate lan messages --- lib/ewelink-lan.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/ewelink-lan.js b/lib/ewelink-lan.js index 41810271..36e09c25 100644 --- a/lib/ewelink-lan.js +++ b/lib/ewelink-lan.js @@ -15,11 +15,13 @@ module.exports = class eWeLinkLAN { this.emitter = new eventEmitter() this.devices = devices this.deviceMap = new Map() + this.lastIV = null devices.forEach(device => { this.deviceMap.set(device.deviceid, { apiKey: device.devicekey, online: helpers.hasProperty(this.config.ipOverride, device.deviceid), - ip: helpers.hasProperty(this.config.ipOverride, device.deviceid) ? this.config.ipOverride[device.deviceid] : null + ip: helpers.hasProperty(this.config.ipOverride, device.deviceid) ? this.config.ipOverride[device.deviceid] : null, + lastIV: null }) }) } @@ -34,7 +36,8 @@ module.exports = class eWeLinkLAN { this.deviceMap.set(deviceId, { apiKey: d.apiKey, online: true, - ip: device.address + ip: device.address, + lastIV: null }) } } @@ -52,6 +55,8 @@ module.exports = class eWeLinkLAN { .forEach(value => { const rdata = value.rdata const deviceInfo = this.deviceMap.get(rdata.id) + if (deviceInfo.lastIV === rdata.iv) return + deviceInfo.lastIV = rdata.iv const data = rdata.data1 + (helpers.hasProperty(rdata, 'data2') ? rdata.data2 : '') + @@ -65,7 +70,8 @@ module.exports = class eWeLinkLAN { this.deviceMap.set(rdata.id, { apiKey: deviceInfo.apiKey, online: true, - ip: packet.address + ip: packet.address, + lastIV: rdata.iv }) if (this.debug) this.log.warn('[%s] updating IP address to [%s].', rdata.id, packet.address) } @@ -167,7 +173,8 @@ module.exports = class eWeLinkLAN { this.deviceMap.set(device.deviceid, { apiKey: device.devicekey, online: helpers.hasProperty(this.config.ipOverride, device.deviceid), - ip: helpers.hasProperty(this.config.ipOverride, device.deviceid) ? this.config.ipOverride[device.deviceid] : null + ip: helpers.hasProperty(this.config.ipOverride, device.deviceid) ? this.config.ipOverride[device.deviceid] : null, + lastIV: null }) } From ade6c9620aac485ab131e565448c30e75084e3ee Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 16 Oct 2020 15:46:51 +0100 Subject: [PATCH 0496/3183] unused var --- lib/ewelink-lan.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/ewelink-lan.js b/lib/ewelink-lan.js index 36e09c25..e8e85045 100644 --- a/lib/ewelink-lan.js +++ b/lib/ewelink-lan.js @@ -15,7 +15,6 @@ module.exports = class eWeLinkLAN { this.emitter = new eventEmitter() this.devices = devices this.deviceMap = new Map() - this.lastIV = null devices.forEach(device => { this.deviceMap.set(device.deviceid, { apiKey: device.devicekey, From aa6cde86b3ba47f70cf32c892a7cf38ee54078f2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 16 Oct 2020 15:47:25 +0100 Subject: [PATCH 0497/3183] 3.6.2-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 34b8bf76..b2ebd78c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.2-0", + "version": "3.6.2-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 996c9e66..3d17955c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.2-0", + "version": "3.6.2-1", "author": "bwp91", "contributors": [ "gbro115", From 8d218e449fa814995ec9cf7e23f4fb75e74d88c2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 17 Oct 2020 13:00:11 +0100 Subject: [PATCH 0498/3183] garage_four skeleton --- config.schema.json | 6 ++++++ lib/ewelink-platform.js | 10 ++++++++++ lib/helpers.js | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/config.schema.json b/config.schema.json index e34e5776..509820c8 100644 --- a/config.schema.json +++ b/config.schema.json @@ -167,6 +167,12 @@ "garage_two" ] }, + { + "title": "4 Garage Doors (using multi-channel device)", + "enum": [ + "garage_four" + ] + }, { "title": "1 Garage Door (using Eachen GD-DC5)", "enum": [ diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 13dba7ba..29e1bef8 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -5,6 +5,7 @@ const deviceCurtain = require('./device/curtain') const deviceBlind = require('./device/blind') const deviceGarage = require('./device/garage') const deviceGarageTwo = require('./device/garage-two') +const deviceGarageFour = require('./device/garage-four') const deviceGarageEachen = require('./device/garage-eachen') const deviceLock = require('./device/lock') const deviceValve = require('./device/valve') @@ -191,6 +192,15 @@ module.exports = class eWeLinkPlatform { : this.addAccessory(device, device.deviceid + 'SWX', false, helpers.defaultGarageTwoCache) accessory.control = new deviceGarageTwo(this, accessory) /*********************************/ + } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage_four') { + /********************************** + GARAGE DOORS [FOUR] [ACCESSORY SIMULATION] + **********************************/ + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new deviceGarageFour(this, accessory) + /*********************************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage_eachen') { /*************************** GARAGE DOORS [EACHEN GD-DC5] diff --git a/lib/helpers.js b/lib/helpers.js index b88b9be5..fc9abbf3 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -11,7 +11,7 @@ module.exports = { appId: 'oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq', appSecret: '6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM', httpRetryCodes: ['ENOTFOUND', 'ETIMEDOUT', 'EAI_AGAIN'], - allowedGroups: ['blind', 'garage', 'garage_two', 'garage_eachen', 'lock', 'valve'], + allowedGroups: ['blind', 'garage', 'garage_two', 'garage_four' 'garage_eachen', 'lock', 'valve'], devicesHideable: ['switch', 'light'], devicesNonLAN: [22, 28, 34, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], From 94c1105c15ccd6936b67cdb5b78cf8860e7d23e2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 17 Oct 2020 13:00:23 +0100 Subject: [PATCH 0499/3183] garage_four internalUpdate 1 --- lib/device/garage-four.js | 80 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 lib/device/garage-four.js diff --git a/lib/device/garage-four.js b/lib/device/garage-four.js new file mode 100644 index 00000000..85c427a9 --- /dev/null +++ b/lib/device/garage-four.js @@ -0,0 +1,80 @@ +/* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ +'use strict' +const helpers = require('./../helpers') +module.exports = class deviceGarageFour { + constructor (platform, accessory) { + this.platform = platform + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + ;['1', '2', '3', '4'].forEach(v => { + let gdService + if (!(gdService = accessory.getService('Garage ' + v))) { + accessory + .addService(this.Service.GarageDoorOpener, 'Garage ' + v, 'garage' + v) + .setCharacteristic(this.Characteristic.CurrentDoorState, 1) + .setCharacteristic(this.Characteristic.TargetDoorState, 1) + .setCharacteristic(this.Characteristic.ObstructionDetected, false) + gdService = accessory.getService('Garage ' + v) + } + gdService + .getCharacteristic(this.Characteristic.TargetDoorState) + .on('set', (value, callback) => this.internalUpdate(v, value, callback)) + }) + this.accessory = accessory + } + + async internalUpdate (garage, value, callback) { + callback() + try { + let garageConfig + if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { + throw new Error('group config missing') + } + if (garageConfig.type !== 'garage_four') { + throw new Error('improper configuration') + } + const params = { switches: this.accessory.context.switchState } + const gdService = this.accessory.getService('Garage ' + v) + if (value === gdService.getCharacteristic(this.Characteristic.CurrentDoorState).value % 2) return + params.switches[parseInt(garage) - 1].switch = value === 0 ? 'on' : 'off' + this.accessory.context.inUse = true + await this.platform.sendDeviceUpdate(this.accessory, params) + gdService + .updateCharacteristic(this.Characteristic.TargetDoorState, value) + .updateCharacteristic(this.Characteristic.CurrentDoorState, value + 2) + await helpers.sleep(2000) + this.accessory.context.inUse = false + if (value === 0) { + await helpers.sleep(Math.max((garageConfig.operationTime - 20) * 100, 0)) + gdService.updateCharacteristic(this.Characteristic.CurrentDoorState, 0) + } + } catch (err) { + this.accessory.context.inUse = false + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async externalUpdate (params) { + try { + if (!helpers.hasProperty(params, 'switch') || this.accessory.context.inUse) return + let garageConfig + if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { + throw new Error('group config missing') + } + if (garageConfig.type !== 'garage_four') { + throw new Error('improper configuration') + } + this.accessory.context.switchState = params.switches + this.accessory.context.inUse = true + const gdService = this.accessory.getService(this.Service.GarageDoorOpener) + gdService + .updateCharacteristic(this.Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) + .updateCharacteristic(this.Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) + this.accessory.context.inUse = false + } catch (err) { + this.accessory.context.inUse = false + this.platform.deviceUpdateError(this.accessory, err, false) + } + } +} From 68de82fe8b0213a5ad3b02db97e2dcd3f2724017 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 17 Oct 2020 13:01:40 +0100 Subject: [PATCH 0500/3183] syntax --- lib/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers.js b/lib/helpers.js index fc9abbf3..6f1bf1e0 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -11,7 +11,7 @@ module.exports = { appId: 'oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq', appSecret: '6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM', httpRetryCodes: ['ENOTFOUND', 'ETIMEDOUT', 'EAI_AGAIN'], - allowedGroups: ['blind', 'garage', 'garage_two', 'garage_four' 'garage_eachen', 'lock', 'valve'], + allowedGroups: ['blind', 'garage', 'garage_two', 'garage_four', 'garage_eachen', 'lock', 'valve'], devicesHideable: ['switch', 'light'], devicesNonLAN: [22, 28, 34, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], From 66b506f715903dc952417e054d2884f1bafd4556 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 17 Oct 2020 13:01:51 +0100 Subject: [PATCH 0501/3183] v to garage --- lib/device/garage-four.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/garage-four.js b/lib/device/garage-four.js index 85c427a9..652b0035 100644 --- a/lib/device/garage-four.js +++ b/lib/device/garage-four.js @@ -35,7 +35,7 @@ module.exports = class deviceGarageFour { throw new Error('improper configuration') } const params = { switches: this.accessory.context.switchState } - const gdService = this.accessory.getService('Garage ' + v) + const gdService = this.accessory.getService('Garage ' + garage) if (value === gdService.getCharacteristic(this.Characteristic.CurrentDoorState).value % 2) return params.switches[parseInt(garage) - 1].switch = value === 0 ? 'on' : 'off' this.accessory.context.inUse = true From e8bf03d6ad075330ba015c448d883f630feada8c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 17 Oct 2020 13:04:17 +0100 Subject: [PATCH 0502/3183] 3.6.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index b2ebd78c..fa87551d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.2-1", + "version": "3.6.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 3d17955c..c5216803 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.2-1", + "version": "3.6.2", "author": "bwp91", "contributors": [ "gbro115", From eda3efbd1933d4a0671e9f8875ede5e6a7d23363 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 17 Oct 2020 13:59:59 +0100 Subject: [PATCH 0503/3183] garage-four internalUpdate 2 --- lib/device/garage-four.js | 70 +++++++++++++++++++++++++-------------- lib/helpers.js | 18 ++++++++++ 2 files changed, 63 insertions(+), 25 deletions(-) diff --git a/lib/device/garage-four.js b/lib/device/garage-four.js index 652b0035..bc469859 100644 --- a/lib/device/garage-four.js +++ b/lib/device/garage-four.js @@ -7,7 +7,7 @@ module.exports = class deviceGarageFour { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic - ;['1', '2', '3', '4'].forEach(v => { + ;['A', 'B', 'C', 'D'].forEach(v => { let gdService if (!(gdService = accessory.getService('Garage ' + v))) { accessory @@ -34,21 +34,55 @@ module.exports = class deviceGarageFour { if (garageConfig.type !== 'garage_four') { throw new Error('improper configuration') } - const params = { switches: this.accessory.context.switchState } + let garageChannel + switch (garage) { + case 'A': + garageChannel = 0 + break + case 'B': + garageChannel = 1 + break + case 'C': + garageChannel = 2 + break + case 'D': + garageChannel = 3 + break + } + let sensorDefinition = garageConfig.sensorId || false + if (sensorDefinition) { + const sensors = garageConfig.sensorId.split(',') + sensorDefinition = sensors[garageChannel] || false + } + let sAccessory = false + if (sensorDefinition && !(sAccessory = this.platform.devicesInHB.get(garageConfig.sensorId + 'SWX'))) { + throw new Error("defined DW2 sensor doesn't exist") + } + if (sensorDefinition && sAccessory.context.type !== 'sensor') { + throw new Error("defined DW2 sensor isn't a sensor") + } + const prevState = sAccessory + ? sAccessory.getService(this.Service.ContactSensor).getCharacteristic(this.Characteristic.ContactSensorState).value === 0 + ? 1 + : 0 + : this.accessory.context[garageChannel].cacheCurrentDoorState + if (value === prevState % 2) return const gdService = this.accessory.getService('Garage ' + garage) - if (value === gdService.getCharacteristic(this.Characteristic.CurrentDoorState).value % 2) return - params.switches[parseInt(garage) - 1].switch = value === 0 ? 'on' : 'off' this.accessory.context.inUse = true - await this.platform.sendDeviceUpdate(this.accessory, params) gdService .updateCharacteristic(this.Characteristic.TargetDoorState, value) .updateCharacteristic(this.Characteristic.CurrentDoorState, value + 2) - await helpers.sleep(2000) - this.accessory.context.inUse = false - if (value === 0) { - await helpers.sleep(Math.max((garageConfig.operationTime - 20) * 100, 0)) - gdService.updateCharacteristic(this.Characteristic.CurrentDoorState, 0) + this.accessory.context[garageChannel].cacheTargetDoorState = value + this.accessory.context[garageChannel].cacheCurrentDoorState = value + 2 + const params = { switches: helpers.defaultMultiSwitchOff } + params.switches[garageChannel].switch = 'on' + await this.platform.sendDeviceUpdate(this.accessory, params) + await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) + if (!sAccessory) { + gdService.updateCharacteristic(this.Characteristic.CurrentDoorState, value) + this.accessory.context[garageChannel].cacheCurrentDoorState = value } + this.accessory.context.inUse = false } catch (err) { this.accessory.context.inUse = false this.platform.deviceUpdateError(this.accessory, err, true) @@ -57,21 +91,7 @@ module.exports = class deviceGarageFour { async externalUpdate (params) { try { - if (!helpers.hasProperty(params, 'switch') || this.accessory.context.inUse) return - let garageConfig - if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { - throw new Error('group config missing') - } - if (garageConfig.type !== 'garage_four') { - throw new Error('improper configuration') - } - this.accessory.context.switchState = params.switches - this.accessory.context.inUse = true - const gdService = this.accessory.getService(this.Service.GarageDoorOpener) - gdService - .updateCharacteristic(this.Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) - .updateCharacteristic(this.Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) - this.accessory.context.inUse = false + } catch (err) { this.accessory.context.inUse = false this.platform.deviceUpdateError(this.accessory, err, false) diff --git a/lib/helpers.js b/lib/helpers.js index 6f1bf1e0..34b4e2b6 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -83,6 +83,24 @@ module.exports = { cacheTwoCurrentDoorState: 1, cacheTwoTargetDoorState: 1 }, + defaultGarageFourCache: [ + { + cacheCurrentDoorState: 1, + cacheTargetDoorState: 1 + }, + { + cacheCurrentDoorState: 1, + cacheTargetDoorState: 1 + }, + { + cacheCurrentDoorState: 1, + cacheTargetDoorState: 1 + }, + { + cacheCurrentDoorState: 1, + cacheTargetDoorState: 1 + } + ], chansFromUiid: { 1: 1, // "SOCKET" \\ 20, MINI, BASIC, S26 2: 2, // "SOCKET_2" \\ From 22d4d343c088592c46f7b30ff510527f08cd125c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 17 Oct 2020 14:03:39 +0100 Subject: [PATCH 0504/3183] 3.7.0-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index fa87551d..2c1b6fe7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.2", + "version": "3.7.0-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index c5216803..b51a300e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.6.2", + "version": "3.7.0-0", "author": "bwp91", "contributors": [ "gbro115", From 455bef78daaa66c14541b99ab76d5b7476596b65 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 17 Oct 2020 18:01:39 +0100 Subject: [PATCH 0505/3183] hoobs fix --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 731ea97a..b66ae1c9 100644 --- a/index.js +++ b/index.js @@ -2,4 +2,4 @@ /* eslint-disable new-cap */ 'use strict' const eWeLinkPlatform = require('./lib/ewelink-platform.js') -module.exports = hb => hb.registerPlatform('eWeLink', eWeLinkPlatform) +module.exports = hb => hb.registerPlatform('homebridge-ewelink', 'eWeLink', eWeLinkPlatform) From 44429ba797accd98f527e21f57c9253e5820bc0c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 17 Oct 2020 18:03:03 +0100 Subject: [PATCH 0506/3183] 3.7.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2c1b6fe7..1d40bf39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.7.0-0", + "version": "3.7.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index b51a300e..2ec2f355 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.7.0-0", + "version": "3.7.0", "author": "bwp91", "contributors": [ "gbro115", From 19be90a2df6bc493db0963480804fdd21c36859a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 17 Oct 2020 19:21:40 +0100 Subject: [PATCH 0507/3183] garage-four internalUpdate 3 --- lib/device/garage-four.js | 13 +++++++++---- lib/ewelink-platform.js | 2 +- lib/helpers.js | 38 ++++++++++++++++++++------------------ 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/lib/device/garage-four.js b/lib/device/garage-four.js index bc469859..92074b1d 100644 --- a/lib/device/garage-four.js +++ b/lib/device/garage-four.js @@ -22,6 +22,7 @@ module.exports = class deviceGarageFour { .on('set', (value, callback) => this.internalUpdate(v, value, callback)) }) this.accessory = accessory + this.platform.log.error(accessory.context) } async internalUpdate (garage, value, callback) { @@ -34,6 +35,7 @@ module.exports = class deviceGarageFour { if (garageConfig.type !== 'garage_four') { throw new Error('improper configuration') } + const tempLogger = msg => this.platform.log.warn('[%s] %s', this.accessory.displayName, msg) let garageChannel switch (garage) { case 'A': @@ -49,6 +51,7 @@ module.exports = class deviceGarageFour { garageChannel = 3 break } + tempLogger('New position value requested - TargetDoorState: ' + value) let sensorDefinition = garageConfig.sensorId || false if (sensorDefinition) { const sensors = garageConfig.sensorId.split(',') @@ -61,26 +64,28 @@ module.exports = class deviceGarageFour { if (sensorDefinition && sAccessory.context.type !== 'sensor') { throw new Error("defined DW2 sensor isn't a sensor") } + tempLogger('sAccessory:' + sAccessory + ' as no sensor defined') const prevState = sAccessory ? sAccessory.getService(this.Service.ContactSensor).getCharacteristic(this.Characteristic.ContactSensorState).value === 0 ? 1 : 0 - : this.accessory.context[garageChannel].cacheCurrentDoorState + : this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState + tempLogger('Previous state retrieved as prevState:' + prevState) if (value === prevState % 2) return const gdService = this.accessory.getService('Garage ' + garage) this.accessory.context.inUse = true gdService .updateCharacteristic(this.Characteristic.TargetDoorState, value) .updateCharacteristic(this.Characteristic.CurrentDoorState, value + 2) - this.accessory.context[garageChannel].cacheTargetDoorState = value - this.accessory.context[garageChannel].cacheCurrentDoorState = value + 2 + this.accessory.context.cacheStates[garageChannel].cacheTargetDoorState = value + this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = value + 2 const params = { switches: helpers.defaultMultiSwitchOff } params.switches[garageChannel].switch = 'on' await this.platform.sendDeviceUpdate(this.accessory, params) await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) if (!sAccessory) { gdService.updateCharacteristic(this.Characteristic.CurrentDoorState, value) - this.accessory.context[garageChannel].cacheCurrentDoorState = value + this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = value } this.accessory.context.inUse = false } catch (err) { diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 29e1bef8..75a8cc80 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -198,7 +198,7 @@ module.exports = class eWeLinkPlatform { **********************************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX', false, helpers.defaultGarageFourCache) accessory.control = new deviceGarageFour(this, accessory) /*********************************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'garage_eachen') { diff --git a/lib/helpers.js b/lib/helpers.js index 34b4e2b6..1096a34d 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -83,24 +83,26 @@ module.exports = { cacheTwoCurrentDoorState: 1, cacheTwoTargetDoorState: 1 }, - defaultGarageFourCache: [ - { - cacheCurrentDoorState: 1, - cacheTargetDoorState: 1 - }, - { - cacheCurrentDoorState: 1, - cacheTargetDoorState: 1 - }, - { - cacheCurrentDoorState: 1, - cacheTargetDoorState: 1 - }, - { - cacheCurrentDoorState: 1, - cacheTargetDoorState: 1 - } - ], + defaultGarageFourCache: { + cacheStates: [ + { + cacheCurrentDoorState: 1, + cacheTargetDoorState: 1 + }, + { + cacheCurrentDoorState: 1, + cacheTargetDoorState: 1 + }, + { + cacheCurrentDoorState: 1, + cacheTargetDoorState: 1 + }, + { + cacheCurrentDoorState: 1, + cacheTargetDoorState: 1 + } + ] + }, chansFromUiid: { 1: 1, // "SOCKET" \\ 20, MINI, BASIC, S26 2: 2, // "SOCKET_2" \\ From 401cab520e9b3cc08e4590872a3bf8588fd81cd0 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 17 Oct 2020 19:22:25 +0100 Subject: [PATCH 0508/3183] 3.7.1-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1d40bf39..f82e2c11 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.7.0", + "version": "3.7.1-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 2ec2f355..bca9cf1d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.7.0", + "version": "3.7.1-0", "author": "bwp91", "contributors": [ "gbro115", From 46463dbb3aa9dd1bd70a4399b0bf051fe66b6b9d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 17 Oct 2020 20:18:22 +0100 Subject: [PATCH 0509/3183] garage-four internalUpdate 4 --- lib/device/garage-four.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/device/garage-four.js b/lib/device/garage-four.js index 92074b1d..3f7c32b5 100644 --- a/lib/device/garage-four.js +++ b/lib/device/garage-four.js @@ -22,7 +22,6 @@ module.exports = class deviceGarageFour { .on('set', (value, callback) => this.internalUpdate(v, value, callback)) }) this.accessory = accessory - this.platform.log.error(accessory.context) } async internalUpdate (garage, value, callback) { @@ -51,7 +50,6 @@ module.exports = class deviceGarageFour { garageChannel = 3 break } - tempLogger('New position value requested - TargetDoorState: ' + value) let sensorDefinition = garageConfig.sensorId || false if (sensorDefinition) { const sensors = garageConfig.sensorId.split(',') @@ -64,13 +62,11 @@ module.exports = class deviceGarageFour { if (sensorDefinition && sAccessory.context.type !== 'sensor') { throw new Error("defined DW2 sensor isn't a sensor") } - tempLogger('sAccessory:' + sAccessory + ' as no sensor defined') const prevState = sAccessory ? sAccessory.getService(this.Service.ContactSensor).getCharacteristic(this.Characteristic.ContactSensorState).value === 0 ? 1 : 0 : this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState - tempLogger('Previous state retrieved as prevState:' + prevState) if (value === prevState % 2) return const gdService = this.accessory.getService('Garage ' + garage) this.accessory.context.inUse = true @@ -80,7 +76,7 @@ module.exports = class deviceGarageFour { this.accessory.context.cacheStates[garageChannel].cacheTargetDoorState = value this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = value + 2 const params = { switches: helpers.defaultMultiSwitchOff } - params.switches[garageChannel].switch = 'on' + ;[0, 1, 2, 3].forEach(i => (params.switches[i].switch = garageChannel === i ? 'on' : 'off')) await this.platform.sendDeviceUpdate(this.accessory, params) await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) if (!sAccessory) { From 4c4252b2ab26adf1681599683cc208ee9a8f860a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 17 Oct 2020 20:19:10 +0100 Subject: [PATCH 0510/3183] 3.7.1-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f82e2c11..167b072c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.7.1-0", + "version": "3.7.1-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index bca9cf1d..1fc754e6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.7.1-0", + "version": "3.7.1-1", "author": "bwp91", "contributors": [ "gbro115", From a9ce0491d94c85238f7bd4630ac56db979de8c98 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 18 Oct 2020 11:14:12 +0100 Subject: [PATCH 0511/3183] one liners --- lib/device/curtain.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/device/curtain.js b/lib/device/curtain.js index 645a38f8..dfc70ae1 100644 --- a/lib/device/curtain.js +++ b/lib/device/curtain.js @@ -31,13 +31,9 @@ module.exports = class deviceCurtain { const newPos = value if (newPos === prevPos) return if (newPos === 0 || newPos === 100) { - params = { - switch: newPos === 100 ? 'on' : 'off' - } + params = { switch: newPos === 100 ? 'on' : 'off' } } else { - params = { - setclose: Math.abs(100 - newPos) - } + params = { setclose: Math.abs(100 - newPos) } } await this.platform.sendDeviceUpdate(this.accessory, params) cService From 2d5b5cef2173b42826e69cf1bebe9298e78bf4fc Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 18 Oct 2020 11:14:23 +0100 Subject: [PATCH 0512/3183] garage-four externalUpdate 1 --- lib/device/garage-four.js | 56 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/lib/device/garage-four.js b/lib/device/garage-four.js index 3f7c32b5..f6cbdd82 100644 --- a/lib/device/garage-four.js +++ b/lib/device/garage-four.js @@ -70,6 +70,8 @@ module.exports = class deviceGarageFour { if (value === prevState % 2) return const gdService = this.accessory.getService('Garage ' + garage) this.accessory.context.inUse = true + const updateKey = Math.random().toString(36).substr(2, 8) + this.accessory.context.updateKey = updateKey gdService .updateCharacteristic(this.Characteristic.TargetDoorState, value) .updateCharacteristic(this.Characteristic.CurrentDoorState, value + 2) @@ -78,12 +80,14 @@ module.exports = class deviceGarageFour { const params = { switches: helpers.defaultMultiSwitchOff } ;[0, 1, 2, 3].forEach(i => (params.switches[i].switch = garageChannel === i ? 'on' : 'off')) await this.platform.sendDeviceUpdate(this.accessory, params) - await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) + await helpers.sleep(1000) + this.accessory.context.inUse = false + await helpers.sleep(Math.max((garageConfig.operationTime - 10) * 100, 0)) + if (this.accessory.context.updateKey !== updateKey || sAccessory) return if (!sAccessory) { gdService.updateCharacteristic(this.Characteristic.CurrentDoorState, value) this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = value } - this.accessory.context.inUse = false } catch (err) { this.accessory.context.inUse = false this.platform.deviceUpdateError(this.accessory, err, true) @@ -92,9 +96,53 @@ module.exports = class deviceGarageFour { async externalUpdate (params) { try { - + if (!helpers.hasProperty(params, 'switches') || this.accessory.context.inUse) return + let garageConfig + if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { + throw new Error('group config missing') + } + if (garageConfig.type !== 'garage_four') { + throw new Error('improper configuration') + } + if (this.accessory.context.inUse) return + ;['A', 'B', 'C', 'D'].forEach(async v => { + let garageChannel + switch (v) { + case 'A': + garageChannel = 0 + break + case 'B': + garageChannel = 1 + break + case 'C': + garageChannel = 2 + break + case 'D': + garageChannel = 3 + break + } + let sensorDefinition = garageConfig.sensorId || false + if (sensorDefinition) { + const sensors = garageConfig.sensorId.split(',') + sensorDefinition = sensors[garageChannel] || false + } + let sAccessory = false + if (sensorDefinition && !(sAccessory = this.platform.devicesInHB.get(garageConfig.sensorId + 'SWX'))) { + throw new Error("defined DW2 sensor doesn't exist") + } + if (sensorDefinition && sAccessory.context.type !== 'sensor') { + throw new Error("defined DW2 sensor isn't a sensor") + } + if (sensorDefinition) return + const gcService = this.accessory.getService('Garage ' + v) + const prevState = this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState + const newPos = [0, 2].includes(prevState) ? 1 : 0 + if (params.switches[garageChannel].switch === 'off') return + gcService.updateCharacteristic(this.Characteristic.CurrentDoorState, newPos) + this.accessory.context.cacheStates[garageChannel].cacheTargetDoorState = newPos + this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = newPos + }) } catch (err) { - this.accessory.context.inUse = false this.platform.deviceUpdateError(this.accessory, err, false) } } From d9911219afc05b8771a3327505fa8b8a7a7dcfde Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 18 Oct 2020 12:03:04 +0100 Subject: [PATCH 0513/3183] Update helpers.js --- lib/helpers.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/helpers.js b/lib/helpers.js index 1096a34d..d9f99bd4 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -2,12 +2,8 @@ /* eslint-disable new-cap */ 'use strict' module.exports = { - sleep: ms => { - return new Promise(resolve => setTimeout(resolve, ms)) - }, - hasProperty: (obj, prop) => { - return Object.prototype.hasOwnProperty.call(obj, prop) - }, + sleep: ms => new Promise(resolve => setTimeout(resolve, ms)), + hasProperty: (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop), appId: 'oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq', appSecret: '6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM', httpRetryCodes: ['ENOTFOUND', 'ETIMEDOUT', 'EAI_AGAIN'], From 67c901c45f1521ffa4e5e4c9c4e519e76a4675d7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 18 Oct 2020 14:37:50 +0100 Subject: [PATCH 0514/3183] Update ewelink-platform.js --- lib/ewelink-platform.js | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 75a8cc80..520ed5b9 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -43,17 +43,14 @@ module.exports = class eWeLinkPlatform { this.cusG = new Map() this.cusS = new Map() this.hiddenMasters = [] - this.eveLogPath = this.api.user.storagePath() + '/homebridge-ewelink/' - this.wsRefreshFlag = true this.nameOverrideTmp = {} this.ipOverrideTmp = {} - if (this.config.nameOverride) this.config.nameOverride.forEach(x => (this.nameOverrideTmp[x.fullDeviceId] = x.deviceName)) - if (this.config.ipOverride) this.config.ipOverride.forEach(x => (this.ipOverrideTmp[x.deviceId] = x.deviceIP)) + if (config.nameOverride) config.nameOverride.forEach(x => (this.nameOverrideTmp[x.fullDeviceId] = x.deviceName)) + if (config.ipOverride) config.ipOverride.forEach(x => (this.ipOverrideTmp[x.deviceId] = x.deviceIP)) this.config.nameOverride = this.nameOverrideTmp this.config.ipOverride = this.ipOverrideTmp - //* ** UPGRADE **\\ - this.config.hideChanFromHB += ',' + this.config.hideMasters + ',' + this.config.hideFromHB - //* *************\\ + this.wsRefreshFlag = true + this.eveLogPath = this.api.user.storagePath() + '/homebridge-ewelink/' this.api .on('didFinishLaunching', () => this.eWeLinkSetup()) .on('shutdown', () => this.eWeLinkShutdown()) @@ -557,17 +554,12 @@ module.exports = class eWeLinkPlatform { deviceid: accessory.context.eweDeviceId, params } - let res - if (helpers.devicesNonLAN.includes(accessory.context.eweUIID)) { - res = "device doesn't support LAN mode" - } else { - res = await this.lanClient.sendUpdate(payload) - } + const res = helpers.devicesNonLAN.includes(accessory.context.eweUIID) + ? "device doesn't support LAN mode" + : await this.lanClient.sendUpdate(payload) if (res !== 'ok') { if (accessory.context.reachableWAN) { - if (this.debug) { - this.log('[%s] Reverting to web socket as %s.', accessory.displayName, res) - } + if (this.debug) this.log('[%s] Reverting to web socket as %s.', accessory.displayName, res) await this.wsClient.sendUpdate(payload) } else { throw new Error("it is unreachable. It's status will be corrected once it is reachable") From a74c6af316cf7bb5aaf84da7d0d90827db0608aa Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 18 Oct 2020 17:19:00 +0100 Subject: [PATCH 0515/3183] 3.7.1-2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 167b072c..7bec4299 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.7.1-1", + "version": "3.7.1-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1fc754e6..b5f9eb35 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.7.1-1", + "version": "3.7.1-2", "author": "bwp91", "contributors": [ "gbro115", From fb4468b4a24bd748b372b4f2b5f65db4f77ec0f8 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 19 Oct 2020 20:08:11 +0100 Subject: [PATCH 0516/3183] option to hide fan light --- config.schema.json | 6 ++++++ lib/device/fan.js | 30 ++++++++++++++++++++---------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/config.schema.json b/config.schema.json index 509820c8..34ad95d6 100644 --- a/config.schema.json +++ b/config.schema.json @@ -77,6 +77,11 @@ "description": "If enabled, the switch for the TH10/TH16 devices will be hidden from Homebridge.", "default": false }, + "hideLightFromFan": { + "type": "string", + "title": "Hide Fan Lights", + "description": "A list of eWeLink iFan devices for which the light will be hidden from Homebridge. For example '10009553c8' or multiple separated with a comma '10009553c8,10009553c9'" + }, "lowBattThreshold": { "type": "integer", "title": "Low Battery Threshold", @@ -341,6 +346,7 @@ "expandable": true, "items": [ "hideChanFromHB", + "hideLightFromFan", "disableEveLogging", "inUsePowerThreshold", "hideTHSwitch", diff --git a/lib/device/fan.js b/lib/device/fan.js index 48037085..72e48a68 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -7,8 +7,8 @@ module.exports = class deviceFan { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic + this.visibleLight = true const fanService = accessory.getService(this.Service.Fanv2) || accessory.addService(this.Service.Fanv2) - const fanLightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) fanService .getCharacteristic(this.Characteristic.Active) .on('set', async (value, callback) => { @@ -24,9 +24,17 @@ module.exports = class deviceFan { .setProps({ minStep: 33 }) - fanLightService - .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate('light', value, callback)) + if ((this.platform.config.hideLightFromFan || '').includes(accessory.context.eweDeviceId)) { + if (accessory.getService(this.Service.Lightbulb)) { + accessory.removeService(accessory.getService(this.Service.Lightbulb)) + } + this.visibleLight = false + } else { + const fanLightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) + fanLightService + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalUpdate('light', value, callback)) + } this.accessory = accessory } @@ -36,19 +44,20 @@ module.exports = class deviceFan { let newPower let newSpeed let newLight - const lightService = this.accessory.getService(this.Service.Lightbulb) + let lightService + if (this.visibleLight) lightService = this.accessory.getService(this.Service.Lightbulb) const fanService = this.accessory.getService(this.Service.Fanv2) const params = { switches: helpers.defaultMultiSwitchOff } switch (type) { case 'speed': newPower = value >= 33 ? 1 : 0 newSpeed = value - newLight = lightService.getCharacteristic(this.Characteristic.On).value + newLight = this.visibleLight ? lightService.getCharacteristic(this.Characteristic.On).value : true break case 'light': newPower = fanService.getCharacteristic(this.Characteristic.Active).value newSpeed = fanService.getCharacteristic(this.Characteristic.RotationSpeed).value - newLight = value + newLight = this.visibleLight ? value : true break } params.switches[0].switch = newLight ? 'on' : 'off' @@ -56,7 +65,7 @@ module.exports = class deviceFan { params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? 'on' : 'off' params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? 'on' : 'off' - lightService.updateCharacteristic(this.Characteristic.On, newLight) + if (this.visibleLight) lightService.updateCharacteristic(this.Characteristic.On, newLight) fanService .updateCharacteristic(this.Characteristic.Active, newPower) .updateCharacteristic(this.Characteristic.RotationSpeed, newSpeed) @@ -69,7 +78,8 @@ module.exports = class deviceFan { async externalUpdate (params) { try { if (params.switches && Array.isArray(params.switches)) { - const lightService = this.accessory.getService(this.Service.Lightbulb) + let lightService + if (this.visibleLight) lightService = this.accessory.getService(this.Service.Lightbulb) const fanService = this.accessory.getService(this.Service.Fanv2) const light = params.switches[0].switch === 'on' let status @@ -91,7 +101,7 @@ module.exports = class deviceFan { status = 1 speed = 99 } - lightService.updateCharacteristic(this.Characteristic.On, light) + if (this.visibleLight) lightService.updateCharacteristic(this.Characteristic.On, light) fanService .updateCharacteristic(this.Characteristic.Active, status) .updateCharacteristic(this.Characteristic.RotationSpeed, speed) From 08d0fb60bd9db6ee9237d7d9bc2d0d6cdd01b80c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 19 Oct 2020 20:11:40 +0100 Subject: [PATCH 0517/3183] 3.7.1-3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7bec4299..b9c1cf46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.7.1-2", + "version": "3.7.1-3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index b5f9eb35..f184b8cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.7.1-2", + "version": "3.7.1-3", "author": "bwp91", "contributors": [ "gbro115", From 9842fbc5b690716f57e503bbf6e182ca6a912874 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 20 Oct 2020 09:57:16 +0100 Subject: [PATCH 0518/3183] Convert Fanv2 to Fan --- lib/device/fan.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index 72e48a68..323aefcd 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -8,9 +8,13 @@ module.exports = class deviceFan { this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic this.visibleLight = true - const fanService = accessory.getService(this.Service.Fanv2) || accessory.addService(this.Service.Fanv2) + /****************** UPGRADE 3.7.* -> 3.8.* ******************/ + const fanServiceOld = accessory.getService(this.Service.Fanv2) + if (fanServiceOld) accessory.removeService(fanServiceOld) + /************************************************************/ + const fanService = accessory.getService(this.Service.Fan) || accessory.addService(this.Service.Fan) fanService - .getCharacteristic(this.Characteristic.Active) + .getCharacteristic(this.Characteristic.On) .on('set', async (value, callback) => { callback() if (value === 0) { @@ -46,7 +50,7 @@ module.exports = class deviceFan { let newLight let lightService if (this.visibleLight) lightService = this.accessory.getService(this.Service.Lightbulb) - const fanService = this.accessory.getService(this.Service.Fanv2) + const fanService = this.accessory.getService(this.Service.Fan) const params = { switches: helpers.defaultMultiSwitchOff } switch (type) { case 'speed': @@ -55,7 +59,7 @@ module.exports = class deviceFan { newLight = this.visibleLight ? lightService.getCharacteristic(this.Characteristic.On).value : true break case 'light': - newPower = fanService.getCharacteristic(this.Characteristic.Active).value + newPower = fanService.getCharacteristic(this.Characteristic.On).value newSpeed = fanService.getCharacteristic(this.Characteristic.RotationSpeed).value newLight = this.visibleLight ? value : true break @@ -67,7 +71,7 @@ module.exports = class deviceFan { if (this.visibleLight) lightService.updateCharacteristic(this.Characteristic.On, newLight) fanService - .updateCharacteristic(this.Characteristic.Active, newPower) + .updateCharacteristic(this.Characteristic.On, newPower) .updateCharacteristic(this.Characteristic.RotationSpeed, newSpeed) await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { @@ -80,7 +84,7 @@ module.exports = class deviceFan { if (params.switches && Array.isArray(params.switches)) { let lightService if (this.visibleLight) lightService = this.accessory.getService(this.Service.Lightbulb) - const fanService = this.accessory.getService(this.Service.Fanv2) + const fanService = this.accessory.getService(this.Service.Fan) const light = params.switches[0].switch === 'on' let status let speed @@ -103,7 +107,7 @@ module.exports = class deviceFan { } if (this.visibleLight) lightService.updateCharacteristic(this.Characteristic.On, light) fanService - .updateCharacteristic(this.Characteristic.Active, status) + .updateCharacteristic(this.Characteristic.On, status) .updateCharacteristic(this.Characteristic.RotationSpeed, speed) } } catch (err) { From f8e095fb3ebf565f7961d5dad4894c2d8eaeac14 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 20 Oct 2020 10:40:33 +0100 Subject: [PATCH 0519/3183] unnecessary updates --- lib/device/fan.js | 5 ---- lib/device/light.js | 58 +++++++++------------------------------- lib/device/outlet.js | 6 +---- lib/device/rf-bridge.js | 7 +++-- lib/device/scm.js | 2 -- lib/device/switch.js | 5 ---- lib/device/thermostat.js | 2 -- lib/device/usb.js | 2 -- 8 files changed, 16 insertions(+), 71 deletions(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index 323aefcd..8c39e2a4 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -68,11 +68,6 @@ module.exports = class deviceFan { params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? 'on' : 'off' params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? 'on' : 'off' params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? 'on' : 'off' - - if (this.visibleLight) lightService.updateCharacteristic(this.Characteristic.On, newLight) - fanService - .updateCharacteristic(this.Characteristic.On, newPower) - .updateCharacteristic(this.Characteristic.RotationSpeed, newSpeed) await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) diff --git a/lib/device/light.js b/lib/device/light.js index 6a1ba5de..70d41bf8 100644 --- a/lib/device/light.js +++ b/lib/device/light.js @@ -13,27 +13,11 @@ module.exports = class deviceLight { .getCharacteristic(this.Characteristic.On) .on('set', (value, callback) => this.internalUpdate('onoff', value, callback)) if (helpers.devicesBrightable.includes(accessory.context.eweUIID)) { - lightService.getCharacteristic(this.Characteristic.Brightness).on('set', (value, callback) => { - if (value > 0) { - if (!lightService.getCharacteristic(this.Characteristic.On).value) { - this.internalUpdate('onoff', true, function () {}) - } - this.internalUpdate('brightness', value, callback) - } else { - this.internalUpdate('onoff', false, callback) - } - }) + lightService.getCharacteristic(this.Characteristic.Brightness) + .on('set', (value, callback) => this.internalUpdate('brightness', value, callback)) } else if (helpers.devicesColourable.includes(accessory.context.eweUIID)) { - lightService.getCharacteristic(this.Characteristic.Brightness).on('set', (value, callback) => { - if (value > 0) { - if (!lightService.getCharacteristic(this.Characteristic.On).value) { - this.internalUpdate('onoff', true, function () {}) - } - this.internalUpdate('c_brightness', value, callback) - } else { - this.internalUpdate('onoff', false, callback) - } - }) + lightService.getCharacteristic(this.Characteristic.Brightness) + .on('set', (value, callback) => this.internalUpdate('c_brightness', value, callback)) lightService .getCharacteristic(this.Characteristic.Hue) .on('set', (value, callback) => this.internalUpdate('c_hue', value, callback)) @@ -87,9 +71,6 @@ module.exports = class deviceLight { } await this.platform.sendDeviceUpdate(this.accessory, params) switch (this.accessory.context.switchNumber) { - case 'X': - lightService.updateCharacteristic(this.Characteristic.On, value) - break case '0': for (let i = 0; i <= 4; i++) { if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { @@ -101,7 +82,6 @@ module.exports = class deviceLight { case '2': case '3': case '4': { - lightService.updateCharacteristic(this.Characteristic.On, value) let masterState = 'off' for (let i = 1; i <= 4; i++) { if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { @@ -119,29 +99,17 @@ module.exports = class deviceLight { } break case 'brightness': - if (value === 0) { - params.switch = 'off' - } else { - if (!lightService.getCharacteristic(this.Characteristic.On).value) { - params.switch = 'on' - } - switch (this.accessory.context.eweUIID) { - case 36: //* ** KING-M4 ***\\ - params.bright = Math.round((value * 9) / 10 + 10) - break - case 44: //* ** D1 ***\\ - params.brightness = value - params.mode = 0 - break - } + switch (this.accessory.context.eweUIID) { + case 36: //* ** KING-M4 ***\\ + params.bright = Math.round((value * 9) / 10 + 10) + break + case 44: //* ** D1 ***\\ + params.brightness = value + params.mode = 0 + break } await helpers.sleep(250) await this.platform.sendDeviceUpdate(this.accessory, params) - if (value === 0) { - lightService.updateCharacteristic(this.Characteristic.On, false) - } else { - lightService.updateCharacteristic(this.Characteristic.Brightness, value) - } break case 'c_brightness': switch (this.accessory.context.eweUIID) { @@ -170,7 +138,6 @@ module.exports = class deviceLight { } await helpers.sleep(250) await this.platform.sendDeviceUpdate(this.accessory, params) - lightService.updateCharacteristic(this.Characteristic.Brightness, value) break case 'c_hue': newRGB = convert.hsv.rgb(value, lightService.getCharacteristic(this.Characteristic.Saturation).value, 100) @@ -197,7 +164,6 @@ module.exports = class deviceLight { } await helpers.sleep(250) await this.platform.sendDeviceUpdate(this.accessory, params) - lightService.updateCharacteristic(this.Characteristic.Hue, value) break } } catch (err) { diff --git a/lib/device/outlet.js b/lib/device/outlet.js index ae80e022..37619b78 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -113,12 +113,8 @@ module.exports = class deviceOutlet { async internalUpdate (value, callback) { callback() try { - const params = { - switch: value ? 'on' : 'off' - } - const outletService = this.accessory.getService(this.Service.Outlet) + const params = { switch: value ? 'on' : 'off' } await this.platform.sendDeviceUpdate(this.accessory, params) - outletService.updateCharacteristic(this.Characteristic.On, value) } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) } diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index 9270cd89..fa7d9bb8 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -34,7 +34,8 @@ module.exports = class deviceRFBridge { Object.entries(accessory.context.buttons).forEach(([chan, name]) => { if (!accessory.getService(name)) accessory.addService(this.Service.Switch, name, 'switch' + chan) accessory.getService(name).updateCharacteristic(this.Characteristic.On, false) - accessory.getService(name).getCharacteristic(this.Characteristic.On) + accessory.getService(name) + .getCharacteristic(this.Characteristic.On) .on('set', (value, callback) => this.internalUpdate(chan, name, value, callback)) }) break @@ -50,10 +51,8 @@ module.exports = class deviceRFBridge { cmd: 'transmit', rfChl: parseInt(rfChl) } - const rfService = this.accessory.getService(service) - rfService.updateCharacteristic(this.Characteristic.On, true) await helpers.sleep(1000) - rfService.updateCharacteristic(this.Characteristic.On, false) + this.accessory.getService(service).updateCharacteristic(this.Characteristic.On, false) await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) diff --git a/lib/device/scm.js b/lib/device/scm.js index 961b1b83..b92fd847 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -18,10 +18,8 @@ module.exports = class deviceSCM { callback() try { const params = { switches: helpers.defaultMultiSwitchOff } - const switchService = this.accessory.getService(this.Service.Switch) params.switches[0].switch = value ? 'on' : 'off' await this.platform.sendDeviceUpdate(this.accessory, params) - switchService.updateCharacteristic(this.Characteristic.On, value) } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) } diff --git a/lib/device/switch.js b/lib/device/switch.js index 9cea49b7..dce815af 100644 --- a/lib/device/switch.js +++ b/lib/device/switch.js @@ -19,7 +19,6 @@ module.exports = class deviceSwitch { try { let oAccessory const params = {} - const switchService = this.accessory.getService(this.Service.Switch) switch (this.accessory.context.switchNumber) { case 'X': params.switch = value ? 'on' : 'off' @@ -51,9 +50,6 @@ module.exports = class deviceSwitch { } await this.platform.sendDeviceUpdate(this.accessory, params) switch (this.accessory.context.switchNumber) { - case 'X': - switchService.updateCharacteristic(this.Characteristic.On, value) - break case '0': for (let i = 0; i <= 4; i++) { if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { @@ -65,7 +61,6 @@ module.exports = class deviceSwitch { case '2': case '3': case '4': { - switchService.updateCharacteristic(this.Characteristic.On, value) let masterState = 'off' for (let i = 1; i <= 4; i++) { if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index eed8ccba..0a2a5d3a 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -49,9 +49,7 @@ module.exports = class deviceThermostat { switch: value ? 'on' : 'off', mainSwitch: value ? 'on' : 'off' } - const switchService = this.accessory.getService(this.Service.Switch) await this.platform.sendDeviceUpdate(this.accessory, params) - switchService.updateCharacteristic(this.Characteristic.On, value) } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) } diff --git a/lib/device/usb.js b/lib/device/usb.js index 695d0391..fa5bc4f6 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -18,10 +18,8 @@ module.exports = class deviceUSB { callback() try { const params = { switches: helpers.defaultMultiSwitchOff } - const outletService = this.accessory.getService(this.Service.Outlet) params.switches[0].switch = value ? 'on' : 'off' await this.platform.sendDeviceUpdate(this.accessory, params) - outletService.updateCharacteristic(this.Characteristic.On, value) } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) } From 3ea87558a07d4727f4f9e1773f97652de39bc7f3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 20 Oct 2020 10:47:21 +0100 Subject: [PATCH 0520/3183] unnecessary updates 2 --- lib/device/blind.js | 3 --- lib/device/curtain.js | 5 +---- lib/device/lock.js | 3 --- lib/device/valve.js | 1 - 4 files changed, 1 insertion(+), 11 deletions(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index 31e7bc82..b481d65e 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -60,9 +60,6 @@ module.exports = class deviceBlind { params.switches[0].switch = setToMoveUp ? 'on' : 'off' params.switches[1].switch = setToMoveUp ? 'off' : 'on' await this.platform.sendDeviceUpdate(this.accessory, params) - wcService - .updateCharacteristic(this.Characteristic.TargetPosition, newTarget) - .updateCharacteristic(this.Characteristic.PositionState, setToMoveUp) this.accessory.context.cacheTargetPosition = newTarget this.accessory.context.cachePositionState = setToMoveUp ? 1 : 0 this.accessory.context.cacheLastStartTime = Math.floor(Date.now() / 100) diff --git a/lib/device/curtain.js b/lib/device/curtain.js index dfc70ae1..f6c8031a 100644 --- a/lib/device/curtain.js +++ b/lib/device/curtain.js @@ -35,11 +35,8 @@ module.exports = class deviceCurtain { } else { params = { setclose: Math.abs(100 - newPos) } } - await this.platform.sendDeviceUpdate(this.accessory, params) - cService - .updateCharacteristic(this.Characteristic.TargetPosition, newPos) - .updateCharacteristic(this.Characteristic.PositionState, newPos > prevPos ? 1 : 0) this.accessory.context.cacheCurrentPosition = newPos + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) } diff --git a/lib/device/lock.js b/lib/device/lock.js index 24c8c6ec..b69ea0cc 100644 --- a/lib/device/lock.js +++ b/lib/device/lock.js @@ -28,9 +28,6 @@ module.exports = class deviceLock { } this.accessory.context.inUse = true await this.platform.sendDeviceUpdate(this.accessory, params) - lmService - .updateCharacteristic(this.Characteristic.LockTargetState, 0) - .updateCharacteristic(this.Characteristic.LockCurrentState, 0) await helpers.sleep(Math.max(lockConfig.operationTime * 100, 1000)) lmService .updateCharacteristic(this.Characteristic.LockTargetState, 1) diff --git a/lib/device/valve.js b/lib/device/valve.js index d5993430..e5bc5633 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -67,7 +67,6 @@ module.exports = class deviceValve { } await this.platform.sendDeviceUpdate(this.accessory, params) serviceValve - .updateCharacteristic(this.Characteristic.Active, value) .updateCharacteristic(this.Characteristic.InUse, value) switch (value) { case 0: From 53545dfa6f3206dc664964b273dbbc1cedc778a2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 20 Oct 2020 10:50:15 +0100 Subject: [PATCH 0521/3183] formatting --- lib/device/curtain.js | 1 - lib/device/fan.js | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/device/curtain.js b/lib/device/curtain.js index f6c8031a..67ca977b 100644 --- a/lib/device/curtain.js +++ b/lib/device/curtain.js @@ -26,7 +26,6 @@ module.exports = class deviceCurtain { callback() try { let params - const cService = this.accessory.getService(this.Service.WindowCovering) const prevPos = this.accessory.context.cacheCurrentPosition const newPos = value if (newPos === prevPos) return diff --git a/lib/device/fan.js b/lib/device/fan.js index 8c39e2a4..761afef6 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -8,10 +8,10 @@ module.exports = class deviceFan { this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic this.visibleLight = true - /****************** UPGRADE 3.7.* -> 3.8.* ******************/ + /** *************** UPGRADE 3.7.* -> 3.8.* ******************/ const fanServiceOld = accessory.getService(this.Service.Fanv2) if (fanServiceOld) accessory.removeService(fanServiceOld) - /************************************************************/ + /** *********************************************************/ const fanService = accessory.getService(this.Service.Fan) || accessory.addService(this.Service.Fan) fanService .getCharacteristic(this.Characteristic.On) From ccd55d5f7640d7c512d069d736e5e98db07c3a25 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 20 Oct 2020 10:52:54 +0100 Subject: [PATCH 0522/3183] 3.8.0-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index b9c1cf46..df39a3ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.7.1-3", + "version": "3.8.0-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f184b8cd..ff11f65a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.7.1-3", + "version": "3.8.0-0", "author": "bwp91", "contributors": [ "gbro115", From e9cd321f7984f10e8d706b15e569d102570ca217 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 20 Oct 2020 13:01:15 +0100 Subject: [PATCH 0523/3183] eve logging for sensors --- lib/device/outlet.js | 4 +-- lib/device/rf-bridge.js | 60 ++++++++++++++++++++++++++++++--- lib/device/sensor.js | 27 ++++++++++++++- lib/device/thermostat.js | 4 +-- lib/device/zb-dev.js | 71 ++++++++++++++++++++++++++++++++-------- 5 files changed, 143 insertions(+), 23 deletions(-) diff --git a/lib/device/outlet.js b/lib/device/outlet.js index 37619b78..1493ddd4 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -43,7 +43,7 @@ module.exports = class deviceOutlet { accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('energy', accessory, { storage: 'fs', - minutes: 5, + minutes: 10, path: this.platform.eveLogPath }) corrInterval.setCorrectingInterval(() => { @@ -78,7 +78,7 @@ module.exports = class deviceOutlet { time: Date.now(), power: currentWatt }) - }, 300000) + }, 600000) outletService .getCharacteristic(this.EveCharacteristics.TotalConsumption) .on('get', callback => { diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index fa7d9bb8..1ab23e68 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -1,12 +1,15 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' +const corrInterval = require('correcting-interval') +const fakegato = require('fakegato-history') const helpers = require('./../helpers') module.exports = class deviceRFBridge { constructor (platform, accessory) { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic + this.EveHistoryService = fakegato(platform.api) switch (accessory.context.subType) { case 'water': if (!accessory.getService(this.Service.LeakSensor)) accessory.addService(this.Service.LeakSensor) @@ -21,15 +24,47 @@ module.exports = class deviceRFBridge { case 'co2': if (!accessory.getService(this.Service.CarbonDioxideSensor)) accessory.addService(this.Service.CarbonDioxideSensor) break - case 'contact': - if (!accessory.getService(this.Service.ContactSensor)) accessory.addService(this.Service.ContactSensor) + case 'contact': { + const contactService = accessory.getService(this.Service.ContactSensor) || accessory.addService(this.Service.ContactSensor) + if (!this.platform.config.disableEveLogging) { + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('door', accessory, { + storage: 'fs', + minutes: 10, + path: this.platform.eveLogPath + }) + corrInterval.setCorrectingInterval(() => { + const dataToAdd = { + time: Date.now(), + status: contactService.getCharacteristic(this.Characteristic.ContactSensorState).value + } + accessory.eveLogger.addEntry(dataToAdd) + }, 600000) + } break + } case 'occupancy': if (!accessory.getService(this.Service.OccupancySensor)) accessory.addService(this.Service.OccupancySensor) break - default: - if (!accessory.getService(this.Service.MotionSensor)) accessory.addService(this.Service.MotionSensor) + default: { + const motionService = accessory.getService(this.Service.MotionSensor) || accessory.addService(this.Service.MotionSensor) + if (!this.platform.config.disableEveLogging) { + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('motion', accessory, { + storage: 'fs', + minutes: 10, + path: this.platform.eveLogPath + }) + corrInterval.setCorrectingInterval(() => { + const dataToAdd = { + time: Date.now(), + status: motionService.getCharacteristic(this.Characteristic.MotionDetected).value ? 1 : 0 + } + accessory.eveLogger.addEntry(dataToAdd) + }, 600000) + } break + } case 'button': Object.entries(accessory.context.buttons).forEach(([chan, name]) => { if (!accessory.getService(name)) accessory.addService(this.Service.Switch, name, 'switch' + chan) @@ -100,6 +135,7 @@ module.exports = class deviceRFBridge { const diff = (timeNow.getTime() - timeOfMotion.getTime()) / 1000 let serv let char + let eveLog = false if (diff < (this.platform.config.sensorTimeDifference || 120)) { switch (oAccessory.context.subType) { case 'button': @@ -124,6 +160,7 @@ module.exports = class deviceRFBridge { case 'contact': serv = this.Service.ContactSensor char = this.Characteristic.ContactSensorState + eveLog = true break case 'occupancy': serv = this.Service.OccupancySensor @@ -132,11 +169,26 @@ module.exports = class deviceRFBridge { default: serv = this.Service.MotionSensor char = this.Characteristic.MotionDetected + eveLog = true break } oAccessory.getService(serv).updateCharacteristic(char, 1) + if (!this.platform.config.disableEveLogging && eveLog) { + const eveLog = { + time: Date.now(), + status: 1 + } + oAccessory.eveLogger.addEntry(eveLog) + } await helpers.sleep((this.platform.config.sensorTimeLength || 2) * 1000) oAccessory.getService(serv).updateCharacteristic(char, 0) + if (!this.platform.config.disableEveLogging && eveLog) { + const eveLog = { + time: Date.now(), + status: 0 + } + oAccessory.eveLogger.addEntry(eveLog) + } } } }) diff --git a/lib/device/sensor.js b/lib/device/sensor.js index ee5ae854..47f5ad7d 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -1,14 +1,32 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' +const corrInterval = require('correcting-interval') +const fakegato = require('fakegato-history') const helpers = require('./../helpers') module.exports = class deviceSensor { constructor (platform, accessory) { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic - if (!accessory.getService(this.Service.ContactSensor)) accessory.addService(this.Service.ContactSensor) + this.EveHistoryService = fakegato(platform.api) + const contactService = accessory.getService(this.Service.ContactSensor) || accessory.addService(this.Service.ContactSensor) if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) + if (!this.platform.config.disableEveLogging) { + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('door', accessory, { + storage: 'fs', + minutes: 10, + path: this.platform.eveLogPath + }) + corrInterval.setCorrectingInterval(() => { + const dataToAdd = { + time: Date.now(), + status: contactService.getCharacteristic(this.Characteristic.ContactSensorState).value + } + accessory.eveLogger.addEntry(dataToAdd) + }, 600000) + } this.accessory = accessory } @@ -29,6 +47,13 @@ module.exports = class deviceSensor { let oAccessory = false const contactService = this.accessory.getService(this.Service.ContactSensor) contactService.updateCharacteristic(this.Characteristic.ContactSensorState, newState) + if (!this.platform.config.disableEveLogging) { + const eveLog = { + time: Date.now(), + status: newState + } + this.accessory.eveLogger.addEntry(eveLog) + } this.platform.cusG.forEach(async group => { if (group.sensorId === this.accessory.context.eweDeviceId && group.type === 'garage') { if ((oAccessory = this.platform.devicesInHB.get(group.deviceId + 'SWX'))) { diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index 0a2a5d3a..6843ae0c 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -25,7 +25,7 @@ module.exports = class deviceThermostat { accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('weather', accessory, { storage: 'fs', - minutes: 5, + minutes: 10, path: this.platform.eveLogPath }) corrInterval.setCorrectingInterval(() => { @@ -37,7 +37,7 @@ module.exports = class deviceThermostat { dataToAdd.humidity = humiService.getCharacteristic(this.Characteristic.CurrentRelativeHumidity).value } accessory.eveLogger.addEntry(dataToAdd) - }, 300000) + }, 600000) } this.accessory = accessory } diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index bda0352e..a496bf84 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -32,7 +32,7 @@ module.exports = class deviceZBDev { accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('weather', accessory, { storage: 'fs', - minutes: 5, + minutes: 10, path: this.platform.eveLogPath }) corrInterval.setCorrectingInterval(() => { @@ -42,16 +42,48 @@ module.exports = class deviceZBDev { humidity: zbHumiService.getCharacteristic(this.Characteristic.CurrentRelativeHumidity).value } accessory.eveLogger.addEntry(dataToAdd) - }, 300000) + }, 600000) } break } - case 2026: - if (!accessory.getService(this.Service.MotionSensor)) accessory.addService(this.Service.MotionSensor) + case 2026: { + const motionService = accessory.getService(this.Service.MotionSensor) || accessory.addService(this.Service.MotionSensor) + if (!this.platform.config.disableEveLogging) { + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('motion', accessory, { + storage: 'fs', + minutes: 10, + path: this.platform.eveLogPath + }) + corrInterval.setCorrectingInterval(() => { + const dataToAdd = { + time: Date.now(), + status: motionService.getCharacteristic(this.Characteristic.MotionDetected).value ? 1 : 0 + } + accessory.eveLogger.addEntry(dataToAdd) + }, 600000) + } break - case 3026: - if (!accessory.getService(this.Service.ContactSensor)) accessory.addService(this.Service.ContactSensor) + } + case 3026: { + const contactService = accessory.getService(this.Service.ContactSensor) || accessory.addService(this.Service.ContactSensor) + if (!this.platform.config.disableEveLogging) { + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('door', accessory, { + storage: 'fs', + minutes: 10, + path: this.platform.eveLogPath + }) + corrInterval.setCorrectingInterval(() => { + const dataToAdd = { + time: Date.now(), + status: contactService.getCharacteristic(this.Characteristic.ContactSensorState).value + } + accessory.eveLogger.addEntry(dataToAdd) + }, 600000) + } break + } } this.accessory = accessory } @@ -107,14 +139,18 @@ module.exports = class deviceZBDev { if (helpers.hasProperty(params, 'motion') && helpers.hasProperty(params, 'trigTime')) { const timeNow = new Date() const diff = (timeNow.getTime() - params.trigTime) / 1000 - this.accessory - .getService(this.Service.MotionSensor) - .updateCharacteristic( - this.Characteristic.MotionDetected, - helpers.hasProperty(params, 'updateSource') && - params.motion === 1 && - diff < (this.platform.config.sensorTimeDifference || 120) - ) + const motionDetected = + helpers.hasProperty(params, 'updateSource') && + params.motion === 1 && + diff < (this.platform.config.sensorTimeDifference || 120) + if (!this.platform.config.disableEveLogging) { + const eveLog = { + time: Date.now(), + status: motionDetected ? 1 : 0 + } + this.accessory.eveLogger.addEntry(eveLog) + } + this.accessory.getService(this.Service.MotionSensor).updateCharacteristic(this.Characteristic.MotionDetected, motionDetected) break } break @@ -123,6 +159,13 @@ module.exports = class deviceZBDev { this.accessory .getService(this.Service.ContactSensor) .updateCharacteristic(this.Characteristic.ContactSensorState, params.lock) + if (!this.platform.config.disableEveLogging) { + const eveLog = { + time: Date.now(), + status: params.lock + } + this.accessory.eveLogger.addEntry(eveLog) + } } break default: From 02ad28b744c70ed3076a72e450e0083012b16bb5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 20 Oct 2020 13:03:48 +0100 Subject: [PATCH 0524/3183] 3.8.0-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index df39a3ff..33e0e6a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.8.0-0", + "version": "3.8.0-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index ff11f65a..4b8d06f5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.8.0-0", + "version": "3.8.0-1", "author": "bwp91", "contributors": [ "gbro115", From 6017176a562a112122e6638d1289b7cc0c460e9e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 20 Oct 2020 15:46:23 +0100 Subject: [PATCH 0525/3183] updates to B1 brightness --- lib/device/light.js | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/lib/device/light.js b/lib/device/light.js index 70d41bf8..9172b63e 100644 --- a/lib/device/light.js +++ b/lib/device/light.js @@ -18,6 +18,13 @@ module.exports = class deviceLight { } else if (helpers.devicesColourable.includes(accessory.context.eweUIID)) { lightService.getCharacteristic(this.Characteristic.Brightness) .on('set', (value, callback) => this.internalUpdate('c_brightness', value, callback)) + if (accessory.context.eweUIID === 22) { + lightService + .getCharacteristic(this.Characteristic.Brightness) + .setProps({ + minStep: 100 + }) + } lightService .getCharacteristic(this.Characteristic.Hue) .on('set', (value, callback) => this.internalUpdate('c_hue', value, callback)) @@ -98,7 +105,9 @@ module.exports = class deviceLight { } } break - case 'brightness': + case 'brightness': { + const updateKey = Math.random().toString(36).substr(2, 8) + this.accessory.context.updateKey = updateKey switch (this.accessory.context.eweUIID) { case 36: //* ** KING-M4 ***\\ params.bright = Math.round((value * 9) / 10 + 10) @@ -108,10 +117,14 @@ module.exports = class deviceLight { params.mode = 0 break } - await helpers.sleep(250) + await helpers.sleep(750) + if (updateKey !== this.accessory.context.updateKey) return await this.platform.sendDeviceUpdate(this.accessory, params) break - case 'c_brightness': + } + case 'c_brightness': { + const updateKey = Math.random().toString(36).substr(2, 8) + this.accessory.context.updateKey = updateKey switch (this.accessory.context.eweUIID) { case 22: //* ** B1 ***\\ newRGB = convert.hsv.rgb( @@ -119,6 +132,7 @@ module.exports = class deviceLight { lightService.getCharacteristic(this.Characteristic.Saturation).value, value ) + if (newRGB[0] + newRGB[1] + newRGB[2] === 0) return params = { zyx_mode: 2, type: 'middle', @@ -136,10 +150,14 @@ module.exports = class deviceLight { } break } - await helpers.sleep(250) + await helpers.sleep(750) + if (updateKey !== this.accessory.context.updateKey) return await this.platform.sendDeviceUpdate(this.accessory, params) break - case 'c_hue': + } + case 'c_hue': { + const updateKey = Math.random().toString(36).substr(2, 8) + this.accessory.context.updateKey = updateKey newRGB = convert.hsv.rgb(value, lightService.getCharacteristic(this.Characteristic.Saturation).value, 100) switch (this.accessory.context.eweUIID) { case 22: //* ** B1 ***\\ @@ -162,9 +180,11 @@ module.exports = class deviceLight { } break } - await helpers.sleep(250) + await helpers.sleep(750) + if (updateKey !== this.accessory.context.updateKey) return await this.platform.sendDeviceUpdate(this.accessory, params) break + } } } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) From 5ba4f925123a6528ac0190c5130dcdc45d0d1944 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 20 Oct 2020 19:06:47 +0100 Subject: [PATCH 0526/3183] bug?: Char.Active to .On --- lib/device/fan.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index 761afef6..74405872 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -17,7 +17,7 @@ module.exports = class deviceFan { .getCharacteristic(this.Characteristic.On) .on('set', async (value, callback) => { callback() - if (value === 0) { + if (!value) { await helpers.sleep(500) fanService.setCharacteristic(this.Characteristic.RotationSpeed, 0) } From d386fdd26043f2336f82dd0912856722637b21d2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 20 Oct 2020 19:08:00 +0100 Subject: [PATCH 0527/3183] 3.8.0-2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 33e0e6a1..7e110452 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.8.0-1", + "version": "3.8.0-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 4b8d06f5..70068ab0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.8.0-1", + "version": "3.8.0-2", "author": "bwp91", "contributors": [ "gbro115", From 0540474bc81d34f35c0690a0b54d4e497730a288 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 21 Oct 2020 07:40:45 +0100 Subject: [PATCH 0528/3183] initialise sensors last --- lib/ewelink-http.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/ewelink-http.js b/lib/ewelink-http.js index 4ac13318..8219f8f8 100644 --- a/lib/ewelink-http.js +++ b/lib/ewelink-http.js @@ -171,6 +171,7 @@ module.exports = class eWeLinkHTTP { throw new Error(JSON.stringify(body, null, 2)) } const deviceList = [] + const sensorList = [] if (body.data.thingList && body.data.thingList.length > 0) { body.data.thingList.forEach(d => { if ( @@ -179,11 +180,15 @@ module.exports = class eWeLinkHTTP { helpers.hasProperty(d.itemData.extra, 'uiid') && !this.hideDevFromHB.includes(d.itemData.deviceid) ) { - deviceList.push(d.itemData) + if (d.itemData.extra.uiid === 102) { + sensorList.push(d.itemData) + } else { + deviceList.push(d.itemData) + } } }) } - return deviceList + return deviceList.concat(sensorList) } catch (err) { if (helpers.hasProperty(err, 'code') && helpers.httpRetryCodes.includes(err.code)) { if (this.debug) { From 64901b9113864250f3635095906158d88e0549cd Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 21 Oct 2020 07:45:57 +0100 Subject: [PATCH 0529/3183] 3.8.0-3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7e110452..7787ae85 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.8.0-2", + "version": "3.8.0-3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 70068ab0..68bf985f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.8.0-2", + "version": "3.8.0-3", "author": "bwp91", "contributors": [ "gbro115", From 7c4352fff26772fb726298c5d0259ba06fcf94e9 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Wed, 21 Oct 2020 09:23:19 +0100 Subject: [PATCH 0530/3183] Update codeql-analysis.yml --- .github/workflows/codeql-analysis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 7158717c..bc0e9c59 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -2,10 +2,10 @@ name: "CodeQL" on: push: - branches: [master, ] + branches: [release] pull_request: # The branches below must be a subset of the branches above - branches: [master] + branches: [release] schedule: - cron: '0 1 * * 5' From 8b0e98145aa769c61d40a6de0503246e2e5bc65c Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Wed, 21 Oct 2020 09:27:06 +0100 Subject: [PATCH 0531/3183] Update codeql-analysis.yml --- .github/workflows/codeql-analysis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index bc0e9c59..51bab658 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -2,10 +2,10 @@ name: "CodeQL" on: push: - branches: [release] + branches: [latest] pull_request: # The branches below must be a subset of the branches above - branches: [release] + branches: [latest] schedule: - cron: '0 1 * * 5' From 8b41825d2bb887fa79e3213a35991e48cb436d1d Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Wed, 21 Oct 2020 09:32:58 +0100 Subject: [PATCH 0532/3183] Update codeql-analysis.yml --- .github/workflows/codeql-analysis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 7158717c..51bab658 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -2,10 +2,10 @@ name: "CodeQL" on: push: - branches: [master, ] + branches: [latest] pull_request: # The branches below must be a subset of the branches above - branches: [master] + branches: [latest] schedule: - cron: '0 1 * * 5' From f0cc347cdf844cf7cb3bd3103f9aaf2552b207f7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 21 Oct 2020 09:35:21 +0100 Subject: [PATCH 0533/3183] 3.8.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7787ae85..88e02e95 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.8.0-3", + "version": "3.8.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 68bf985f..64f5a284 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.8.0-3", + "version": "3.8.0", "author": "bwp91", "contributors": [ "gbro115", From c300f38394874fa28751810df8fa686aee60ba97 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Thu, 22 Oct 2020 20:56:59 +0100 Subject: [PATCH 0534/3183] add hoobs certification badge --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4fb13bae..649fd4db 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ Homebridge plugin to control eWeLink devices with original firmware. -[![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) +[![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) +[![hoobs-certified](https://badgen.net/badge/HOOBS/Certified/yellow)](https://plugins.hoobs.org/plugin/homebridge-govee) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/latest?label=latest)](https://www.npmjs.com/package/homebridge-ewelink) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://github.com/bwp91/homebridge-ewelink/wiki/Beta-Version) [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) From a0bb003935904ea8f0f57713ed183c90836819d5 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 23 Oct 2020 11:16:50 +0100 Subject: [PATCH 0535/3183] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 649fd4db..f08d80a3 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@

- Homebridge Verified + Homebridge Verified

# homebridge-ewelink -Homebridge plugin to control eWeLink devices with original firmware. +Homebridge/HOOBS plugin to control eWeLink devices with original firmware. [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) [![hoobs-certified](https://badgen.net/badge/HOOBS/Certified/yellow)](https://plugins.hoobs.org/plugin/homebridge-govee) @@ -17,8 +17,8 @@ Homebridge plugin to control eWeLink devices with original firmware. -### Homebridge -To use this plugin, you will need to already have Homebridge installed. Please refer to the [Homebridge website](https://homebridge.io) for more information and installation instructions. +### Prerequisites +To use this plugin, you will need to already have [Homebridge](https://homebridge.io) or [HOOBS](https://hoobs.org) installed. Please refer to the links for more information and installation instructions. ### Setup * [Installation (Homebridge)](https://github.com/bwp91/homebridge-ewelink/wiki/Installation-(Homebridge)) From 1fd1c8923dfdfd2a42ea6aeba502bdbf677a0b27 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 23 Oct 2020 11:21:24 +0100 Subject: [PATCH 0536/3183] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f08d80a3..f73a85c9 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Homebridge/HOOBS plugin to control eWeLink devices with original firmware. [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) -[![hoobs-certified](https://badgen.net/badge/HOOBS/Certified/yellow)](https://plugins.hoobs.org/plugin/homebridge-govee) +[![hoobs-certified](https://badgen.net/badge/HOOBS/Certified/yellow)](https://plugins.hoobs.org/plugin/homebridge-ewelink) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/latest?label=latest)](https://www.npmjs.com/package/homebridge-ewelink) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://github.com/bwp91/homebridge-ewelink/wiki/Beta-Version) [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) From 22538fcc16e4a5b20a50ecafb19ee0edfa46e6c8 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 23 Oct 2020 15:59:11 +0100 Subject: [PATCH 0537/3183] 3.8.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 88e02e95..01904ac4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.8.0", + "version": "3.8.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 64f5a284..812bd92b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.8.0", + "version": "3.8.1", "author": "bwp91", "contributors": [ "gbro115", From d4b8ae675615dfd88f5133a168a6be51e67144e1 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 24 Oct 2020 09:13:24 +0100 Subject: [PATCH 0538/3183] reorder keywords --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 812bd92b..d7a09be8 100644 --- a/package.json +++ b/package.json @@ -27,12 +27,12 @@ "keywords": [ "homebridge", "homebridge-plugin", - "sonoff", + "homebridge-ewelink", + "hoobs", "homekit", "siri", "ewelink", - "homebridge-ewelink", - "hoobs", + "sonoff", "eachen" ], "engines": { From 7dd7f7fd8523a6966d6cc1b653d19af0d4af34ba Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 24 Oct 2020 09:13:39 +0100 Subject: [PATCH 0539/3183] plugin desc --- config.schema.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config.schema.json b/config.schema.json index 34ad95d6..7c03af88 100644 --- a/config.schema.json +++ b/config.schema.json @@ -2,7 +2,7 @@ "pluginAlias": "eWeLink", "pluginType": "platform", "singular": true, - "headerDisplay": "Homebridge plugin to control eWeLink devices with original firmware.", + "headerDisplay": "Homebridge/HOOBS plugin to control eWeLink devices with original firmware.", "footerDisplay": "For help and support please visit our [GitHub Wiki](https://github.com/bwp91/homebridge-ewelink/wiki).", "schema": { "type": "object", diff --git a/package.json b/package.json index d7a09be8..b98fa8ce 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ } ], "dependencies": { - "axios": "0.20.0", + "axios": "0.21.0", "color-convert": "2.0.1", "correcting-interval": "2.0.0", "fakegato-history": "0.5.6", From 010f798f9d9073a4310efd681f466ee2631656cb Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 24 Oct 2020 09:14:09 +0100 Subject: [PATCH 0540/3183] update axios dep --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 01904ac4..4ac4d924 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54,9 +54,9 @@ "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" }, "axios": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz", - "integrity": "sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==", + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.0.tgz", + "integrity": "sha512-fmkJBknJKoZwem3/IKSSLpkdNXZeBu5Q7GA/aRsr2btgrptmSCxi2oFjZHqGdK9DoTil9PIHlPIZw2EcRJXRvw==", "requires": { "follow-redirects": "^1.10.0" } diff --git a/package.json b/package.json index b98fa8ce..0d98836b 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "JuniorGenius", "BobbySlope" ], - "description": "Homebridge plugin to control eWeLink devices with original firmware.", + "description": "Homebridge/HOOBS plugin to control eWeLink devices with original firmware.", "license": "MIT", "keywords": [ "homebridge", From 3f703ec3f387f84553fd4404193b386f50dbd0e2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 24 Oct 2020 10:36:36 +0100 Subject: [PATCH 0541/3183] doesnt need to be anon func --- lib/ewelink-platform.js | 76 ++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 520ed5b9..250dc4d5 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -76,47 +76,45 @@ module.exports = class eWeLinkPlatform { this.wsClient.login() this.lanDevices = await this.lanClient.getHosts() await this.lanClient.startMonitor() - ;(() => { - if (Object.keys(this.config.groups || []).length > 0) { - this.config.groups - .filter(g => helpers.hasProperty(g, 'type') && helpers.allowedGroups.includes(g.type)) - .filter(g => helpers.hasProperty(g, 'deviceId') && this.devicesInEW.has(g.deviceId)) - .forEach(g => this.cusG.set(g.deviceId + 'SWX', g)) - } - if (Object.keys(this.config.bridgeSensors || []).length > 0) { - this.config.bridgeSensors - .filter(s => helpers.hasProperty(s, 'deviceId') && this.devicesInEW.has(s.deviceId)) - .forEach(s => this.cusS.set(s.fullDeviceId, s)) - } - this.log('[%s] eWeLink devices loaded from the Homebridge cache.', this.devicesInHB.size) - this.log('[%s] primary devices loaded from your eWeLink account.', this.devicesInEW.size) - this.devicesInHB.forEach(a => { - if (!this.devicesInEW.has(a.context.eweDeviceId)) this.removeAccessory(a) - }) - this.devicesInEW.forEach(d => this.initialiseDevice(d)) - this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)) - this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)) - this.wsRefresh = promInterval( - async () => { - if (this.wsRefreshFlag) { - try { - if (this.wsClient) { - await this.wsClient.getHost() - await this.wsClient.closeConnection() - await helpers.sleep(250) - await this.wsClient.login() - } - } catch (err) { - this.log.warn(this.debug ? err : err.message) + if (Object.keys(this.config.groups || []).length > 0) { + this.config.groups + .filter(g => helpers.hasProperty(g, 'type') && helpers.allowedGroups.includes(g.type)) + .filter(g => helpers.hasProperty(g, 'deviceId') && this.devicesInEW.has(g.deviceId)) + .forEach(g => this.cusG.set(g.deviceId + 'SWX', g)) + } + if (Object.keys(this.config.bridgeSensors || []).length > 0) { + this.config.bridgeSensors + .filter(s => helpers.hasProperty(s, 'deviceId') && this.devicesInEW.has(s.deviceId)) + .forEach(s => this.cusS.set(s.fullDeviceId, s)) + } + this.log('[%s] eWeLink devices loaded from the Homebridge cache.', this.devicesInHB.size) + this.log('[%s] primary devices loaded from your eWeLink account.', this.devicesInEW.size) + this.devicesInHB.forEach(a => { + if (!this.devicesInEW.has(a.context.eweDeviceId)) this.removeAccessory(a) + }) + this.devicesInEW.forEach(d => this.initialiseDevice(d)) + this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)) + this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)) + this.wsRefresh = promInterval( + async () => { + if (this.wsRefreshFlag) { + try { + if (this.wsClient) { + await this.wsClient.getHost() + await this.wsClient.closeConnection() + await helpers.sleep(250) + await this.wsClient.login() } + } catch (err) { + this.log.warn(this.debug ? err : err.message) } - }, 1800000, { stopOnError: false } - ) - this.log("eWeLink sync complete. Don't forget to ⭐ī¸ this plugin on GitHub if you're finding it useful!") - if (this.config.debugReqRes) { - this.log.warn("Note: 'Request & Response Logging' is not advised for long-term use.") - } - })() + } + }, 1800000, { stopOnError: false } + ) + this.log("eWeLink sync complete. Don't forget to ⭐ī¸ this plugin on GitHub if you're finding it useful!") + if (this.config.debugReqRes) { + this.log.warn("Note: 'Request & Response Logging' is not advised for long-term use.") + } } catch (err) { this.log.error('************* Cannot load homebridge-ewelink *************') this.log.error(this.debug ? err : err.message) From ffbea0b650b84ff7a38dbd21e19c79d6dcb71b50 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 24 Oct 2020 10:39:34 +0100 Subject: [PATCH 0542/3183] formatting --- lib/helpers.js | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/lib/helpers.js b/lib/helpers.js index d9f99bd4..cafb56f6 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -44,22 +44,23 @@ module.exports = { 'switches', 'temperature', 'trigTime', 'type', 'voltage', 'zyx_mode' ], - defaultMultiSwitchOff: [{ - switch: 'off', - outlet: 0 - }, - { - switch: 'off', - outlet: 1 - }, - { - switch: 'off', - outlet: 2 - }, - { - switch: 'off', - outlet: 3 - } + defaultMultiSwitchOff: [ + { + switch: 'off', + outlet: 0 + }, + { + switch: 'off', + outlet: 1 + }, + { + switch: 'off', + outlet: 2 + }, + { + switch: 'off', + outlet: 3 + } ], defaultCurtainCache: { cacheCurrentPosition: 0 From 6e42b8e7df9fca41711128d61dd83c6fa892f16e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 24 Oct 2020 10:39:48 +0100 Subject: [PATCH 0543/3183] remove as not used --- lib/helpers.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/helpers.js b/lib/helpers.js index cafb56f6..1da12b5b 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -8,7 +8,6 @@ module.exports = { appSecret: '6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM', httpRetryCodes: ['ENOTFOUND', 'ETIMEDOUT', 'EAI_AGAIN'], allowedGroups: ['blind', 'garage', 'garage_two', 'garage_four', 'garage_eachen', 'lock', 'valve'], - devicesHideable: ['switch', 'light'], devicesNonLAN: [22, 28, 34, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], From 0b53d1d851e4af6fe4e3096281516f2637d760cd Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 24 Oct 2020 16:07:34 +0100 Subject: [PATCH 0544/3183] eve characteristics --- lib/device/outlet.js | 80 ++++++++++++++--- package-lock.json | 208 ------------------------------------------- package.json | 1 - 3 files changed, 67 insertions(+), 222 deletions(-) diff --git a/lib/device/outlet.js b/lib/device/outlet.js index 1493ddd4..4dfce9f8 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -3,15 +3,69 @@ 'use strict' const corrInterval = require('correcting-interval') const fakegato = require('fakegato-history') -const hbLib = require('homebridge-lib') const helpers = require('./../helpers') +const util = require('util') module.exports = class deviceOutlet { constructor (platform, accessory) { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic - this.EveCharacteristics = new hbLib.EveHomeKitTypes(platform.api).Characteristics this.EveHistoryService = fakegato(platform.api) + const self = this + this.eveCurrentConsumption = function () { + self.Characteristic.call(this, 'Current Consumption', 'E863F10D-079E-48FF-8F27-9C2605A29F52') + this.setProps({ + format: self.Characteristic.Formats.FLOAT, + unit: 'W', + perms: [self.Characteristic.Perms.READ, self.Characteristic.Perms.NOTIFY] + }) + this.value = this.getDefaultValue() + } + this.eveTotalConsumption = function () { + self.Characteristic.call(this, 'Total Consumption', 'E863F10C-079E-48FF-8F27-9C2605A29F52') + this.setProps({ + format: self.Characteristic.Formats.FLOAT, + unit: 'kWh', + perms: [self.Characteristic.Perms.READ, self.Characteristic.Perms.NOTIFY] + }) + this.value = this.getDefaultValue() + } + this.eveVoltage = function () { + self.Characteristic.call(this, 'Voltage', 'E863F10A-079E-48FF-8F27-9C2605A29F52') + this.setProps({ + format: self.Characteristic.Formats.FLOAT, + unit: 'V', + perms: [self.Characteristic.Perms.READ, self.Characteristic.Perms.NOTIFY] + }) + this.value = this.getDefaultValue() + } + this.eveElectricCurrent = function () { + self.Characteristic.call(this, 'Electric Current', 'E863F126-079E-48FF-8F27-9C2605A29F52') + this.setProps({ + format: self.Characteristic.Formats.FLOAT, + unit: 'A', + perms: [self.Characteristic.Perms.READ, self.Characteristic.Perms.NOTIFY] + }) + this.value = this.getDefaultValue() + } + this.eveResetTotal = function () { + self.Characteristic.call(this, 'Reset Total', 'E863F112-079E-48FF-8F27-9C2605A29F52') + this.setProps({ + format: self.Characteristic.Formats.UINT32, + perms: [self.Characteristic.Perms.READ, self.Characteristic.Perms.NOTIFY, self.Characteristic.Perms.WRITE] + }) + this.value = this.getDefaultValue() + } + util.inherits(this.eveCurrentConsumption, this.Characteristic) + util.inherits(this.eveTotalConsumption, this.Characteristic) + util.inherits(this.eveVoltage, this.Characteristic) + util.inherits(this.eveElectricCurrent, this.Characteristic) + util.inherits(this.eveResetTotal, this.Characteristic) + this.eveCurrentConsumption.UUID = 'E863F10D-079E-48FF-8F27-9C2605A29F52' + this.eveTotalConsumption.UUID = 'E863F10C-079E-48FF-8F27-9C2605A29F52' + this.eveVoltage.UUID = 'E863F10A-079E-48FF-8F27-9C2605A29F52' + this.eveElectricCurrent.UUID = 'E863F126-079E-48FF-8F27-9C2605A29F52' + this.eveResetTotal.UUID = 'E863F112-079E-48FF-8F27-9C2605A29F52' if (accessory.getService(this.Service.Switch)) { accessory.removeService(accessory.getService(this.Service.Switch)) } @@ -20,11 +74,11 @@ module.exports = class deviceOutlet { accessory.addService(this.Service.Outlet) outletService = accessory.getService(this.Service.Outlet) if (!helpers.devicesSingleSwitchOutlet.includes(accessory.context.eweModel) && !this.platform.config.disableEveLogging) { - outletService.addCharacteristic(this.EveCharacteristics.Voltage) - outletService.addCharacteristic(this.EveCharacteristics.CurrentConsumption) - outletService.addCharacteristic(this.EveCharacteristics.ElectricCurrent) - outletService.addCharacteristic(this.EveCharacteristics.TotalConsumption) - outletService.addCharacteristic(this.EveCharacteristics.ResetTotal) + outletService.addCharacteristic(this.eveVoltage) + outletService.addCharacteristic(this.eveCurrentConsumption) + outletService.addCharacteristic(this.eveElectricCurrent) + outletService.addCharacteristic(this.eveTotalConsumption) + outletService.addCharacteristic(this.eveResetTotal) accessory.context = { ...accessory.context, ...{ @@ -49,7 +103,7 @@ module.exports = class deviceOutlet { corrInterval.setCorrectingInterval(() => { const isOn = outletService.getCharacteristic(this.Characteristic.On).value const currentWatt = isOn - ? outletService.getCharacteristic(this.EveCharacteristics.CurrentConsumption).value + ? outletService.getCharacteristic(this.eveCurrentConsumption).value : 0 if (accessory.eveLogger.isHistoryLoaded()) { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() @@ -80,7 +134,7 @@ module.exports = class deviceOutlet { }) }, 600000) outletService - .getCharacteristic(this.EveCharacteristics.TotalConsumption) + .getCharacteristic(this.eveTotalConsumption) .on('get', callback => { accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() if (accessory.context.extraPersistedData !== undefined) { @@ -89,7 +143,7 @@ module.exports = class deviceOutlet { callback(null, accessory.context.totalEnergy) }) outletService - .getCharacteristic(this.EveCharacteristics.ResetTotal) + .getCharacteristic(this.eveResetTotal) .on('set', (value, callback) => { accessory.context.totalEnergy = 0 accessory.context.lastReset = value @@ -130,7 +184,7 @@ module.exports = class deviceOutlet { } } if (helpers.hasProperty(params, 'power')) { - outletService.updateCharacteristic(this.EveCharacteristics.CurrentConsumption, parseFloat(params.power)) + outletService.updateCharacteristic(this.eveCurrentConsumption, parseFloat(params.power)) if (!helpers.devicesSingleSwitchOutlet.includes(this.accessory.context.eweModel) && !this.platform.config.disableEveLogging) { outletService.updateCharacteristic( this.Characteristic.OutletInUse, @@ -144,10 +198,10 @@ module.exports = class deviceOutlet { } } if (helpers.hasProperty(params, 'voltage')) { - outletService.updateCharacteristic(this.EveCharacteristics.Voltage, parseFloat(params.voltage)) + outletService.updateCharacteristic(this.eveVoltage, parseFloat(params.voltage)) } if (helpers.hasProperty(params, 'current')) { - outletService.updateCharacteristic(this.EveCharacteristics.ElectricCurrent, parseFloat(params.current)) + outletService.updateCharacteristic(this.eveElectricCurrent, parseFloat(params.current)) } } catch (err) { this.platform.deviceUpdateError(this.accessory, err, false) diff --git a/package-lock.json b/package-lock.json index 4ac4d924..bfa79b88 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,19 +35,6 @@ } } }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" - }, "arrify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", @@ -71,38 +58,11 @@ "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" }, - "bonjour": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", - "requires": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" - } - }, "buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" }, - "buffer-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, "chnl": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/chnl/-/chnl-1.2.0.tgz", @@ -134,19 +94,6 @@ "ms": "2.0.0" } }, - "deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - } - }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -155,28 +102,6 @@ "object-keys": "^1.0.12" } }, - "dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" - }, - "dns-packet": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", - "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", - "requires": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", - "requires": { - "buffer-indexof": "^1.0.0" - } - }, "ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -334,42 +259,11 @@ "function-bind": "^1.1.1" } }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, "has-symbols": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" }, - "homebridge-lib": { - "version": "4.7.16", - "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-4.7.16.tgz", - "integrity": "sha512-+MYkMUUjP7mPdGT9fJU6ifjvg1SinCUlmdrzjPQZaoe119EN28d0bQSr1jpaVjWW1bqVo+KJT+ap5vnfAgFp1g==", - "requires": { - "bonjour": "^3.5.0", - "chalk": "^4.1.0", - "debug": "^4.2.0", - "semver": "^7.3.2" - }, - "dependencies": { - "debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, "https-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", @@ -399,16 +293,6 @@ "resolved": "https://registry.npmjs.org/interval-promise/-/interval-promise-1.4.0.tgz", "integrity": "sha512-PUwEmGqUglJhb6M01JNvMDvxr4DA8FCeYoYCLHPEcBBZiq/8yOpCchfs1VJui7fXj69l170gAxzF1FeSA0nSlg==" }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" - }, - "is-arguments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", - "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==" - }, "is-callable": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.1.tgz", @@ -419,11 +303,6 @@ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" }, - "is-negative-zero": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", - "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=" - }, "is-regex": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", @@ -495,20 +374,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "multicast-dns": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", - "requires": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" - } - }, - "multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" - }, "node-dns-sd": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/node-dns-sd/-/node-dns-sd-0.4.2.tgz", @@ -529,52 +394,6 @@ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==" }, - "object-is": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.3.tgz", - "integrity": "sha512-teyqLvFWzLkq5B9ki8FVWA902UER2qkxmdA4nLf+wjOLAWgxzCWZNCxpDq9MvE8MmhWNr+I8w3BN49Vx36Y6Xg==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - }, - "is-callable": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", - "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==" - }, - "object.assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", - "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.0", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - } - } - }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -611,25 +430,11 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" }, - "regexp.prototype.flags": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", - "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" - }, "string.prototype.trimend": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", @@ -648,19 +453,6 @@ "es-abstract": "^1.17.5" } }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - }, - "thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" - }, "url-template": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", diff --git a/package.json b/package.json index 0d98836b..289853a6 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,6 @@ "color-convert": "2.0.1", "correcting-interval": "2.0.0", "fakegato-history": "0.5.6", - "homebridge-lib": "4.7.16", "interval-promise": "1.4.0", "node-dns-sd": "0.4.2", "websocket-as-promised": "1.1.0", From 2a536bcdbe59cf435371033ac4a2c6fb5be726bf Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 24 Oct 2020 16:57:44 +0100 Subject: [PATCH 0545/3183] 3.8.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index bfa79b88..c630ad00 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.8.1", + "version": "3.8.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 289853a6..f6e2722c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.8.1", + "version": "3.8.2", "author": "bwp91", "contributors": [ "gbro115", From 78c069eb6285e9be486c04e8f0e5617403ca4619 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 25 Oct 2020 12:33:45 +0000 Subject: [PATCH 0546/3183] clarity for enabled/disabled --- config.schema.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/config.schema.json b/config.schema.json index 7c03af88..3da13469 100644 --- a/config.schema.json +++ b/config.schema.json @@ -32,13 +32,13 @@ "debug": { "title": "Debug Logging", "type": "boolean", - "description": "If enabled, more information will be added to the Homebridge log.", + "description": "If checked, more information will be added to the Homebridge log.", "default": false }, "debugReqRes": { "title": "Request & Response Logging", "type": "boolean", - "description": "If enabled, HTTP, web socket and LAN mode messages will be added to the log. Not recommended for long-term use.", + "description": "If checked, HTTP, web socket and LAN mode messages will be added to the log. Not recommended for long-term use.", "default": false }, "hideDevFromHB": { @@ -54,13 +54,13 @@ "disableHTTPRefresh": { "type": "boolean", "title": "Disable Initial Device Refresh", - "description": "If enabled, devices will not be refreshed with their most recent status from eWeLink when Homebridge starts. This setting can be useful for users who block their devices from accessing the internet.", + "description": "If checked, devices will not be refreshed with their most recent status from eWeLink when Homebridge starts. This setting can be useful for users who block their devices from accessing the internet.", "default": false }, "disableEveLogging": { "type": "boolean", "title": "Disable Eve Logging", - "description": "If enabled, switch, thermostat and power readings will not be logged to the Eve App.", + "description": "If checked, switch, thermostat and power readings will not be logged to the Eve App.", "default": false }, "inUsePowerThreshold": { @@ -72,9 +72,9 @@ "maximum": 100 }, "hideTHSwitch": { - "title": "TH10/TH16 Hide Switch", + "title": "Hide TH10/TH16 Switch", "type": "boolean", - "description": "If enabled, the switch for the TH10/TH16 devices will be hidden from Homebridge.", + "description": "If checked, the switch for the TH10/TH16 devices will be hidden from Homebridge.", "default": false }, "hideLightFromFan": { @@ -109,7 +109,7 @@ "hideZBLDPress": { "title": "Zigbee Button Hide Double/Long Press", "type": "boolean", - "description": "If enabled, double and long press options will be hidden for the ZigBee button.", + "description": "If checked, double and long press options will be hidden for the ZigBee button.", "default": false }, "nameOverride": { From 478a0c0cb8b04ab25846f1228bd22ca4e5ea0212 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 25 Oct 2020 12:36:27 +0000 Subject: [PATCH 0547/3183] reorder setup steps --- lib/ewelink-platform.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 250dc4d5..0758509b 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -71,9 +71,9 @@ module.exports = class eWeLinkPlatform { const deviceList = await this.httpClient.getDevices() deviceList.forEach(device => this.devicesInEW.set(device.deviceid, device)) this.wsClient = new eWeLinkWS(this.config, this.log, this.authData) - this.lanClient = new eWeLinkLAN(this.config, this.log, deviceList) await this.wsClient.getHost() this.wsClient.login() + this.lanClient = new eWeLinkLAN(this.config, this.log, deviceList) this.lanDevices = await this.lanClient.getHosts() await this.lanClient.startMonitor() if (Object.keys(this.config.groups || []).length > 0) { From 274db96e36ecff7618d0b7a4fcb12a484261e74a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 25 Oct 2020 17:53:09 +0000 Subject: [PATCH 0548/3183] rf bridge more than 9 devs fix --- lib/ewelink-platform.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 0758509b..3126f23b 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -496,7 +496,7 @@ module.exports = class eWeLinkPlatform { } addAccessory (device, hbDeviceId, hidden = false, extraContext = {}, type = '') { - const switchNumber = hbDeviceId.substr(-1).toString() + const switchNumber = hbDeviceId.split('SW')[1].toString() let newDeviceName = type === 'rf_sub' ? device.tags.zyx_info[switchNumber - 1].name : device.name const channelCount = type === 'rf_pri' From f08009dbd3a275fef1a5bb880797d512712c10d5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 25 Oct 2020 17:56:45 +0000 Subject: [PATCH 0549/3183] 3.8.3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index c630ad00..73f36f6d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.8.2", + "version": "3.8.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f6e2722c..6cdd8bd4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.8.2", + "version": "3.8.3", "author": "bwp91", "contributors": [ "gbro115", From 5f02e5b1e8c319800ee1109d40c2ed1b4b32de5e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 26 Oct 2020 06:17:19 +0000 Subject: [PATCH 0550/3183] fix for if chan > 9 --- lib/device/rf-bridge.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index 1ab23e68..dc5b11fa 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -125,7 +125,7 @@ module.exports = class deviceRFBridge { if ( acc.context.eweDeviceId === this.accessory.context.eweDeviceId && helpers.hasProperty(acc.context, 'buttons') && - helpers.hasProperty(acc.context.buttons, chan.substr(-1).toString()) + helpers.hasProperty(acc.context.buttons, chan.split('g')[1].toString()) ) { oAccessory = acc } From 4a8170a68c750eabdf9976bce4d56800b02b5d9a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 26 Oct 2020 06:18:01 +0000 Subject: [PATCH 0551/3183] 3.8.4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 73f36f6d..d0282a10 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.8.3", + "version": "3.8.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 6cdd8bd4..5e588068 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.8.3", + "version": "3.8.4", "author": "bwp91", "contributors": [ "gbro115", From f6077fc0be6dcf656197a9814e68d9ba510aa254 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 27 Oct 2020 10:02:23 +0000 Subject: [PATCH 0552/3183] parse config option --- lib/device/outlet.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/device/outlet.js b/lib/device/outlet.js index 4dfce9f8..c444c782 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -11,6 +11,12 @@ module.exports = class deviceOutlet { this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic this.EveHistoryService = fakegato(platform.api) + this.inUsePowerThreshold = parseInt(this.platform.config.inUsePowerThreshold) + this.inUsePowerThreshold = isNaN(this.inUsePowerThreshold) + ? helpers.defaults.inUsePowerThreshold + : this.inUsePowerThreshold < 0 + ? helpers.defaults.inUsePowerThreshold + : this.inUsePowerThreshold const self = this this.eveCurrentConsumption = function () { self.Characteristic.call(this, 'Current Consumption', 'E863F10D-079E-48FF-8F27-9C2605A29F52') @@ -188,7 +194,7 @@ module.exports = class deviceOutlet { if (!helpers.devicesSingleSwitchOutlet.includes(this.accessory.context.eweModel) && !this.platform.config.disableEveLogging) { outletService.updateCharacteristic( this.Characteristic.OutletInUse, - parseFloat(params.power) > (this.platform.config.inUsePowerThreshold || 0) + parseFloat(params.power) > (this.inUsePowerThreshold) ) const isOn = this.accessory.getService(this.Service.Outlet).getCharacteristic(this.Characteristic.On).value this.accessory.eveLogger.addEntry({ From 310cd24100586fee29f27ee000e56b91213acc0c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 27 Oct 2020 10:09:36 +0000 Subject: [PATCH 0553/3183] parse config option --- lib/device/sensor.js | 8 +++++++- lib/device/zb-dev.js | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/device/sensor.js b/lib/device/sensor.js index 47f5ad7d..c7e81ce3 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -10,6 +10,12 @@ module.exports = class deviceSensor { this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic this.EveHistoryService = fakegato(platform.api) + this.lowBattThreshold = parseInt(this.platform.config.lowBattThreshold) + this.lowBattThreshold = isNaN(this.lowBattThreshold) + ? helpers.defaults.lowBattThreshold + : this.lowBattThreshold < 5 + ? helpers.defaults.lowBattThreshold + : this.lowBattThreshold const contactService = accessory.getService(this.Service.ContactSensor) || accessory.addService(this.Service.ContactSensor) if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) if (!this.platform.config.disableEveLogging) { @@ -39,7 +45,7 @@ module.exports = class deviceSensor { batteryService.updateCharacteristic(this.Characteristic.BatteryLevel, scaledBattery) batteryService.updateCharacteristic( this.Characteristic.StatusLowBattery, - scaledBattery < (this.platform.config.lowBattThreshold || 25) + scaledBattery < this.lowBattThreshold ) } if (!helpers.hasProperty(params, 'switch')) return diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index a496bf84..d993a656 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -10,6 +10,12 @@ module.exports = class deviceZBDev { this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic this.EveHistoryService = fakegato(platform.api) + this.lowBattThreshold = parseInt(this.platform.config.lowBattThreshold) + this.lowBattThreshold = isNaN(this.lowBattThreshold) + ? helpers.defaults.lowBattThreshold + : this.lowBattThreshold < 5 + ? helpers.defaults.lowBattThreshold + : this.lowBattThreshold if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) switch (accessory.context.eweUIID) { case 1000: { @@ -100,7 +106,7 @@ module.exports = class deviceZBDev { batteryService.updateCharacteristic(this.Characteristic.BatteryLevel, params.battery) batteryService.updateCharacteristic( this.Characteristic.StatusLowBattery, - params.battery < (this.platform.config.lowBattThreshold || 25) + params.battery < this.lowBattThreshold ) } switch (this.accessory.context.eweUIID) { From 1732a897b2f46cfb0d3ec561d8f8f065965fd877 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 27 Oct 2020 10:16:37 +0000 Subject: [PATCH 0554/3183] reset rf bridge option --- lib/ewelink-platform.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 3126f23b..8d4f60c3 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -373,6 +373,12 @@ module.exports = class eWeLinkPlatform { /********************* RF BRIDGE + SUBDEVICES *********************/ + if (this.config.resetRFBridge) { + this.devicesInHB + .filter(a => helpers.hasProperty(a, 'context') && a.context.eweDeviceId === device.deviceId) + .foreach(a => this.removeAccessory(a)) + this.log.warn('[%s] has been reset.', device.name) + } let rfChlCounter = 0 const rfMap = [] if (helpers.hasProperty(device, 'tags') && helpers.hasProperty(device.tags, 'zyx_info')) { From a689feb738db9935b5a670971e5bfad4528c14ab Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 27 Oct 2020 10:18:00 +0000 Subject: [PATCH 0555/3183] parse config option --- lib/device/rf-bridge.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index dc5b11fa..4831d994 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -10,6 +10,12 @@ module.exports = class deviceRFBridge { this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic this.EveHistoryService = fakegato(platform.api) + this.sensorTimeLength = parseInt(this.platform.config.sensorTimeLength) + this.sensorTimeLength = isNaN(this.sensorTimeLength) + ? helpers.defaults.sensorTimeLength + : this.sensorTimeLength < 0 + ? helpers.defaults.sensorTimeLength + : this.sensorTimeLength switch (accessory.context.subType) { case 'water': if (!accessory.getService(this.Service.LeakSensor)) accessory.addService(this.Service.LeakSensor) @@ -180,7 +186,7 @@ module.exports = class deviceRFBridge { } oAccessory.eveLogger.addEntry(eveLog) } - await helpers.sleep((this.platform.config.sensorTimeLength || 2) * 1000) + await helpers.sleep(this.sensorTimeLength * 1000) oAccessory.getService(serv).updateCharacteristic(char, 0) if (!this.platform.config.disableEveLogging && eveLog) { const eveLog = { From 17d7657ac6e0102453a707020912605f0d567d4c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 27 Oct 2020 10:22:03 +0000 Subject: [PATCH 0556/3183] parse config option --- lib/device/rf-bridge.js | 14 ++++++++++---- lib/device/zb-dev.js | 14 ++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index 4831d994..d5ed292d 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -12,10 +12,16 @@ module.exports = class deviceRFBridge { this.EveHistoryService = fakegato(platform.api) this.sensorTimeLength = parseInt(this.platform.config.sensorTimeLength) this.sensorTimeLength = isNaN(this.sensorTimeLength) - ? helpers.defaults.sensorTimeLength - : this.sensorTimeLength < 0 ? helpers.defaults.sensorTimeLength - : this.sensorTimeLength + : this.sensorTimeLength < 0 + ? helpers.defaults.sensorTimeLength + : this.sensorTimeLength + this.sensorTimeDifference = parseInt(this.platform.config.sensorTimeDifference) + this.sensorTimeDifference = isNaN(this.sensorTimeDifference) + ? helpers.defaults.sensorTimeDifference + : this.sensorTimeDifference < 10 + ? helpers.defaults.sensorTimeDifference + : this.sensorTimeDifference switch (accessory.context.subType) { case 'water': if (!accessory.getService(this.Service.LeakSensor)) accessory.addService(this.Service.LeakSensor) @@ -142,7 +148,7 @@ module.exports = class deviceRFBridge { let serv let char let eveLog = false - if (diff < (this.platform.config.sensorTimeDifference || 120)) { + if (diff < this.sensorTimeDifference) { switch (oAccessory.context.subType) { case 'button': return diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index d993a656..74dec0ce 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -12,10 +12,16 @@ module.exports = class deviceZBDev { this.EveHistoryService = fakegato(platform.api) this.lowBattThreshold = parseInt(this.platform.config.lowBattThreshold) this.lowBattThreshold = isNaN(this.lowBattThreshold) - ? helpers.defaults.lowBattThreshold - : this.lowBattThreshold < 5 ? helpers.defaults.lowBattThreshold - : this.lowBattThreshold + : this.lowBattThreshold < 5 + ? helpers.defaults.lowBattThreshold + : this.lowBattThreshold + this.sensorTimeDifference = parseInt(this.platform.config.sensorTimeDifference) + this.sensorTimeDifference = isNaN(this.sensorTimeDifference) + ? helpers.defaults.sensorTimeDifference + : this.sensorTimeDifference < 10 + ? helpers.defaults.sensorTimeDifference + : this.sensorTimeDifference if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) switch (accessory.context.eweUIID) { case 1000: { @@ -148,7 +154,7 @@ module.exports = class deviceZBDev { const motionDetected = helpers.hasProperty(params, 'updateSource') && params.motion === 1 && - diff < (this.platform.config.sensorTimeDifference || 120) + diff < this.sensorTimeDifference if (!this.platform.config.disableEveLogging) { const eveLog = { time: Date.now(), From 21226e55406239ae12d527941d1cffa10f59b8db Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 27 Oct 2020 10:22:10 +0000 Subject: [PATCH 0557/3183] formatting --- lib/device/outlet.js | 6 +++--- lib/device/sensor.js | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/device/outlet.js b/lib/device/outlet.js index c444c782..5a794b14 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -13,10 +13,10 @@ module.exports = class deviceOutlet { this.EveHistoryService = fakegato(platform.api) this.inUsePowerThreshold = parseInt(this.platform.config.inUsePowerThreshold) this.inUsePowerThreshold = isNaN(this.inUsePowerThreshold) - ? helpers.defaults.inUsePowerThreshold - : this.inUsePowerThreshold < 0 ? helpers.defaults.inUsePowerThreshold - : this.inUsePowerThreshold + : this.inUsePowerThreshold < 0 + ? helpers.defaults.inUsePowerThreshold + : this.inUsePowerThreshold const self = this this.eveCurrentConsumption = function () { self.Characteristic.call(this, 'Current Consumption', 'E863F10D-079E-48FF-8F27-9C2605A29F52') diff --git a/lib/device/sensor.js b/lib/device/sensor.js index c7e81ce3..df9a30f5 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -12,10 +12,10 @@ module.exports = class deviceSensor { this.EveHistoryService = fakegato(platform.api) this.lowBattThreshold = parseInt(this.platform.config.lowBattThreshold) this.lowBattThreshold = isNaN(this.lowBattThreshold) - ? helpers.defaults.lowBattThreshold - : this.lowBattThreshold < 5 ? helpers.defaults.lowBattThreshold - : this.lowBattThreshold + : this.lowBattThreshold < 5 + ? helpers.defaults.lowBattThreshold + : this.lowBattThreshold const contactService = accessory.getService(this.Service.ContactSensor) || accessory.addService(this.Service.ContactSensor) if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) if (!this.platform.config.disableEveLogging) { From d54ebf9ded193c0f2936503c904351a485d2568a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 27 Oct 2020 10:23:29 +0000 Subject: [PATCH 0558/3183] add sensortimelength per rf device --- config.schema.json | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/config.schema.json b/config.schema.json index 3da13469..e11d61bf 100644 --- a/config.schema.json +++ b/config.schema.json @@ -96,7 +96,7 @@ "description": "The number of seconds which the sensor tile in the Home app will light up for if a sensor detects something. This setting applies to sensors connected to RF/Zigbee Bridges.", "default": 60, "minimum": 1, - "maximum": 120 + "maximum": 300 }, "sensorTimeDifference": { "type": "integer", @@ -310,6 +310,14 @@ ] } ] + }, + "sensorTimeLength": { + "type": "integer", + "title": "Sensor Time Length", + "description": "The number of seconds which the sensor tile in the Home app will light up for if this sensor detects something. This setting will override the global time length set abov for this sensor.", + "default": 60, + "minimum": 1, + "maximum": 300 } } } @@ -387,7 +395,8 @@ "items": [ "bridgeSensors[].deviceId", "bridgeSensors[].fullDeviceId", - "bridgeSensors[].type" + "bridgeSensors[].type", + "bridgeSensors[].sensorTimeLength" ] } ] From 5689027ba5da01025aaf628bf675a9d4480708a8 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 27 Oct 2020 10:23:38 +0000 Subject: [PATCH 0559/3183] add defaults to helpers --- lib/helpers.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/helpers.js b/lib/helpers.js index 1da12b5b..8a526f14 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -8,6 +8,13 @@ module.exports = { appSecret: '6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM', httpRetryCodes: ['ENOTFOUND', 'ETIMEDOUT', 'EAI_AGAIN'], allowedGroups: ['blind', 'garage', 'garage_two', 'garage_four', 'garage_eachen', 'lock', 'valve'], + defaults: { + inUsePowerThreshold: 0, + lowBattThreshold: 25, + sensorTimeLength: 60, + sensorTimeDifference: 120 + }, + sensorTimeLength: 2, devicesNonLAN: [22, 28, 34, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], From 2911a176f56f020d6e453fe992dc173b8cc30bda Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 27 Oct 2020 10:54:05 +0000 Subject: [PATCH 0560/3183] add custom sensortimelength to context --- lib/ewelink-platform.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 8d4f60c3..75a3b85c 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -400,6 +400,7 @@ module.exports = class eWeLinkPlatform { rfMap.forEach(subDevice => { const swNumber = rfChlCounter + 1 let subType + let sensorTimeLength let subExtraContext = {} if (['1', '2', '3', '4'].includes(subDevice.type)) { subType = 'button' @@ -407,13 +408,19 @@ module.exports = class eWeLinkPlatform { subType = this.cusS.has(device.deviceid + 'SW' + swNumber) ? this.cusS.get(device.deviceid + 'SW' + swNumber).type : 'motion' + if (this.cusS.has(device.deviceid + 'SW' + swNumber)) { + sensorTimeLength = helpers.hasProperty(this.cusS.get(device.deviceid + 'SW' + swNumber), 'sensorTimeLength') + ? this.cusS.get(device.deviceid + 'SW' + swNumber).sensorTimeLength + : undefined + } } else { return } subExtraContext = { buttons: subDevice.buttons, subType, - swNumber + swNumber, + sensorTimeLength } if ((oAccessory = this.devicesInHB.get(device.deviceid + 'SW' + swNumber))) { if (oAccessory.context.subType !== subType || oAccessory.context.swNumber !== swNumber) { From 127c2d2de43322d546931a5cf738757f3e5da26c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 27 Oct 2020 10:54:23 +0000 Subject: [PATCH 0561/3183] use context sensorTimeLength if exists --- lib/device/rf-bridge.js | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index d5ed292d..acd3125a 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -10,12 +10,28 @@ module.exports = class deviceRFBridge { this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic this.EveHistoryService = fakegato(platform.api) - this.sensorTimeLength = parseInt(this.platform.config.sensorTimeLength) - this.sensorTimeLength = isNaN(this.sensorTimeLength) - ? helpers.defaults.sensorTimeLength - : this.sensorTimeLength < 0 + this.sensorTimeLengthPri = parseInt(accessory.context.sensorTimeLength) + this.sensorTimeLengthSec = parseInt(this.platform.config.sensorTimeLength) + this.sensorTimeLength = isNaN(this.sensorTimeLengthPri) + ? isNaN(this.sensorTimeLengthSec) ? helpers.defaults.sensorTimeLength - : this.sensorTimeLength + : this.sensorTimeLengthSec < 0 + ? helpers.defaults.sensorTimeLength + : this.sensorTimeLengthSec + : this.sensorTimeLengthPri < 0 + ? isNaN(this.sensorTimeLengthSec) + ? helpers.defaults.sensorTimeLength + : this.sensorTimeLengthSec < 0 + ? helpers.defaults.sensorTimeLength + : this.sensorTimeLengthSec + : this.sensorTimeLengthPri + if (helpers.hasProperty(accessory.context, 'sensorTimeDifference')) { + this.sensorTimeLength = isNaN(this.sensorTimeLength) + ? helpers.defaults.sensorTimeLength + : this.sensorTimeLength < 0 + ? helpers.defaults.sensorTimeLength + : this.sensorTimeLength + } this.sensorTimeDifference = parseInt(this.platform.config.sensorTimeDifference) this.sensorTimeDifference = isNaN(this.sensorTimeDifference) ? helpers.defaults.sensorTimeDifference From 4598412d304541a460eed0756d6d5a555b5ac03e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 27 Oct 2020 10:57:18 +0000 Subject: [PATCH 0562/3183] typo --- config.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.schema.json b/config.schema.json index e11d61bf..fb680d43 100644 --- a/config.schema.json +++ b/config.schema.json @@ -314,7 +314,7 @@ "sensorTimeLength": { "type": "integer", "title": "Sensor Time Length", - "description": "The number of seconds which the sensor tile in the Home app will light up for if this sensor detects something. This setting will override the global time length set abov for this sensor.", + "description": "The number of seconds which the sensor tile in the Home app will light up for if this sensor detects something. This setting will override the global time length set above for this sensor.", "default": 60, "minimum": 1, "maximum": 300 From df9435dd9277108ec72d3254e416c3ace203153f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 27 Oct 2020 12:07:32 +0000 Subject: [PATCH 0563/3183] add custom time per rf sensor --- lib/device/rf-bridge.js | 42 ++++++++++++++++++----------------------- lib/ewelink-platform.js | 11 ++--------- lib/helpers.js | 1 - 3 files changed, 20 insertions(+), 34 deletions(-) diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index acd3125a..cdf173b7 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -10,28 +10,6 @@ module.exports = class deviceRFBridge { this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic this.EveHistoryService = fakegato(platform.api) - this.sensorTimeLengthPri = parseInt(accessory.context.sensorTimeLength) - this.sensorTimeLengthSec = parseInt(this.platform.config.sensorTimeLength) - this.sensorTimeLength = isNaN(this.sensorTimeLengthPri) - ? isNaN(this.sensorTimeLengthSec) - ? helpers.defaults.sensorTimeLength - : this.sensorTimeLengthSec < 0 - ? helpers.defaults.sensorTimeLength - : this.sensorTimeLengthSec - : this.sensorTimeLengthPri < 0 - ? isNaN(this.sensorTimeLengthSec) - ? helpers.defaults.sensorTimeLength - : this.sensorTimeLengthSec < 0 - ? helpers.defaults.sensorTimeLength - : this.sensorTimeLengthSec - : this.sensorTimeLengthPri - if (helpers.hasProperty(accessory.context, 'sensorTimeDifference')) { - this.sensorTimeLength = isNaN(this.sensorTimeLength) - ? helpers.defaults.sensorTimeLength - : this.sensorTimeLength < 0 - ? helpers.defaults.sensorTimeLength - : this.sensorTimeLength - } this.sensorTimeDifference = parseInt(this.platform.config.sensorTimeDifference) this.sensorTimeDifference = isNaN(this.sensorTimeDifference) ? helpers.defaults.sensorTimeDifference @@ -159,6 +137,21 @@ module.exports = class deviceRFBridge { } }) if (oAccessory) { + const sensorTimeLengthPri = parseInt(oAccessory.context.sensorTimeLength) + const sensorTimeLengthSec = parseInt(this.platform.config.sensorTimeLength) + const sensorTimeLength = isNaN(sensorTimeLengthPri) + ? isNaN(sensorTimeLengthSec) + ? helpers.defaults.sensorTimeLength + : sensorTimeLengthSec < 0 + ? helpers.defaults.sensorTimeLength + : sensorTimeLengthSec + : sensorTimeLengthPri < 0 + ? isNaN(sensorTimeLengthSec) + ? helpers.defaults.sensorTimeLength + : sensorTimeLengthSec < 0 + ? helpers.defaults.sensorTimeLength + : sensorTimeLengthSec + : sensorTimeLengthPri const timeOfMotion = new Date(params[chan]) const diff = (timeNow.getTime() - timeOfMotion.getTime()) / 1000 let serv @@ -175,7 +168,7 @@ module.exports = class deviceRFBridge { case 'fire': case 'smoke': serv = this.Service.SmokeSensor - char = this.Characteristic.LeakDetected + char = this.Characteristic.SmokeDetected break case 'co': serv = this.Service.CarbonMonoxideSensor @@ -208,7 +201,8 @@ module.exports = class deviceRFBridge { } oAccessory.eveLogger.addEntry(eveLog) } - await helpers.sleep(this.sensorTimeLength * 1000) + await helpers.sleep(sensorTimeLength * 1000) + this.platform.log('awaiting %s seconds', sensorTimeLength) oAccessory.getService(serv).updateCharacteristic(char, 0) if (!this.platform.config.disableEveLogging && eveLog) { const eveLog = { diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 75a3b85c..1ed96dbe 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -373,12 +373,6 @@ module.exports = class eWeLinkPlatform { /********************* RF BRIDGE + SUBDEVICES *********************/ - if (this.config.resetRFBridge) { - this.devicesInHB - .filter(a => helpers.hasProperty(a, 'context') && a.context.eweDeviceId === device.deviceId) - .foreach(a => this.removeAccessory(a)) - this.log.warn('[%s] has been reset.', device.name) - } let rfChlCounter = 0 const rfMap = [] if (helpers.hasProperty(device, 'tags') && helpers.hasProperty(device.tags, 'zyx_info')) { @@ -409,9 +403,7 @@ module.exports = class eWeLinkPlatform { ? this.cusS.get(device.deviceid + 'SW' + swNumber).type : 'motion' if (this.cusS.has(device.deviceid + 'SW' + swNumber)) { - sensorTimeLength = helpers.hasProperty(this.cusS.get(device.deviceid + 'SW' + swNumber), 'sensorTimeLength') - ? this.cusS.get(device.deviceid + 'SW' + swNumber).sensorTimeLength - : undefined + sensorTimeLength = this.cusS.get(device.deviceid + 'SW' + swNumber).sensorTimeLength } } else { return @@ -427,6 +419,7 @@ module.exports = class eWeLinkPlatform { this.removeAccessory(oAccessory) } } + if (this.config.resetRFBridge) this.removeAccessory(oAccessory) oAccessory = this.devicesInHB.has(device.deviceid + 'SW' + swNumber) ? this.devicesInHB.get(device.deviceid + 'SW' + swNumber) : this.addAccessory(device, device.deviceid + 'SW' + swNumber, false, subExtraContext, 'rf_sub') diff --git a/lib/helpers.js b/lib/helpers.js index 8a526f14..cca771bb 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -14,7 +14,6 @@ module.exports = { sensorTimeLength: 60, sensorTimeDifference: 120 }, - sensorTimeLength: 2, devicesNonLAN: [22, 28, 34, 59, 102], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], From ecf0ba81ede12d27280b981d13ea28b5e9598b37 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 27 Oct 2020 12:17:41 +0000 Subject: [PATCH 0564/3183] tidying up --- lib/device/rf-bridge.js | 1 - lib/ewelink-platform.js | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index cdf173b7..5087ecab 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -202,7 +202,6 @@ module.exports = class deviceRFBridge { oAccessory.eveLogger.addEntry(eveLog) } await helpers.sleep(sensorTimeLength * 1000) - this.platform.log('awaiting %s seconds', sensorTimeLength) oAccessory.getService(serv).updateCharacteristic(char, 0) if (!this.platform.config.disableEveLogging && eveLog) { const eveLog = { diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 1ed96dbe..5f1e3d8f 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -414,12 +414,13 @@ module.exports = class eWeLinkPlatform { swNumber, sensorTimeLength } - if ((oAccessory = this.devicesInHB.get(device.deviceid + 'SW' + swNumber))) { + if (this.config.resetRFBridge) { + this.removeAccessory(oAccessory) + } else if ((oAccessory = this.devicesInHB.get(device.deviceid + 'SW' + swNumber))) { if (oAccessory.context.subType !== subType || oAccessory.context.swNumber !== swNumber) { this.removeAccessory(oAccessory) } } - if (this.config.resetRFBridge) this.removeAccessory(oAccessory) oAccessory = this.devicesInHB.has(device.deviceid + 'SW' + swNumber) ? this.devicesInHB.get(device.deviceid + 'SW' + swNumber) : this.addAccessory(device, device.deviceid + 'SW' + swNumber, false, subExtraContext, 'rf_sub') From 026559c8b55a5be2768f41d7c8dc8fd4dbb63229 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 27 Oct 2020 15:12:12 +0000 Subject: [PATCH 0565/3183] redundant brackets --- lib/device/outlet.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/outlet.js b/lib/device/outlet.js index 5a794b14..7de0d622 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -194,7 +194,7 @@ module.exports = class deviceOutlet { if (!helpers.devicesSingleSwitchOutlet.includes(this.accessory.context.eweModel) && !this.platform.config.disableEveLogging) { outletService.updateCharacteristic( this.Characteristic.OutletInUse, - parseFloat(params.power) > (this.inUsePowerThreshold) + parseFloat(params.power) > this.inUsePowerThreshold ) const isOn = this.accessory.getService(this.Service.Outlet).getCharacteristic(this.Characteristic.On).value this.accessory.eveLogger.addEntry({ From 92c3f48efaa15124b84d575071b45f986e2fc9aa Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 27 Oct 2020 15:12:28 +0000 Subject: [PATCH 0566/3183] tidy up of sensor time --- config.schema.json | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/config.schema.json b/config.schema.json index fb680d43..e1d1faf2 100644 --- a/config.schema.json +++ b/config.schema.json @@ -85,19 +85,11 @@ "lowBattThreshold": { "type": "integer", "title": "Low Battery Threshold", - "description": "Homebridge will set the low battery status for supported devices when the device battery reaches this pecentage level.", + "description": "Homebridge will set the low battery status for supported devices when the device battery reaches this percentage level.", "default": 25, "minimum": 5, "maximum": 50 }, - "sensorTimeLength": { - "type": "integer", - "title": "Sensor Length", - "description": "The number of seconds which the sensor tile in the Home app will light up for if a sensor detects something. This setting applies to sensors connected to RF/Zigbee Bridges.", - "default": 60, - "minimum": 1, - "maximum": 300 - }, "sensorTimeDifference": { "type": "integer", "title": "Sensor Lag", @@ -143,6 +135,9 @@ "disablePlugin": { "type": "boolean" }, + "sensorTimeLength": { + "type": "integer" + }, "groups": { "type": "array", "title": "Accessory Simulations", @@ -314,7 +309,7 @@ "sensorTimeLength": { "type": "integer", "title": "Sensor Time Length", - "description": "The number of seconds which the sensor tile in the Home app will light up for if this sensor detects something. This setting will override the global time length set above for this sensor.", + "description": "The number of seconds which the sensor tile in the Home app will light up for if this sensor is activated.", "default": 60, "minimum": 1, "maximum": 300 @@ -359,7 +354,6 @@ "inUsePowerThreshold", "hideTHSwitch", "lowBattThreshold", - "sensorTimeLength", "sensorTimeDifference", "hideZBLDPress" ] From 4f989acf9e9f3a536c9ca834daac657ff48f476f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 27 Oct 2020 15:21:44 +0000 Subject: [PATCH 0567/3183] re-add subdevice checks --- lib/ewelink-platform.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 5f1e3d8f..76e14214 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -414,10 +414,13 @@ module.exports = class eWeLinkPlatform { swNumber, sensorTimeLength } - if (this.config.resetRFBridge) { - this.removeAccessory(oAccessory) - } else if ((oAccessory = this.devicesInHB.get(device.deviceid + 'SW' + swNumber))) { - if (oAccessory.context.subType !== subType || oAccessory.context.swNumber !== swNumber) { + if ((oAccessory = this.devicesInHB.get(device.deviceid + 'SW' + swNumber))) { + if ( + this.config.resetRFBridge || + oAccessory.context.subType !== subType || + oAccessory.context.sensorTimeLength !== sensorTimeLength || + oAccessory.context.swNumber !== swNumber + ) { this.removeAccessory(oAccessory) } } From 48298d017a11739646299e53d306bd705952b7cd Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 27 Oct 2020 15:23:36 +0000 Subject: [PATCH 0568/3183] 3.9.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index d0282a10..3d792761 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.8.4", + "version": "3.9.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 5e588068..6d91501a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.8.4", + "version": "3.9.0", "author": "bwp91", "contributors": [ "gbro115", From e49d942e4812c0a647783ce6b8549529e710b9a9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 28 Oct 2020 10:09:33 +0000 Subject: [PATCH 0569/3183] remove unnecessary intervals --- lib/device/rf-bridge.js | 20 ++------------------ lib/device/sensor.js | 10 +--------- lib/device/thermostat.js | 13 +------------ lib/device/zb-dev.js | 31 +++---------------------------- 4 files changed, 7 insertions(+), 67 deletions(-) diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index 5087ecab..80f3f6ca 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -36,16 +36,8 @@ module.exports = class deviceRFBridge { accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('door', accessory, { storage: 'fs', - minutes: 10, path: this.platform.eveLogPath }) - corrInterval.setCorrectingInterval(() => { - const dataToAdd = { - time: Date.now(), - status: contactService.getCharacteristic(this.Characteristic.ContactSensorState).value - } - accessory.eveLogger.addEntry(dataToAdd) - }, 600000) } break } @@ -58,16 +50,8 @@ module.exports = class deviceRFBridge { accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('motion', accessory, { storage: 'fs', - minutes: 10, path: this.platform.eveLogPath }) - corrInterval.setCorrectingInterval(() => { - const dataToAdd = { - time: Date.now(), - status: motionService.getCharacteristic(this.Characteristic.MotionDetected).value ? 1 : 0 - } - accessory.eveLogger.addEntry(dataToAdd) - }, 600000) } break } @@ -196,7 +180,7 @@ module.exports = class deviceRFBridge { oAccessory.getService(serv).updateCharacteristic(char, 1) if (!this.platform.config.disableEveLogging && eveLog) { const eveLog = { - time: Date.now(), + time: Math.round(new Date().valueOf() / 1000), status: 1 } oAccessory.eveLogger.addEntry(eveLog) @@ -205,7 +189,7 @@ module.exports = class deviceRFBridge { oAccessory.getService(serv).updateCharacteristic(char, 0) if (!this.platform.config.disableEveLogging && eveLog) { const eveLog = { - time: Date.now(), + time: Math.round(new Date().valueOf() / 1000), status: 0 } oAccessory.eveLogger.addEntry(eveLog) diff --git a/lib/device/sensor.js b/lib/device/sensor.js index df9a30f5..2090861e 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -22,16 +22,8 @@ module.exports = class deviceSensor { accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('door', accessory, { storage: 'fs', - minutes: 10, path: this.platform.eveLogPath }) - corrInterval.setCorrectingInterval(() => { - const dataToAdd = { - time: Date.now(), - status: contactService.getCharacteristic(this.Characteristic.ContactSensorState).value - } - accessory.eveLogger.addEntry(dataToAdd) - }, 600000) } this.accessory = accessory } @@ -55,7 +47,7 @@ module.exports = class deviceSensor { contactService.updateCharacteristic(this.Characteristic.ContactSensorState, newState) if (!this.platform.config.disableEveLogging) { const eveLog = { - time: Date.now(), + time: Math.round(new Date().valueOf() / 1000), status: newState } this.accessory.eveLogger.addEntry(eveLog) diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index 6843ae0c..ef0c65d9 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -25,19 +25,8 @@ module.exports = class deviceThermostat { accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('weather', accessory, { storage: 'fs', - minutes: 10, path: this.platform.eveLogPath }) - corrInterval.setCorrectingInterval(() => { - const dataToAdd = { - time: Date.now(), - temp: tempService.getCharacteristic(this.Characteristic.CurrentTemperature).value - } - if (humiService) { - dataToAdd.humidity = humiService.getCharacteristic(this.Characteristic.CurrentRelativeHumidity).value - } - accessory.eveLogger.addEntry(dataToAdd) - }, 600000) } this.accessory = accessory } @@ -65,7 +54,7 @@ module.exports = class deviceThermostat { const switchService = this.accessory.getService(this.Service.Switch) switchService.updateCharacteristic(this.Characteristic.On, newState) } - const eveLog = { time: Date.now() } + const eveLog = { time: Math.round(new Date().valueOf() / 1000) } if (helpers.hasProperty(params, 'currentTemperature') && this.accessory.getService(this.Service.TemperatureSensor)) { const currentTemp = parseFloat(params.currentTemperature !== 'unavailable' ? params.currentTemperature : 0) this.accessory diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index 74dec0ce..8b40ac63 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -44,17 +44,8 @@ module.exports = class deviceZBDev { accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('weather', accessory, { storage: 'fs', - minutes: 10, path: this.platform.eveLogPath }) - corrInterval.setCorrectingInterval(() => { - const dataToAdd = { - time: Date.now(), - temp: zbTempService.getCharacteristic(this.Characteristic.CurrentTemperature).value, - humidity: zbHumiService.getCharacteristic(this.Characteristic.CurrentRelativeHumidity).value - } - accessory.eveLogger.addEntry(dataToAdd) - }, 600000) } break } @@ -64,16 +55,8 @@ module.exports = class deviceZBDev { accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('motion', accessory, { storage: 'fs', - minutes: 10, path: this.platform.eveLogPath }) - corrInterval.setCorrectingInterval(() => { - const dataToAdd = { - time: Date.now(), - status: motionService.getCharacteristic(this.Characteristic.MotionDetected).value ? 1 : 0 - } - accessory.eveLogger.addEntry(dataToAdd) - }, 600000) } break } @@ -83,16 +66,8 @@ module.exports = class deviceZBDev { accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('door', accessory, { storage: 'fs', - minutes: 10, path: this.platform.eveLogPath }) - corrInterval.setCorrectingInterval(() => { - const dataToAdd = { - time: Date.now(), - status: contactService.getCharacteristic(this.Characteristic.ContactSensorState).value - } - accessory.eveLogger.addEntry(dataToAdd) - }, 600000) } break } @@ -124,7 +99,7 @@ module.exports = class deviceZBDev { } break case 1770: { - const eveLog = { time: Date.now() } + const eveLog = { time: Math.round(new Date().valueOf() / 1000) } if (helpers.hasProperty(params, 'temperature')) { const currentTemp = parseInt(params.temperature) / 100 this.accessory @@ -157,7 +132,7 @@ module.exports = class deviceZBDev { diff < this.sensorTimeDifference if (!this.platform.config.disableEveLogging) { const eveLog = { - time: Date.now(), + time: Math.round(new Date().valueOf() / 1000), status: motionDetected ? 1 : 0 } this.accessory.eveLogger.addEntry(eveLog) @@ -173,7 +148,7 @@ module.exports = class deviceZBDev { .updateCharacteristic(this.Characteristic.ContactSensorState, params.lock) if (!this.platform.config.disableEveLogging) { const eveLog = { - time: Date.now(), + time: Math.round(new Date().valueOf() / 1000), status: params.lock } this.accessory.eveLogger.addEntry(eveLog) From 20e39d4655b7d3549e7a72f3058afe7cb92809a3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 28 Oct 2020 10:09:43 +0000 Subject: [PATCH 0570/3183] change interval to 5 mins --- lib/device/outlet.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/device/outlet.js b/lib/device/outlet.js index 7de0d622..b8b7eea4 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -103,7 +103,7 @@ module.exports = class deviceOutlet { accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('energy', accessory, { storage: 'fs', - minutes: 10, + minutes: 5, path: this.platform.eveLogPath }) corrInterval.setCorrectingInterval(() => { @@ -117,13 +117,13 @@ module.exports = class deviceOutlet { accessory.context.totalEnergy = accessory.context.extraPersistedData.totalenergy + accessory.context.totalEnergyTemp + - (currentWatt * 10) / 3600 / 1000 + (currentWatt * 5) / 3600 / 1000 accessory.eveLogger.setExtraPersistedData({ totalenergy: accessory.context.totalEnergy, lastReset: accessory.context.extraPersistedData.lastReset }) } else { - accessory.context.totalEnergy = accessory.context.totalEnergyTemp + (currentWatt * 10) / 3600 / 1000 + accessory.context.totalEnergy = accessory.context.totalEnergyTemp + (currentWatt * 5) / 3600 / 1000 accessory.eveLogger.setExtraPersistedData({ totalenergy: accessory.context.totalEnergy, lastReset: 0 @@ -131,14 +131,14 @@ module.exports = class deviceOutlet { } accessory.context.totalEnergytemp = 0 } else { - accessory.context.totalEnergyTemp += (currentWatt * 10) / 3600 / 1000 + accessory.context.totalEnergyTemp += (currentWatt * 5) / 3600 / 1000 accessory.context.totalEnergy = accessory.context.totalEnergyTemp } accessory.eveLogger.addEntry({ - time: Date.now(), + time: Math.round(new Date().valueOf() / 1000), power: currentWatt }) - }, 600000) + }, 300000) outletService .getCharacteristic(this.eveTotalConsumption) .on('get', callback => { @@ -198,7 +198,7 @@ module.exports = class deviceOutlet { ) const isOn = this.accessory.getService(this.Service.Outlet).getCharacteristic(this.Characteristic.On).value this.accessory.eveLogger.addEntry({ - time: Date.now(), + time: Math.round(new Date().valueOf() / 1000), power: isOn ? parseFloat(params.power) : 0 }) } From acac7ace5c4bb65785ecca1ecfd40f27ad0c670c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 28 Oct 2020 10:09:50 +0000 Subject: [PATCH 0571/3183] Update package-lock.json --- package-lock.json | 170 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 126 insertions(+), 44 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3d792761..c109a535 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,9 +13,9 @@ } }, "agent-base": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.1.tgz", - "integrity": "sha512-01q25QQDwLSsyfhrKbn8yuur+JNw0H+0Y4JiGIKd3z9aYk/w/2kxD/Upc+t2ZBBSUNff50VjPsSW2YxM8QYKVg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "requires": { "debug": "4" }, @@ -111,19 +111,19 @@ } }, "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", + "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "has": "^1.0.3", "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", + "is-callable": "^1.2.2", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", "object-keys": "^1.1.1", - "object.assign": "^4.1.0", + "object.assign": "^4.1.1", "string.prototype.trimend": "^1.0.1", "string.prototype.trimstart": "^1.0.1" } @@ -174,9 +174,9 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "gaxios": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.2.0.tgz", - "integrity": "sha512-+6WPeVzPvOshftpxJwRi2Ozez80tn/hdtOUag7+gajDHRJvAblKxTFSSMPtr2hmnLy7p0mvYz0rMXLBl8pSO7Q==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.0.1.tgz", + "integrity": "sha512-jOin8xRZ/UytQeBpSXFqIzqU7Fi5TqgPNLlUsSB8kjJ76+FiGBfImF8KJu++c6J4jOldfJUtt0YmkRj2ZpSHTQ==", "requires": { "abort-controller": "^3.0.0", "extend": "^3.0.2", @@ -192,19 +192,33 @@ "requires": { "gaxios": "^3.0.0", "json-bigint": "^1.0.0" + }, + "dependencies": { + "gaxios": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.2.0.tgz", + "integrity": "sha512-+6WPeVzPvOshftpxJwRi2Ozez80tn/hdtOUag7+gajDHRJvAblKxTFSSMPtr2hmnLy7p0mvYz0rMXLBl8pSO7Q==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + } + } } }, "google-auth-library": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.1.tgz", - "integrity": "sha512-0WfExOx3FrLYnY88RICQxvpaNzdwjz44OsHqHkIoAJfjY6Jck6CZRl1ASWadk+wbJ0LhkQ8rNY4zZebKml4Ghg==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.3.tgz", + "integrity": "sha512-m9mwvY3GWbr7ZYEbl61isWmk+fvTmOt0YNUfPOUY2VH8K5pZlAIWJjxEi0PqR3OjMretyiQLI6GURMrPSwHQ2g==", "requires": { "arrify": "^2.0.0", "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "fast-text-encoding": "^1.0.0", - "gaxios": "^3.0.0", - "gcp-metadata": "^4.1.0", + "gaxios": "^4.0.0", + "gcp-metadata": "^4.2.0", "gtoken": "^5.0.4", "jws": "^4.0.0", "lru-cache": "^6.0.0" @@ -228,12 +242,12 @@ } }, "googleapis-common": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-4.4.1.tgz", - "integrity": "sha512-F1QcH8oU7TOuZex9p+XW7TeyLY0332NwBwJ3dZoN+51pXZXB5JjrKswrpgbhuREuIe8xAy8J1rlmFqxeP2mFfA==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-4.4.2.tgz", + "integrity": "sha512-booWj8k9BwN2j+nbCaThbXscbbsO+FkV4h3xHW+RRC6+RwtqS2I3gqXbP8bqE1BgQBcN+49xFODCfAxy9PGfOQ==", "requires": { "extend": "^3.0.2", - "gaxios": "^3.2.0", + "gaxios": "^4.0.0", "google-auth-library": "^6.0.0", "qs": "^6.7.0", "url-template": "^2.0.8", @@ -241,11 +255,11 @@ } }, "gtoken": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.4.tgz", - "integrity": "sha512-U9wnSp4GZ7ov6zRdPuRHG4TuqEWqRRgT1gfXGNArhzBUn9byrPeH8uTmBWU/ZiWJJvTEmkjhDIC3mqHWdVi3xQ==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.5.tgz", + "integrity": "sha512-wvjkecutFh8kVfbcdBdUWqDRrXb+WrgD79DBDEYf1Om8S1FluhylhtFjrL7Tx69vNhh259qA3Q1P4sPtb+kUYw==", "requires": { - "gaxios": "^3.0.0", + "gaxios": "^4.0.0", "google-p12-pem": "^3.0.3", "jws": "^4.0.0", "mime": "^2.2.0" @@ -294,15 +308,20 @@ "integrity": "sha512-PUwEmGqUglJhb6M01JNvMDvxr4DA8FCeYoYCLHPEcBBZiq/8yOpCchfs1VJui7fXj69l170gAxzF1FeSA0nSlg==" }, "is-callable": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.1.tgz", - "integrity": "sha512-wliAfSzx6V+6WfMOmus1xy0XvSgf/dlStkvTfq7F0g4bOIW0PSUbnyse3NhDwdyYS1ozfUtAAySqTws3z9Eqgg==" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==" }, "is-date-object": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" }, + "is-negative-zero": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", + "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=" + }, "is-regex": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", @@ -400,14 +419,35 @@ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", + "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.0", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "promise-controller": { @@ -436,21 +476,63 @@ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.2.tgz", + "integrity": "sha512-8oAG/hi14Z4nOVP0z6mdiVZ/wqjDtWSLygMigTzAb+7aPEDTleeFf+WrF+alzecxIRkckkJVn+dTlwzJXORATw==", "requires": { "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" + "es-abstract": "^1.18.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.2.tgz", + "integrity": "sha512-7F6CdBTl5zyu30BJFdzSTlSlLPwODC23Od+iLoVH8X6+3fvDPPuBVVj9iaB1GOsSTSIgVfsfm27R2FGrAPznWg==", "requires": { "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" + "es-abstract": "^1.18.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "url-template": { From e79b38e9a03be6c5ff98d538d1e397ef4c0b31fd Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 28 Oct 2020 11:20:17 +0000 Subject: [PATCH 0572/3183] add nameOverride and ipOverride to plugin settings --- config.schema.json | 109 ++++++++++++++++++++++++++++++++------------- 1 file changed, 78 insertions(+), 31 deletions(-) diff --git a/config.schema.json b/config.schema.json index e1d1faf2..9ec04513 100644 --- a/config.schema.json +++ b/config.schema.json @@ -104,37 +104,6 @@ "description": "If checked, double and long press options will be hidden for the ZigBee button.", "default": false }, - "nameOverride": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fullDeviceId": { - "type": "string" - }, - "deviceName": { - "type": "string" - } - } - } - }, - "ipOverride": { - "type": "array", - "items": { - "type": "object", - "properties": { - "deviceId": { - "type": "string" - }, - "deviceIP": { - "type": "string" - } - } - } - }, - "disablePlugin": { - "type": "boolean" - }, "sensorTimeLength": { "type": "integer" }, @@ -316,6 +285,52 @@ } } } + }, + "nameOverride": { + "type": "array", + "title": "Accessory Name Overrides", + "description": "You can override the default name given to a device when it is added to Homebridge.", + "items": { + "type": "object", + "properties": { + "fullDeviceId": { + "title": "Device ID", + "type": "string", + "description": "Full device ID of the device from Homebridge (13 digits normally in the format 1000ab23cdSW2)." + }, + "deviceName": { + "title": "Name", + "type": "string", + "description": "The name for the accessory for when it is added to Homebridge." + } + } + } + }, + "ipOverride": { + "type": "array", + "title": "IP Overrides", + "description": "You can override the IP for a device in Homebridge.", + "items": { + "type": "object", + "properties": { + "deviceId": { + "title": "Device ID", + "type": "string", + "description": "Device ID from your eWeLink app (ten digits normally in the format 1000ab23cd)." + }, + "deviceIP": { + "title": "IP Address", + "type": "string", + "description": "The IP address of this device which will be used by the plugin." + } + } + } + }, + "disablePlugin": { + "type": "boolean" + }, + "resetRFBridge": { + "type": "boolean" } } }, @@ -394,6 +409,38 @@ ] } ] + }, + { + "key": "nameOverride", + "title": "Accessory Name Overrides", + "expandable": true, + "add": "Add Another Name Override", + "type": "array", + "items": [ + { + "type": "fieldset", + "items": [ + "nameOverride[].fullDeviceId", + "nameOverride[].deviceName" + ] + } + ] + }, + { + "key": "ipOverride", + "title": "IP Overrides", + "expandable": true, + "add": "Add Another IP Override", + "type": "array", + "items": [ + { + "type": "fieldset", + "items": [ + "ipOverride[].deviceId", + "ipOverride[].deviceIP" + ] + } + ] } ] } \ No newline at end of file From fe3259856b8ff006e944e8e7537321a05f937d71 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 28 Oct 2020 11:24:31 +0000 Subject: [PATCH 0573/3183] standard js formatting --- lib/device/garage-four.js | 1 - lib/device/rf-bridge.js | 5 ++--- lib/device/sensor.js | 3 +-- lib/device/thermostat.js | 6 ++---- lib/device/zb-dev.js | 11 ++++------- 5 files changed, 9 insertions(+), 17 deletions(-) diff --git a/lib/device/garage-four.js b/lib/device/garage-four.js index f6cbdd82..f21f1e4d 100644 --- a/lib/device/garage-four.js +++ b/lib/device/garage-four.js @@ -34,7 +34,6 @@ module.exports = class deviceGarageFour { if (garageConfig.type !== 'garage_four') { throw new Error('improper configuration') } - const tempLogger = msg => this.platform.log.warn('[%s] %s', this.accessory.displayName, msg) let garageChannel switch (garage) { case 'A': diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index 80f3f6ca..a244acf8 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -1,7 +1,6 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const corrInterval = require('correcting-interval') const fakegato = require('fakegato-history') const helpers = require('./../helpers') module.exports = class deviceRFBridge { @@ -31,7 +30,7 @@ module.exports = class deviceRFBridge { if (!accessory.getService(this.Service.CarbonDioxideSensor)) accessory.addService(this.Service.CarbonDioxideSensor) break case 'contact': { - const contactService = accessory.getService(this.Service.ContactSensor) || accessory.addService(this.Service.ContactSensor) + if (!accessory.getService(this.Service.ContactSensor)) accessory.addService(this.Service.ContactSensor) if (!this.platform.config.disableEveLogging) { accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('door', accessory, { @@ -45,7 +44,7 @@ module.exports = class deviceRFBridge { if (!accessory.getService(this.Service.OccupancySensor)) accessory.addService(this.Service.OccupancySensor) break default: { - const motionService = accessory.getService(this.Service.MotionSensor) || accessory.addService(this.Service.MotionSensor) + if (!accessory.getService(this.Service.MotionSensor)) accessory.addService(this.Service.MotionSensor) if (!this.platform.config.disableEveLogging) { accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('motion', accessory, { diff --git a/lib/device/sensor.js b/lib/device/sensor.js index 2090861e..5deee35b 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -1,7 +1,6 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const corrInterval = require('correcting-interval') const fakegato = require('fakegato-history') const helpers = require('./../helpers') module.exports = class deviceSensor { @@ -16,7 +15,7 @@ module.exports = class deviceSensor { : this.lowBattThreshold < 5 ? helpers.defaults.lowBattThreshold : this.lowBattThreshold - const contactService = accessory.getService(this.Service.ContactSensor) || accessory.addService(this.Service.ContactSensor) + if (!accessory.getService(this.Service.ContactSensor)) accessory.addService(this.Service.ContactSensor) if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) if (!this.platform.config.disableEveLogging) { accessory.log = this.platform.log diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index ef0c65d9..62d177bc 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -1,7 +1,6 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const corrInterval = require('correcting-interval') const fakegato = require('fakegato-history') const helpers = require('./../helpers') module.exports = class deviceThermostat { @@ -10,10 +9,9 @@ module.exports = class deviceThermostat { this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic this.EveHistoryService = fakegato(platform.api) - const tempService = accessory.getService(this.Service.TemperatureSensor) || accessory.addService(this.Service.TemperatureSensor) - let humiService = false + if (!accessory.getService(this.Service.TemperatureSensor)) accessory.addService(this.Service.TemperatureSensor) if (accessory.context.sensorType !== 'DS18B20') { - humiService = accessory.getService(this.Service.HumiditySensor) || accessory.addService(this.Service.HumiditySensor) + if (!accessory.getService(this.Service.HumiditySensor)) accessory.addService(this.Service.HumiditySensor) } if (!this.platform.config.hideTHSwitch) { const switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index 8b40ac63..1614d1c9 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -1,7 +1,6 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const corrInterval = require('correcting-interval') const fakegato = require('fakegato-history') const helpers = require('./../helpers') module.exports = class deviceZBDev { @@ -36,10 +35,8 @@ module.exports = class deviceZBDev { break } case 1770: { - const zbTempService = - accessory.getService(this.Service.TemperatureSensor) || accessory.addService(this.Service.TemperatureSensor) - const zbHumiService = - accessory.getService(this.Service.HumiditySensor) || accessory.addService(this.Service.HumiditySensor) + if (!accessory.getService(this.Service.TemperatureSensor)) accessory.addService(this.Service.TemperatureSensor) + if (!accessory.getService(this.Service.HumiditySensor)) accessory.addService(this.Service.HumiditySensor) if (!this.platform.config.disableEveLogging) { accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('weather', accessory, { @@ -50,7 +47,7 @@ module.exports = class deviceZBDev { break } case 2026: { - const motionService = accessory.getService(this.Service.MotionSensor) || accessory.addService(this.Service.MotionSensor) + if (!accessory.getService(this.Service.MotionSensor)) accessory.addService(this.Service.MotionSensor) if (!this.platform.config.disableEveLogging) { accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('motion', accessory, { @@ -61,7 +58,7 @@ module.exports = class deviceZBDev { break } case 3026: { - const contactService = accessory.getService(this.Service.ContactSensor) || accessory.addService(this.Service.ContactSensor) + if (!accessory.getService(this.Service.ContactSensor)) accessory.addService(this.Service.ContactSensor) if (!this.platform.config.disableEveLogging) { accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('door', accessory, { From 0534667453ff4be84e4d2bee0ac2c3a86c14d192 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 28 Oct 2020 13:03:02 +0000 Subject: [PATCH 0574/3183] no need for intervals --- lib/device/outlet.js | 76 ++------------------------------------------ 1 file changed, 3 insertions(+), 73 deletions(-) diff --git a/lib/device/outlet.js b/lib/device/outlet.js index b8b7eea4..74ff0acf 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -1,7 +1,6 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const corrInterval = require('correcting-interval') const fakegato = require('fakegato-history') const helpers = require('./../helpers') const util = require('util') @@ -79,93 +78,24 @@ module.exports = class deviceOutlet { if (!(outletService = accessory.getService(this.Service.Outlet))) { accessory.addService(this.Service.Outlet) outletService = accessory.getService(this.Service.Outlet) - if (!helpers.devicesSingleSwitchOutlet.includes(accessory.context.eweModel) && !this.platform.config.disableEveLogging) { + if (!this.platform.config.disableEveLogging) { outletService.addCharacteristic(this.eveVoltage) outletService.addCharacteristic(this.eveCurrentConsumption) outletService.addCharacteristic(this.eveElectricCurrent) outletService.addCharacteristic(this.eveTotalConsumption) outletService.addCharacteristic(this.eveResetTotal) - accessory.context = { - ...accessory.context, - ...{ - extraPersistedData: {}, - lastReset: 0, - totalEnergy: 0, - totalEnergyTemp: 0 - } - } } } outletService .getCharacteristic(this.Characteristic.On) .on('set', (value, callback) => this.internalUpdate(value, callback)) - if (!helpers.devicesSingleSwitchOutlet.includes(accessory.context.eweModel) && !this.platform.config.disableEveLogging) { + if (!this.platform.config.disableEveLogging) { accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('energy', accessory, { storage: 'fs', minutes: 5, path: this.platform.eveLogPath }) - corrInterval.setCorrectingInterval(() => { - const isOn = outletService.getCharacteristic(this.Characteristic.On).value - const currentWatt = isOn - ? outletService.getCharacteristic(this.eveCurrentConsumption).value - : 0 - if (accessory.eveLogger.isHistoryLoaded()) { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalEnergy = - accessory.context.extraPersistedData.totalenergy + - accessory.context.totalEnergyTemp + - (currentWatt * 5) / 3600 / 1000 - accessory.eveLogger.setExtraPersistedData({ - totalenergy: accessory.context.totalEnergy, - lastReset: accessory.context.extraPersistedData.lastReset - }) - } else { - accessory.context.totalEnergy = accessory.context.totalEnergyTemp + (currentWatt * 5) / 3600 / 1000 - accessory.eveLogger.setExtraPersistedData({ - totalenergy: accessory.context.totalEnergy, - lastReset: 0 - }) - } - accessory.context.totalEnergytemp = 0 - } else { - accessory.context.totalEnergyTemp += (currentWatt * 5) / 3600 / 1000 - accessory.context.totalEnergy = accessory.context.totalEnergyTemp - } - accessory.eveLogger.addEntry({ - time: Math.round(new Date().valueOf() / 1000), - power: currentWatt - }) - }, 300000) - outletService - .getCharacteristic(this.eveTotalConsumption) - .on('get', callback => { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.totalEnergy = accessory.context.extraPersistedData.totalPower - } - callback(null, accessory.context.totalEnergy) - }) - outletService - .getCharacteristic(this.eveResetTotal) - .on('set', (value, callback) => { - accessory.context.totalEnergy = 0 - accessory.context.lastReset = value - accessory.eveLogger.setExtraPersistedData({ - totalPower: 0, - lastReset: value - }) - callback() - }) - .on('get', callback => { - accessory.context.extraPersistedData = accessory.eveLogger.getExtraPersistedData() - if (accessory.context.extraPersistedData !== undefined) { - accessory.context.lastReset = accessory.context.extraPersistedData.lastReset - } - callback(null, accessory.context.lastReset) - }) } this.accessory = accessory } @@ -191,7 +121,7 @@ module.exports = class deviceOutlet { } if (helpers.hasProperty(params, 'power')) { outletService.updateCharacteristic(this.eveCurrentConsumption, parseFloat(params.power)) - if (!helpers.devicesSingleSwitchOutlet.includes(this.accessory.context.eweModel) && !this.platform.config.disableEveLogging) { + if (helpers.devicesSingleSwitchOutlet.includes(this.accessory.context.eweModel) && !this.platform.config.disableEveLogging) { outletService.updateCharacteristic( this.Characteristic.OutletInUse, parseFloat(params.power) > this.inUsePowerThreshold From d1a5b6356c7540b28b350f14db521b8423ef9f3a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 28 Oct 2020 13:03:27 +0000 Subject: [PATCH 0575/3183] remove corrInteval & beta fakegato branch --- package-lock.json | 18 +++--------------- package.json | 3 +-- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index c109a535..cadf94fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -81,11 +81,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "correcting-interval": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/correcting-interval/-/correcting-interval-2.0.0.tgz", - "integrity": "sha1-iTdklFcN+C7axTQRHV8n/z6gstM=" - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -149,13 +144,11 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "fakegato-history": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/fakegato-history/-/fakegato-history-0.5.6.tgz", - "integrity": "sha512-LlsOkiw9LntVlRlBkssD5ozhEkQzYuEJUlvXk5YAgBQcWzk19PQ5g+NoKfs6SRY1qAeC1onb65hes4mCvY+JmA==", + "version": "github:simont77/fakegato-history#7854aa29789c400ee284c9edfbec196e11bdfa4b", + "from": "github:simont77/fakegato-history#Updated-Energy", "requires": { "debug": "^2.2.0", - "googleapis": ">39.1.0", - "moment": "*" + "googleapis": ">39.1.0" } }, "fast-text-encoding": { @@ -383,11 +376,6 @@ "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" }, - "moment": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", - "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", diff --git a/package.json b/package.json index 6d91501a..94062907 100644 --- a/package.json +++ b/package.json @@ -67,8 +67,7 @@ "dependencies": { "axios": "0.21.0", "color-convert": "2.0.1", - "correcting-interval": "2.0.0", - "fakegato-history": "0.5.6", + "fakegato-history": "simont77/fakegato-history#Updated-Energy", "interval-promise": "1.4.0", "node-dns-sd": "0.4.2", "websocket-as-promised": "1.1.0", From 2f9fcf9bf9e8a8ada2efd9fdb2262730d5e0a204 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 28 Oct 2020 13:20:05 +0000 Subject: [PATCH 0576/3183] eveLogging config option --- config.schema.json | 7 ----- lib/device/outlet.js | 46 ++++++++++++--------------- lib/device/rf-bridge.js | 38 ++++++++++------------- lib/device/sensor.js | 22 ++++++------- lib/device/thermostat.js | 18 +++++------ lib/device/zb-dev.js | 67 ++++++++++++++++------------------------ 6 files changed, 78 insertions(+), 120 deletions(-) diff --git a/config.schema.json b/config.schema.json index 9ec04513..4a88d666 100644 --- a/config.schema.json +++ b/config.schema.json @@ -57,12 +57,6 @@ "description": "If checked, devices will not be refreshed with their most recent status from eWeLink when Homebridge starts. This setting can be useful for users who block their devices from accessing the internet.", "default": false }, - "disableEveLogging": { - "type": "boolean", - "title": "Disable Eve Logging", - "description": "If checked, switch, thermostat and power readings will not be logged to the Eve App.", - "default": false - }, "inUsePowerThreshold": { "type": "integer", "title": "Outlet 'In Use' Threshold", @@ -365,7 +359,6 @@ "items": [ "hideChanFromHB", "hideLightFromFan", - "disableEveLogging", "inUsePowerThreshold", "hideTHSwitch", "lowBattThreshold", diff --git a/lib/device/outlet.js b/lib/device/outlet.js index 74ff0acf..1ac2d8e2 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -78,25 +78,21 @@ module.exports = class deviceOutlet { if (!(outletService = accessory.getService(this.Service.Outlet))) { accessory.addService(this.Service.Outlet) outletService = accessory.getService(this.Service.Outlet) - if (!this.platform.config.disableEveLogging) { - outletService.addCharacteristic(this.eveVoltage) - outletService.addCharacteristic(this.eveCurrentConsumption) - outletService.addCharacteristic(this.eveElectricCurrent) - outletService.addCharacteristic(this.eveTotalConsumption) - outletService.addCharacteristic(this.eveResetTotal) - } + outletService.addCharacteristic(this.eveVoltage) + outletService.addCharacteristic(this.eveCurrentConsumption) + outletService.addCharacteristic(this.eveElectricCurrent) + outletService.addCharacteristic(this.eveTotalConsumption) + outletService.addCharacteristic(this.eveResetTotal) } outletService .getCharacteristic(this.Characteristic.On) .on('set', (value, callback) => this.internalUpdate(value, callback)) - if (!this.platform.config.disableEveLogging) { - accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('energy', accessory, { - storage: 'fs', - minutes: 5, - path: this.platform.eveLogPath - }) - } + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('energy', accessory, { + storage: 'fs', + minutes: 5, + path: this.platform.eveLogPath + }) this.accessory = accessory } @@ -115,23 +111,19 @@ module.exports = class deviceOutlet { const outletService = this.accessory.getService(this.Service.Outlet) if (helpers.hasProperty(params, 'switch')) { outletService.updateCharacteristic(this.Characteristic.On, params.switch === 'on') - if (helpers.devicesSingleSwitchOutlet.includes(this.accessory.context.eweModel) || this.platform.config.disableEveLogging) { + if (!this.accessory.context.powerReadings) { outletService.updateCharacteristic(this.Characteristic.OutletInUse, params.switch === 'on') } } if (helpers.hasProperty(params, 'power')) { + this.accessory.context.powerReadings = true + outletService.updateCharacteristic(this.Characteristic.OutletInUse, parseFloat(params.power) > this.inUsePowerThreshold) outletService.updateCharacteristic(this.eveCurrentConsumption, parseFloat(params.power)) - if (helpers.devicesSingleSwitchOutlet.includes(this.accessory.context.eweModel) && !this.platform.config.disableEveLogging) { - outletService.updateCharacteristic( - this.Characteristic.OutletInUse, - parseFloat(params.power) > this.inUsePowerThreshold - ) - const isOn = this.accessory.getService(this.Service.Outlet).getCharacteristic(this.Characteristic.On).value - this.accessory.eveLogger.addEntry({ - time: Math.round(new Date().valueOf() / 1000), - power: isOn ? parseFloat(params.power) : 0 - }) - } + const isOn = this.accessory.getService(this.Service.Outlet).getCharacteristic(this.Characteristic.On).value + this.accessory.eveLogger.addEntry({ + time: Math.round(new Date().valueOf() / 1000), + power: isOn ? parseFloat(params.power) : 0 + }) } if (helpers.hasProperty(params, 'voltage')) { outletService.updateCharacteristic(this.eveVoltage, parseFloat(params.voltage)) diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index a244acf8..d795d64d 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -31,13 +31,11 @@ module.exports = class deviceRFBridge { break case 'contact': { if (!accessory.getService(this.Service.ContactSensor)) accessory.addService(this.Service.ContactSensor) - if (!this.platform.config.disableEveLogging) { - accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('door', accessory, { - storage: 'fs', - path: this.platform.eveLogPath - }) - } + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('door', accessory, { + storage: 'fs', + path: this.platform.eveLogPath + }) break } case 'occupancy': @@ -45,13 +43,11 @@ module.exports = class deviceRFBridge { break default: { if (!accessory.getService(this.Service.MotionSensor)) accessory.addService(this.Service.MotionSensor) - if (!this.platform.config.disableEveLogging) { - accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('motion', accessory, { - storage: 'fs', - path: this.platform.eveLogPath - }) - } + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('motion', accessory, { + storage: 'fs', + path: this.platform.eveLogPath + }) break } case 'button': @@ -177,21 +173,19 @@ module.exports = class deviceRFBridge { break } oAccessory.getService(serv).updateCharacteristic(char, 1) - if (!this.platform.config.disableEveLogging && eveLog) { - const eveLog = { + if (eveLog) { + oAccessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: 1 - } - oAccessory.eveLogger.addEntry(eveLog) + }) } await helpers.sleep(sensorTimeLength * 1000) oAccessory.getService(serv).updateCharacteristic(char, 0) - if (!this.platform.config.disableEveLogging && eveLog) { - const eveLog = { + if (eveLog) { + oAccessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: 0 - } - oAccessory.eveLogger.addEntry(eveLog) + }) } } } diff --git a/lib/device/sensor.js b/lib/device/sensor.js index 5deee35b..a0b2c995 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -17,13 +17,11 @@ module.exports = class deviceSensor { : this.lowBattThreshold if (!accessory.getService(this.Service.ContactSensor)) accessory.addService(this.Service.ContactSensor) if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) - if (!this.platform.config.disableEveLogging) { - accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('door', accessory, { - storage: 'fs', - path: this.platform.eveLogPath - }) - } + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('door', accessory, { + storage: 'fs', + path: this.platform.eveLogPath + }) this.accessory = accessory } @@ -44,13 +42,11 @@ module.exports = class deviceSensor { let oAccessory = false const contactService = this.accessory.getService(this.Service.ContactSensor) contactService.updateCharacteristic(this.Characteristic.ContactSensorState, newState) - if (!this.platform.config.disableEveLogging) { - const eveLog = { - time: Math.round(new Date().valueOf() / 1000), - status: newState - } - this.accessory.eveLogger.addEntry(eveLog) + const eveLog = { + time: Math.round(new Date().valueOf() / 1000), + status: newState } + this.accessory.eveLogger.addEntry(eveLog) this.platform.cusG.forEach(async group => { if (group.sensorId === this.accessory.context.eweDeviceId && group.type === 'garage') { if ((oAccessory = this.platform.devicesInHB.get(group.deviceId + 'SWX'))) { diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index 62d177bc..6a8d9f8e 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -19,13 +19,11 @@ module.exports = class deviceThermostat { .getCharacteristic(this.Characteristic.On) .on('set', (value, callback) => this.internalUpdate(value, callback)) } - if (!this.platform.config.disableEveLogging) { - accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('weather', accessory, { - storage: 'fs', - path: this.platform.eveLogPath - }) - } + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('weather', accessory, { + storage: 'fs', + path: this.platform.eveLogPath + }) this.accessory = accessory } @@ -67,10 +65,8 @@ module.exports = class deviceThermostat { .updateCharacteristic(this.Characteristic.CurrentRelativeHumidity, currentHumi) eveLog.humidity = currentHumi } - if (!this.platform.config.disableEveLogging) { - if (helpers.hasProperty(eveLog, 'temp') || helpers.hasProperty(eveLog, 'humidity')) { - this.accessory.eveLogger.addEntry(eveLog) - } + if (helpers.hasProperty(eveLog, 'temp') || helpers.hasProperty(eveLog, 'humidity')) { + this.accessory.eveLogger.addEntry(eveLog) } } catch (err) { this.platform.deviceUpdateError(this.accessory, err, false) diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index 1614d1c9..532b6680 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -37,35 +37,29 @@ module.exports = class deviceZBDev { case 1770: { if (!accessory.getService(this.Service.TemperatureSensor)) accessory.addService(this.Service.TemperatureSensor) if (!accessory.getService(this.Service.HumiditySensor)) accessory.addService(this.Service.HumiditySensor) - if (!this.platform.config.disableEveLogging) { - accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('weather', accessory, { - storage: 'fs', - path: this.platform.eveLogPath - }) - } + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('weather', accessory, { + storage: 'fs', + path: this.platform.eveLogPath + }) break } case 2026: { if (!accessory.getService(this.Service.MotionSensor)) accessory.addService(this.Service.MotionSensor) - if (!this.platform.config.disableEveLogging) { - accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('motion', accessory, { - storage: 'fs', - path: this.platform.eveLogPath - }) - } + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('motion', accessory, { + storage: 'fs', + path: this.platform.eveLogPath + }) break } case 3026: { if (!accessory.getService(this.Service.ContactSensor)) accessory.addService(this.Service.ContactSensor) - if (!this.platform.config.disableEveLogging) { - accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('door', accessory, { - storage: 'fs', - path: this.platform.eveLogPath - }) - } + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('door', accessory, { + storage: 'fs', + path: this.platform.eveLogPath + }) break } } @@ -111,10 +105,7 @@ module.exports = class deviceZBDev { .updateCharacteristic(this.Characteristic.CurrentRelativeHumidity, currentHumi) eveLog.humidity = parseFloat(currentHumi) } - if ( - !this.platform.config.disableEveLogging && - (helpers.hasProperty(eveLog, 'temp') || helpers.hasProperty(eveLog, 'humidity')) - ) { + if (helpers.hasProperty(eveLog, 'temp') || helpers.hasProperty(eveLog, 'humidity')) { this.accessory.eveLogger.addEntry(eveLog) } break @@ -124,16 +115,14 @@ module.exports = class deviceZBDev { const timeNow = new Date() const diff = (timeNow.getTime() - params.trigTime) / 1000 const motionDetected = - helpers.hasProperty(params, 'updateSource') && - params.motion === 1 && - diff < this.sensorTimeDifference - if (!this.platform.config.disableEveLogging) { - const eveLog = { - time: Math.round(new Date().valueOf() / 1000), - status: motionDetected ? 1 : 0 - } - this.accessory.eveLogger.addEntry(eveLog) + helpers.hasProperty(params, 'updateSource') && + params.motion === 1 && + diff < this.sensorTimeDifference + const eveLog = { + time: Math.round(new Date().valueOf() / 1000), + status: motionDetected ? 1 : 0 } + this.accessory.eveLogger.addEntry(eveLog) this.accessory.getService(this.Service.MotionSensor).updateCharacteristic(this.Characteristic.MotionDetected, motionDetected) break } @@ -143,13 +132,11 @@ module.exports = class deviceZBDev { this.accessory .getService(this.Service.ContactSensor) .updateCharacteristic(this.Characteristic.ContactSensorState, params.lock) - if (!this.platform.config.disableEveLogging) { - const eveLog = { - time: Math.round(new Date().valueOf() / 1000), - status: params.lock - } - this.accessory.eveLogger.addEntry(eveLog) + const eveLog = { + time: Math.round(new Date().valueOf() / 1000), + status: params.lock } + this.accessory.eveLogger.addEntry(eveLog) } break default: From f0a6a6eff8d9fe6d0750beeef463be0fb4faffbe Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 28 Oct 2020 17:30:13 +0000 Subject: [PATCH 0577/3183] 3.10.0-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index cadf94fb..d5ac77a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.9.0", + "version": "3.10.0-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 94062907..cd3c7fb1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.9.0", + "version": "3.10.0-0", "author": "bwp91", "contributors": [ "gbro115", From daad75d76c9fe4c9c2c903823457eb2090953508 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 28 Oct 2020 17:35:19 +0000 Subject: [PATCH 0578/3183] add channel names --- lib/ewelink-platform.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 76e14214..7a8346e2 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -513,7 +513,15 @@ module.exports = class eWeLinkPlatform { ? Object.keys((device.tags && device.tags.zyx_info) || []).length : helpers.chansFromUiid[device.extra.uiid] if (['1', '2', '3', '4'].includes(switchNumber) && type !== 'rf_sub') { - newDeviceName += ' SW' + switchNumber + if ( + helpers.hasProperty(device, 'tags') && + helpers.hasProperty(device.tags, 'ck_channel_name') && + device.tags.ck_channel_name[parseInt(switchNumber) - 1] + ) { + newDeviceName = device.tags.ck_channel_name[parseInt(switchNumber) - 1] + } else { + newDeviceName += ' SW' + switchNumber + } } if (helpers.hasProperty(this.config.nameOverride, hbDeviceId)) { newDeviceName = this.config.nameOverride[hbDeviceId] From b461ff70e62117a6b8946f62eb23b1a81da93ca5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 28 Oct 2020 17:36:00 +0000 Subject: [PATCH 0579/3183] 3.10.0-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index d5ac77a4..b1155e9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-0", + "version": "3.10.0-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index cd3c7fb1..5148955d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-0", + "version": "3.10.0-1", "author": "bwp91", "contributors": [ "gbro115", From 356bd3c19ae6c52fa0827c1a84fd3f6a888c82e5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 29 Oct 2020 08:39:46 +0000 Subject: [PATCH 0580/3183] plugin version in logs --- lib/ewelink-platform.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 7a8346e2..66ddccb4 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -24,12 +24,13 @@ const eWeLinkLAN = require('./ewelink-lan') const eWeLinkWS = require('./ewelink-ws') const helpers = require('./helpers') const promInterval = require('interval-promise') +const version = require('./../package.json').version module.exports = class eWeLinkPlatform { constructor (log, config, api) { if (!log || !api || !config) return if (!config.username || !config.password || !config.countryCode) { - log.error('************* Cannot load homebridge-ewelink *************') - log.error('*** eWeLink credentials missing from Homebridge config ***') + log.warn('******** Disabling plugin [v%s] *********', version) + log.warn('*** eWeLink credentials missing from configuration ***') return } this.log = log @@ -60,11 +61,11 @@ module.exports = class eWeLinkPlatform { try { if (this.config.disablePlugin) { this.devicesInHB.forEach(a => this.removeAccessory(a)) - this.log.warn('********* Not loading homebridge-ewelink *********') + this.log.warn('***** Disabling plugin [v%s] *********', version) this.log.warn('*** To change this, set disablePlugin to false ***') return } - this.log('Plugin has finished initialising. Syncing with eWeLink.') + this.log('Plugin [v%s] initialised. Syncing with eWeLink...', version) this.httpClient = new eWeLinkHTTP(this.config, this.log) await this.httpClient.getHost() this.authData = await this.httpClient.login() @@ -116,7 +117,7 @@ module.exports = class eWeLinkPlatform { this.log.warn("Note: 'Request & Response Logging' is not advised for long-term use.") } } catch (err) { - this.log.error('************* Cannot load homebridge-ewelink *************') + this.log.error('********** Disabling plugin [v%s] *********', version) this.log.error(this.debug ? err : err.message) try { if (this.lanClient) this.lanClient.closeConnection() From e860d9fa20450120be6726f2359b4f1ac791731a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 29 Oct 2020 08:40:20 +0000 Subject: [PATCH 0581/3183] 3.10.0-2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index b1155e9d..d018ee6f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-1", + "version": "3.10.0-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 5148955d..5b1262f9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-1", + "version": "3.10.0-2", "author": "bwp91", "contributors": [ "gbro115", From 82222ba82ddefeb2f7aeacafc9efa0c6ad3deab7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 29 Oct 2020 09:27:00 +0000 Subject: [PATCH 0582/3183] decrease versions --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 5b1262f9..58219fc8 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,8 @@ "eachen" ], "engines": { - "homebridge": ">=1.1.0", - "node": ">=12.19.0" + "homebridge": ">=1.0.0", + "node": ">=12.0.0" }, "repository": { "type": "git", From 62224e24d28c4c76090ddd0cce28d9b2a0caaae9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 29 Oct 2020 09:35:18 +0000 Subject: [PATCH 0583/3183] log to warn --- lib/ewelink-platform.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 66ddccb4..07b82c60 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -117,8 +117,8 @@ module.exports = class eWeLinkPlatform { this.log.warn("Note: 'Request & Response Logging' is not advised for long-term use.") } } catch (err) { - this.log.error('********** Disabling plugin [v%s] *********', version) - this.log.error(this.debug ? err : err.message) + this.log.warn('********** Disabling plugin [v%s] *********', version) + this.log.warn(this.debug ? err : err.message) try { if (this.lanClient) this.lanClient.closeConnection() if (this.wsClient) this.wsClient.closeConnection() From e3d734ecea20a43c644a5ef565c0c68ec5f3bd5c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 29 Oct 2020 09:43:23 +0000 Subject: [PATCH 0584/3183] Update ewelink-platform.js --- lib/ewelink-platform.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 07b82c60..0aa759ef 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -29,7 +29,7 @@ module.exports = class eWeLinkPlatform { constructor (log, config, api) { if (!log || !api || !config) return if (!config.username || !config.password || !config.countryCode) { - log.warn('******** Disabling plugin [v%s] *********', version) + log.warn('*** Disabling plugin [v%s] ***', version) log.warn('*** eWeLink credentials missing from configuration ***') return } @@ -61,7 +61,7 @@ module.exports = class eWeLinkPlatform { try { if (this.config.disablePlugin) { this.devicesInHB.forEach(a => this.removeAccessory(a)) - this.log.warn('***** Disabling plugin [v%s] *********', version) + this.log.warn('*** Disabling plugin [v%s] ***', version) this.log.warn('*** To change this, set disablePlugin to false ***') return } @@ -117,7 +117,7 @@ module.exports = class eWeLinkPlatform { this.log.warn("Note: 'Request & Response Logging' is not advised for long-term use.") } } catch (err) { - this.log.warn('********** Disabling plugin [v%s] *********', version) + this.log.warn('*** Disabling plugin [v%s] ***', version) this.log.warn(this.debug ? err : err.message) try { if (this.lanClient) this.lanClient.closeConnection() From 00ad6a95b69b6de3e83fc40436a24cad1cdeb6c1 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 29 Oct 2020 10:06:00 +0000 Subject: [PATCH 0585/3183] 3.10.0-3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index d018ee6f..56e9aa3c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-2", + "version": "3.10.0-3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 58219fc8..a247574b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-2", + "version": "3.10.0-3", "author": "bwp91", "contributors": [ "gbro115", From 95dc81197c30240164e2b8ba9a4ef98ee4c5d746 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 29 Oct 2020 11:50:23 +0000 Subject: [PATCH 0586/3183] user defined expose outlet as switch --- config.schema.json | 6 ++++++ lib/device/switch.js | 8 +++++++- lib/ewelink-platform.js | 9 +++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/config.schema.json b/config.schema.json index 4a88d666..51c854c2 100644 --- a/config.schema.json +++ b/config.schema.json @@ -57,6 +57,11 @@ "description": "If checked, devices will not be refreshed with their most recent status from eWeLink when Homebridge starts. This setting can be useful for users who block their devices from accessing the internet.", "default": false }, + "outletAsSwitch": { + "type": "string", + "title": "Outlets As Switch", + "description": "A list of eWeLink outlet devices to show as switches in Homebridge. For example '10009553c8' or multiple separated with a comma '10009553c8,10009553c9'" + }, "inUsePowerThreshold": { "type": "integer", "title": "Outlet 'In Use' Threshold", @@ -358,6 +363,7 @@ "expandable": true, "items": [ "hideChanFromHB", + "outletAsSwitch", "hideLightFromFan", "inUsePowerThreshold", "hideTHSwitch", diff --git a/lib/device/switch.js b/lib/device/switch.js index dce815af..75de3450 100644 --- a/lib/device/switch.js +++ b/lib/device/switch.js @@ -11,6 +11,9 @@ module.exports = class deviceSwitch { switchService .getCharacteristic(this.Characteristic.On) .on('set', (value, callback) => this.internalUpdate(value, callback)) + if (accessory.getService(this.Service.Outlet)) { + accessory.removeService(accessory.getService(this.Service.Outlet)) + } this.accessory = accessory } @@ -83,7 +86,10 @@ module.exports = class deviceSwitch { async externalUpdate (params) { try { - if (helpers.devicesSingleSwitch.includes(this.accessory.context.eweUIID)) { + if ( + helpers.devicesSingleSwitch.includes(this.accessory.context.eweUIID) || + (this.platform.config.outletAsSwitch || '').split(',').includes(this.accessory.context.eweDeviceid) + ) { if (!helpers.hasProperty(params, 'switch')) return this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, params.switch === 'on') } else if (helpers.devicesMultiSwitch.includes(this.accessory.context.eweUIID)) { diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 0aa759ef..7923fce7 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -253,6 +253,15 @@ module.exports = class eWeLinkPlatform { }) accessory.control = new deviceThermostat(this, accessory) /*********/ + } else if ((this.config.outletAsSwitch || '').split(',').includes(device.deviceid)) { + /****************** + OUTLETS [AS SWITCH] + ******************/ + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new deviceSwitch(this, accessory) + /***********************/ } else if (helpers.devicesOutlet.includes(device.extra.uiid) || (helpers.devicesSingleSwitch.includes(device.extra.uiid) && helpers.devicesSingleSwitchOutlet.includes(device.productModel))) { /****** OUTLETS From e3e99d8fb14116e38e13e976e217517b226f3311 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 29 Oct 2020 11:51:20 +0000 Subject: [PATCH 0587/3183] 3.10.0-4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 56e9aa3c..fb65b490 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-3", + "version": "3.10.0-4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a247574b..668b970b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-3", + "version": "3.10.0-4", "author": "bwp91", "contributors": [ "gbro115", From a35ab5f79b4656d244c15068fefbc653426d7422 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 29 Oct 2020 14:19:29 +0000 Subject: [PATCH 0588/3183] use persist folder --- lib/ewelink-platform.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 7923fce7..7504f1ca 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -51,7 +51,7 @@ module.exports = class eWeLinkPlatform { this.config.nameOverride = this.nameOverrideTmp this.config.ipOverride = this.ipOverrideTmp this.wsRefreshFlag = true - this.eveLogPath = this.api.user.storagePath() + '/homebridge-ewelink/' + this.eveLogPath = this.api.user.storagePath() + '/persist/' this.api .on('didFinishLaunching', () => this.eWeLinkSetup()) .on('shutdown', () => this.eWeLinkShutdown()) From efdd3e6667344337e822ab46395221ffbd8cb712 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 29 Oct 2020 14:20:33 +0000 Subject: [PATCH 0589/3183] 3.10.0-5 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index fb65b490..1a189fa2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-4", + "version": "3.10.0-5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 668b970b..659ff512 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-4", + "version": "3.10.0-5", "author": "bwp91", "contributors": [ "gbro115", From 68029e492ce6de99b4ecbfc8235701638623b9d5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 29 Oct 2020 14:41:41 +0000 Subject: [PATCH 0590/3183] revert back to 10 mins --- lib/device/outlet.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/device/outlet.js b/lib/device/outlet.js index 1ac2d8e2..f5143736 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -90,7 +90,6 @@ module.exports = class deviceOutlet { accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('energy', accessory, { storage: 'fs', - minutes: 5, path: this.platform.eveLogPath }) this.accessory = accessory From 29a2b7388dd319146e276703ae0b568e7a1d5980 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 29 Oct 2020 15:07:04 +0000 Subject: [PATCH 0591/3183] delay between updates --- lib/ewelink-platform.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 7504f1ca..ac009750 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -51,6 +51,7 @@ module.exports = class eWeLinkPlatform { this.config.nameOverride = this.nameOverrideTmp this.config.ipOverride = this.ipOverrideTmp this.wsRefreshFlag = true + this.updateInProgress = false this.eveLogPath = this.api.user.storagePath() + '/persist/' this.api .on('didFinishLaunching', () => this.eWeLinkSetup()) @@ -575,6 +576,12 @@ module.exports = class eWeLinkPlatform { } async sendDeviceUpdate (accessory, params) { + if (this.updateInProgress) { + if (this.debug) this.log('Another device update is in progress. Will try again now.') + await helpers.sleep(500) + return await this.sendDeviceUpdate(accessory, params) + } + this.updateInProgress = true const payload = { apikey: accessory.context.eweApiKey, deviceid: accessory.context.eweDeviceId, @@ -583,11 +590,15 @@ module.exports = class eWeLinkPlatform { const res = helpers.devicesNonLAN.includes(accessory.context.eweUIID) ? "device doesn't support LAN mode" : await this.lanClient.sendUpdate(payload) - if (res !== 'ok') { + if (res === 'ok') { + this.updateInProgress = false + } else { if (accessory.context.reachableWAN) { if (this.debug) this.log('[%s] Reverting to web socket as %s.', accessory.displayName, res) await this.wsClient.sendUpdate(payload) + this.updateInProgress = false } else { + this.updateInProgress = false throw new Error("it is unreachable. It's status will be corrected once it is reachable") } } From e6c9fbf3f6e80ae0bc73c8b93f28144ab2d799bb Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 29 Oct 2020 15:16:04 +0000 Subject: [PATCH 0592/3183] Revert "delay between updates" This reverts commit 29a2b7388dd319146e276703ae0b568e7a1d5980. --- lib/ewelink-platform.js | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index ac009750..7504f1ca 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -51,7 +51,6 @@ module.exports = class eWeLinkPlatform { this.config.nameOverride = this.nameOverrideTmp this.config.ipOverride = this.ipOverrideTmp this.wsRefreshFlag = true - this.updateInProgress = false this.eveLogPath = this.api.user.storagePath() + '/persist/' this.api .on('didFinishLaunching', () => this.eWeLinkSetup()) @@ -576,12 +575,6 @@ module.exports = class eWeLinkPlatform { } async sendDeviceUpdate (accessory, params) { - if (this.updateInProgress) { - if (this.debug) this.log('Another device update is in progress. Will try again now.') - await helpers.sleep(500) - return await this.sendDeviceUpdate(accessory, params) - } - this.updateInProgress = true const payload = { apikey: accessory.context.eweApiKey, deviceid: accessory.context.eweDeviceId, @@ -590,15 +583,11 @@ module.exports = class eWeLinkPlatform { const res = helpers.devicesNonLAN.includes(accessory.context.eweUIID) ? "device doesn't support LAN mode" : await this.lanClient.sendUpdate(payload) - if (res === 'ok') { - this.updateInProgress = false - } else { + if (res !== 'ok') { if (accessory.context.reachableWAN) { if (this.debug) this.log('[%s] Reverting to web socket as %s.', accessory.displayName, res) await this.wsClient.sendUpdate(payload) - this.updateInProgress = false } else { - this.updateInProgress = false throw new Error("it is unreachable. It's status will be corrected once it is reachable") } } From af3da7ae6aaaa3b285524fb5e8b47f2efe69a554 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 30 Oct 2020 09:47:15 +0000 Subject: [PATCH 0593/3183] a form of update-queueing --- lib/ewelink-platform.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 7504f1ca..7eecf7bf 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -51,6 +51,7 @@ module.exports = class eWeLinkPlatform { this.config.nameOverride = this.nameOverrideTmp this.config.ipOverride = this.ipOverrideTmp this.wsRefreshFlag = true + this.updateInProgress = false this.eveLogPath = this.api.user.storagePath() + '/persist/' this.api .on('didFinishLaunching', () => this.eWeLinkSetup()) @@ -575,6 +576,13 @@ module.exports = class eWeLinkPlatform { } async sendDeviceUpdate (accessory, params) { + await helpers.sleep(Math.floor(Math.random() * (100 - 10 + 1) + 10)) + if (this.updateInProgress) { + await helpers.sleep(400) + return await this.sendDeviceUpdate(accessory, params) + } + this.updateInProgress = true + setTimeout(() => (this.updateInProgress = false), 350) const payload = { apikey: accessory.context.eweApiKey, deviceid: accessory.context.eweDeviceId, From 72257ab7bac1d8344d2facdb139d441174918094 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 30 Oct 2020 09:56:58 +0000 Subject: [PATCH 0594/3183] 3.10.0-6 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1a189fa2..b411dcea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-5", + "version": "3.10.0-6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 659ff512..1ca7a21b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-5", + "version": "3.10.0-6", "author": "bwp91", "contributors": [ "gbro115", From b6ebb77a05bc84a717a4a482d6b746188885b5c8 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 30 Oct 2020 17:40:26 +0000 Subject: [PATCH 0595/3183] better eveTotalConsumption support --- lib/device/outlet.js | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/lib/device/outlet.js b/lib/device/outlet.js index f5143736..d3064231 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -20,8 +20,11 @@ module.exports = class deviceOutlet { this.eveCurrentConsumption = function () { self.Characteristic.call(this, 'Current Consumption', 'E863F10D-079E-48FF-8F27-9C2605A29F52') this.setProps({ - format: self.Characteristic.Formats.FLOAT, + format: self.Characteristic.Formats.UINT16, unit: 'W', + maxValue: 100000, + minValue: 0, + minStep: 1, perms: [self.Characteristic.Perms.READ, self.Characteristic.Perms.NOTIFY] }) this.value = this.getDefaultValue() @@ -31,6 +34,9 @@ module.exports = class deviceOutlet { this.setProps({ format: self.Characteristic.Formats.FLOAT, unit: 'kWh', + maxValue: 100000000000, + minValue: 0, + minStep: 0.01, perms: [self.Characteristic.Perms.READ, self.Characteristic.Perms.NOTIFY] }) this.value = this.getDefaultValue() @@ -40,6 +46,9 @@ module.exports = class deviceOutlet { this.setProps({ format: self.Characteristic.Formats.FLOAT, unit: 'V', + maxValue: 100000000000, + minValue: 0, + minStep: 1, perms: [self.Characteristic.Perms.READ, self.Characteristic.Perms.NOTIFY] }) this.value = this.getDefaultValue() @@ -49,6 +58,9 @@ module.exports = class deviceOutlet { this.setProps({ format: self.Characteristic.Formats.FLOAT, unit: 'A', + maxValue: 100000000000, + minValue: 0, + minStep: 0.1, perms: [self.Characteristic.Perms.READ, self.Characteristic.Perms.NOTIFY] }) this.value = this.getDefaultValue() @@ -71,6 +83,8 @@ module.exports = class deviceOutlet { this.eveVoltage.UUID = 'E863F10A-079E-48FF-8F27-9C2605A29F52' this.eveElectricCurrent.UUID = 'E863F126-079E-48FF-8F27-9C2605A29F52' this.eveResetTotal.UUID = 'E863F112-079E-48FF-8F27-9C2605A29F52' + if (!helpers.hasProperty(accessory.context, 'energyReadings')) accessory.context.energyReadings = [] + if (!helpers.hasProperty(accessory.context, 'energyReadingTotal')) accessory.context.energyReadingTotal = 0 if (accessory.getService(this.Service.Switch)) { accessory.removeService(accessory.getService(this.Service.Switch)) } @@ -87,11 +101,31 @@ module.exports = class deviceOutlet { outletService .getCharacteristic(this.Characteristic.On) .on('set', (value, callback) => this.internalUpdate(value, callback)) + outletService + .getCharacteristic(this.eveResetTotal) + .on('set', (value, callback) => { + callback() + accessory.context.energyReadings = [] + accessory.context.energyReadingTotal = 0 + outletService.updateCharacteristic(this.eveTotalConsumption, 0) + }) accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('energy', accessory, { storage: 'fs', path: this.platform.eveLogPath }) + setInterval(() => { + let total = 0 + if (accessory.context.energyReadings.length > 0) { + accessory.context.energyReadings.forEach(x => (total += x)) + total /= accessory.context.energyReadings.length // W5m + total /= 12 // Wh + total /= 1000 // kWh + accessory.context.energyReadingTotal += total + } + accessory.context.energyReadings = [] + outletService.updateCharacteristic(this.eveTotalConsumption, accessory.context.energyReadingTotal) + }, 300000) this.accessory = accessory } @@ -123,6 +157,7 @@ module.exports = class deviceOutlet { time: Math.round(new Date().valueOf() / 1000), power: isOn ? parseFloat(params.power) : 0 }) + this.accessory.context.energyReadings.push(parseFloat(params.power)) } if (helpers.hasProperty(params, 'voltage')) { outletService.updateCharacteristic(this.eveVoltage, parseFloat(params.voltage)) From ac9ceec22d87b00dce66723f25d681c8cfc5a328 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 30 Oct 2020 17:46:51 +0000 Subject: [PATCH 0596/3183] fakegato to 0.6.0 --- package-lock.json | 41 ++++++++++++++--------------------------- package.json | 2 +- 2 files changed, 15 insertions(+), 28 deletions(-) diff --git a/package-lock.json b/package-lock.json index b411dcea..3cf0e1e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -144,8 +144,9 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "fakegato-history": { - "version": "github:simont77/fakegato-history#7854aa29789c400ee284c9edfbec196e11bdfa4b", - "from": "github:simont77/fakegato-history#Updated-Energy", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/fakegato-history/-/fakegato-history-0.6.0.tgz", + "integrity": "sha512-byGVbvoumtYaoZkVzZ+p3sxXdw5cne1yfUdL1vXLE5RlcKakv5I9lc/EtfT+R92s7z22o5dbeeIkf8aPIsiR9w==", "requires": { "debug": "^2.2.0", "googleapis": ">39.1.0" @@ -179,26 +180,12 @@ } }, "gcp-metadata": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.2.0.tgz", - "integrity": "sha512-vQZD57cQkqIA6YPGXM/zc+PIZfNRFdukWGsGZ5+LcJzesi5xp6Gn7a02wRJi4eXPyArNMIYpPET4QMxGqtlk6Q==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.2.1.tgz", + "integrity": "sha512-tSk+REe5iq/N+K+SK1XjZJUrFPuDqGZVzCy2vocIHIGmPlTGsa8owXMJwGkrXr73NO0AzhPW4MF2DEHz7P2AVw==", "requires": { - "gaxios": "^3.0.0", + "gaxios": "^4.0.0", "json-bigint": "^1.0.0" - }, - "dependencies": { - "gaxios": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.2.0.tgz", - "integrity": "sha512-+6WPeVzPvOshftpxJwRi2Ozez80tn/hdtOUag7+gajDHRJvAblKxTFSSMPtr2hmnLy7p0mvYz0rMXLBl8pSO7Q==", - "requires": { - "abort-controller": "^3.0.0", - "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", - "is-stream": "^2.0.0", - "node-fetch": "^2.3.0" - } - } } }, "google-auth-library": { @@ -226,18 +213,18 @@ } }, "googleapis": { - "version": "61.0.0", - "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-61.0.0.tgz", - "integrity": "sha512-aXaNgWKaALiYrfwrJ0ZYhRo2abyIBcqUjyNMgkbghKJMiCeOwcktlaGseH6JbPlCxXYCE8ZDfvAQqVNsf+6/RA==", + "version": "62.0.0", + "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-62.0.0.tgz", + "integrity": "sha512-IKWMdnrEzaVcambJ90QjH4Rl6e6L+bljB4SRniPgnhTQ8BG/p/M6fuNhzbBssu61GYu5q8EcxKndmRZQIIo2iQ==", "requires": { "google-auth-library": "^6.0.0", - "googleapis-common": "^4.4.0" + "googleapis-common": "^4.4.1" } }, "googleapis-common": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-4.4.2.tgz", - "integrity": "sha512-booWj8k9BwN2j+nbCaThbXscbbsO+FkV4h3xHW+RRC6+RwtqS2I3gqXbP8bqE1BgQBcN+49xFODCfAxy9PGfOQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-4.4.3.tgz", + "integrity": "sha512-W46WKCk3QtlCCfmZyQIH5zxmDOyeV5Qj+qs7nr2ox08eRkEJMWp6iwv542R/PsokXaGUSrmif4vCC4+rGzRSsQ==", "requires": { "extend": "^3.0.2", "gaxios": "^4.0.0", diff --git a/package.json b/package.json index 1ca7a21b..3f133d50 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "dependencies": { "axios": "0.21.0", "color-convert": "2.0.1", - "fakegato-history": "simont77/fakegato-history#Updated-Energy", + "fakegato-history": "0.6.0", "interval-promise": "1.4.0", "node-dns-sd": "0.4.2", "websocket-as-promised": "1.1.0", From c06ba267dd1c8c4331e3404689ec98e3793bee2e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 30 Oct 2020 17:49:25 +0000 Subject: [PATCH 0597/3183] 3.10.0-7 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3cf0e1e3..822ab285 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-6", + "version": "3.10.0-7", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 3f133d50..a55eebe2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-6", + "version": "3.10.0-7", "author": "bwp91", "contributors": [ "gbro115", From 0f73a5af408a50404c450cf73f4cda42060d8330 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 30 Oct 2020 18:37:33 +0000 Subject: [PATCH 0598/3183] eve switch history (usb+scm) --- lib/device/scm.js | 11 +++++++++++ lib/device/usb.js | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/lib/device/scm.js b/lib/device/scm.js index b92fd847..0b71f8e3 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -1,16 +1,23 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' +const fakegato = require('fakegato-history') const helpers = require('./../helpers') module.exports = class deviceSCM { constructor (platform, accessory) { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic + this.EveHistoryService = fakegato(platform.api) const scmService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) scmService .getCharacteristic(this.Characteristic.On) .on('set', (value, callback) => this.internalUpdate(value, callback)) + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('switch', accessory, { + storage: 'fs', + path: this.platform.eveLogPath + }) this.accessory = accessory } @@ -29,6 +36,10 @@ module.exports = class deviceSCM { try { if (!helpers.hasProperty(params, 'switches')) return this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, params.switches[0].switch === 'on') + this.accessory.eveLogger.addEntry({ + time: Math.round(new Date().valueOf() / 1000), + power: params.switches[0].switch === 'on' ? 1 : 0 + }) } catch (err) { this.platform.deviceUpdateError(this.accessory, err, false) } diff --git a/lib/device/usb.js b/lib/device/usb.js index fa5bc4f6..d7b4f30d 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -1,16 +1,23 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' +const fakegato = require('fakegato-history') const helpers = require('./../helpers') module.exports = class deviceUSB { constructor (platform, accessory) { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic + this.EveHistoryService = fakegato(platform.api) const usbService = accessory.getService(this.Service.Outlet) || accessory.addService(this.Service.Outlet) usbService .getCharacteristic(this.Characteristic.On) .on('set', (value, callback) => this.internalUpdate(value, callback)) + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('switch', accessory, { + storage: 'fs', + path: this.platform.eveLogPath + }) this.accessory = accessory } @@ -29,6 +36,10 @@ module.exports = class deviceUSB { try { if (!helpers.hasProperty(params, 'switches')) return this.accessory.getService(this.Service.Outlet).updateCharacteristic(this.Characteristic.On, params.switches[0].switch === 'on') + this.accessory.eveLogger.addEntry({ + time: Math.round(new Date().valueOf() / 1000), + power: params.switches[0].switch === 'on' ? 1 : 0 + }) } catch (err) { this.platform.deviceUpdateError(this.accessory, err, false) } From 9611cd24b83d11f30170cc7b601dc402afe1ed28 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 30 Oct 2020 18:54:54 +0000 Subject: [PATCH 0599/3183] eveLogger formatting --- lib/device/sensor.js | 5 ++--- lib/device/zb-dev.js | 10 ++++------ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/device/sensor.js b/lib/device/sensor.js index a0b2c995..befaa3f3 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -42,11 +42,10 @@ module.exports = class deviceSensor { let oAccessory = false const contactService = this.accessory.getService(this.Service.ContactSensor) contactService.updateCharacteristic(this.Characteristic.ContactSensorState, newState) - const eveLog = { + this.accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: newState - } - this.accessory.eveLogger.addEntry(eveLog) + }) this.platform.cusG.forEach(async group => { if (group.sensorId === this.accessory.context.eweDeviceId && group.type === 'garage') { if ((oAccessory = this.platform.devicesInHB.get(group.deviceId + 'SWX'))) { diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index 532b6680..18994bb7 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -118,11 +118,10 @@ module.exports = class deviceZBDev { helpers.hasProperty(params, 'updateSource') && params.motion === 1 && diff < this.sensorTimeDifference - const eveLog = { + this.accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: motionDetected ? 1 : 0 - } - this.accessory.eveLogger.addEntry(eveLog) + }) this.accessory.getService(this.Service.MotionSensor).updateCharacteristic(this.Characteristic.MotionDetected, motionDetected) break } @@ -132,11 +131,10 @@ module.exports = class deviceZBDev { this.accessory .getService(this.Service.ContactSensor) .updateCharacteristic(this.Characteristic.ContactSensorState, params.lock) - const eveLog = { + this.accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: params.lock - } - this.accessory.eveLogger.addEntry(eveLog) + }) } break default: From a80df1fdd04f822d681972665234b704f822c437 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 30 Oct 2020 18:56:12 +0000 Subject: [PATCH 0600/3183] eve log for all sensor types --- lib/device/rf-bridge.js | 120 +++++++++++++++++++++------------------- 1 file changed, 64 insertions(+), 56 deletions(-) diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index d795d64d..9a01a6be 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -15,50 +15,63 @@ module.exports = class deviceRFBridge { : this.sensorTimeDifference < 10 ? helpers.defaults.sensorTimeDifference : this.sensorTimeDifference - switch (accessory.context.subType) { - case 'water': - if (!accessory.getService(this.Service.LeakSensor)) accessory.addService(this.Service.LeakSensor) - break - case 'fire': - case 'smoke': - if (!accessory.getService(this.Service.SmokeSensor)) accessory.addService(this.Service.SmokeSensor) - break - case 'co': - if (!accessory.getService(this.Service.CarbonMonoxideSensor)) accessory.addService(this.Service.CarbonMonoxideSensor) - break - case 'co2': - if (!accessory.getService(this.Service.CarbonDioxideSensor)) accessory.addService(this.Service.CarbonDioxideSensor) - break - case 'contact': { - if (!accessory.getService(this.Service.ContactSensor)) accessory.addService(this.Service.ContactSensor) - accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('door', accessory, { - storage: 'fs', - path: this.platform.eveLogPath - }) - break - } - case 'occupancy': - if (!accessory.getService(this.Service.OccupancySensor)) accessory.addService(this.Service.OccupancySensor) - break - default: { - if (!accessory.getService(this.Service.MotionSensor)) accessory.addService(this.Service.MotionSensor) - accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('motion', accessory, { - storage: 'fs', - path: this.platform.eveLogPath - }) - break + if (accessory.context.subType === 'button') { + Object.entries(accessory.context.buttons).forEach(([chan, name]) => { + if (!accessory.getService(name)) accessory.addService(this.Service.Switch, name, 'switch' + chan) + accessory.getService(name).updateCharacteristic(this.Characteristic.On, false) + accessory.getService(name) + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(chan, name, value, callback)) + }) + } else { + let serv + let char + let eveType + switch (accessory.context.subType) { + case 'water': + serv = this.Service.LeakSensor + char = this.Characteristic.LeakDetected + eveType = 'motion' + break + case 'fire': + case 'smoke': + serv = this.Service.SmokeSensor + char = this.Characteristic.SmokeDetected + eveType = 'motion' + break + case 'co': + serv = this.Service.CarbonMonoxideSensor + char = this.Characteristic.CarbonMonoxideDetected + eveType = 'motion' + break + case 'co2': + serv = this.Service.CarbonDioxideSensor + char = this.Characteristic.CarbonDioxideDetected + eveType = 'motion' + break + case 'contact': + serv = this.Service.ContactSensor + char = this.Characteristic.ContactSensorState + eveType = 'door' + break + case 'occupancy': + serv = this.Service.OccupancySensor + char = this.Characteristic.OccupancyDetected + eveType = 'motion' + break + default: + serv = this.Service.MotionSensor + char = this.Characteristic.MotionDetected + eveType = 'motion' + break } - case 'button': - Object.entries(accessory.context.buttons).forEach(([chan, name]) => { - if (!accessory.getService(name)) accessory.addService(this.Service.Switch, name, 'switch' + chan) - accessory.getService(name).updateCharacteristic(this.Characteristic.On, false) - accessory.getService(name) - .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(chan, name, value, callback)) - }) - break + const service = accessory.getService(serv) || accessory.addService(serv) + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService(eveType, accessory, { + storage: 'fs', + path: this.platform.eveLogPath + }) + break } this.accessory = accessory } @@ -135,7 +148,6 @@ module.exports = class deviceRFBridge { const diff = (timeNow.getTime() - timeOfMotion.getTime()) / 1000 let serv let char - let eveLog = false if (diff < this.sensorTimeDifference) { switch (oAccessory.context.subType) { case 'button': @@ -173,20 +185,16 @@ module.exports = class deviceRFBridge { break } oAccessory.getService(serv).updateCharacteristic(char, 1) - if (eveLog) { - oAccessory.eveLogger.addEntry({ - time: Math.round(new Date().valueOf() / 1000), - status: 1 - }) - } + oAccessory.eveLogger.addEntry({ + time: Math.round(new Date().valueOf() / 1000), + status: 1 + }) await helpers.sleep(sensorTimeLength * 1000) oAccessory.getService(serv).updateCharacteristic(char, 0) - if (eveLog) { - oAccessory.eveLogger.addEntry({ - time: Math.round(new Date().valueOf() / 1000), - status: 0 - }) - } + oAccessory.eveLogger.addEntry({ + time: Math.round(new Date().valueOf() / 1000), + status: 0 + }) } } }) From e00440e7a4b1c08fc2acb87234f4390536c2d83c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 30 Oct 2020 18:56:29 +0000 Subject: [PATCH 0601/3183] sensor off on hb restart --- lib/device/rf-bridge.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index 9a01a6be..cb1e6914 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -66,6 +66,7 @@ module.exports = class deviceRFBridge { break } const service = accessory.getService(serv) || accessory.addService(serv) + service.updateCharacteristic(char, 0) accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService(eveType, accessory, { storage: 'fs', From 7e7ecb9d1c9cad38fdd66c6caca210789d28afe9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 30 Oct 2020 19:04:17 +0000 Subject: [PATCH 0602/3183] switch eve history --- lib/device/switch.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/device/switch.js b/lib/device/switch.js index 75de3450..2ff2006e 100644 --- a/lib/device/switch.js +++ b/lib/device/switch.js @@ -1,12 +1,14 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' +const fakegato = require('fakegato-history') const helpers = require('./../helpers') module.exports = class deviceSwitch { constructor (platform, accessory) { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic + this.EveHistoryService = fakegato(platform.api) const switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) switchService .getCharacteristic(this.Characteristic.On) @@ -14,6 +16,11 @@ module.exports = class deviceSwitch { if (accessory.getService(this.Service.Outlet)) { accessory.removeService(accessory.getService(this.Service.Outlet)) } + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('switch', accessory, { + storage: 'fs', + path: this.platform.eveLogPath + }) this.accessory = accessory } @@ -92,6 +99,10 @@ module.exports = class deviceSwitch { ) { if (!helpers.hasProperty(params, 'switch')) return this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, params.switch === 'on') + this.accessory.eveLogger.addEntry({ + time: Math.round(new Date().valueOf() / 1000), + power: params.switch === 'on' ? 1 : 0 + }) } else if (helpers.devicesMultiSwitch.includes(this.accessory.context.eweUIID)) { if (!helpers.hasProperty(params, 'switches')) return const idToCheck = this.accessory.context.hbDeviceId.slice(0, -1) @@ -106,10 +117,18 @@ module.exports = class deviceSwitch { oAccessory .getService(this.Service.Switch) .updateCharacteristic(this.Characteristic.On, params.switches[i - 1].switch === 'on') + oAccessory.eveLogger.addEntry({ + time: Math.round(new Date().valueOf() / 1000), + power: params.switches[i - 1].switch === 'on' ? 1 : 0 + }) } } if (!this.platform.hiddenMasters.includes(this.accessory.context.eweDeviceId)) { this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, primaryState) + this.accessory.eveLogger.addEntry({ + time: Math.round(new Date().valueOf() / 1000), + power: primaryState ? 1 : 0 + }) } } } catch (err) { From 8b17290153eef58a0b692b3e9ed17836dd3c8fad Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 30 Oct 2020 19:05:50 +0000 Subject: [PATCH 0603/3183] fixes/formatting --- lib/device/rf-bridge.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index cb1e6914..9007f8d9 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -72,7 +72,6 @@ module.exports = class deviceRFBridge { storage: 'fs', path: this.platform.eveLogPath }) - break } this.accessory = accessory } @@ -173,7 +172,6 @@ module.exports = class deviceRFBridge { case 'contact': serv = this.Service.ContactSensor char = this.Characteristic.ContactSensorState - eveLog = true break case 'occupancy': serv = this.Service.OccupancySensor @@ -182,7 +180,6 @@ module.exports = class deviceRFBridge { default: serv = this.Service.MotionSensor char = this.Characteristic.MotionDetected - eveLog = true break } oAccessory.getService(serv).updateCharacteristic(char, 1) From 98767b95cb09e7930c775cb44c052a1e5923520f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 30 Oct 2020 19:10:58 +0000 Subject: [PATCH 0604/3183] 3.10.0-8 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 822ab285..ba0dfa7c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-7", + "version": "3.10.0-8", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a55eebe2..96bb46e4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-7", + "version": "3.10.0-8", "author": "bwp91", "contributors": [ "gbro115", From 6d856ddb744b6db03693f9f7bad2aac4cae05447 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 30 Oct 2020 21:10:51 +0000 Subject: [PATCH 0605/3183] eve power to status --- lib/device/scm.js | 2 +- lib/device/switch.js | 6 +++--- lib/device/usb.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/device/scm.js b/lib/device/scm.js index 0b71f8e3..55fd2ef8 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -38,7 +38,7 @@ module.exports = class deviceSCM { this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, params.switches[0].switch === 'on') this.accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), - power: params.switches[0].switch === 'on' ? 1 : 0 + status: params.switches[0].switch === 'on' ? 1 : 0 }) } catch (err) { this.platform.deviceUpdateError(this.accessory, err, false) diff --git a/lib/device/switch.js b/lib/device/switch.js index 2ff2006e..fee27aff 100644 --- a/lib/device/switch.js +++ b/lib/device/switch.js @@ -101,7 +101,7 @@ module.exports = class deviceSwitch { this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, params.switch === 'on') this.accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), - power: params.switch === 'on' ? 1 : 0 + status: params.switch === 'on' ? 1 : 0 }) } else if (helpers.devicesMultiSwitch.includes(this.accessory.context.eweUIID)) { if (!helpers.hasProperty(params, 'switches')) return @@ -119,7 +119,7 @@ module.exports = class deviceSwitch { .updateCharacteristic(this.Characteristic.On, params.switches[i - 1].switch === 'on') oAccessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), - power: params.switches[i - 1].switch === 'on' ? 1 : 0 + status: params.switches[i - 1].switch === 'on' ? 1 : 0 }) } } @@ -127,7 +127,7 @@ module.exports = class deviceSwitch { this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, primaryState) this.accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), - power: primaryState ? 1 : 0 + status: primaryState ? 1 : 0 }) } } diff --git a/lib/device/usb.js b/lib/device/usb.js index d7b4f30d..d00664aa 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -38,7 +38,7 @@ module.exports = class deviceUSB { this.accessory.getService(this.Service.Outlet).updateCharacteristic(this.Characteristic.On, params.switches[0].switch === 'on') this.accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), - power: params.switches[0].switch === 'on' ? 1 : 0 + status: params.switches[0].switch === 'on' ? 1 : 0 }) } catch (err) { this.platform.deviceUpdateError(this.accessory, err, false) From aa0193add1f3f6a6700c69976a517a49053c788c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 30 Oct 2020 21:11:26 +0000 Subject: [PATCH 0606/3183] eve custom design with switch and temp --- lib/device/thermostat.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index 6a8d9f8e..cd969a20 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -20,7 +20,7 @@ module.exports = class deviceThermostat { .on('set', (value, callback) => this.internalUpdate(value, callback)) } accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('weather', accessory, { + accessory.eveLogger = new this.EveHistoryService('custom', accessory, { storage: 'fs', path: this.platform.eveLogPath }) @@ -49,6 +49,10 @@ module.exports = class deviceThermostat { const newState = helpers.hasProperty(params, 'switch') ? params.switch === 'on' : params.mainSwitch === 'on' const switchService = this.accessory.getService(this.Service.Switch) switchService.updateCharacteristic(this.Characteristic.On, newState) + this.accessory.eveLogger.addEntry({ + time: Math.round(new Date().valueOf() / 1000), + status: newState ? 1 : 0 + }) } const eveLog = { time: Math.round(new Date().valueOf() / 1000) } if (helpers.hasProperty(params, 'currentTemperature') && this.accessory.getService(this.Service.TemperatureSensor)) { From dfccbf5141141b3dae187fc9e0646df963cbf7c9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 30 Oct 2020 21:15:05 +0000 Subject: [PATCH 0607/3183] 3.10.0-9 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index ba0dfa7c..97b83e98 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-8", + "version": "3.10.0-9", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 96bb46e4..445ffaee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-8", + "version": "3.10.0-9", "author": "bwp91", "contributors": [ "gbro115", From a47508f30fd9013d6f8c77db963fdfdafbd4f193 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 31 Oct 2020 11:44:00 +0000 Subject: [PATCH 0608/3183] fork fakegato without google deps --- package-lock.json | 304 ++++------------------------------------------ package.json | 2 +- 2 files changed, 23 insertions(+), 283 deletions(-) diff --git a/package-lock.json b/package-lock.json index 97b83e98..2f8ab375 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,42 +4,6 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "requires": { - "event-target-shim": "^5.0.0" - } - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "requires": { - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" - }, "axios": { "version": "0.21.0", "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.0.tgz", @@ -48,20 +12,14 @@ "follow-redirects": "^1.10.0" } }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" - }, - "bignumber.js": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", - "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" - }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + "call-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", + "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.0" + } }, "chnl": { "version": "1.2.0", @@ -97,14 +55,6 @@ "object-keys": "^1.0.12" } }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, "es-abstract": { "version": "1.17.7", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", @@ -133,30 +83,13 @@ "is-symbol": "^1.0.2" } }, - "event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, "fakegato-history": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/fakegato-history/-/fakegato-history-0.6.0.tgz", - "integrity": "sha512-byGVbvoumtYaoZkVzZ+p3sxXdw5cne1yfUdL1vXLE5RlcKakv5I9lc/EtfT+R92s7z22o5dbeeIkf8aPIsiR9w==", + "version": "github:bwp91/fakegato-history#39a065f0a443f6c5b460edcb6e177872d939cc13", + "from": "github:bwp91/fakegato-history", "requires": { - "debug": "^2.2.0", - "googleapis": ">39.1.0" + "debug": "^2.2.0" } }, - "fast-text-encoding": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", - "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" - }, "follow-redirects": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", @@ -167,82 +100,14 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, - "gaxios": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.0.1.tgz", - "integrity": "sha512-jOin8xRZ/UytQeBpSXFqIzqU7Fi5TqgPNLlUsSB8kjJ76+FiGBfImF8KJu++c6J4jOldfJUtt0YmkRj2ZpSHTQ==", - "requires": { - "abort-controller": "^3.0.0", - "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", - "is-stream": "^2.0.0", - "node-fetch": "^2.3.0" - } - }, - "gcp-metadata": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.2.1.tgz", - "integrity": "sha512-tSk+REe5iq/N+K+SK1XjZJUrFPuDqGZVzCy2vocIHIGmPlTGsa8owXMJwGkrXr73NO0AzhPW4MF2DEHz7P2AVw==", - "requires": { - "gaxios": "^4.0.0", - "json-bigint": "^1.0.0" - } - }, - "google-auth-library": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.3.tgz", - "integrity": "sha512-m9mwvY3GWbr7ZYEbl61isWmk+fvTmOt0YNUfPOUY2VH8K5pZlAIWJjxEi0PqR3OjMretyiQLI6GURMrPSwHQ2g==", - "requires": { - "arrify": "^2.0.0", - "base64-js": "^1.3.0", - "ecdsa-sig-formatter": "^1.0.11", - "fast-text-encoding": "^1.0.0", - "gaxios": "^4.0.0", - "gcp-metadata": "^4.2.0", - "gtoken": "^5.0.4", - "jws": "^4.0.0", - "lru-cache": "^6.0.0" - } - }, - "google-p12-pem": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.3.tgz", - "integrity": "sha512-wS0ek4ZtFx/ACKYF3JhyGe5kzH7pgiQ7J5otlumqR9psmWMYc+U9cErKlCYVYHoUaidXHdZ2xbo34kB+S+24hA==", - "requires": { - "node-forge": "^0.10.0" - } - }, - "googleapis": { - "version": "62.0.0", - "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-62.0.0.tgz", - "integrity": "sha512-IKWMdnrEzaVcambJ90QjH4Rl6e6L+bljB4SRniPgnhTQ8BG/p/M6fuNhzbBssu61GYu5q8EcxKndmRZQIIo2iQ==", - "requires": { - "google-auth-library": "^6.0.0", - "googleapis-common": "^4.4.1" - } - }, - "googleapis-common": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-4.4.3.tgz", - "integrity": "sha512-W46WKCk3QtlCCfmZyQIH5zxmDOyeV5Qj+qs7nr2ox08eRkEJMWp6iwv542R/PsokXaGUSrmif4vCC4+rGzRSsQ==", - "requires": { - "extend": "^3.0.2", - "gaxios": "^4.0.0", - "google-auth-library": "^6.0.0", - "qs": "^6.7.0", - "url-template": "^2.0.8", - "uuid": "^8.0.0" - } - }, - "gtoken": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.5.tgz", - "integrity": "sha512-wvjkecutFh8kVfbcdBdUWqDRrXb+WrgD79DBDEYf1Om8S1FluhylhtFjrL7Tx69vNhh259qA3Q1P4sPtb+kUYw==", + "get-intrinsic": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz", + "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==", "requires": { - "gaxios": "^4.0.0", - "google-p12-pem": "^3.0.3", - "jws": "^4.0.0", - "mime": "^2.2.0" + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" } }, "has": { @@ -258,30 +123,6 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "requires": { - "agent-base": "6", - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, "interval-promise": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/interval-promise/-/interval-promise-1.4.0.tgz", @@ -310,11 +151,6 @@ "has-symbols": "^1.0.1" } }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" - }, "is-symbol": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", @@ -323,46 +159,6 @@ "has-symbols": "^1.0.1" } }, - "json-bigint": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "requires": { - "bignumber.js": "^9.0.0" - } - }, - "jwa": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", - "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "requires": { - "jwa": "^2.0.0", - "safe-buffer": "^5.0.1" - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "mime": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", - "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -373,16 +169,6 @@ "resolved": "https://registry.npmjs.org/node-dns-sd/-/node-dns-sd-0.4.2.tgz", "integrity": "sha512-fZvDqy19zyaiSXajmRjwue1VWLrJcy8bTV/LJVtAx8DeEFVlXRBMyZknW+q6CEfiW8Y4MQDDKh9x5wF32BHAHQ==" }, - "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" - }, - "node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" - }, "object-inspect": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", @@ -394,35 +180,14 @@ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "object.assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", - "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "requires": { + "call-bind": "^1.0.0", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.0", "has-symbols": "^1.0.1", "object-keys": "^1.1.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } } }, "promise-controller": { @@ -440,16 +205,6 @@ "function-bind": "^1.1.1" } }, - "qs": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", - "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, "string.prototype.trimend": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.2.tgz", @@ -510,16 +265,6 @@ } } }, - "url-template": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", - "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" - }, - "uuid": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", - "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==" - }, "websocket-as-promised": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/websocket-as-promised/-/websocket-as-promised-1.1.0.tgz", @@ -534,11 +279,6 @@ "version": "7.3.1", "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz", "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } } diff --git a/package.json b/package.json index 445ffaee..d4bac7e0 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "dependencies": { "axios": "0.21.0", "color-convert": "2.0.1", - "fakegato-history": "0.6.0", + "fakegato-history": "bwp91/fakegato-history", "interval-promise": "1.4.0", "node-dns-sd": "0.4.2", "websocket-as-promised": "1.1.0", From 75b77dcc2259cc7b542da222a25d21f6bd676c50 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 31 Oct 2020 11:46:13 +0000 Subject: [PATCH 0609/3183] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d4bac7e0..5da727f7 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/bwp91/homebridge-ewelink" + "url": "https://github.com/bwp91/homebridge-ewelink.git" }, "bugs": { "url": "https://github.com/bwp91/homebridge-ewelink/issues" From 844a73768a61a6d7ddf899fe72f01ae82d837b7d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 31 Oct 2020 11:51:41 +0000 Subject: [PATCH 0610/3183] 3.10.0-10 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2f8ab375..7f76bc96 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-9", + "version": "3.10.0-10", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 5da727f7..f9004c58 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-9", + "version": "3.10.0-10", "author": "bwp91", "contributors": [ "gbro115", From b43505019e1aaa16fe1b344ec275e5dc337f3fde Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sat, 31 Oct 2020 13:01:03 +0000 Subject: [PATCH 0611/3183] Update config.yml --- .github/ISSUE_TEMPLATE/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index af5ef704..f43c4539 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -2,4 +2,4 @@ blank_issues_enabled: false contact_links: - name: Homebridge Discord url: https://discord.gg/7X36mdw - about: Chat to me on Discord - my username is bwp91. + about: The Homebridge Discord is a community where you can ask questions and get general help with Homebridge and plugins. You can also message me directly on there - my username is bwp91. From 9c5d4de3ce985168861ef9c700b09ad2bc0335a4 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 31 Oct 2020 14:12:01 +0000 Subject: [PATCH 0612/3183] extra check for response --- lib/ewelink-http.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/ewelink-http.js b/lib/ewelink-http.js index 8219f8f8..86655aa0 100644 --- a/lib/ewelink-http.js +++ b/lib/ewelink-http.js @@ -46,6 +46,9 @@ module.exports = class eWeLinkHTTP { }, params }) + if (!res || !res.data) { + throw new Error('Unknown response from eWeLink server.\n' + JSON.stringify(res, null, 2)) + } const body = res.data if (!body.region) { throw new Error('Server did not respond with a region.\n' + JSON.stringify(body, null, 2)) From 2e0c1d8d76220904739606f052342df2c6c13be0 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 31 Oct 2020 14:24:46 +0000 Subject: [PATCH 0613/3183] 3.10.0-11 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7f76bc96..52deb60f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-10", + "version": "3.10.0-11", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f9004c58..59da1f39 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-10", + "version": "3.10.0-11", "author": "bwp91", "contributors": [ "gbro115", From 69e503730409f8ad127015b3ed1ac9ad013f557f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 31 Oct 2020 15:12:56 +0000 Subject: [PATCH 0614/3183] revert last check --- lib/ewelink-http.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/ewelink-http.js b/lib/ewelink-http.js index 86655aa0..8219f8f8 100644 --- a/lib/ewelink-http.js +++ b/lib/ewelink-http.js @@ -46,9 +46,6 @@ module.exports = class eWeLinkHTTP { }, params }) - if (!res || !res.data) { - throw new Error('Unknown response from eWeLink server.\n' + JSON.stringify(res, null, 2)) - } const body = res.data if (!body.region) { throw new Error('Server did not respond with a region.\n' + JSON.stringify(body, null, 2)) From b44c5b4ac0d77b40574c06ecfc63deefd2ec0507 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 09:18:08 +0000 Subject: [PATCH 0615/3183] updates are now queued anyway --- lib/device/fan.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index 74405872..8abbdce1 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -17,10 +17,7 @@ module.exports = class deviceFan { .getCharacteristic(this.Characteristic.On) .on('set', async (value, callback) => { callback() - if (!value) { - await helpers.sleep(500) - fanService.setCharacteristic(this.Characteristic.RotationSpeed, 0) - } + if (!value) fanService.setCharacteristic(this.Characteristic.RotationSpeed, 0) }) fanService .getCharacteristic(this.Characteristic.RotationSpeed) From 78153863aad555aad8d9067e6acbdd23e21adb6f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 09:18:15 +0000 Subject: [PATCH 0616/3183] change to 500ms --- lib/device/light.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/device/light.js b/lib/device/light.js index 9172b63e..923d5205 100644 --- a/lib/device/light.js +++ b/lib/device/light.js @@ -117,7 +117,7 @@ module.exports = class deviceLight { params.mode = 0 break } - await helpers.sleep(750) + await helpers.sleep(500) if (updateKey !== this.accessory.context.updateKey) return await this.platform.sendDeviceUpdate(this.accessory, params) break @@ -150,7 +150,7 @@ module.exports = class deviceLight { } break } - await helpers.sleep(750) + await helpers.sleep(500) if (updateKey !== this.accessory.context.updateKey) return await this.platform.sendDeviceUpdate(this.accessory, params) break @@ -180,7 +180,7 @@ module.exports = class deviceLight { } break } - await helpers.sleep(750) + await helpers.sleep(500) if (updateKey !== this.accessory.context.updateKey) return await this.platform.sendDeviceUpdate(this.accessory, params) break From f134dafb12d801f25e7170542df4738cb92bb66b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 10:39:31 +0000 Subject: [PATCH 0617/3183] support for led colour bulb --- lib/device/light.js | 55 ++++++++++++++++++++++++++++++++++++++++++--- lib/helpers.js | 15 +++++++------ 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/lib/device/light.js b/lib/device/light.js index 923d5205..338261d1 100644 --- a/lib/device/light.js +++ b/lib/device/light.js @@ -149,6 +149,17 @@ module.exports = class deviceLight { bright: value } break + case 104: + params = { + ltype: 'color', + color: { + br: value, + r: this.accessory.context.cacheR, + g: this.accessory.context.cacheG, + b: this.accessory.context.cacheB + } + } + break } await helpers.sleep(500) if (updateKey !== this.accessory.context.updateKey) return @@ -179,6 +190,20 @@ module.exports = class deviceLight { colorB: newRGB[2] } break + case 104: + params = { + ltype: 'color', + color: { + r: newRGB[0], + g: newRGB[1], + b: newRGB[2], + br: lightService.getCharacteristic(this.Characteristic.Brightness).value + } + } + this.accessory.context.cacheR = newRGB[0] + this.accessory.context.cacheG = newRGB[1] + this.accessory.context.cacheB = newRGB[2] + break } await helpers.sleep(500) if (updateKey !== this.accessory.context.updateKey) return @@ -231,7 +256,6 @@ module.exports = class deviceLight { mode = 2 } if (mode === 2) { - lightService.updateCharacteristic(this.Characteristic.On, true) newColour = convert.rgb.hsv( parseInt(params.channel2), parseInt(params.channel3), @@ -241,8 +265,6 @@ module.exports = class deviceLight { .updateCharacteristic(this.Characteristic.Hue, newColour[0]) .updateCharacteristic(this.Characteristic.Saturation, 100) .updateCharacteristic(this.Characteristic.Brightness, 100) - } else if (mode === 1) { - throw new Error('has been set to white mode which is not supported') } break case 59: // L1 @@ -256,6 +278,33 @@ module.exports = class deviceLight { .updateCharacteristic(this.Characteristic.Saturation, newColour[1]) } break + case 104: // GTLC104 + if (helpers.hasProperty(params, 'ltype')) { + mode = params.ltype + if (mode === 'color' && helpers.hasProperty(params, 'color')) { + if (helpers.hasProperty(params.color, 'br')) { + lightService.updateCharacteristic(this.Characteristic.Brightness, params.color.br) + } + if ( + helpers.hasProperty(params.color, 'r') && + helpers.hasProperty(params.color, 'g') && + helpers.hasProperty(params.color, 'b') + ) { + newColour = convert.rgb.hsv( + parseInt(params.color.r), + parseInt(params.color.g), + parseInt(params.color.b) + ) + lightService + .updateCharacteristic(this.Characteristic.Hue, newColour[0]) + .updateCharacteristic(this.Characteristic.Saturation, 100) + } + this.accessory.context.cacheR = params.color.r + this.accessory.context.cacheG = params.color.g + this.accessory.context.cacheB = params.color.b + } + } + break default: return } diff --git a/lib/helpers.js b/lib/helpers.js index cca771bb..f13fa707 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -15,17 +15,18 @@ module.exports = { sensorTimeDifference: 120 }, devicesNonLAN: [22, 28, 34, 59, 102], - devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59], + devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59, 104], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], devicesSingleSwitchLight: [ 'T1 1C', 'L1', 'B1', 'B1_R2', 'TX1C', 'D1', 'D1R1', - 'KING-M4', 'Slampher', 'GTTA59' + 'KING-M4', 'Slampher', 'GTTA59', + 'GTLC104' ], devicesMultiSwitchLight: ['T1 2C', 'T1 3C', 'TX2C', 'TX3C'], devicesSingleSwitchOutlet: ['Sonoff Pow', 'S20', 'S26', 'S55'], devicesBrightable: [36, 44], - devicesColourable: [22, 59], + devicesColourable: [22, 59, 104], devicesCurtain: [11], devicesSensor: [102], devicesThermostat: [15], @@ -39,15 +40,15 @@ module.exports = { devicesZB: [1000, 1770, 2026, 3026], paramsToKeep: [ 'battery', 'bright', 'brightness', - 'channel', 'cmd', 'colorB', 'colorG', + 'channel', 'cmd', 'color', 'colorB', 'colorG', 'colorR', 'current', 'currentHumidity', 'currentTemperature', 'humidity', - 'key', 'lock', 'mainSwitch', 'mode', + 'key', 'lock', 'ltype', 'mainSwitch', 'mode', 'motion', 'online', 'power', 'rfChl', 'rfList', 'rfTrig', 'sensorType', 'setclose', 'state', 'switch', 'switches', 'temperature', 'trigTime', - 'type', 'voltage', 'zyx_mode' + 'type', 'voltage', 'white', 'zyx_mode' ], defaultMultiSwitchOff: [ { @@ -185,7 +186,7 @@ module.exports = { 98: 0, // "DOORBELL_RFBRIDGE" \\ 102: 1, // "DOOR_MAGNETIC" \\ OPL-DMA, DW2 103: 0, // "WOTEWODE_TEM_LIGHT" \\ - 104: 0, // "WOTEWODE_RGB_TEM_LIGHT" \\ + 104: 1, // "WOTEWODE_RGB_TEM_LIGHT" \\ 107: 0, // "GSM_SOCKET_NO_FLOW" \\ 109: 0, // "YK_INFRARED_2" \\ 1000: 1, // "ZIGBEE_WIRELESS_SWITCH" \\ From 3849011cd400bfea5bcd0121128a7897c673b0ed Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 10:40:00 +0000 Subject: [PATCH 0618/3183] formatting --- lib/device/light.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/device/light.js b/lib/device/light.js index 338261d1..2eeef4fb 100644 --- a/lib/device/light.js +++ b/lib/device/light.js @@ -283,21 +283,21 @@ module.exports = class deviceLight { mode = params.ltype if (mode === 'color' && helpers.hasProperty(params, 'color')) { if (helpers.hasProperty(params.color, 'br')) { - lightService.updateCharacteristic(this.Characteristic.Brightness, params.color.br) + lightService.updateCharacteristic(this.Characteristic.Brightness, params.color.br) } if ( helpers.hasProperty(params.color, 'r') && helpers.hasProperty(params.color, 'g') && helpers.hasProperty(params.color, 'b') ) { - newColour = convert.rgb.hsv( - parseInt(params.color.r), - parseInt(params.color.g), - parseInt(params.color.b) - ) - lightService - .updateCharacteristic(this.Characteristic.Hue, newColour[0]) - .updateCharacteristic(this.Characteristic.Saturation, 100) + newColour = convert.rgb.hsv( + parseInt(params.color.r), + parseInt(params.color.g), + parseInt(params.color.b) + ) + lightService + .updateCharacteristic(this.Characteristic.Hue, newColour[0]) + .updateCharacteristic(this.Characteristic.Saturation, 100) } this.accessory.context.cacheR = params.color.r this.accessory.context.cacheG = params.color.g From a274492a69c19a181fd486f41de78d16385358c3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 10:40:50 +0000 Subject: [PATCH 0619/3183] 3.10.0-12 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 52deb60f..9d05e0b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-11", + "version": "3.10.0-12", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 59da1f39..ac0f7499 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-11", + "version": "3.10.0-12", "author": "bwp91", "contributors": [ "gbro115", From 12707dfbc66f04cfef57de14d6ee9155fc28a8d0 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 10:54:09 +0000 Subject: [PATCH 0620/3183] ignore lan updates for unsupported --- lib/device/fan.js | 1 + lib/device/light.js | 1 + lib/ewelink-platform.js | 2 +- lib/helpers.js | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index 8abbdce1..baeaaf4a 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -73,6 +73,7 @@ module.exports = class deviceFan { async externalUpdate (params) { try { + if (helpers.hasProperty(params, 'updateSource') && params.updateSource === 'LAN') return if (params.switches && Array.isArray(params.switches)) { let lightService if (this.visibleLight) lightService = this.accessory.getService(this.Service.Lightbulb) diff --git a/lib/device/light.js b/lib/device/light.js index 2eeef4fb..8fbea051 100644 --- a/lib/device/light.js +++ b/lib/device/light.js @@ -279,6 +279,7 @@ module.exports = class deviceLight { } break case 104: // GTLC104 + if (helpers.hasProperty(params, 'updateSource') && params.updateSource === 'LAN') return if (helpers.hasProperty(params, 'ltype')) { mode = params.ltype if (mode === 'color' && helpers.hasProperty(params, 'color')) { diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 7eecf7bf..16651855 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -589,7 +589,7 @@ module.exports = class eWeLinkPlatform { params } const res = helpers.devicesNonLAN.includes(accessory.context.eweUIID) - ? "device doesn't support LAN mode" + ? "LAN mode is not supported for this device" : await this.lanClient.sendUpdate(payload) if (res !== 'ok') { if (accessory.context.reachableWAN) { diff --git a/lib/helpers.js b/lib/helpers.js index f13fa707..084b1f9f 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -14,7 +14,7 @@ module.exports = { sensorTimeLength: 60, sensorTimeDifference: 120 }, - devicesNonLAN: [22, 28, 34, 59, 102], + devicesNonLAN: [22, 28, 34, 59, 102, 104], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59, 104], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], devicesSingleSwitchLight: [ From 7d6ffa56509c108f5863c4b3f9ee46b780652f3f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 10:54:52 +0000 Subject: [PATCH 0621/3183] formatting --- lib/ewelink-platform.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 16651855..e73804c2 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -589,7 +589,7 @@ module.exports = class eWeLinkPlatform { params } const res = helpers.devicesNonLAN.includes(accessory.context.eweUIID) - ? "LAN mode is not supported for this device" + ? 'LAN mode is not supported for this device' : await this.lanClient.sendUpdate(payload) if (res !== 'ok') { if (accessory.context.reachableWAN) { From 3a9e61c15e8e3ed5112683212a902fb6c3423a44 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 10:55:33 +0000 Subject: [PATCH 0622/3183] 3.10.0-13 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9d05e0b7..f4039186 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-12", + "version": "3.10.0-13", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index ac0f7499..61e3100d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-12", + "version": "3.10.0-13", "author": "bwp91", "contributors": [ "gbro115", From a7bf6df6c750ca486d5ac8f02be2e3f7b930b2be Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 11:20:43 +0000 Subject: [PATCH 0623/3183] remove host field --- lib/ewelink-http.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/ewelink-http.js b/lib/ewelink-http.js index 8219f8f8..6337989b 100644 --- a/lib/ewelink-http.js +++ b/lib/ewelink-http.js @@ -100,7 +100,6 @@ module.exports = class eWeLinkHTTP { headers: { Authorization: 'Sign ' + dataToSign, 'Content-Type': 'application/json', - Host: this.httpHost, 'X-CK-Appid': helpers.appId, 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) } @@ -157,7 +156,6 @@ module.exports = class eWeLinkHTTP { headers: { Authorization: 'Bearer ' + this.aToken, 'Content-Type': 'application/json', - Host: this.httpHost, 'X-CK-Appid': helpers.appId, 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) } @@ -213,7 +211,6 @@ module.exports = class eWeLinkHTTP { headers: { Authorization: 'Bearer ' + this.aToken, 'Content-Type': 'application/json', - Host: this.httpHost, 'X-CK-Appid': helpers.appId, 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) } From cba451bdb5cadc5dce7d3d6df36bc3015ee0ad88 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 11:21:47 +0000 Subject: [PATCH 0624/3183] 3.10.0-14 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f4039186..b438a271 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-13", + "version": "3.10.0-14", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 61e3100d..1833c12c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-13", + "version": "3.10.0-14", "author": "bwp91", "contributors": [ "gbro115", From a8ae14c5233d9471e72b1cc9508c5d0837cfc65d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 11:27:49 +0000 Subject: [PATCH 0625/3183] order of fields (for hoobs) --- config.schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.schema.json b/config.schema.json index 51c854c2..8438480d 100644 --- a/config.schema.json +++ b/config.schema.json @@ -325,10 +325,10 @@ } } }, - "disablePlugin": { + "resetRFBridge": { "type": "boolean" }, - "resetRFBridge": { + "disablePlugin": { "type": "boolean" } } From f4c015da463006782948a67ad0ee41e37a99b71a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 11:53:02 +0000 Subject: [PATCH 0626/3183] Update ewelink-http.js --- lib/ewelink-http.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ewelink-http.js b/lib/ewelink-http.js index 6337989b..4e8ba976 100644 --- a/lib/ewelink-http.js +++ b/lib/ewelink-http.js @@ -80,6 +80,7 @@ module.exports = class eWeLinkHTTP { } async login () { + if (this.httpHost === undefined) this.httpHost = 'eu-apia.coolkit.cc' const data = { countryCode: this.cCode, password: this.password From 26514accff915505e2f8c17ca8fb4eebaf183766 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 11:53:51 +0000 Subject: [PATCH 0627/3183] 3.10.0-15 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index b438a271..5fa1ffcd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-14", + "version": "3.10.0-15", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1833c12c..d17a9845 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-14", + "version": "3.10.0-15", "author": "bwp91", "contributors": [ "gbro115", From 1c7b0520c7795d2e45d6e6cc3f69481abdf2a5f0 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 12:45:39 +0000 Subject: [PATCH 0628/3183] Update light.js --- lib/device/light.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/device/light.js b/lib/device/light.js index 8fbea051..7738df6a 100644 --- a/lib/device/light.js +++ b/lib/device/light.js @@ -299,10 +299,10 @@ module.exports = class deviceLight { lightService .updateCharacteristic(this.Characteristic.Hue, newColour[0]) .updateCharacteristic(this.Characteristic.Saturation, 100) + this.accessory.context.cacheR = params.color.r + this.accessory.context.cacheG = params.color.g + this.accessory.context.cacheB = params.color.b } - this.accessory.context.cacheR = params.color.r - this.accessory.context.cacheG = params.color.g - this.accessory.context.cacheB = params.color.b } } break From 82b33382f8a15a438696058c9379aa5f069d9c51 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 13:19:02 +0000 Subject: [PATCH 0629/3183] remove white param --- lib/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers.js b/lib/helpers.js index 084b1f9f..35167723 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -48,7 +48,7 @@ module.exports = { 'rfList', 'rfTrig', 'sensorType', 'setclose', 'state', 'switch', 'switches', 'temperature', 'trigTime', - 'type', 'voltage', 'white', 'zyx_mode' + 'type', 'voltage', 'zyx_mode' ], defaultMultiSwitchOff: [ { From 1954e35fb6ac8be43d6cda54b87d08b1f9a9df91 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 13:19:11 +0000 Subject: [PATCH 0630/3183] unnecessary returns, formatting --- lib/ewelink-http.js | 56 ++++++++++++++++++--------------------------- lib/ewelink-ws.js | 15 +++++------- 2 files changed, 28 insertions(+), 43 deletions(-) diff --git a/lib/ewelink-http.js b/lib/ewelink-http.js index 4e8ba976..031f0a06 100644 --- a/lib/ewelink-http.js +++ b/lib/ewelink-http.js @@ -62,15 +62,10 @@ module.exports = class eWeLinkHTTP { default: throw new Error('No valid region received - [' + body.region + '].') } - if (this.debug) { - this.log('HTTP API host received [%s].', this.httpHost) - } - return this.httpHost + if (this.debug) this.log('HTTP API host received [%s].', this.httpHost) } catch (err) { if (helpers.hasProperty(err, 'code') && helpers.httpRetryCodes.includes(err.code)) { - if (this.debug) { - this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') - } + if (this.debug) this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') await helpers.sleep(30000) return await this.getHost() } else { @@ -125,28 +120,25 @@ module.exports = class eWeLinkHTTP { default: throw new Error('No valid region received - [' + givenRegion + '].') } - if (this.debug) { - this.log('New HTTP API host received [%s].', this.httpHost) - } - return await this.login() - } - if (body.data.at) { - this.aToken = body.data.at - this.apiKey = body.data.user.apikey - return { - aToken: this.aToken, - apiKey: this.apiKey, - httpHost: this.httpHost - } + if (this.debug) this.log('New HTTP API host received [%s].', this.httpHost) + await this.login() } else { - if (body.error === 500) { - if (this.debug) { - this.log.warn('An eWeLink error [500] occured. Retrying in 30 seconds.') + if (body.data.at) { + this.aToken = body.data.at + this.apiKey = body.data.user.apikey + return { + aToken: this.aToken, + apiKey: this.apiKey, + httpHost: this.httpHost } - await helpers.sleep(30000) - return await this.login() } else { - throw new Error('No auth token received.\n' + JSON.stringify(body, null, 2)) + if (body.error === 500) { + if (this.debug) this.log.warn('An eWeLink error [500] occured. Retrying in 30 seconds.') + await helpers.sleep(30000) + await this.login() + } else { + throw new Error('No auth token received.\n' + JSON.stringify(body, null, 2)) + } } } } @@ -190,11 +182,9 @@ module.exports = class eWeLinkHTTP { return deviceList.concat(sensorList) } catch (err) { if (helpers.hasProperty(err, 'code') && helpers.httpRetryCodes.includes(err.code)) { - if (this.debug) { - this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') - } + if (this.debug) this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') await helpers.sleep(30000) - return await this.getDevices() + await this.getDevices() } else { return err } @@ -231,11 +221,9 @@ module.exports = class eWeLinkHTTP { } } catch (err) { if (helpers.hasProperty(err, 'code') && helpers.httpRetryCodes.includes(err.code)) { - if (this.debug) { - this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') - } + if (this.debug) this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') await helpers.sleep(30000) - return await this.getDevice(deviceId) + await this.getDevice(deviceId) } else { return err } diff --git a/lib/ewelink-ws.js b/lib/ewelink-ws.js index 04f4a0d4..ee7f60ef 100644 --- a/lib/ewelink-ws.js +++ b/lib/ewelink-ws.js @@ -41,12 +41,11 @@ module.exports = class eWeLinkWS { } if (this.debug) this.log('Web socket host received [%s].', body.domain) this.wsHost = body.domain - return body.domain } catch (err) { if (helpers.hasProperty(err, 'code') && helpers.httpRetryCodes.includes(err.code)) { if (this.debug) this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') await helpers.sleep(30000) - return await this.getHost() + await this.getHost() } else { return err } @@ -168,7 +167,7 @@ module.exports = class eWeLinkWS { this.log.warn('Web socket will try to reconnect in five seconds.') } await helpers.sleep(5000) - return await this.login() + await this.login() }) this.wsp.onError.addListener(async e => { this.wsIsOpen = false @@ -182,7 +181,7 @@ module.exports = class eWeLinkWS { this.log.warn('Web socket will try to reconnect in five seconds.') } await helpers.sleep(5000) - return await this.login() + await this.login() }) } @@ -218,11 +217,9 @@ module.exports = class eWeLinkWS { return new Error('device update failed as ' + msg) } } else { - if (this.debug) { - this.log.warn('Command will be resent when WS is reconnected.') - } + if (this.debug) this.log.warn('Command will be resent when WS is reconnected.') await helpers.sleep(30000) - return await this.sendUpdate(json) + await this.sendUpdate(json) } } @@ -250,7 +247,7 @@ module.exports = class eWeLinkWS { } else { if (this.debug) this.log.warn('Command will be resent when WS is reconnected.') await helpers.sleep(30000) - return await this.requestUpdate(accessory) + await this.requestUpdate(accessory) } } From 95652b0e985f81def7100ed161d604e8b4c83973 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 13:20:42 +0000 Subject: [PATCH 0631/3183] 3.10.0-16 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5fa1ffcd..c07a0c6d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-15", + "version": "3.10.0-16", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index d17a9845..b80cf619 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-15", + "version": "3.10.0-16", "author": "bwp91", "contributors": [ "gbro115", From e1aa660535bcacd2ec06182bad25f5a0f59c56f1 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 13:43:49 +0000 Subject: [PATCH 0632/3183] support zigbee 1256 type --- lib/device/zb-dev.js | 33 +++++++++++++++++++++++++++++++++ lib/ewelink-platform.js | 2 +- lib/helpers.js | 2 +- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index 18994bb7..17ecc7cb 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -34,6 +34,18 @@ module.exports = class deviceZBDev { } break } + case 1256: { + if (!accessory.getService(this.Service.Switch)) accessory.addService(this.Service.Switch) + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('switch', accessory, { + storage: 'fs', + path: this.platform.eveLogPath + }) + accessory.getService(this.Service.Switch) + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(value, callback)) + break + } case 1770: { if (!accessory.getService(this.Service.TemperatureSensor)) accessory.addService(this.Service.TemperatureSensor) if (!accessory.getService(this.Service.HumiditySensor)) accessory.addService(this.Service.HumiditySensor) @@ -66,6 +78,16 @@ module.exports = class deviceZBDev { this.accessory = accessory } + async internalUpdate (value, callback) { + callback() + try { + const params = { switch: value ? 'on' : 'off' } + await this.platform.sendDeviceUpdate(this.accessory, params) + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + async externalUpdate (params) { try { //* ** credit @tasict ***\\ @@ -89,6 +111,17 @@ module.exports = class deviceZBDev { .updateCharacteristic(this.Characteristic.ProgrammableSwitchEvent, params.key) } break + case 1256: + if (helpers.hasProperty(params, 'switch') && ['off', 'on'].includes(params.switch)) { + this.accessory + .getService(this.Service.Switch) + .updateCharacteristic(this.Characteristic.On, params.switch === 'on') + this.accessory.eveLogger.addEntry({ + time: Math.round(new Date().valueOf() / 1000), + status: params.switch === 'on' ? 1 : 0 + }) + } + break case 1770: { const eveLog = { time: Math.round(new Date().valueOf() / 1000) } if (helpers.hasProperty(params, 'temperature')) { diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index e73804c2..a217733f 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -545,7 +545,7 @@ module.exports = class eWeLinkPlatform { .setCharacteristic(this.Characteristic.SerialNumber, hbDeviceId) .setCharacteristic(this.Characteristic.Manufacturer, device.brandName) .setCharacteristic(this.Characteristic.Model, device.productModel + ' (' + device.extra.model + ')') - .setCharacteristic(this.Characteristic.FirmwareRevision, device.params.fwVersion) + .setCharacteristic(this.Characteristic.FirmwareRevision, device.params.fwVersion || version) .setCharacteristic(this.Characteristic.Identify, true) accessory.on('identify', (paired, callback) => { this.log('[%s] - identify button pressed.', accessory.displayName) diff --git a/lib/helpers.js b/lib/helpers.js index 35167723..7121c9a3 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -37,7 +37,7 @@ module.exports = { devicesSCM: [78], devicesRFBridge: [28], devicesZBBridge: [66], - devicesZB: [1000, 1770, 2026, 3026], + devicesZB: [1000, 1256, 1770, 2026, 3026], paramsToKeep: [ 'battery', 'bright', 'brightness', 'channel', 'cmd', 'color', 'colorB', 'colorG', From 36ce992bdb4e139272f3566085d08584c11781f8 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 13:44:38 +0000 Subject: [PATCH 0633/3183] 3.10.0-17 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index c07a0c6d..14826457 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-16", + "version": "3.10.0-17", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index b80cf619..1431b73f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-16", + "version": "3.10.0-17", "author": "bwp91", "contributors": [ "gbro115", From 4cce64e5dc51c2d2b8f608b33ec4eebac3edee1c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 16:57:45 +0000 Subject: [PATCH 0634/3183] reorder, add resetRF + disablePlugin to ui --- config.schema.json | 49 +++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/config.schema.json b/config.schema.json index 8438480d..0e3b2a8d 100644 --- a/config.schema.json +++ b/config.schema.json @@ -41,6 +41,18 @@ "description": "If checked, HTTP, web socket and LAN mode messages will be added to the log. Not recommended for long-term use.", "default": false }, + "disableHTTPRefresh": { + "type": "boolean", + "title": "Disable Initial Device Refresh", + "description": "If checked, devices will not be refreshed with their most recent status from eWeLink when Homebridge starts. This setting can be useful for users who block their devices from accessing the internet.", + "default": false + }, + "disablePlugin": { + "title": "Disable Plugin", + "type": "boolean", + "description": "If checked, the plugin will remove all eWeLink accessories from Homebridge and not load the plugin on Homebridge restart.", + "default": false + }, "hideDevFromHB": { "type": "string", "title": "Hide Devices", @@ -51,12 +63,6 @@ "title": "Hide Light/Switch Channels", "description": "A list of light/switch channels to hide from Homebridge. For example '10009553c8SW0' or multiple separated with a comma '10009553c8SW0,10009553c9SW2'." }, - "disableHTTPRefresh": { - "type": "boolean", - "title": "Disable Initial Device Refresh", - "description": "If checked, devices will not be refreshed with their most recent status from eWeLink when Homebridge starts. This setting can be useful for users who block their devices from accessing the internet.", - "default": false - }, "outletAsSwitch": { "type": "string", "title": "Outlets As Switch", @@ -70,17 +76,17 @@ "minimum": 0, "maximum": 100 }, + "hideLightFromFan": { + "type": "string", + "title": "Hide Fan Lights", + "description": "A list of eWeLink iFan devices for which the light will be hidden from Homebridge. For example '10009553c8' or multiple separated with a comma '10009553c8,10009553c9'" + }, "hideTHSwitch": { "title": "Hide TH10/TH16 Switch", "type": "boolean", "description": "If checked, the switch for the TH10/TH16 devices will be hidden from Homebridge.", "default": false }, - "hideLightFromFan": { - "type": "string", - "title": "Hide Fan Lights", - "description": "A list of eWeLink iFan devices for which the light will be hidden from Homebridge. For example '10009553c8' or multiple separated with a comma '10009553c8,10009553c9'" - }, "lowBattThreshold": { "type": "integer", "title": "Low Battery Threshold", @@ -103,8 +109,11 @@ "description": "If checked, double and long press options will be hidden for the ZigBee button.", "default": false }, - "sensorTimeLength": { - "type": "integer" + "resetRFBridge": { + "title": "Reset RF Bridges", + "type": "boolean", + "description": "If checked, the plugin will remove and re-add all RF Bridges on Homebridge restart. This is needed when adding/removed sub-devices from the RF Bridge.", + "default": false }, "groups": { "type": "array", @@ -324,12 +333,6 @@ } } } - }, - "resetRFBridge": { - "type": "boolean" - }, - "disablePlugin": { - "type": "boolean" } } }, @@ -353,7 +356,7 @@ "debug", "debugReqRes", "disableHTTPRefresh", - "hideDevFromHB" + "disablePlugin" ] }, { @@ -362,14 +365,16 @@ "description": "A variety of optional settings for specific device types.", "expandable": true, "items": [ + "hideDevFromHB", "hideChanFromHB", "outletAsSwitch", - "hideLightFromFan", "inUsePowerThreshold", + "hideLightFromFan", "hideTHSwitch", "lowBattThreshold", "sensorTimeDifference", - "hideZBLDPress" + "hideZBLDPress", + "resetRFBridge" ] }, { From 941253120bf5122a58f71755fd2afe466a515d33 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 17:04:15 +0000 Subject: [PATCH 0635/3183] formatting, no changes --- lib/helpers.js | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/lib/helpers.js b/lib/helpers.js index 7121c9a3..1d1c8413 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -18,10 +18,9 @@ module.exports = { devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59, 104], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], devicesSingleSwitchLight: [ - 'T1 1C', 'L1', 'B1', - 'B1_R2', 'TX1C', 'D1', 'D1R1', - 'KING-M4', 'Slampher', 'GTTA59', - 'GTLC104' + 'T1 1C', 'L1', 'B1', 'B1_R2', + 'TX1C', 'D1', 'D1R1', 'KING-M4', + 'Slampher', 'GTTA59', 'GTLC104' ], devicesMultiSwitchLight: ['T1 2C', 'T1 3C', 'TX2C', 'TX3C'], devicesSingleSwitchOutlet: ['Sonoff Pow', 'S20', 'S26', 'S55'], @@ -40,15 +39,15 @@ module.exports = { devicesZB: [1000, 1256, 1770, 2026, 3026], paramsToKeep: [ 'battery', 'bright', 'brightness', - 'channel', 'cmd', 'color', 'colorB', 'colorG', - 'colorR', 'current', 'currentHumidity', - 'currentTemperature', 'humidity', - 'key', 'lock', 'ltype', 'mainSwitch', 'mode', - 'motion', 'online', 'power', 'rfChl', - 'rfList', 'rfTrig', 'sensorType', - 'setclose', 'state', 'switch', - 'switches', 'temperature', 'trigTime', - 'type', 'voltage', 'zyx_mode' + 'channel', 'cmd', 'color', 'colorB', + 'colorG', 'colorR', 'current', + 'currentHumidity', 'currentTemperature', + 'humidity', 'key', 'lock', 'ltype', + 'mainSwitch', 'mode', 'motion', 'online', + 'power', 'rfChl', 'rfList', 'rfTrig', + 'sensorType', 'setclose', 'state', + 'switch', 'switches', 'temperature', + 'trigTime', 'type', 'voltage', 'zyx_mode' ], defaultMultiSwitchOff: [ { From 026238226c1485cc5b8274e867965c33aa83ebdb Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 17:14:21 +0000 Subject: [PATCH 0636/3183] formatting, no changes --- lib/ewelink-platform.js | 45 ++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index a217733f..f9eef5e9 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -97,22 +97,20 @@ module.exports = class eWeLinkPlatform { this.devicesInEW.forEach(d => this.initialiseDevice(d)) this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)) this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)) - this.wsRefresh = promInterval( - async () => { - if (this.wsRefreshFlag) { - try { - if (this.wsClient) { - await this.wsClient.getHost() - await this.wsClient.closeConnection() - await helpers.sleep(250) - await this.wsClient.login() - } - } catch (err) { - this.log.warn(this.debug ? err : err.message) + this.wsRefresh = promInterval(async () => { + if (this.wsRefreshFlag) { + try { + if (this.wsClient) { + await this.wsClient.getHost() + await this.wsClient.closeConnection() + await helpers.sleep(250) + await this.wsClient.login() } + } catch (err) { + this.log.warn(this.debug ? err : err.message) } - }, 1800000, { stopOnError: false } - ) + } + }, 1800000, { stopOnError: false }) this.log("eWeLink sync complete. Don't forget to ⭐ī¸ this plugin on GitHub if you're finding it useful!") if (this.config.debugReqRes) { this.log.warn("Note: 'Request & Response Logging' is not advised for long-term use.") @@ -263,7 +261,10 @@ module.exports = class eWeLinkPlatform { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new deviceSwitch(this, accessory) /***********************/ - } else if (helpers.devicesOutlet.includes(device.extra.uiid) || (helpers.devicesSingleSwitch.includes(device.extra.uiid) && helpers.devicesSingleSwitchOutlet.includes(device.productModel))) { + } else if ( + helpers.devicesOutlet.includes(device.extra.uiid) || + (helpers.devicesSingleSwitch.includes(device.extra.uiid) && helpers.devicesSingleSwitchOutlet.includes(device.productModel)) + ) { /****** OUTLETS ******/ @@ -299,7 +300,10 @@ module.exports = class eWeLinkPlatform { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new deviceLight(this, accessory) /*********************/ - } else if (helpers.devicesMultiSwitch.includes(device.extra.uiid) && helpers.devicesMultiSwitchLight.includes(device.productModel)) { + } else if ( + helpers.devicesMultiSwitch.includes(device.extra.uiid) && + helpers.devicesMultiSwitchLight.includes(device.productModel) + ) { /********************* LIGHTS [MULTI CHANNEL] *********************/ @@ -472,7 +476,7 @@ module.exports = class eWeLinkPlatform { /****** CAMERAS ******/ - this.log.warn(' → [%s] please see the homebridge-ewelink wiki for details to enable the camera.', device.name) + this.log(' → [%s] please see the homebridge-ewelink wiki for details to enable the camera.', device.name) return /*****/ } else { @@ -519,10 +523,9 @@ module.exports = class eWeLinkPlatform { addAccessory (device, hbDeviceId, hidden = false, extraContext = {}, type = '') { const switchNumber = hbDeviceId.split('SW')[1].toString() let newDeviceName = type === 'rf_sub' ? device.tags.zyx_info[switchNumber - 1].name : device.name - const channelCount = - type === 'rf_pri' - ? Object.keys((device.tags && device.tags.zyx_info) || []).length - : helpers.chansFromUiid[device.extra.uiid] + const channelCount = type === 'rf_pri' + ? Object.keys((device.tags && device.tags.zyx_info) || []).length + : helpers.chansFromUiid[device.extra.uiid] if (['1', '2', '3', '4'].includes(switchNumber) && type !== 'rf_sub') { if ( helpers.hasProperty(device, 'tags') && From b6bfec2007d1c9f80acdcfe986cea6c406cb0fe9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 1 Nov 2020 17:15:15 +0000 Subject: [PATCH 0637/3183] 3.10.0-18 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 14826457..49ea6963 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-17", + "version": "3.10.0-18", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1431b73f..7b588c2e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-17", + "version": "3.10.0-18", "author": "bwp91", "contributors": [ "gbro115", From a2456bac5ef1442fda2c0024f05093786902b1ba Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 2 Nov 2020 08:57:05 +0000 Subject: [PATCH 0638/3183] split light types into files --- lib/device/light-colour.js | 222 +++++++++++++++++++++++++++++++++++++ lib/device/light-dimmer.js | 83 ++++++++++++++ lib/device/light-multi.js | 105 ++++++++++++++++++ lib/device/light-single.js | 33 ++++++ lib/ewelink-platform.js | 41 ++++++- lib/helpers.js | 1 + 6 files changed, 479 insertions(+), 6 deletions(-) create mode 100644 lib/device/light-colour.js create mode 100644 lib/device/light-dimmer.js create mode 100644 lib/device/light-multi.js create mode 100644 lib/device/light-single.js diff --git a/lib/device/light-colour.js b/lib/device/light-colour.js new file mode 100644 index 00000000..92a7d0c2 --- /dev/null +++ b/lib/device/light-colour.js @@ -0,0 +1,222 @@ +/* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ +'use strict' +const convert = require('color-convert') +const helpers = require('./../helpers') +module.exports = class deviceLightColour { + constructor (platform, accessory) { + this.platform = platform + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + const lightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) + lightService + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalUpdate('onoff', value, callback)) + lightService + .getCharacteristic(this.Characteristic.Brightness) + .on('set', (value, callback) => this.internalUpdate('brightness', value, callback)) + lightService + .getCharacteristic(this.Characteristic.Hue) + .on('set', (value, callback) => this.internalUpdate('hue', value, callback)) + lightService + .getCharacteristic(this.Characteristic.Saturation) + .on('set', (value, callback) => callback()) + if (accessory.context.eweUIID === 22) { + // *** B1 doesn't support brightness *** \\ + lightService + .getCharacteristic(this.Characteristic.Brightness) + .setProps({ + minStep: 100 + }) + } + this.accessory = accessory + } + + async internalUpdate (type, value, callback) { + callback() + try { + let newRGB + let params = {} + const lightService = this.accessory.getService(this.Service.Lightbulb) + switch (type) { + case 'onoff': + if (this.accessory.context.eweUIID === 22) { + // **** B1 uses state rather than switch *** \\ + params.state = value ? 'on' : 'off' + } else { + params.switch = value ? 'on' : 'off' + } + await this.platform.sendDeviceUpdate(this.accessory, params) + break + case 'brightness': { + const updateKey = Math.random().toString(36).substr(2, 8) + this.accessory.context.updateKey = updateKey + switch (this.accessory.context.eweUIID) { + case 22: + // *** B1 doesn't support brightness *** \\ + return + case 59: + // *** L1 *** \\ + params = { + mode: 1, + bright: value + } + break + case 104: + // *** GTLC104 needs the current rgb values sent too *** \\ + params = { + ltype: 'color', + color: { + br: value, + r: this.accessory.context.cacheR, + g: this.accessory.context.cacheG, + b: this.accessory.context.cacheB + } + } + break + } + await helpers.sleep(500) + if (updateKey !== this.accessory.context.updateKey) return + await this.platform.sendDeviceUpdate(this.accessory, params) + break + } + case 'hue': { + const updateKey = Math.random().toString(36).substr(2, 8) + this.accessory.context.updateKey = updateKey + newRGB = convert.hsv.rgb(value, lightService.getCharacteristic(this.Characteristic.Saturation).value, 100) + switch (this.accessory.context.eweUIID) { + case 22: + // *** B1 *** \\ + params = { + zyx_mode: 2, + type: 'middle', + channel0: '0', + channel1: '0', + channel2: newRGB[0].toString(), + channel3: newRGB[1].toString(), + channel4: newRGB[2].toString() + } + break + case 59: + // *** L1 *** \\ + params = { + mode: 1, + colorR: newRGB[0], + colorG: newRGB[1], + colorB: newRGB[2] + } + break + case 104: + // *** GTLC104 *** \\ + params = { + ltype: 'color', + color: { + r: newRGB[0], + g: newRGB[1], + b: newRGB[2], + br: lightService.getCharacteristic(this.Characteristic.Brightness).value + } + } + this.accessory.context.cacheR = newRGB[0] + this.accessory.context.cacheG = newRGB[1] + this.accessory.context.cacheB = newRGB[2] + break + } + await helpers.sleep(500) + if (updateKey !== this.accessory.context.updateKey) return + await this.platform.sendDeviceUpdate(this.accessory, params) + break + } + } + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async externalUpdate (params) { + try { + let newColour + let mode + let isOn = false + const lightService = this.accessory.getService(this.Service.Lightbulb) + if (this.accessory.context.eweUIID === 22 && helpers.hasProperty(params, 'state')) { + isOn = params.state === 'on' + } else if (this.accessory.context.eweUIID !== 22 && helpers.hasProperty(params, 'switch')) { + isOn = params.switch === 'on' + } else { + isOn = lightService.getCharacteristic(this.Characteristic.On).value + } + if (isOn) { + lightService.updateCharacteristic(this.Characteristic.On, true) + switch (this.accessory.context.eweUIID) { + case 22: + // *** B1 *** \\ + if (helpers.hasProperty(params, 'zyx_mode')) { + mode = parseInt(params.zyx_mode) + } else if (helpers.hasProperty(params, 'channel0') && parseInt(params.channel0) + parseInt(params.channel1) > 0) { + mode = 1 + } else { + mode = 2 + } + if (mode === 2) { + newColour = convert.rgb.hsv( + parseInt(params.channel2), + parseInt(params.channel3), + parseInt(params.channel4) + ) + lightService + .updateCharacteristic(this.Characteristic.Hue, newColour[0]) + .updateCharacteristic(this.Characteristic.Saturation, 100) + .updateCharacteristic(this.Characteristic.Brightness, 100) + } + break + case 59: + // *** L1 *** \\ + if (helpers.hasProperty(params, 'bright')) { + lightService.updateCharacteristic(this.Characteristic.Brightness, params.bright) + } + if (helpers.hasProperty(params, 'colorR')) { + newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB) + lightService + .updateCharacteristic(this.Characteristic.Hue, newColour[0]) + .updateCharacteristic(this.Characteristic.Saturation, newColour[1]) + } + break + case 104: + // *** GTLC104 *** \\ + if (helpers.hasProperty(params, 'updateSource') && params.updateSource === 'LAN') return + if (helpers.hasProperty(params, 'ltype')) { + mode = params.ltype + if (mode === 'color' && helpers.hasProperty(params, 'color')) { + if (helpers.hasProperty(params.color, 'br')) { + lightService.updateCharacteristic(this.Characteristic.Brightness, params.color.br) + } + if ( + helpers.hasProperty(params.color, 'r') && + helpers.hasProperty(params.color, 'g') && + helpers.hasProperty(params.color, 'b') + ) { + newColour = convert.rgb.hsv( + parseInt(params.color.r), + parseInt(params.color.g), + parseInt(params.color.b) + ) + lightService + .updateCharacteristic(this.Characteristic.Hue, newColour[0]) + .updateCharacteristic(this.Characteristic.Saturation, 100) + this.accessory.context.cacheR = params.color.r + this.accessory.context.cacheG = params.color.g + this.accessory.context.cacheB = params.color.b + } + } + } + break + } + } else { + lightService.updateCharacteristic(this.Characteristic.On, false) + } + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, false) + } + } +} diff --git a/lib/device/light-dimmer.js b/lib/device/light-dimmer.js new file mode 100644 index 00000000..b7c30db4 --- /dev/null +++ b/lib/device/light-dimmer.js @@ -0,0 +1,83 @@ +/* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ +'use strict' +const helpers = require('./../helpers') +module.exports = class deviceLightDimmer { + constructor (platform, accessory) { + this.platform = platform + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + const lightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) + lightService + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalUpdate('onoff', value, callback)) + lightService.getCharacteristic(this.Characteristic.Brightness) + .on('set', (value, callback) => this.internalUpdate('brightness', value, callback)) + this.accessory = accessory + } + + async internalUpdate (type, value, callback) { + callback() + try { + const params = {} + switch (type) { + case 'onoff': + params.switch = value ? 'on' : 'off' + await this.platform.sendDeviceUpdate(this.accessory, params) + break + case 'brightness': { + const updateKey = Math.random().toString(36).substr(2, 8) + this.accessory.context.updateKey = updateKey + switch (this.accessory.context.eweUIID) { + case 36: + // *** KING-M4 eWeLink scale is 10-100 and HomeKit scale is 0-100. *** \\ + params.bright = Math.round((value * 9) / 10 + 10) + break + case 44: + // *** D1 eWeLink scale matches HomeKit scale of 0-100 *** \\ + params.brightness = value + params.mode = 0 + break + } + await helpers.sleep(500) + if (updateKey !== this.accessory.context.updateKey) return + await this.platform.sendDeviceUpdate(this.accessory, params) + break + } + } + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async externalUpdate (params) { + try { + const lightService = this.accessory.getService(this.Service.Lightbulb) + const isOn = helpers.hasProperty(params, 'switch') + ? params.switch === 'on' + : lightService.getCharacteristic(this.Characteristic.On).value + if (isOn) { + lightService.updateCharacteristic(this.Characteristic.On, true) + switch (this.accessory.context.eweUIID) { + case 36: + // *** KING-M4 eWeLink scale is 10-100 and HomeKit scale is 0-100. *** \\ + if (helpers.hasProperty(params, 'bright')) { + const nb = Math.round(((params.bright - 10) * 10) / 9) + lightService.updateCharacteristic(this.Characteristic.Brightness, nb) + } + break + case 44: + // *** D1 eWeLink scale matches HomeKit scale of 0-100 *** \\ + if (helpers.hasProperty(params, 'brightness')) { + lightService.updateCharacteristic(this.Characteristic.Brightness, params.brightness) + } + break + } + } else { + lightService.updateCharacteristic(this.Characteristic.On, false) + } + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, false) + } + } +} diff --git a/lib/device/light-multi.js b/lib/device/light-multi.js new file mode 100644 index 00000000..c851d09f --- /dev/null +++ b/lib/device/light-multi.js @@ -0,0 +1,105 @@ +/* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ +'use strict' +const helpers = require('./../helpers') +module.exports = class deviceLightMulti { + constructor (platform, accessory) { + this.platform = platform + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + const lightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) + lightService + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(value, callback)) + this.accessory = accessory + } + + async internalUpdate (value, callback) { + callback() + try { + let oAccessory + const params = {} + switch (this.accessory.context.switchNumber) { + case '0': + params.switches = helpers.defaultMultiSwitchOff + params.switches[0].switch = value ? 'on' : 'off' + params.switches[1].switch = value ? 'on' : 'off' + params.switches[2].switch = value ? 'on' : 'off' + params.switches[3].switch = value ? 'on' : 'off' + break + case '1': + case '2': + case '3': + case '4': + params.switches = helpers.defaultMultiSwitchOff + for (let i = 1; i <= 4; i++) { + if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { + if (i === parseInt(this.accessory.context.switchNumber)) { + params.switches[i - 1].switch = value ? 'on' : 'off' + } else { + params.switches[i - 1].switch = oAccessory.context.cacheOn ? 'on' : 'off' + } + } else { + params.switches[i - 1].switch = 'off' + } + } + break + } + await this.platform.sendDeviceUpdate(this.accessory, params) + switch (this.accessory.context.switchNumber) { + case '0': + for (let i = 0; i <= 4; i++) { + if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { + oAccessory.getService(this.Service.Lightbulb).updateCharacteristic(this.Characteristic.On, value) + } + } + break + case '1': + case '2': + case '3': + case '4': { + let masterState = 'off' + for (let i = 1; i <= 4; i++) { + if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { + if (oAccessory.getService(this.Service.Lightbulb).getCharacteristic(this.Characteristic.On).value) { + masterState = 'on' + } + } + } + if (!this.platform.hiddenMasters.includes(this.accessory.context.eweDeviceId)) { + oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW0') + oAccessory.getService(this.Service.Lightbulb).updateCharacteristic(this.Characteristic.On, masterState === 'on') + } + break + } + } + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async externalUpdate (params) { + try { + if (!helpers.hasProperty(params, 'switches')) return + const idToCheck = this.accessory.context.hbDeviceId.slice(0, -1) + let primaryState = false + for (let i = 1; i <= this.accessory.context.channelCount; i++) { + if (params.switches[i - 1].switch === 'on') { + primaryState = true + } + if (this.platform.devicesInHB.has(idToCheck + i)) { + const oAccessory = this.platform.devicesInHB.get(idToCheck + i) + oAccessory.context.cacheOn = params.switches[i - 1].switch === 'on' + oAccessory + .getService(this.Service.Lightbulb) + .updateCharacteristic(this.Characteristic.On, params.switches[i - 1].switch === 'on') + } + } + if (!this.platform.hiddenMasters.includes(this.accessory.context.eweDeviceId)) { + this.accessory.getService(this.Service.Lightbulb).updateCharacteristic(this.Characteristic.On, primaryState) + } + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, false) + } + } +} diff --git a/lib/device/light-single.js b/lib/device/light-single.js new file mode 100644 index 00000000..c62ee8fa --- /dev/null +++ b/lib/device/light-single.js @@ -0,0 +1,33 @@ +/* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ +'use strict' +module.exports = class deviceLightSingle { + constructor (platform, accessory) { + this.platform = platform + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + const lightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) + lightService + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(value, callback)) + this.accessory = accessory + } + + async internalUpdate (value, callback) { + callback() + try { + const params = { switch: value ? 'on' : 'off' } + await this.platform.sendDeviceUpdate(this.accessory, params) + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async externalUpdate (params) { + try { + this.accessory.getService(this.Service.Lightbulb).updateCharacteristic(this.Characteristic.On, params.switch === 'on') + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, false) + } + } +} diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index f9eef5e9..41cf0f13 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -15,7 +15,10 @@ const deviceThermostat = require('./device/thermostat') const deviceOutlet = require('./device/outlet') const deviceUSB = require('./device/usb') const deviceSCM = require('./device/scm') -const deviceLight = require('./device/light') +const deviceLightColour = require('./device/light-colour') +const deviceLightDimmer = require('./device/light-dimmer') +const deviceLightMulti = require('./device/light-multi') +const deviceLightSingle = require('./device/light-single') const deviceSwitch = require('./device/switch') const deviceRFBridge = require('./device/rf-bridge') const deviceZBDev = require('./device/zb-dev') @@ -291,21 +294,47 @@ module.exports = class eWeLinkPlatform { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new deviceSCM(this, accessory) /********************************/ + } else if ( + helpers.devicesSingleSwitch.includes(device.extra.uiid) && + helpers.devicesSingleSwitchLight.includes(device.productModel) && + helpers.devicesColourable.includes(device.extra.uiid) + ) { + /********************** + LIGHTS [COLOUR RGB] + **********************/ + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new deviceLightColour(this, accessory) + /*********************/ + } else if ( + helpers.devicesSingleSwitch.includes(device.extra.uiid) && + helpers.devicesSingleSwitchLight.includes(device.productModel) && + helpers.devicesBrightable.includes(device.extra.uiid) + ) { + /********************** + LIGHTS [DIMMER] + **********************/ + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new deviceLightDimmer(this, accessory) + /*********************/ } else if (helpers.devicesSingleSwitch.includes(device.extra.uiid) && helpers.devicesSingleSwitchLight.includes(device.productModel)) { /********************** - LIGHTS [SINGLE CHANNEL] + LIGHTS [ON/OFF SINGLE CHANNEL] **********************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new deviceLight(this, accessory) + accessory.control = new deviceLightSingle(this, accessory) /*********************/ } else if ( helpers.devicesMultiSwitch.includes(device.extra.uiid) && helpers.devicesMultiSwitchLight.includes(device.productModel) ) { /********************* - LIGHTS [MULTI CHANNEL] + LIGHTS [ON/OFF MULTI CHANNEL] *********************/ if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid + 'SW0')) { if (this.devicesInHB.has(device.deviceid + 'SW0')) { @@ -318,7 +347,7 @@ module.exports = class eWeLinkPlatform { ? this.devicesInHB.get(device.deviceid + 'SW0') : this.addAccessory(device, device.deviceid + 'SW0') } - accessory.control = new deviceLight(this, accessory) + accessory.control = new deviceLightMulti(this, accessory) for (let i = 1; i <= helpers.chansFromUiid[device.extra.uiid]; i++) { if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid + 'SW' + i)) { if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { @@ -336,7 +365,7 @@ module.exports = class eWeLinkPlatform { oAccessory.context.reachableWAN = device.online oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) - oAccessory.control = new deviceLight(this, oAccessory) + oAccessory.control = new deviceLightMulti(this, oAccessory) } /********************/ } else if (helpers.devicesSingleSwitch.includes(device.extra.uiid)) { diff --git a/lib/helpers.js b/lib/helpers.js index 1d1c8413..bc503898 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -26,6 +26,7 @@ module.exports = { devicesSingleSwitchOutlet: ['Sonoff Pow', 'S20', 'S26', 'S55'], devicesBrightable: [36, 44], devicesColourable: [22, 59, 104], + devicesCTemptable: [], devicesCurtain: [11], devicesSensor: [102], devicesThermostat: [15], From 7932b65421ece6df958294c781447656ce4f0c0c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 2 Nov 2020 08:59:07 +0000 Subject: [PATCH 0639/3183] Delete light.js --- lib/device/light.js | 342 -------------------------------------------- 1 file changed, 342 deletions(-) delete mode 100644 lib/device/light.js diff --git a/lib/device/light.js b/lib/device/light.js deleted file mode 100644 index 7738df6a..00000000 --- a/lib/device/light.js +++ /dev/null @@ -1,342 +0,0 @@ -/* jshint -W014, -W033, esversion: 9 */ -/* eslint-disable new-cap */ -'use strict' -const convert = require('color-convert') -const helpers = require('./../helpers') -module.exports = class deviceLight { - constructor (platform, accessory) { - this.platform = platform - this.Service = platform.api.hap.Service - this.Characteristic = platform.api.hap.Characteristic - const lightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) - lightService - .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate('onoff', value, callback)) - if (helpers.devicesBrightable.includes(accessory.context.eweUIID)) { - lightService.getCharacteristic(this.Characteristic.Brightness) - .on('set', (value, callback) => this.internalUpdate('brightness', value, callback)) - } else if (helpers.devicesColourable.includes(accessory.context.eweUIID)) { - lightService.getCharacteristic(this.Characteristic.Brightness) - .on('set', (value, callback) => this.internalUpdate('c_brightness', value, callback)) - if (accessory.context.eweUIID === 22) { - lightService - .getCharacteristic(this.Characteristic.Brightness) - .setProps({ - minStep: 100 - }) - } - lightService - .getCharacteristic(this.Characteristic.Hue) - .on('set', (value, callback) => this.internalUpdate('c_hue', value, callback)) - lightService.getCharacteristic(this.Characteristic.Saturation).on('set', (value, callback) => callback()) - } - this.accessory = accessory - } - - async internalUpdate (type, value, callback) { - callback() - try { - let oAccessory - let newRGB - let params = {} - const lightService = this.accessory.getService(this.Service.Lightbulb) - switch (type) { - case 'onoff': - switch (this.accessory.context.switchNumber) { - case 'X': - if (this.accessory.context.eweUIID === 22) { - //* ** B1 ***\\ - params.state = value ? 'on' : 'off' - } else { - params.switch = value ? 'on' : 'off' - } - break - case '0': - params.switches = helpers.defaultMultiSwitchOff - params.switches[0].switch = value ? 'on' : 'off' - params.switches[1].switch = value ? 'on' : 'off' - params.switches[2].switch = value ? 'on' : 'off' - params.switches[3].switch = value ? 'on' : 'off' - break - case '1': - case '2': - case '3': - case '4': - params.switches = helpers.defaultMultiSwitchOff - for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { - if (i === parseInt(this.accessory.context.switchNumber)) { - params.switches[i - 1].switch = value ? 'on' : 'off' - } else { - params.switches[i - 1].switch = oAccessory.context.cacheOn ? 'on' : 'off' - } - } else { - params.switches[i - 1].switch = 'off' - } - } - break - } - await this.platform.sendDeviceUpdate(this.accessory, params) - switch (this.accessory.context.switchNumber) { - case '0': - for (let i = 0; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { - oAccessory.getService(this.Service.Lightbulb).updateCharacteristic(this.Characteristic.On, value) - } - } - break - case '1': - case '2': - case '3': - case '4': { - let masterState = 'off' - for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { - if (oAccessory.getService(this.Service.Lightbulb).getCharacteristic(this.Characteristic.On).value) { - masterState = 'on' - } - } - } - if (!this.platform.hiddenMasters.includes(this.accessory.context.eweDeviceId)) { - oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW0') - oAccessory.getService(this.Service.Lightbulb).updateCharacteristic(this.Characteristic.On, masterState === 'on') - } - break - } - } - break - case 'brightness': { - const updateKey = Math.random().toString(36).substr(2, 8) - this.accessory.context.updateKey = updateKey - switch (this.accessory.context.eweUIID) { - case 36: //* ** KING-M4 ***\\ - params.bright = Math.round((value * 9) / 10 + 10) - break - case 44: //* ** D1 ***\\ - params.brightness = value - params.mode = 0 - break - } - await helpers.sleep(500) - if (updateKey !== this.accessory.context.updateKey) return - await this.platform.sendDeviceUpdate(this.accessory, params) - break - } - case 'c_brightness': { - const updateKey = Math.random().toString(36).substr(2, 8) - this.accessory.context.updateKey = updateKey - switch (this.accessory.context.eweUIID) { - case 22: //* ** B1 ***\\ - newRGB = convert.hsv.rgb( - lightService.getCharacteristic(this.Characteristic.Hue).value, - lightService.getCharacteristic(this.Characteristic.Saturation).value, - value - ) - if (newRGB[0] + newRGB[1] + newRGB[2] === 0) return - params = { - zyx_mode: 2, - type: 'middle', - channel0: '0', - channel1: '0', - channel2: newRGB[0].toString(), - channel3: newRGB[1].toString(), - channel4: newRGB[2].toString() - } - break - case 59: //* ** L1 ***\\ - params = { - mode: 1, - bright: value - } - break - case 104: - params = { - ltype: 'color', - color: { - br: value, - r: this.accessory.context.cacheR, - g: this.accessory.context.cacheG, - b: this.accessory.context.cacheB - } - } - break - } - await helpers.sleep(500) - if (updateKey !== this.accessory.context.updateKey) return - await this.platform.sendDeviceUpdate(this.accessory, params) - break - } - case 'c_hue': { - const updateKey = Math.random().toString(36).substr(2, 8) - this.accessory.context.updateKey = updateKey - newRGB = convert.hsv.rgb(value, lightService.getCharacteristic(this.Characteristic.Saturation).value, 100) - switch (this.accessory.context.eweUIID) { - case 22: //* ** B1 ***\\ - params = { - zyx_mode: 2, - type: 'middle', - channel0: '0', - channel1: '0', - channel2: newRGB[0].toString(), - channel3: newRGB[1].toString(), - channel4: newRGB[2].toString() - } - break - case 59: //* ** L1 ***\\ - params = { - mode: 1, - colorR: newRGB[0], - colorG: newRGB[1], - colorB: newRGB[2] - } - break - case 104: - params = { - ltype: 'color', - color: { - r: newRGB[0], - g: newRGB[1], - b: newRGB[2], - br: lightService.getCharacteristic(this.Characteristic.Brightness).value - } - } - this.accessory.context.cacheR = newRGB[0] - this.accessory.context.cacheG = newRGB[1] - this.accessory.context.cacheB = newRGB[2] - break - } - await helpers.sleep(500) - if (updateKey !== this.accessory.context.updateKey) return - await this.platform.sendDeviceUpdate(this.accessory, params) - break - } - } - } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) - } - } - - async externalUpdate (params) { - try { - if ( - helpers.devicesSingleSwitch.includes(this.accessory.context.eweUIID) && - helpers.devicesSingleSwitchLight.includes(this.accessory.context.eweModel) - ) { - let newColour - let mode - let isOn = false - const lightService = this.accessory.getService(this.Service.Lightbulb) - if (this.accessory.context.eweUIID === 22 && helpers.hasProperty(params, 'state')) { - isOn = params.state === 'on' - } else if (this.accessory.context.eweUIID !== 22 && helpers.hasProperty(params, 'switch')) { - isOn = params.switch === 'on' - } else { - isOn = lightService.getCharacteristic(this.Characteristic.On).value - } - if (isOn) { - lightService.updateCharacteristic(this.Characteristic.On, true) - switch (this.accessory.context.eweUIID) { - case 36: // KING-M4 - if (helpers.hasProperty(params, 'bright')) { - const nb = Math.round(((params.bright - 10) * 10) / 9) // eWeLink scale is 10-100 and HomeKit scale is 0-100. - lightService.updateCharacteristic(this.Characteristic.Brightness, nb) - } - break - case 44: // D1 - if (helpers.hasProperty(params, 'brightness')) { - lightService.updateCharacteristic(this.Characteristic.Brightness, params.brightness) - } - break - case 22: // B1 - if (helpers.hasProperty(params, 'zyx_mode')) { - mode = parseInt(params.zyx_mode) - } else if (helpers.hasProperty(params, 'channel0') && parseInt(params.channel0) + parseInt(params.channel1) > 0) { - mode = 1 - } else { - mode = 2 - } - if (mode === 2) { - newColour = convert.rgb.hsv( - parseInt(params.channel2), - parseInt(params.channel3), - parseInt(params.channel4) - ) - lightService - .updateCharacteristic(this.Characteristic.Hue, newColour[0]) - .updateCharacteristic(this.Characteristic.Saturation, 100) - .updateCharacteristic(this.Characteristic.Brightness, 100) - } - break - case 59: // L1 - if (helpers.hasProperty(params, 'bright')) { - lightService.updateCharacteristic(this.Characteristic.Brightness, params.bright) - } - if (helpers.hasProperty(params, 'colorR')) { - newColour = convert.rgb.hsv(params.colorR, params.colorG, params.colorB) - lightService - .updateCharacteristic(this.Characteristic.Hue, newColour[0]) - .updateCharacteristic(this.Characteristic.Saturation, newColour[1]) - } - break - case 104: // GTLC104 - if (helpers.hasProperty(params, 'updateSource') && params.updateSource === 'LAN') return - if (helpers.hasProperty(params, 'ltype')) { - mode = params.ltype - if (mode === 'color' && helpers.hasProperty(params, 'color')) { - if (helpers.hasProperty(params.color, 'br')) { - lightService.updateCharacteristic(this.Characteristic.Brightness, params.color.br) - } - if ( - helpers.hasProperty(params.color, 'r') && - helpers.hasProperty(params.color, 'g') && - helpers.hasProperty(params.color, 'b') - ) { - newColour = convert.rgb.hsv( - parseInt(params.color.r), - parseInt(params.color.g), - parseInt(params.color.b) - ) - lightService - .updateCharacteristic(this.Characteristic.Hue, newColour[0]) - .updateCharacteristic(this.Characteristic.Saturation, 100) - this.accessory.context.cacheR = params.color.r - this.accessory.context.cacheG = params.color.g - this.accessory.context.cacheB = params.color.b - } - } - } - break - default: - return - } - } else { - lightService.updateCharacteristic(this.Characteristic.On, false) - } - } else if ( - helpers.devicesMultiSwitch.includes(this.accessory.context.eweUIID) && - helpers.devicesMultiSwitchLight.includes(this.accessory.context.eweModel) - ) { - if (!helpers.hasProperty(params, 'switches')) return - const idToCheck = this.accessory.context.hbDeviceId.slice(0, -1) - let primaryState = false - for (let i = 1; i <= this.accessory.context.channelCount; i++) { - if (params.switches[i - 1].switch === 'on') { - primaryState = true - } - if (this.platform.devicesInHB.has(idToCheck + i)) { - const oAccessory = this.platform.devicesInHB.get(idToCheck + i) - oAccessory.context.cacheOn = params.switches[i - 1].switch === 'on' - oAccessory - .getService(this.Service.Lightbulb) - .updateCharacteristic(this.Characteristic.On, params.switches[i - 1].switch === 'on') - } - } - if (!this.platform.hiddenMasters.includes(this.accessory.context.eweDeviceId)) { - this.accessory.getService(this.Service.Lightbulb).updateCharacteristic(this.Characteristic.On, primaryState) - } - } - } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) - } - } -} From 917bce7d09044bf830747dda1a4cde20a4209af2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 2 Nov 2020 09:53:57 +0000 Subject: [PATCH 0640/3183] color temp light scaffolding --- lib/device/light-ctemp.js | 35 +++++++++++++++++++++++++++++++++++ lib/ewelink-platform.js | 14 ++++++++++++++ lib/helpers.js | 2 +- 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 lib/device/light-ctemp.js diff --git a/lib/device/light-ctemp.js b/lib/device/light-ctemp.js new file mode 100644 index 00000000..66fa2e25 --- /dev/null +++ b/lib/device/light-ctemp.js @@ -0,0 +1,35 @@ +/* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ +'use strict' +module.exports = class deviceLightCTemp { + constructor (platform, accessory) { + this.platform = platform + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + const lightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) + lightService + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalUpdate('onoff', value, callback)) + lightService + .getCharacteristic(this.Characteristic.Brightness) + .on('set', (value, callback) => this.internalUpdate('brightness', value, callback)) + this.accessory = accessory + } + + async internalUpdate (type, value, callback) { + callback() + try { + + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async externalUpdate (params) { + try { + + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, false) + } + } +} diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 41cf0f13..84349615 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -16,6 +16,7 @@ const deviceOutlet = require('./device/outlet') const deviceUSB = require('./device/usb') const deviceSCM = require('./device/scm') const deviceLightColour = require('./device/light-colour') +const deviceLightCTemp = require('./device/light-ctemp') const deviceLightDimmer = require('./device/light-dimmer') const deviceLightMulti = require('./device/light-multi') const deviceLightSingle = require('./device/light-single') @@ -294,6 +295,19 @@ module.exports = class eWeLinkPlatform { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new deviceSCM(this, accessory) /********************************/ + } else if ( + helpers.devicesSingleSwitch.includes(device.extra.uiid) && + helpers.devicesSingleSwitchLight.includes(device.productModel) && + helpers.devicesCTempable.includes(device.extra.uiid) + ) { + /********************** + LIGHTS [COLOUR TEMP] + **********************/ + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new deviceLightCTemp(this, accessory) + /*********************/ } else if ( helpers.devicesSingleSwitch.includes(device.extra.uiid) && helpers.devicesSingleSwitchLight.includes(device.productModel) && diff --git a/lib/helpers.js b/lib/helpers.js index bc503898..b6878e00 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -26,7 +26,7 @@ module.exports = { devicesSingleSwitchOutlet: ['Sonoff Pow', 'S20', 'S26', 'S55'], devicesBrightable: [36, 44], devicesColourable: [22, 59, 104], - devicesCTemptable: [], + devicesCTempable: [], devicesCurtain: [11], devicesSensor: [102], devicesThermostat: [15], From 851f1562f7367b81535ce5378e059869c424f4cb Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 2 Nov 2020 15:04:05 +0000 Subject: [PATCH 0641/3183] 3.10.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 49ea6963..7222477f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-18", + "version": "3.10.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 7b588c2e..6222178d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0-18", + "version": "3.10.0", "author": "bwp91", "contributors": [ "gbro115", From 8a05f7258e6d2f4905139143b4e47aafaffa7e87 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 3 Nov 2020 13:23:21 +0000 Subject: [PATCH 0642/3183] rethrow errors --- lib/ewelink-http.js | 6 +++--- lib/ewelink-ws.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/ewelink-http.js b/lib/ewelink-http.js index 031f0a06..5b23d67b 100644 --- a/lib/ewelink-http.js +++ b/lib/ewelink-http.js @@ -69,7 +69,7 @@ module.exports = class eWeLinkHTTP { await helpers.sleep(30000) return await this.getHost() } else { - return err + throw err } } } @@ -186,7 +186,7 @@ module.exports = class eWeLinkHTTP { await helpers.sleep(30000) await this.getDevices() } else { - return err + throw err } } } @@ -225,7 +225,7 @@ module.exports = class eWeLinkHTTP { await helpers.sleep(30000) await this.getDevice(deviceId) } else { - return err + throw err } } } diff --git a/lib/ewelink-ws.js b/lib/ewelink-ws.js index ee7f60ef..f04a5bc6 100644 --- a/lib/ewelink-ws.js +++ b/lib/ewelink-ws.js @@ -47,7 +47,7 @@ module.exports = class eWeLinkWS { await helpers.sleep(30000) await this.getHost() } else { - return err + throw err } } } From 02f7abcda18b2b9f89794f7e1e99f76fa3d5bd8e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 3 Nov 2020 13:24:06 +0000 Subject: [PATCH 0643/3183] support zigbee 1009 type --- lib/device/zb-dev.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index 17ecc7cb..bebe372c 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -34,6 +34,7 @@ module.exports = class deviceZBDev { } break } + case 1009: case 1256: { if (!accessory.getService(this.Service.Switch)) accessory.addService(this.Service.Switch) accessory.log = this.platform.log @@ -111,6 +112,7 @@ module.exports = class deviceZBDev { .updateCharacteristic(this.Characteristic.ProgrammableSwitchEvent, params.key) } break + case 1009: case 1256: if (helpers.hasProperty(params, 'switch') && ['off', 'on'].includes(params.switch)) { this.accessory From 8ad0aba22f0b5a7e97b6f8a86167f0c07c58508e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 3 Nov 2020 13:34:03 +0000 Subject: [PATCH 0644/3183] commend lengths --- lib/ewelink-platform.js | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 84349615..ae02129f 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -300,56 +300,58 @@ module.exports = class eWeLinkPlatform { helpers.devicesSingleSwitchLight.includes(device.productModel) && helpers.devicesCTempable.includes(device.extra.uiid) ) { - /********************** + /******************* LIGHTS [COLOUR TEMP] - **********************/ + *******************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new deviceLightCTemp(this, accessory) - /*********************/ + /******************/ } else if ( helpers.devicesSingleSwitch.includes(device.extra.uiid) && helpers.devicesSingleSwitchLight.includes(device.productModel) && helpers.devicesColourable.includes(device.extra.uiid) ) { - /********************** + /****************** LIGHTS [COLOUR RGB] - **********************/ + ******************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new deviceLightColour(this, accessory) - /*********************/ + /*****************/ } else if ( helpers.devicesSingleSwitch.includes(device.extra.uiid) && helpers.devicesSingleSwitchLight.includes(device.productModel) && helpers.devicesBrightable.includes(device.extra.uiid) ) { - /********************** + /************** LIGHTS [DIMMER] - **********************/ + **************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new deviceLightDimmer(this, accessory) - /*********************/ + /*************/ } else if (helpers.devicesSingleSwitch.includes(device.extra.uiid) && helpers.devicesSingleSwitchLight.includes(device.productModel)) { - /********************** + /***************************** LIGHTS [ON/OFF SINGLE CHANNEL] - **********************/ + *****************************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new deviceLightSingle(this, accessory) - /*********************/ + accessory.control = (this.config.lightAsSwitch || '').split(',').includes(device.deviceid) + ? new deviceSwitch(this, accessory) + : new deviceLightSingle(this, accessory) + /****************************/ } else if ( helpers.devicesMultiSwitch.includes(device.extra.uiid) && helpers.devicesMultiSwitchLight.includes(device.productModel) ) { - /********************* + /**************************** LIGHTS [ON/OFF MULTI CHANNEL] - *********************/ + ****************************/ if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid + 'SW0')) { if (this.devicesInHB.has(device.deviceid + 'SW0')) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) @@ -381,7 +383,7 @@ module.exports = class eWeLinkPlatform { this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) oAccessory.control = new deviceLightMulti(this, oAccessory) } - /********************/ + /***********************/ } else if (helpers.devicesSingleSwitch.includes(device.extra.uiid)) { /************************ SWITCHES [SINGLE CHANNEL] From ac7a35354664a43a28b783f34c65725bd0725bda Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 3 Nov 2020 13:34:40 +0000 Subject: [PATCH 0645/3183] lights as switch --- config.schema.json | 8 +++++++- lib/ewelink-platform.js | 21 +++++++++------------ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/config.schema.json b/config.schema.json index 0e3b2a8d..27b5f577 100644 --- a/config.schema.json +++ b/config.schema.json @@ -63,9 +63,14 @@ "title": "Hide Light/Switch Channels", "description": "A list of light/switch channels to hide from Homebridge. For example '10009553c8SW0' or multiple separated with a comma '10009553c8SW0,10009553c9SW2'." }, + "lightAsSwitch": { + "type": "string", + "title": "Light As Switch (beta)", + "description": "A list of eWeLink light switch devices to show as switches in Homebridge. For example '10009553c8' or multiple separated with a comma '10009553c8,10009553c9'" + }, "outletAsSwitch": { "type": "string", - "title": "Outlets As Switch", + "title": "Outlet As Switch", "description": "A list of eWeLink outlet devices to show as switches in Homebridge. For example '10009553c8' or multiple separated with a comma '10009553c8,10009553c9'" }, "inUsePowerThreshold": { @@ -367,6 +372,7 @@ "items": [ "hideDevFromHB", "hideChanFromHB", + "lightAsSwitch", "outletAsSwitch", "inUsePowerThreshold", "hideLightFromFan", diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index ae02129f..36cff2e3 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -256,15 +256,6 @@ module.exports = class eWeLinkPlatform { }) accessory.control = new deviceThermostat(this, accessory) /*********/ - } else if ((this.config.outletAsSwitch || '').split(',').includes(device.deviceid)) { - /****************** - OUTLETS [AS SWITCH] - ******************/ - accessory = this.devicesInHB.has(device.deviceid + 'SWX') - ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new deviceSwitch(this, accessory) - /***********************/ } else if ( helpers.devicesOutlet.includes(device.extra.uiid) || (helpers.devicesSingleSwitch.includes(device.extra.uiid) && helpers.devicesSingleSwitchOutlet.includes(device.productModel)) @@ -275,7 +266,9 @@ module.exports = class eWeLinkPlatform { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new deviceOutlet(this, accessory) + accessory.control = (this.config.outletAsSwitch || '').split(',').includes(device.deviceid) + ? new deviceSwitch(this, accessory) + : new deviceOutlet(this, accessory) /*****/ } else if (helpers.devicesUSB.includes(device.extra.uiid)) { /********** @@ -363,7 +356,9 @@ module.exports = class eWeLinkPlatform { ? this.devicesInHB.get(device.deviceid + 'SW0') : this.addAccessory(device, device.deviceid + 'SW0') } - accessory.control = new deviceLightMulti(this, accessory) + accessory.control = (this.config.lightAsSwitch || '').split(',').includes(device.deviceid) + ? new deviceSwitch(this, accessory) + : new deviceLightMulti(this, accessory) for (let i = 1; i <= helpers.chansFromUiid[device.extra.uiid]; i++) { if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid + 'SW' + i)) { if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { @@ -381,7 +376,9 @@ module.exports = class eWeLinkPlatform { oAccessory.context.reachableWAN = device.online oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) - oAccessory.control = new deviceLightMulti(this, oAccessory) + oAccessory.control = (this.config.lightAsSwitch || '').split(',').includes(device.deviceid) + ? new deviceSwitch(this, oAccessory) + : new deviceLightMulti(this, oAccessory) } /***********************/ } else if (helpers.devicesSingleSwitch.includes(device.extra.uiid)) { From d0387f872dd4096790f006a6fbe78deecb80f31a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 3 Nov 2020 13:35:22 +0000 Subject: [PATCH 0646/3183] formatting --- lib/ewelink-platform.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 36cff2e3..bacd4862 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -377,8 +377,8 @@ module.exports = class eWeLinkPlatform { oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) oAccessory.control = (this.config.lightAsSwitch || '').split(',').includes(device.deviceid) - ? new deviceSwitch(this, oAccessory) - : new deviceLightMulti(this, oAccessory) + ? new deviceSwitch(this, oAccessory) + : new deviceLightMulti(this, oAccessory) } /***********************/ } else if (helpers.devicesSingleSwitch.includes(device.extra.uiid)) { From d8e709cc8f078218e39a648bf647907782c9ad74 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 3 Nov 2020 13:36:06 +0000 Subject: [PATCH 0647/3183] 3.11.0-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7222477f..8c0c977c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0", + "version": "3.11.0-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 6222178d..8a3d42db 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.10.0", + "version": "3.11.0-0", "author": "bwp91", "contributors": [ "gbro115", From 8a6397584f88d0ffea52d0d7bc3b92ef9f27f084 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 3 Nov 2020 13:50:22 +0000 Subject: [PATCH 0648/3183] lights to switches --- config.schema.json | 6 -- lib/device/{switch.js => switch-multi.js} | 60 +++++++--------- lib/device/switch-single.js | 52 ++++++++++++++ lib/ewelink-platform.js | 85 +++-------------------- lib/helpers.js | 6 -- 5 files changed, 85 insertions(+), 124 deletions(-) rename lib/device/{switch.js => switch-multi.js} (69%) create mode 100644 lib/device/switch-single.js diff --git a/config.schema.json b/config.schema.json index 27b5f577..4d770c92 100644 --- a/config.schema.json +++ b/config.schema.json @@ -63,11 +63,6 @@ "title": "Hide Light/Switch Channels", "description": "A list of light/switch channels to hide from Homebridge. For example '10009553c8SW0' or multiple separated with a comma '10009553c8SW0,10009553c9SW2'." }, - "lightAsSwitch": { - "type": "string", - "title": "Light As Switch (beta)", - "description": "A list of eWeLink light switch devices to show as switches in Homebridge. For example '10009553c8' or multiple separated with a comma '10009553c8,10009553c9'" - }, "outletAsSwitch": { "type": "string", "title": "Outlet As Switch", @@ -372,7 +367,6 @@ "items": [ "hideDevFromHB", "hideChanFromHB", - "lightAsSwitch", "outletAsSwitch", "inUsePowerThreshold", "hideLightFromFan", diff --git a/lib/device/switch.js b/lib/device/switch-multi.js similarity index 69% rename from lib/device/switch.js rename to lib/device/switch-multi.js index fee27aff..29a059cf 100644 --- a/lib/device/switch.js +++ b/lib/device/switch-multi.js @@ -16,6 +16,9 @@ module.exports = class deviceSwitch { if (accessory.getService(this.Service.Outlet)) { accessory.removeService(accessory.getService(this.Service.Outlet)) } + if (accessory.getService(this.Service.Lightbulb)) { + accessory.removeService(accessory.getService(this.Service.Lightbulb)) + } accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('switch', accessory, { storage: 'fs', @@ -30,9 +33,6 @@ module.exports = class deviceSwitch { let oAccessory const params = {} switch (this.accessory.context.switchNumber) { - case 'X': - params.switch = value ? 'on' : 'off' - break case '0': params.switches = helpers.defaultMultiSwitchOff params.switches[0].switch = value ? 'on' : 'off' @@ -93,44 +93,32 @@ module.exports = class deviceSwitch { async externalUpdate (params) { try { - if ( - helpers.devicesSingleSwitch.includes(this.accessory.context.eweUIID) || - (this.platform.config.outletAsSwitch || '').split(',').includes(this.accessory.context.eweDeviceid) - ) { - if (!helpers.hasProperty(params, 'switch')) return - this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, params.switch === 'on') - this.accessory.eveLogger.addEntry({ - time: Math.round(new Date().valueOf() / 1000), - status: params.switch === 'on' ? 1 : 0 - }) - } else if (helpers.devicesMultiSwitch.includes(this.accessory.context.eweUIID)) { - if (!helpers.hasProperty(params, 'switches')) return - const idToCheck = this.accessory.context.hbDeviceId.slice(0, -1) - let primaryState = false - for (let i = 1; i <= this.accessory.context.channelCount; i++) { - if (params.switches[i - 1].switch === 'on') { - primaryState = true - } - if (this.platform.devicesInHB.has(idToCheck + i)) { - const oAccessory = this.platform.devicesInHB.get(idToCheck + i) - oAccessory.context.cacheOn = params.switches[i - 1].switch === 'on' - oAccessory - .getService(this.Service.Switch) - .updateCharacteristic(this.Characteristic.On, params.switches[i - 1].switch === 'on') - oAccessory.eveLogger.addEntry({ - time: Math.round(new Date().valueOf() / 1000), - status: params.switches[i - 1].switch === 'on' ? 1 : 0 - }) - } + if (!helpers.hasProperty(params, 'switches')) return + const idToCheck = this.accessory.context.hbDeviceId.slice(0, -1) + let primaryState = false + for (let i = 1; i <= this.accessory.context.channelCount; i++) { + if (params.switches[i - 1].switch === 'on') { + primaryState = true } - if (!this.platform.hiddenMasters.includes(this.accessory.context.eweDeviceId)) { - this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, primaryState) - this.accessory.eveLogger.addEntry({ + if (this.platform.devicesInHB.has(idToCheck + i)) { + const oAccessory = this.platform.devicesInHB.get(idToCheck + i) + oAccessory.context.cacheOn = params.switches[i - 1].switch === 'on' + oAccessory + .getService(this.Service.Switch) + .updateCharacteristic(this.Characteristic.On, params.switches[i - 1].switch === 'on') + oAccessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), - status: primaryState ? 1 : 0 + status: params.switches[i - 1].switch === 'on' ? 1 : 0 }) } } + if (!this.platform.hiddenMasters.includes(this.accessory.context.eweDeviceId)) { + this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, primaryState) + this.accessory.eveLogger.addEntry({ + time: Math.round(new Date().valueOf() / 1000), + status: primaryState ? 1 : 0 + }) + } } catch (err) { this.platform.deviceUpdateError(this.accessory, err, false) } diff --git a/lib/device/switch-single.js b/lib/device/switch-single.js new file mode 100644 index 00000000..6026bc74 --- /dev/null +++ b/lib/device/switch-single.js @@ -0,0 +1,52 @@ +/* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ +'use strict' +const fakegato = require('fakegato-history') +const helpers = require('./../helpers') +module.exports = class deviceSwitchSingle { + constructor (platform, accessory) { + this.platform = platform + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + this.EveHistoryService = fakegato(platform.api) + const switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) + switchService + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(value, callback)) + if (accessory.getService(this.Service.Outlet)) { + accessory.removeService(accessory.getService(this.Service.Outlet)) + } + if (accessory.getService(this.Service.Lightbulb)) { + accessory.removeService(accessory.getService(this.Service.Lightbulb)) + } + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('switch', accessory, { + storage: 'fs', + path: this.platform.eveLogPath + }) + this.accessory = accessory + } + + async internalUpdate (value, callback) { + callback() + try { + const params = { switch: value ? 'on' : 'off' } + await this.platform.sendDeviceUpdate(this.accessory, params) + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async externalUpdate (params) { + try { + if (!helpers.hasProperty(params, 'switch')) return + this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, params.switch === 'on') + this.accessory.eveLogger.addEntry({ + time: Math.round(new Date().valueOf() / 1000), + status: params.switch === 'on' ? 1 : 0 + }) + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, false) + } + } +} diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index bacd4862..b9a65493 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -18,9 +18,8 @@ const deviceSCM = require('./device/scm') const deviceLightColour = require('./device/light-colour') const deviceLightCTemp = require('./device/light-ctemp') const deviceLightDimmer = require('./device/light-dimmer') -const deviceLightMulti = require('./device/light-multi') -const deviceLightSingle = require('./device/light-single') -const deviceSwitch = require('./device/switch') +const deviceSwitchMulti = require('./device/switch-multi') +const deviceSwitchSingle = require('./device/switch-single') const deviceRFBridge = require('./device/rf-bridge') const deviceZBDev = require('./device/zb-dev') const eWeLinkHTTP = require('./ewelink-http') @@ -267,7 +266,7 @@ module.exports = class eWeLinkPlatform { ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = (this.config.outletAsSwitch || '').split(',').includes(device.deviceid) - ? new deviceSwitch(this, accessory) + ? new deviceSwitchSingle(this, accessory) : new deviceOutlet(this, accessory) /*****/ } else if (helpers.devicesUSB.includes(device.extra.uiid)) { @@ -288,11 +287,7 @@ module.exports = class eWeLinkPlatform { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new deviceSCM(this, accessory) /********************************/ - } else if ( - helpers.devicesSingleSwitch.includes(device.extra.uiid) && - helpers.devicesSingleSwitchLight.includes(device.productModel) && - helpers.devicesCTempable.includes(device.extra.uiid) - ) { + } else if (helpers.devicesCTempable.includes(device.extra.uiid)) { /******************* LIGHTS [COLOUR TEMP] *******************/ @@ -301,11 +296,7 @@ module.exports = class eWeLinkPlatform { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new deviceLightCTemp(this, accessory) /******************/ - } else if ( - helpers.devicesSingleSwitch.includes(device.extra.uiid) && - helpers.devicesSingleSwitchLight.includes(device.productModel) && - helpers.devicesColourable.includes(device.extra.uiid) - ) { + } else if (helpers.devicesColourable.includes(device.extra.uiid)) { /****************** LIGHTS [COLOUR RGB] ******************/ @@ -314,11 +305,7 @@ module.exports = class eWeLinkPlatform { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new deviceLightColour(this, accessory) /*****************/ - } else if ( - helpers.devicesSingleSwitch.includes(device.extra.uiid) && - helpers.devicesSingleSwitchLight.includes(device.productModel) && - helpers.devicesBrightable.includes(device.extra.uiid) - ) { + } else if (helpers.devicesBrightable.includes(device.extra.uiid)) { /************** LIGHTS [DIMMER] **************/ @@ -327,60 +314,6 @@ module.exports = class eWeLinkPlatform { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new deviceLightDimmer(this, accessory) /*************/ - } else if (helpers.devicesSingleSwitch.includes(device.extra.uiid) && helpers.devicesSingleSwitchLight.includes(device.productModel)) { - /***************************** - LIGHTS [ON/OFF SINGLE CHANNEL] - *****************************/ - accessory = this.devicesInHB.has(device.deviceid + 'SWX') - ? this.devicesInHB.get(device.deviceid + 'SWX') - : this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = (this.config.lightAsSwitch || '').split(',').includes(device.deviceid) - ? new deviceSwitch(this, accessory) - : new deviceLightSingle(this, accessory) - /****************************/ - } else if ( - helpers.devicesMultiSwitch.includes(device.extra.uiid) && - helpers.devicesMultiSwitchLight.includes(device.productModel) - ) { - /**************************** - LIGHTS [ON/OFF MULTI CHANNEL] - ****************************/ - if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid + 'SW0')) { - if (this.devicesInHB.has(device.deviceid + 'SW0')) { - this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) - } - this.hiddenMasters.push(device.deviceid) - accessory = this.addAccessory(device, device.deviceid + 'SW0', true) - } else { - accessory = this.devicesInHB.has(device.deviceid + 'SW0') - ? this.devicesInHB.get(device.deviceid + 'SW0') - : this.addAccessory(device, device.deviceid + 'SW0') - } - accessory.control = (this.config.lightAsSwitch || '').split(',').includes(device.deviceid) - ? new deviceSwitch(this, accessory) - : new deviceLightMulti(this, accessory) - for (let i = 1; i <= helpers.chansFromUiid[device.extra.uiid]; i++) { - if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid + 'SW' + i)) { - if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { - this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + i)) - } - oAccessory = this.addAccessory(device, device.deviceid + 'SW' + i, true) - } else { - oAccessory = this.devicesInHB.has(device.deviceid + 'SW' + i) - ? this.devicesInHB.get(device.deviceid + 'SW' + i) - : this.addAccessory(device, device.deviceid + 'SW' + i) - oAccessory - .getService(this.Service.AccessoryInformation) - .setCharacteristic(this.Characteristic.FirmwareRevision, device.params.fwVersion) - } - oAccessory.context.reachableWAN = device.online - oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false - this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) - oAccessory.control = (this.config.lightAsSwitch || '').split(',').includes(device.deviceid) - ? new deviceSwitch(this, oAccessory) - : new deviceLightMulti(this, oAccessory) - } - /***********************/ } else if (helpers.devicesSingleSwitch.includes(device.extra.uiid)) { /************************ SWITCHES [SINGLE CHANNEL] @@ -388,7 +321,7 @@ module.exports = class eWeLinkPlatform { accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new deviceSwitch(this, accessory) + accessory.control = new deviceSwitchSingle(this, accessory) /***********************/ } else if (helpers.devicesMultiSwitch.includes(device.extra.uiid)) { /*********************** @@ -405,7 +338,7 @@ module.exports = class eWeLinkPlatform { ? this.devicesInHB.get(device.deviceid + 'SW0') : this.addAccessory(device, device.deviceid + 'SW0') } - accessory.control = new deviceSwitch(this, accessory) + accessory.control = new deviceSwitchMulti(this, accessory) for (let i = 1; i <= helpers.chansFromUiid[device.extra.uiid]; i++) { if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid + 'SW' + i)) { if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { @@ -423,7 +356,7 @@ module.exports = class eWeLinkPlatform { oAccessory.context.reachableWAN = device.online oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) - oAccessory.control = new deviceSwitch(this, oAccessory) + oAccessory.control = new deviceSwitchMulti(this, oAccessory) } /**********************/ } else if (helpers.devicesRFBridge.includes(device.extra.uiid)) { diff --git a/lib/helpers.js b/lib/helpers.js index b6878e00..23eef1df 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -17,12 +17,6 @@ module.exports = { devicesNonLAN: [22, 28, 34, 59, 102, 104], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59, 104], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], - devicesSingleSwitchLight: [ - 'T1 1C', 'L1', 'B1', 'B1_R2', - 'TX1C', 'D1', 'D1R1', 'KING-M4', - 'Slampher', 'GTTA59', 'GTLC104' - ], - devicesMultiSwitchLight: ['T1 2C', 'T1 3C', 'TX2C', 'TX3C'], devicesSingleSwitchOutlet: ['Sonoff Pow', 'S20', 'S26', 'S55'], devicesBrightable: [36, 44], devicesColourable: [22, 59, 104], From 32f7b88e5ac0714fc973611ac7541759d80a6641 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 3 Nov 2020 13:55:34 +0000 Subject: [PATCH 0649/3183] 3.11.0-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8c0c977c..34e69696 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.0-0", + "version": "3.11.0-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 8a3d42db..5ca254fc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.0-0", + "version": "3.11.0-1", "author": "bwp91", "contributors": [ "gbro115", From 3e9cf875a093aa7764ef7d877fffbb49a4a21567 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 3 Nov 2020 14:17:37 +0000 Subject: [PATCH 0650/3183] add zb 1009 to permitted --- lib/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers.js b/lib/helpers.js index 23eef1df..2cdc67b1 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -31,7 +31,7 @@ module.exports = { devicesSCM: [78], devicesRFBridge: [28], devicesZBBridge: [66], - devicesZB: [1000, 1256, 1770, 2026, 3026], + devicesZB: [1000, 1009, 1256, 1770, 2026, 3026], paramsToKeep: [ 'battery', 'bright', 'brightness', 'channel', 'cmd', 'color', 'colorB', From 7f8afe050bd2a533318a3e60e0ef9605058b1ed7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 3 Nov 2020 14:17:52 +0000 Subject: [PATCH 0651/3183] code style, no changes --- lib/ewelink-platform.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index b9a65493..d490a3f5 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -633,12 +633,11 @@ module.exports = class eWeLinkPlatform { } } else { try { - if (!(this.config.hideDevFromHB || '').includes(deviceId)) { - this.log.warn('[%s] %s update received for new device which will be added.', deviceId, device.params.updateSource) - const newDevice = await this.httpClient.getDevice(deviceId) - this.initialiseDevice(newDevice) - this.lanClient.addDeviceToMap(newDevice) - } + if ((this.config.hideDevFromHB || '').includes(deviceId)) return + this.log.warn('[%s] %s update received for new device which will be added.', deviceId, device.params.updateSource) + const newDevice = await this.httpClient.getDevice(deviceId) + this.initialiseDevice(newDevice) + this.lanClient.addDeviceToMap(newDevice) } catch (err) { this.log.warn('[%s] error getting info [%s]. Restart Homebridge to add device.', deviceId, err.message) } From 7f60a4f7ecc0cf0e2b6c4108676da64e963e24b7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 3 Nov 2020 14:18:50 +0000 Subject: [PATCH 0652/3183] 3.11.0-2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 34e69696..75944394 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.0-1", + "version": "3.11.0-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 5ca254fc..14cedf97 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.0-1", + "version": "3.11.0-2", "author": "bwp91", "contributors": [ "gbro115", From c735853edede16fd4e2f2c24bea3c065864b62c5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 3 Nov 2020 19:35:43 +0000 Subject: [PATCH 0653/3183] returns --- lib/ewelink-http.js | 8 ++++---- lib/ewelink-ws.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/ewelink-http.js b/lib/ewelink-http.js index 5b23d67b..87df8917 100644 --- a/lib/ewelink-http.js +++ b/lib/ewelink-http.js @@ -121,7 +121,7 @@ module.exports = class eWeLinkHTTP { throw new Error('No valid region received - [' + givenRegion + '].') } if (this.debug) this.log('New HTTP API host received [%s].', this.httpHost) - await this.login() + return await this.login() } else { if (body.data.at) { this.aToken = body.data.at @@ -135,7 +135,7 @@ module.exports = class eWeLinkHTTP { if (body.error === 500) { if (this.debug) this.log.warn('An eWeLink error [500] occured. Retrying in 30 seconds.') await helpers.sleep(30000) - await this.login() + return await this.login() } else { throw new Error('No auth token received.\n' + JSON.stringify(body, null, 2)) } @@ -184,7 +184,7 @@ module.exports = class eWeLinkHTTP { if (helpers.hasProperty(err, 'code') && helpers.httpRetryCodes.includes(err.code)) { if (this.debug) this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') await helpers.sleep(30000) - await this.getDevices() + return await this.getDevices() } else { throw err } @@ -223,7 +223,7 @@ module.exports = class eWeLinkHTTP { if (helpers.hasProperty(err, 'code') && helpers.httpRetryCodes.includes(err.code)) { if (this.debug) this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') await helpers.sleep(30000) - await this.getDevice(deviceId) + return await this.getDevice(deviceId) } else { throw err } diff --git a/lib/ewelink-ws.js b/lib/ewelink-ws.js index f04a5bc6..88c78b84 100644 --- a/lib/ewelink-ws.js +++ b/lib/ewelink-ws.js @@ -45,7 +45,7 @@ module.exports = class eWeLinkWS { if (helpers.hasProperty(err, 'code') && helpers.httpRetryCodes.includes(err.code)) { if (this.debug) this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') await helpers.sleep(30000) - await this.getHost() + return await this.getHost() } else { throw err } From c18e4f93e8a1c17e775aa94dcfca1fb4be7f287c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 3 Nov 2020 19:37:44 +0000 Subject: [PATCH 0654/3183] check for authData --- lib/ewelink-platform.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index d490a3f5..618cd2dd 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -73,6 +73,7 @@ module.exports = class eWeLinkPlatform { this.httpClient = new eWeLinkHTTP(this.config, this.log) await this.httpClient.getHost() this.authData = await this.httpClient.login() + if (this.authData === undefined) throw new Error('No auth data received from eWeLink.') const deviceList = await this.httpClient.getDevices() deviceList.forEach(device => this.devicesInEW.set(device.deviceid, device)) this.wsClient = new eWeLinkWS(this.config, this.log, this.authData) From 9f9fddedff72878413cd60f2be23bbf80c103083 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 3 Nov 2020 19:39:23 +0000 Subject: [PATCH 0655/3183] 3.11.0-3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 75944394..e38819ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.0-2", + "version": "3.11.0-3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 14cedf97..52500b1c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.0-2", + "version": "3.11.0-3", "author": "bwp91", "contributors": [ "gbro115", From 2ed38e0c98a3e24338c76498fe8bbd004f6c55ac Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 3 Nov 2020 20:04:44 +0000 Subject: [PATCH 0656/3183] remove log line --- lib/ewelink-platform.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 618cd2dd..faa90cfb 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -635,7 +635,6 @@ module.exports = class eWeLinkPlatform { } else { try { if ((this.config.hideDevFromHB || '').includes(deviceId)) return - this.log.warn('[%s] %s update received for new device which will be added.', deviceId, device.params.updateSource) const newDevice = await this.httpClient.getDevice(deviceId) this.initialiseDevice(newDevice) this.lanClient.addDeviceToMap(newDevice) From 947b57418bc4be46d22cda887a7aa03db8a18604 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 3 Nov 2020 20:17:19 +0000 Subject: [PATCH 0657/3183] reword log message --- lib/ewelink-platform.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index faa90cfb..a085a52a 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -639,7 +639,7 @@ module.exports = class eWeLinkPlatform { this.initialiseDevice(newDevice) this.lanClient.addDeviceToMap(newDevice) } catch (err) { - this.log.warn('[%s] error getting info [%s]. Restart Homebridge to add device.', deviceId, err.message) + this.log.warn('[%s] Restart Homebridge to add new device, failed to add automatically as %s.', deviceId, err.message) } } } From 03687066c0bdbf2bb878ede9b0039c42d84be389 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 3 Nov 2020 21:55:46 +0000 Subject: [PATCH 0658/3183] fakegato in lib --- lib/device/outlet.js | 2 +- lib/device/rf-bridge.js | 2 +- lib/device/scm.js | 2 +- lib/device/sensor.js | 2 +- lib/device/switch-multi.js | 2 +- lib/device/switch-single.js | 2 +- lib/device/thermostat.js | 2 +- lib/device/usb.js | 2 +- lib/device/zb-dev.js | 2 +- lib/fakegato/LICENSE | 21 + lib/fakegato/fakegato-history.js | 847 +++++++++++++++++++++++++++++++ lib/fakegato/fakegato-storage.js | 173 +++++++ lib/fakegato/fakegato-timer.js | 133 +++++ lib/fakegato/uuid.js | 25 + package-lock.json | 20 - package.json | 1 - 16 files changed, 1208 insertions(+), 30 deletions(-) create mode 100644 lib/fakegato/LICENSE create mode 100644 lib/fakegato/fakegato-history.js create mode 100644 lib/fakegato/fakegato-storage.js create mode 100644 lib/fakegato/fakegato-timer.js create mode 100644 lib/fakegato/uuid.js diff --git a/lib/device/outlet.js b/lib/device/outlet.js index d3064231..72339905 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -1,7 +1,7 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const fakegato = require('fakegato-history') +const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') const util = require('util') module.exports = class deviceOutlet { diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index 9007f8d9..f5f61a00 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -1,7 +1,7 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const fakegato = require('fakegato-history') +const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') module.exports = class deviceRFBridge { constructor (platform, accessory) { diff --git a/lib/device/scm.js b/lib/device/scm.js index 55fd2ef8..fc8c339c 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -1,7 +1,7 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const fakegato = require('fakegato-history') +const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') module.exports = class deviceSCM { constructor (platform, accessory) { diff --git a/lib/device/sensor.js b/lib/device/sensor.js index befaa3f3..50c5816e 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -1,7 +1,7 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const fakegato = require('fakegato-history') +const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') module.exports = class deviceSensor { constructor (platform, accessory) { diff --git a/lib/device/switch-multi.js b/lib/device/switch-multi.js index 29a059cf..4722b0d9 100644 --- a/lib/device/switch-multi.js +++ b/lib/device/switch-multi.js @@ -1,7 +1,7 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const fakegato = require('fakegato-history') +const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') module.exports = class deviceSwitch { constructor (platform, accessory) { diff --git a/lib/device/switch-single.js b/lib/device/switch-single.js index 6026bc74..90c7cbf6 100644 --- a/lib/device/switch-single.js +++ b/lib/device/switch-single.js @@ -1,7 +1,7 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const fakegato = require('fakegato-history') +const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') module.exports = class deviceSwitchSingle { constructor (platform, accessory) { diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index cd969a20..2f2216d7 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -1,7 +1,7 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const fakegato = require('fakegato-history') +const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') module.exports = class deviceThermostat { constructor (platform, accessory) { diff --git a/lib/device/usb.js b/lib/device/usb.js index d00664aa..ccc96e56 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -1,7 +1,7 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const fakegato = require('fakegato-history') +const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') module.exports = class deviceUSB { constructor (platform, accessory) { diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index bebe372c..4445ee3b 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -1,7 +1,7 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const fakegato = require('fakegato-history') +const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') module.exports = class deviceZBDev { constructor (platform, accessory) { diff --git a/lib/fakegato/LICENSE b/lib/fakegato/LICENSE new file mode 100644 index 00000000..1e9cf844 --- /dev/null +++ b/lib/fakegato/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 simont77 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/fakegato/fakegato-history.js b/lib/fakegato/fakegato-history.js new file mode 100644 index 00000000..7b0d19d0 --- /dev/null +++ b/lib/fakegato/fakegato-history.js @@ -0,0 +1,847 @@ +/*jshint esversion: 6,node: true,-W041: false */ +'use strict'; + +const Format = require('util').format; +const FakeGatoTimer = require('./fakegato-timer').FakeGatoTimer; +const FakeGatoStorage = require('./fakegato-storage').FakeGatoStorage; + +const EPOCH_OFFSET = 978307200; + +const TYPE_ENERGY = 'energy', + TYPE_ROOM = 'room', + TYPE_WEATHER = 'weather', + TYPE_DOOR = 'door', + TYPE_MOTION = 'motion', + TYPE_SWITCH = 'switch', + TYPE_THERMO = 'thermo', + TYPE_AQUA = 'aqua', + TYPE_CUSTOM = 'custom'; + +var homebridge; +var Characteristic, Service; + +module.exports = function (pHomebridge) { + if (pHomebridge && !homebridge) { + homebridge = pHomebridge; + Characteristic = homebridge.hap.Characteristic; + Service = homebridge.hap.Service; + } + + + var hexToBase64 = function (val) { + return Buffer.from(('' + val).replace(/[^0-9A-F]/ig, ''), 'hex').toString('base64'); + }, + base64ToHex = function (val) { + if (!val) + return val; + return Buffer.from(val, 'base64').toString('hex'); + }, + swap16 = function (val) { + return ((val & 0xFF) << 8) + | ((val >>> 8) & 0xFF); + }, + swap32 = function (val) { + return ((val & 0xFF) << 24) + | ((val & 0xFF00) << 8) + | ((val >>> 8) & 0xFF00) + | ((val >>> 24) & 0xFF); + }, + hexToHPA = function (val) { //unused + return parseInt(swap16(val), 10); + }, + hPAtoHex = function (val) { //unused + return swap16(Math.round(val)).toString(16); + }, + numToHex = function (val, len) { + var s = Number(val >>> 0).toString(16); + if (s.length % 2 != 0) { + s = '0' + s; + } + if (len) { + return ('0000000000000' + s).slice(-1 * len); + } + return s; + }, + ucfirst = function (val) { + return val.charAt(0).toUpperCase() + val.substr(1); + }, + precisionRound = function (number, precision) { + var factor = Math.pow(10, precision); + return Math.round(number * factor) / factor; + }; + + class S2R1Characteristic extends Characteristic { + constructor() { + super('S2R1', S2R1Characteristic.UUID); + this.setProps({ + format: Characteristic.Formats.DATA, + perms: [ + Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.HIDDEN + ] + }); + } + } + + S2R1Characteristic.UUID = 'E863F116-079E-48FF-8F27-9C2605A29F52'; + + class S2R2Characteristic extends Characteristic { + constructor() { + super('S2R2', S2R2Characteristic.UUID); + this.setProps({ + format: Characteristic.Formats.DATA, + perms: [ + Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.HIDDEN + ] + }); + } + } + + S2R2Characteristic.UUID = 'E863F117-079E-48FF-8F27-9C2605A29F52'; + + class S2W1Characteristic extends Characteristic { + constructor() { + super('S2W1', S2W1Characteristic.UUID); + this.setProps({ + format: Characteristic.Formats.DATA, + perms: [ + Characteristic.Perms.WRITE, Characteristic.Perms.HIDDEN + ] + }); + } + } + + S2W1Characteristic.UUID = 'E863F11C-079E-48FF-8F27-9C2605A29F52'; + + class S2W2Characteristic extends Characteristic { + constructor() { + super('S2W2', S2W2Characteristic.UUID); + this.setProps({ + format: Characteristic.Formats.DATA, + perms: [ + Characteristic.Perms.WRITE, Characteristic.Perms.HIDDEN + ] + }); + } + } + + S2W2Characteristic.UUID = 'E863F121-079E-48FF-8F27-9C2605A29F52'; + + class FakeGatoHistoryService extends Service { + constructor(displayName, subtype) { + super(displayName, FakeGatoHistoryService.UUID, subtype); + + this.addCharacteristic(S2R1Characteristic); + this.addCharacteristic(S2R2Characteristic); + this.addCharacteristic(S2W1Characteristic); + this.addCharacteristic(S2W2Characteristic); + } + } + + FakeGatoHistoryService.UUID = 'E863F007-079E-48FF-8F27-9C2605A29F52'; + var thisAccessory = {}; + class FakeGatoHistory extends Service { + constructor(accessoryType, accessory, optionalParams) { + + super(accessory.displayName + " History", FakeGatoHistoryService.UUID); + + var entry2address = function (val) { // not used ? + var temp = val % this.memorySize; + return temp; + }.bind(this); + + thisAccessory = accessory; + this.accessoryName = thisAccessory.displayName; + this.signatures = []; + this.uuid = require('./uuid.js'); + + if (typeof (optionalParams) === 'object') { + this.size = optionalParams.size || 4032; + this.minutes = optionalParams.minutes || 10; // Optional timer length + this.storage = optionalParams.storage; // 'fs' or 'googleDrive' + this.path = optionalParams.path || optionalParams.folder || (this.storage == 'fs' ? homebridge.user.storagePath() : undefined); + this.filename = optionalParams.filename; + this.disableTimer = optionalParams.disableTimer || false; + this.disableRepeatLastData = optionalParams.disableRepeatLastData || false; + this.log = optionalParams.log || thisAccessory.log || {}; // workaround for typescript blocking of changing of accessory object definition + } else { + this.size = 4032; + this.minutes = 10; + this.disableTimer = false; + this.log = thisAccessory.log || {}; + } + + if (!this.log.debug) { + this.log.debug = function () { }; + } + + if (!this.disableTimer) { + if (homebridge.globalFakeGatoTimer === undefined) + homebridge.globalFakeGatoTimer = new FakeGatoTimer({ + minutes: this.minutes, + log: this.log + }); + } + + if (this.storage !== undefined) { + this.loaded = false; + if (homebridge.globalFakeGatoStorage === undefined) { + homebridge.globalFakeGatoStorage = new FakeGatoStorage({ + log: this.log + }); + } + homebridge.globalFakeGatoStorage.addWriter(this, { + storage: this.storage, + path: this.path, + filename: this.filename, + keyPath: optionalParams.keyPath || homebridge.user.storagePath() || undefined, + onReady: function () { + + this.load(function (err, loaded) { + //this.log.debug("Loaded",loaded); + //this.registerEvents(); + if (err) this.log.debug('Load error :', err); + else { + if (loaded) this.log.debug('History Loaded from Persistant Storage'); + this.loaded = true; + } + }.bind(this)); + }.bind(this) + }); + } + + + switch (accessoryType) { + case TYPE_WEATHER: + this.accessoryType116 = "03 0102 0202 0302"; + this.accessoryType117 = "07"; + if (!this.disableTimer) { + homebridge.globalFakeGatoTimer.subscribe(this, this.calculateAverage); + } + break; + case TYPE_ENERGY: + this.accessoryType116 = "04 0102 0202 0702 0f03"; + this.accessoryType117 = "1f"; + if (!this.disableTimer) { + homebridge.globalFakeGatoTimer.subscribe(this, this.calculateAverage); + } + break; + case TYPE_ROOM: + this.accessoryType116 = "04 0102 0202 0402 0f03"; + this.accessoryType117 = "0f"; + if (!this.disableTimer) { + homebridge.globalFakeGatoTimer.subscribe(this, this.calculateAverage); + } + break; + case TYPE_DOOR: + this.accessoryType116 = "01 0601"; + this.accessoryType117 = "01"; + if (!this.disableTimer) { + homebridge.globalFakeGatoTimer.subscribe(this, function (params) { // callback + var backLog = params.backLog || []; + var immediate = params.immediate; + + var fakegato = this.service; + var actualEntry = {}; + + if (backLog.length) { + if (!immediate) { + actualEntry.time = Math.round(new Date().valueOf() / 1000); + actualEntry.status = backLog[0].status; + } + else { + actualEntry.time = backLog[0].time; + actualEntry.status = backLog[0].status; + } + fakegato.log.debug('**Fakegato-timer callbackDoor: ', fakegato.accessoryName, ', immediate: ', immediate, ', entry: ', actualEntry); + + fakegato._addEntry(actualEntry); + } + }); + } + break; + case TYPE_MOTION: + this.accessoryType116 = "02 1301 1c01"; + this.accessoryType117 = "02"; + if (!this.disableTimer) { + homebridge.globalFakeGatoTimer.subscribe(this, function (params) { // callback + var backLog = params.backLog || []; + var immediate = params.immediate; + + var fakegato = this.service; + var actualEntry = {}; + + if (backLog.length) { + if (!immediate) { + actualEntry.time = Math.round(new Date().valueOf() / 1000); + actualEntry.status = backLog[0].status; + } + else { + actualEntry.time = backLog[0].time; + actualEntry.status = backLog[0].status; + } + fakegato.log.debug('**Fakegato-timer callbackMotion: ', fakegato.accessoryName, ', immediate: ', immediate, ', entry: ', actualEntry); + + fakegato._addEntry(actualEntry); + } + }); + } + break; + case TYPE_SWITCH: + this.accessoryType116 = "01 0e01"; + this.accessoryType117 = "01"; + if (!this.disableTimer) { + homebridge.globalFakeGatoTimer.subscribe(this, function (params) { // callback + var backLog = params.backLog || []; + var immediate = params.immediate; + + var fakegato = this.service; + var actualEntry = {}; + + if (backLog.length) { + if (!immediate) { + actualEntry.time = Math.round(new Date().valueOf() / 1000); + actualEntry.status = backLog[0].status; + } + else { + actualEntry.time = backLog[0].time; + actualEntry.status = backLog[0].status; + } + fakegato.log.debug('**Fakegato-timer callbackSwitch: ', fakegato.accessoryName, ', immediate: ', immediate, ', entry: ', actualEntry); + + fakegato._addEntry(actualEntry); + } + }); + } + break; + case TYPE_CUSTOM: + thisAccessory.services.forEach((service, i) => { + service.characteristics.forEach((characteristic, i) => { + // console.log(' characteristics', characteristic.displayName, characteristic.UUID); + switch(this.uuid.toLongFormUUID(characteristic.UUID)) { + case Characteristic.CurrentTemperature.UUID: // Temperature + this.signatures.push({ signature: '0102', length: 4, uuid: this.uuid.toShortFormUUID(characteristic.UUID), factor: 100, entry: "temp" }); + break; + case Characteristic.CurrentRelativeHumidity.UUID: // Humidity + this.signatures.push({ signature: '0202', length: 4, uuid: this.uuid.toShortFormUUID(characteristic.UUID), factor: 100, entry: "humidity" }); + break; + case 'E863F10F-079E-48FF-8F27-9C2605A29F52': // CustomCharacteristic.AtmosphericPressureLevel.UUID + this.signatures.push({ signature: '0302', length: 4, uuid: this.uuid.toShortFormUUID(characteristic.UUID), factor: 10, entry: "pressure" }); + break; + case 'E863F10B-079E-48FF-8F27-9C2605A29F52': // PPM + this.signatures.push({ signature: '0702', length: 4, uuid: this.uuid.toShortFormUUID(characteristic.UUID), factor: 10, entry: "ppm" }); + break; + case Characteristic.ContactSensorState.UUID: // Contact Sensor State + this.signatures.push({ signature: '0601', length: 2, uuid: this.uuid.toShortFormUUID(characteristic.UUID), factor: 1, entry: "contact" }); + break; + case 'E863F10D-079E-48FF-8F27-9C2605A29F52': // Power + this.signatures.push({ signature: '0702', length: 4, uuid: this.uuid.toShortFormUUID(characteristic.UUID), factor: 10, entry: "power" }); + break; + case Characteristic.On.UUID: // Switch On + this.signatures.push({ signature: '0e01', length: 2, uuid: this.uuid.toShortFormUUID(characteristic.UUID), factor: 1, entry: "status" }); + break; + case Characteristic.MotionDetected.UUID: // Motion Detected + this.signatures.push({ signature: '1c01', length: 2, uuid: this.uuid.toShortFormUUID(characteristic.UUID), factor: 1, entry: "motion" }); + break; + } + }); + }); + this.accessoryType116 = (' 0' + this.signatures.length.toString() + ' ' + this.signatures.sort((a, b) => (a.signature > b.signature) ? 1 : -1).map(a => a.signature).join(' ') + ' '); + if (!this.disableTimer) { + homebridge.globalFakeGatoTimer.subscribe(this, this.calculateAverage); + } + break; + case TYPE_AQUA: + this.accessoryType116 = "03 1f01 2a08 2302"; + this.accessoryType117 = "05"; + this.accessoryType117bis = "07"; + break; + case TYPE_THERMO: + this.accessoryType116 = "05 0102 1102 1001 1201 1d01"; + this.accessoryType117 = "1f"; + break; + } + + this.accessoryType = accessoryType; + this.firstEntry = 0; + this.lastEntry = 0; + this.history = ["noValue"]; + this.memorySize = this.size; + this.usedMemory = 0; + this.currentEntry = 1; + this.transfer = false; + this.setTime = true; + this.restarted = true; + this.refTime = 0; + this.memoryAddress = 0; + this.dataStream = ''; + + this.saving = false; + + this.registerEvents(); + if (this.storage === undefined) { + this.loaded = true; + } + } + + calculateAverage(params) { // callback + var backLog = params.backLog || []; + var previousAvrg = params.previousAvrg || {}; + var timer = params.timer; + + var fakegato = this.service; + var calc = { + sum: {}, + num: {}, + avrg: {} + }; + + for (var h in backLog) { + if (backLog.hasOwnProperty(h)) { // only valid keys + for (let key in backLog[h]) { // each record + if (backLog[h].hasOwnProperty(key) && key != 'time') { // except time + if (!calc.sum[key]) + calc.sum[key] = 0; + if (!calc.num[key]) + calc.num[key] = 0; + calc.sum[key] += backLog[h][key]; + calc.num[key]++; + calc.avrg[key] = precisionRound(calc.sum[key] / calc.num[key], 2); + } + } + } + } + calc.avrg.time = Math.round(new Date().valueOf() / 1000); // set the time of the avrg + + if(!fakegato.disableRepeatLastData) { + for (let key in previousAvrg) { // each record of previous average + if (previousAvrg.hasOwnProperty(key) && key != 'time') { // except time + if (!backLog.length ||//calc.avrg[key] == 0 || // zero value + calc.avrg[key] === undefined) // no key (meaning no value received for this key yet) + { + calc.avrg[key] = previousAvrg[key]; + } + } + } + } + + if (Object.keys(calc.avrg).length > 1) { + fakegato._addEntry(calc.avrg); + timer.emptyData(fakegato); + } + return calc.avrg; + } + + registerEvents() { + this.log.debug('Registring Events', thisAccessory.displayName); + if (typeof thisAccessory.getService === "function") { + // Platform API + this.log.debug('Platform', thisAccessory.displayName); + + this.service = thisAccessory.getService(FakeGatoHistoryService); + if (this.service === undefined) { + this.service = thisAccessory.addService(FakeGatoHistoryService, ucfirst(thisAccessory.displayName) + ' History', this.accessoryType); + } + + this.service.getCharacteristic(S2R2Characteristic) + .on('get', this.getCurrentS2R2.bind(this)); + + this.service.getCharacteristic(S2W1Characteristic) + .on('set', this.setCurrentS2W1.bind(this)); + + this.service.getCharacteristic(S2W2Characteristic) + .on('set', this.setCurrentS2W2.bind(this)); + + } + else { + // Accessory API + this.log.debug('Accessory', thisAccessory.displayName); + + this.addCharacteristic(S2R1Characteristic); + + this.addCharacteristic(S2R2Characteristic) + .on('get', this.getCurrentS2R2.bind(this)); + + this.addCharacteristic(S2W1Characteristic) + .on('set', this.setCurrentS2W1.bind(this)); + + this.addCharacteristic(S2W2Characteristic) + .on('set', this.setCurrentS2W2.bind(this)); + } + } + + sendHistory(address) { + if (address != 0) { + this.currentEntry = address; + } else { + this.currentEntry = 1; + } + this.transfer = true; + } + + addEntry(entry) { + switch (this.accessoryType) { + case TYPE_DOOR: + case TYPE_MOTION: + case TYPE_SWITCH: + if (!this.disableTimer) + homebridge.globalFakeGatoTimer.addData({ entry: entry, service: this, immediateCallback: true }); + else + this._addEntry({ time: entry.time, status: entry.status }); + break; + case TYPE_AQUA: + this._addEntry({ time: entry.time, status: entry.status, waterAmount: entry.waterAmount }); + break; + case TYPE_WEATHER: + if (!this.disableTimer) + homebridge.globalFakeGatoTimer.addData({ entry: entry, service: this }); + else + this._addEntry({ time: entry.time, temp: entry.temp, humidity: entry.humidity, pressure: entry.pressure }); + break; + case TYPE_ROOM: + if (!this.disableTimer) + homebridge.globalFakeGatoTimer.addData({ entry: entry, service: this }); + else + this._addEntry({ time: entry.time, temp: entry.temp, humidity: entry.humidity, ppm: entry.ppm }); + break; + case TYPE_ENERGY: + if (!this.disableTimer) + homebridge.globalFakeGatoTimer.addData({ entry: entry, service: this }); + else + this._addEntry({ time: entry.time, power: entry.power }); + break; + case TYPE_CUSTOM: + if (!this.disableTimer) + if ('power' in entry || 'temp' in entry) { // Only put power or temperature thru averager + homebridge.globalFakeGatoTimer.addData({ entry: entry, service: this }); + } else { + this._addEntry(entry); + } + else + this._addEntry(entry); + break; + default: + this._addEntry(entry); + break; + } + } + + //in order to be consistent with Eve, entry address start from 1 + _addEntry(entry) { + if (this.loaded) { + var entry2address = function (val) { + return val % this.memorySize; + } + .bind(this); + + var val; + + if (this.usedMemory < this.memorySize) { + this.usedMemory++; + this.firstEntry = 0; + this.lastEntry = this.usedMemory; + } else { + this.firstEntry++; + this.lastEntry = this.firstEntry + this.usedMemory; + if (this.restarted == true) { + this.history[entry2address(this.lastEntry)] = { + time: entry.time, + setRefTime: 1 + }; + this.firstEntry++; + this.lastEntry = this.firstEntry + this.usedMemory; + this.restarted = false; + } + } + + if (this.refTime == 0) { + this.refTime = entry.time - EPOCH_OFFSET; + this.history[this.lastEntry] = { + time: entry.time, + setRefTime: 1 + }; + this.initialTime = entry.time; + this.lastEntry++; + this.usedMemory++; + } + + this.history[entry2address(this.lastEntry)] = (entry); + + if (this.usedMemory < this.memorySize) { + val = Format( + '%s00000000%s%s%s%s%s000000000101', + numToHex(swap32(entry.time - this.refTime - EPOCH_OFFSET), 8), + numToHex(swap32(this.refTime), 8), + this.accessoryType116, + numToHex(swap16(this.usedMemory + 1), 4), + numToHex(swap16(this.memorySize), 4), + numToHex(swap32(this.firstEntry), 8)); + } else { + val = Format( + '%s00000000%s%s%s%s%s000000000101', + numToHex(swap32(entry.time - this.refTime - EPOCH_OFFSET), 8), + numToHex(swap32(this.refTime), 8), + this.accessoryType116, + numToHex(swap16(this.usedMemory), 4), + numToHex(swap16(this.memorySize), 4), + numToHex(swap32(this.firstEntry + 1), 8)); + } + + if (this.service === undefined) { // Accessory API + this.getCharacteristic(S2R1Characteristic).setValue(hexToBase64(val)); + } + else { // Platform API + this.service.getCharacteristic(S2R1Characteristic).setValue(hexToBase64(val)); + } + + this.log.debug("First entry %s: %s", this.accessoryName, this.firstEntry.toString(16)); + this.log.debug("Last entry %s: %s", this.accessoryName, this.lastEntry.toString(16)); + this.log.debug("Used memory %s: %s", this.accessoryName, this.usedMemory.toString(16)); + this.log.debug("116 %s: %s", this.accessoryName, val); + + if (this.storage !== undefined) this.save(); + } else { + setTimeout(function () { // retry in 100ms + this._addEntry(entry); + }.bind(this), 100); + } + } + getInitialTime() { + return this.initialTime; + } + + setExtraPersistedData(extra) { + this.extra = extra; + } + + getExtraPersistedData() { + return this.extra; + } + + isHistoryLoaded() { + return this.loaded; + } + + save() { + if (this.loaded) { + + let data = { + firstEntry: this.firstEntry, + lastEntry: this.lastEntry, + usedMemory: this.usedMemory, + refTime: this.refTime, + initialTime: this.initialTime, + history: this.history, + extra: this.extra + }; + + + homebridge.globalFakeGatoStorage.write({ + service: this, + data: typeof (data) === "object" ? JSON.stringify(data) : data + }); + + } else { + setTimeout(function () { // retry in 100ms + this.save(); + }.bind(this), 100); + } + } + load(cb) { + this.log.debug("Loading..."); + homebridge.globalFakeGatoStorage.read({ + service: this, + callback: function (err, data) { + if (!err) { + if (data) { + try { + this.log.debug("read data from", this.accessoryName, ":", data); + let jsonFile = typeof (data) === "object" ? data : JSON.parse(data); + + this.firstEntry = jsonFile.firstEntry; + this.lastEntry = jsonFile.lastEntry; + this.usedMemory = jsonFile.usedMemory; + this.refTime = jsonFile.refTime; + this.initialTime = jsonFile.initialTime; + this.history = jsonFile.history; + this.extra = jsonFile.extra; + } catch (e) { + this.log.debug("**ERROR fetching persisting data restart from zero - invalid JSON**", e); + cb(e, false); + } + cb(null, true); + } + } else { + // file don't exists + cb(null, false); + } + }.bind(this) + }); + } + cleanPersist() { + this.log.debug("Cleaning..."); + homebridge.globalFakeGatoStorage.remove({ + service: this + }); + } + + getCurrentS2R2(callback) { + var entry2address = function (val) { + return val % this.memorySize; + }.bind(this); + + if ((this.currentEntry <= this.lastEntry) && (this.transfer == true)) { + this.memoryAddress = entry2address(this.currentEntry); + for (var i = 0; i < 11; i++) { + if ((this.history[this.memoryAddress].setRefTime == 1) || (this.setTime == true) || + (this.currentEntry == this.firstEntry + 1)) { + this.dataStream += Format( + ",15%s 0100 0000 81%s0000 0000 00 0000", + numToHex(swap32(this.currentEntry), 8), + numToHex(swap32(this.refTime), 8)); + this.setTime = false; + } + else { + this.log.debug("%s Entry: %s, Address: %s", this.accessoryName, this.currentEntry, this.memoryAddress); + switch (this.accessoryType) { + case TYPE_WEATHER: + this.dataStream += Format( + ",10 %s%s-%s:%s %s %s", + numToHex(swap32(this.currentEntry), 8), + numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 8), + this.accessoryType117, + numToHex(swap16(this.history[this.memoryAddress].temp * 100), 4), + numToHex(swap16(this.history[this.memoryAddress].humidity * 100), 4), + numToHex(swap16(this.history[this.memoryAddress].pressure * 10), 4)); + break; + case TYPE_ENERGY: + this.dataStream += Format( + ",14 %s%s-%s:0000 0000 %s 0000 0000", + numToHex(swap32(this.currentEntry), 8), + numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 8), + this.accessoryType117, + numToHex(swap16(this.history[this.memoryAddress].power * 10), 4)); + break; + case TYPE_ROOM: + this.dataStream += Format( + ",13 %s%s%s%s%s%s0000 00", + numToHex(swap32(this.currentEntry), 8), + numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 8), + this.accessoryType117, + numToHex(swap16(this.history[this.memoryAddress].temp * 100), 4), + numToHex(swap16(this.history[this.memoryAddress].humidity * 100), 4), + numToHex(swap16(this.history[this.memoryAddress].ppm), 4)); + break; + case TYPE_DOOR: + case TYPE_MOTION: + case TYPE_SWITCH: + this.dataStream += Format( + ",0b %s%s%s%s", + numToHex(swap32(this.currentEntry), 8), + numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 8), + this.accessoryType117, + numToHex(this.history[this.memoryAddress].status, 2)); + break; + case TYPE_AQUA: + if (this.history[this.memoryAddress].status == true) + this.dataStream += Format( + ",0d %s%s%s%s 300c", + numToHex(swap32(this.currentEntry), 8), + numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 8), + this.accessoryType117, + numToHex(this.history[this.memoryAddress].status, 2)); + else + this.dataStream += Format( + ",15 %s%s%s%s%s 00000000 300c", + numToHex(swap32(this.currentEntry), 8), + numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 8), + this.accessoryType117bis, + numToHex(this.history[this.memoryAddress].status, 2), + numToHex(swap32(this.history[this.memoryAddress].waterAmount), 8)); + break; + case TYPE_THERMO: + this.dataStream += Format( + ",11 %s%s%s%s%s%s 0000", + numToHex(swap32(this.currentEntry), 8), + numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 8), + this.accessoryType117, + numToHex(swap16(this.history[this.memoryAddress].currentTemp * 100), 4), + numToHex(swap16(this.history[this.memoryAddress].setTemp * 100), 4), + numToHex(this.history[this.memoryAddress].valvePosition, 2)); + break; + case TYPE_CUSTOM: + var result = []; + var bitmask = 0; + var dataStream = Format("%s%s", + numToHex(swap32(this.currentEntry), 8), + numToHex(swap32(this.history[this.memoryAddress].time - this.refTime - EPOCH_OFFSET), 8)); + for (const [key, value] of Object.entries(this.history[this.memoryAddress])) { + switch (key) { + case 'time': + break; + default: + for (var x = 0, iLen = this.signatures.length; x < iLen; x++) { + if (this.signatures[x].entry === key) { + // console.log('key', key, this.signatures[x].uuid, value, this.signatures[x].factor); + switch(this.signatures[x].length) { + case 8: + result[x] = Format('%s', numToHex(swap32(value * this.signatures[x].factor), this.signatures[x].length)); + break; + case 4: + result[x] = Format('%s', numToHex(swap16(value * this.signatures[x].factor), this.signatures[x].length)); + break; + case 2: + result[x] = Format('%s', numToHex(value * this.signatures[x].factor, this.signatures[x].length)); + break; + } + bitmask += Math.pow(2, x); + } + } + } + } + var results = dataStream + ' ' + numToHex(bitmask, 2) + ' ' + result.map(a => a).join(' '); + // console.log('results', numToHex((results.replace(/[^0-9A-F]/ig, '').length) / 2 + 1) + ' ' + results); + this.dataStream += (' ' + numToHex((results.replace(/[^0-9A-F]/ig, '').length) / 2 + 1) + ' ' + results + ','); + break; + } + } + this.currentEntry++; + this.memoryAddress = entry2address(this.currentEntry); + if (this.currentEntry > this.lastEntry) + break; + } + this.log.debug("Data %s: %s", this.accessoryName, this.dataStream); + callback(null, hexToBase64(this.dataStream)); + this.dataStream = ''; + } + else { + this.transfer = false; + callback(null, hexToBase64('00')); + } + } + + + setCurrentS2W1(val, callback) { + callback(null, val); + this.log.debug("Data request %s: %s", this.accessoryName, base64ToHex(val)); + var valHex = base64ToHex(val); + var substring = valHex.substring(4, 12); + var valInt = parseInt(substring, 16); + var address = swap32(valInt); + var hexAddress = address.toString('16'); + + this.log.debug("Address requested %s: %s", this.accessoryName, hexAddress); + this.sendHistory(address); + + } + + setCurrentS2W2(val, callback) { + this.log.debug("Clock adjust %s: %s", this.accessoryName, base64ToHex(val)); + callback(null, val); + } + + } + + FakeGatoHistoryService.UUID = 'E863F007-079E-48FF-8F27-9C2605A29F52'; + + return FakeGatoHistory; +}; diff --git a/lib/fakegato/fakegato-storage.js b/lib/fakegato/fakegato-storage.js new file mode 100644 index 00000000..626d5a45 --- /dev/null +++ b/lib/fakegato/fakegato-storage.js @@ -0,0 +1,173 @@ +/*jshint esversion: 6,node: true,-W041: false */ +'use strict'; + +const DEBUG = true; + +var fs = require('fs'); +var os = require('os'); +var path = require('path'); +var hostname = os.hostname().split(".")[0]; + +// var googleDrive = require('./lib/googleDrive').drive; + +var fileSuffix = '_persist.json'; + +var thisStorage; + +class FakeGatoStorage { + constructor(params) { + if (!params) + params = {}; + + this.writers = []; + + this.log = params.log || {}; + if (!this.log.debug) { + this.log.debug = DEBUG ? console.log : function () { }; + } + thisStorage = this; + this.addingWriter = false; + } + + addWriter(service, params) { + if (!this.addingWriter) { + this.addingWriter = true; + if (!params) + params = {}; + + this.log.debug("** Fakegato-storage AddWriter :", service.accessoryName); + + let newWriter = { + 'service': service, + 'callback': params.callback, + 'storage': params.storage || 'fs', + 'fileName': params.filename || hostname + "_" + service.accessoryName + fileSuffix // Unique filename per homebridge server. Allows test environments on other servers not to break prod. + }; + var onReady = typeof (params.onReady) == 'function' ? params.onReady : function () { }.bind(this); + + switch (newWriter.storage) { + case 'fs': + newWriter.storageHandler = fs; + newWriter.path = params.path || path.join(os.homedir(), '.homebridge'); + this.writers.push(newWriter); + this.addingWriter = false; + onReady(); + break; + /* + case 'googleDrive': + newWriter.path = params.path || 'fakegato'; + newWriter.keyPath = params.keyPath || path.join(os.homedir(), '.homebridge'); + newWriter.storageHandler = new googleDrive({ + keyPath: newWriter.keyPath, callback: function () { + this.addingWriter = false; + onReady(arguments); + }.bind(this), folder: newWriter.path + }); + this.writers.push(newWriter); + break; + case 'memcached' : + + break; + */ + } + } else { + setTimeout(function () { + this.addWriter(service, params); + }.bind(this), 100); + } + } + getWriter(service) { + let findServ = function (element) { + return element.service === service; + }; + return this.writers.find(findServ); + } + _getWriterIndex(service) { + let findServ = function (element) { + return element.service === service; + }; + return this.writers.findIndex(findServ); + } + getWriters() { + return this.writers; + } + delWriter(service) { + let index = this._getWriterIndex(service); + this.writers.splice(index, 1); + } + + write(params) { // must be asynchronous + if (!this.writing) { + this.writing = true; + let writer = this.getWriter(params.service); + let callBack = typeof (params.callback) == 'function' ? params.callback : (typeof (writer.callback) == 'function' ? writer.callback : function () { }); // use parameter callback or writer callback or empty function + switch (writer.storage) { + case 'fs': + this.log.debug("** Fakegato-storage write FS file:", path.join(writer.path, writer.fileName), params.data.substr(1, 80)); + writer.storageHandler.writeFile(path.join(writer.path, writer.fileName), params.data, 'utf8', function () { + this.writing = false; + callBack(arguments); + }.bind(this)); + break; + /* + case 'googleDrive': + this.log.debug("** Fakegato-storage write googleDrive file:", writer.path, writer.fileName, params.data.substr(1, 80)); + writer.storageHandler.writeFile(writer.path, writer.fileName, params.data, function () { + this.writing = false; + callBack(arguments); + }.bind(this)); + break; + case 'memcached' : + + break; + */ + } + } else { + setTimeout(function () { // retry in 100ms + this.write(params); + }.bind(this), 100); + } + } + read(params) { + let writer = this.getWriter(params.service); + let callBack = typeof (params.callback) == 'function' ? params.callback : (typeof (writer.callback) == 'function' ? writer.callback : function () { }); // use parameter callback or writer callback or empty function + switch (writer.storage) { + case 'fs': + this.log.debug("** Fakegato-storage read FS file:", path.join(writer.path, writer.fileName)); + writer.storageHandler.readFile(path.join(writer.path, writer.fileName), 'utf8', callBack); + break; + /* + case 'googleDrive': + this.log.debug("** Fakegato-storage read googleDrive file: %s/%s", writer.path, writer.fileName); + writer.storageHandler.readFile(writer.path, writer.fileName, callBack); + break; + case 'memcached' : + + break; + */ + } + } + remove(params) { + let writer = this.getWriter(params.service); + let callBack = typeof (params.callback) == 'function' ? params.callback : (typeof (writer.callback) == 'function' ? writer.callback : function () { }); // use parameter callback or writer callback or empty function + switch (writer.storage) { + case 'fs': + this.log.debug("** Fakegato-storage delete FS file:", path.join(writer.path, writer.fileName)); + writer.storageHandler.unlink(path.join(writer.path, writer.fileName), callBack); + break; + /* + case 'googleDrive': + this.log.debug("** Fakegato-storage delete googleDrive file:", writer.path, writer.fileName); + writer.storageHandler.deleteFile(writer.path, writer.fileName, callBack); + break; + case 'memcached' : + + break; + */ + } + } +} + +module.exports = { + FakeGatoStorage: FakeGatoStorage +}; diff --git a/lib/fakegato/fakegato-timer.js b/lib/fakegato/fakegato-timer.js new file mode 100644 index 00000000..2a78bef9 --- /dev/null +++ b/lib/fakegato/fakegato-timer.js @@ -0,0 +1,133 @@ +/*jshint esversion: 6,node: true,-W041: false */ +'use strict'; + +const DEBUG = true; + +class FakeGatoTimer { + constructor(params) { + if (!params) + params = {}; + this.subscribedServices = []; + this.minutes = params.minutes || 10; + + this.intervalID = null; + this.running = false; + this.log = params.log || {}; + if (!this.log.debug) { + this.log.debug = DEBUG ? console.log : function () { }; + } + } + + // Subscription management + subscribe(service, callback) { + this.log.debug("** Fakegato-timer Subscription :", service.accessoryName); + let newService = { + 'service': service, + 'callback': callback, + 'backLog': [], + 'previousBackLog': [], + 'previousAvrg': {} + }; + + this.subscribedServices.push(newService); + } + getSubscriber(service) { + let findServ = function (element) { + return element.service === service; + }; + return this.subscribedServices.find(findServ); + } + _getSubscriberIndex(service) { + let findServ = function (element) { + return element.service === service; + }; + return this.subscribedServices.findIndex(findServ); + } + getSubscribers() { + return this.subscribedServices; + } + unsubscribe(service) { + let index = this._getSubscriberIndex(service); + this.subscribedServices.splice(index, 1); + if (this.subscribedServices.length === 0 && this.running) + this.stop(); + } + + // Timer management + start() { + this.log.debug("**Start Global Fakegato-Timer - " + this.minutes + "min**"); + if (this.running) + this.stop(); + this.running = true; + this.intervalID = setInterval(this.executeCallbacks.bind(this), this.minutes * 60 * 1000); + } + stop() { + this.log.debug("**Stop Global Fakegato-Timer****"); + clearInterval(this.intervalID); + this.running = false; + this.intervalID = null; + } + + // Data management + executeCallbacks() { + this.log.debug("**Fakegato-timer: executeCallbacks**"); + if (this.subscribedServices.length !== 0) { + for (let s in this.subscribedServices) { + if (this.subscribedServices.hasOwnProperty(s)) { + + let service = this.subscribedServices[s]; + if (typeof (service.callback) == 'function') { + service.previousAvrg = service.callback({ + 'backLog': service.backLog, + 'previousAvrg': service.previousAvrg, + 'timer': this, + 'immediate': false + }); + } + } + } + } + } + executeImmediateCallback(service) { + this.log.debug("**Fakegato-timer: executeImmediateCallback**"); + + if (typeof (service.callback) == 'function' && service.backLog.length) + service.callback({ + 'backLog': service.backLog, + 'timer': this, + 'immediate': true + }); + } + addData(params) { + let data = params.entry; + let service = params.service; + let immediateCallback = params.immediateCallback || false; + + this.log.debug("**Fakegato-timer: addData ", service.accessoryName, data, " immediate: ", immediateCallback); + + if (immediateCallback) // door or motion -> replace + this.getSubscriber(service).backLog[0] = data; + else + this.getSubscriber(service).backLog.push(data); + + if (immediateCallback) { + //setTimeout(this.executeImmediateCallback.bind(this), 0,service); + this.executeImmediateCallback(this.getSubscriber(service)); + } + + if (this.running === false) + this.start(); + } + emptyData(service) { + this.log.debug("**Fakegato-timer: emptyData **", service.accessoryName); + let source = this.getSubscriber(service); + + if (source.backLog.length) source.previousBackLog = source.backLog; + source.backLog = []; + } + +} + +module.exports = { + FakeGatoTimer: FakeGatoTimer +}; diff --git a/lib/fakegato/uuid.js b/lib/fakegato/uuid.js new file mode 100644 index 00000000..f8aa9820 --- /dev/null +++ b/lib/fakegato/uuid.js @@ -0,0 +1,25 @@ +// https://github.com/homebridge/HAP-NodeJS/blob/master/src/lib/util/uuid.ts + +const VALID_UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; + +function isValid(UUID) { + return VALID_UUID_REGEX.test(UUID); +} +const VALID_SHORT_REGEX = /^[0-9a-f]{1,8}$/i; + +function toLongFormUUID(uuid, base = '-0000-1000-8000-0026BB765291') { + if (isValid(uuid)) return uuid.toUpperCase(); + if (!VALID_SHORT_REGEX.test(uuid)) throw new TypeError('uuid was not a valid UUID or short form UUID'); + if (!isValid('00000000' + base)) throw new TypeError('base was not a valid base UUID'); + + return (('00000000' + uuid).substr(-8) + base).toUpperCase(); +} + +function toShortFormUUID(uuid, base = '-0000-1000-8000-0026BB765291') { + uuid = toLongFormUUID(uuid, base); + return (uuid.substr(0, 8)); +} + +exports.isValid = isValid; +exports.toLongFormUUID = toLongFormUUID; +exports.toShortFormUUID = toShortFormUUID; diff --git a/package-lock.json b/package-lock.json index e38819ec..b265196e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,14 +39,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -83,13 +75,6 @@ "is-symbol": "^1.0.2" } }, - "fakegato-history": { - "version": "github:bwp91/fakegato-history#39a065f0a443f6c5b460edcb6e177872d939cc13", - "from": "github:bwp91/fakegato-history", - "requires": { - "debug": "^2.2.0" - } - }, "follow-redirects": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", @@ -159,11 +144,6 @@ "has-symbols": "^1.0.1" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, "node-dns-sd": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/node-dns-sd/-/node-dns-sd-0.4.2.tgz", diff --git a/package.json b/package.json index 52500b1c..9d7dbc79 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,6 @@ "dependencies": { "axios": "0.21.0", "color-convert": "2.0.1", - "fakegato-history": "bwp91/fakegato-history", "interval-promise": "1.4.0", "node-dns-sd": "0.4.2", "websocket-as-promised": "1.1.0", From e88d83df4d32387ebf55e8851621321105a84426 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 3 Nov 2020 21:56:22 +0000 Subject: [PATCH 0659/3183] not needed --- lib/device/light-multi.js | 105 ------------------------------------- lib/device/light-single.js | 33 ------------ 2 files changed, 138 deletions(-) delete mode 100644 lib/device/light-multi.js delete mode 100644 lib/device/light-single.js diff --git a/lib/device/light-multi.js b/lib/device/light-multi.js deleted file mode 100644 index c851d09f..00000000 --- a/lib/device/light-multi.js +++ /dev/null @@ -1,105 +0,0 @@ -/* jshint -W014, -W033, esversion: 9 */ -/* eslint-disable new-cap */ -'use strict' -const helpers = require('./../helpers') -module.exports = class deviceLightMulti { - constructor (platform, accessory) { - this.platform = platform - this.Service = platform.api.hap.Service - this.Characteristic = platform.api.hap.Characteristic - const lightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) - lightService - .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(value, callback)) - this.accessory = accessory - } - - async internalUpdate (value, callback) { - callback() - try { - let oAccessory - const params = {} - switch (this.accessory.context.switchNumber) { - case '0': - params.switches = helpers.defaultMultiSwitchOff - params.switches[0].switch = value ? 'on' : 'off' - params.switches[1].switch = value ? 'on' : 'off' - params.switches[2].switch = value ? 'on' : 'off' - params.switches[3].switch = value ? 'on' : 'off' - break - case '1': - case '2': - case '3': - case '4': - params.switches = helpers.defaultMultiSwitchOff - for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { - if (i === parseInt(this.accessory.context.switchNumber)) { - params.switches[i - 1].switch = value ? 'on' : 'off' - } else { - params.switches[i - 1].switch = oAccessory.context.cacheOn ? 'on' : 'off' - } - } else { - params.switches[i - 1].switch = 'off' - } - } - break - } - await this.platform.sendDeviceUpdate(this.accessory, params) - switch (this.accessory.context.switchNumber) { - case '0': - for (let i = 0; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { - oAccessory.getService(this.Service.Lightbulb).updateCharacteristic(this.Characteristic.On, value) - } - } - break - case '1': - case '2': - case '3': - case '4': { - let masterState = 'off' - for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { - if (oAccessory.getService(this.Service.Lightbulb).getCharacteristic(this.Characteristic.On).value) { - masterState = 'on' - } - } - } - if (!this.platform.hiddenMasters.includes(this.accessory.context.eweDeviceId)) { - oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW0') - oAccessory.getService(this.Service.Lightbulb).updateCharacteristic(this.Characteristic.On, masterState === 'on') - } - break - } - } - } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) - } - } - - async externalUpdate (params) { - try { - if (!helpers.hasProperty(params, 'switches')) return - const idToCheck = this.accessory.context.hbDeviceId.slice(0, -1) - let primaryState = false - for (let i = 1; i <= this.accessory.context.channelCount; i++) { - if (params.switches[i - 1].switch === 'on') { - primaryState = true - } - if (this.platform.devicesInHB.has(idToCheck + i)) { - const oAccessory = this.platform.devicesInHB.get(idToCheck + i) - oAccessory.context.cacheOn = params.switches[i - 1].switch === 'on' - oAccessory - .getService(this.Service.Lightbulb) - .updateCharacteristic(this.Characteristic.On, params.switches[i - 1].switch === 'on') - } - } - if (!this.platform.hiddenMasters.includes(this.accessory.context.eweDeviceId)) { - this.accessory.getService(this.Service.Lightbulb).updateCharacteristic(this.Characteristic.On, primaryState) - } - } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) - } - } -} diff --git a/lib/device/light-single.js b/lib/device/light-single.js deleted file mode 100644 index c62ee8fa..00000000 --- a/lib/device/light-single.js +++ /dev/null @@ -1,33 +0,0 @@ -/* jshint -W014, -W033, esversion: 9 */ -/* eslint-disable new-cap */ -'use strict' -module.exports = class deviceLightSingle { - constructor (platform, accessory) { - this.platform = platform - this.Service = platform.api.hap.Service - this.Characteristic = platform.api.hap.Characteristic - const lightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) - lightService - .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(value, callback)) - this.accessory = accessory - } - - async internalUpdate (value, callback) { - callback() - try { - const params = { switch: value ? 'on' : 'off' } - await this.platform.sendDeviceUpdate(this.accessory, params) - } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) - } - } - - async externalUpdate (params) { - try { - this.accessory.getService(this.Service.Lightbulb).updateCharacteristic(this.Characteristic.On, params.switch === 'on') - } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) - } - } -} From 301d91219066090249df214e59c36f9eeceee602 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 3 Nov 2020 22:09:17 +0000 Subject: [PATCH 0660/3183] 3.11.0-4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index b265196e..825e6c59 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.0-3", + "version": "3.11.0-4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 9d7dbc79..2c7708b5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.0-3", + "version": "3.11.0-4", "author": "bwp91", "contributors": [ "gbro115", From 429fef6cefcc3ff9e5f710df48e27e0e3ed620df Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 4 Nov 2020 13:00:09 +0000 Subject: [PATCH 0661/3183] remove battery service for switches --- lib/device/zb-dev.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index 4445ee3b..a7514131 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -21,9 +21,9 @@ module.exports = class deviceZBDev { : this.sensorTimeDifference < 10 ? helpers.defaults.sensorTimeDifference : this.sensorTimeDifference - if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) switch (accessory.context.eweUIID) { case 1000: { + if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) const zbspsService = accessory.getService(this.Service.StatelessProgrammableSwitch) || accessory.addService(this.Service.StatelessProgrammableSwitch) @@ -35,7 +35,8 @@ module.exports = class deviceZBDev { break } case 1009: - case 1256: { + case 1256: + if (accessory.getService(this.Service.BatteryService)) accessory.removeService(accessory.getService(this.Service.BatteryService)) if (!accessory.getService(this.Service.Switch)) accessory.addService(this.Service.Switch) accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('switch', accessory, { @@ -46,8 +47,8 @@ module.exports = class deviceZBDev { .getCharacteristic(this.Characteristic.On) .on('set', (value, callback) => this.internalUpdate(value, callback)) break - } - case 1770: { + case 1770: + if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) if (!accessory.getService(this.Service.TemperatureSensor)) accessory.addService(this.Service.TemperatureSensor) if (!accessory.getService(this.Service.HumiditySensor)) accessory.addService(this.Service.HumiditySensor) accessory.log = this.platform.log @@ -56,8 +57,8 @@ module.exports = class deviceZBDev { path: this.platform.eveLogPath }) break - } - case 2026: { + case 2026: + if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) if (!accessory.getService(this.Service.MotionSensor)) accessory.addService(this.Service.MotionSensor) accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('motion', accessory, { @@ -65,8 +66,8 @@ module.exports = class deviceZBDev { path: this.platform.eveLogPath }) break - } - case 3026: { + case 3026: + if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) if (!accessory.getService(this.Service.ContactSensor)) accessory.addService(this.Service.ContactSensor) accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('door', accessory, { @@ -74,7 +75,6 @@ module.exports = class deviceZBDev { path: this.platform.eveLogPath }) break - } } this.accessory = accessory } @@ -150,9 +150,9 @@ module.exports = class deviceZBDev { const timeNow = new Date() const diff = (timeNow.getTime() - params.trigTime) / 1000 const motionDetected = - helpers.hasProperty(params, 'updateSource') && - params.motion === 1 && - diff < this.sensorTimeDifference + helpers.hasProperty(params, 'updateSource') && + params.motion === 1 && + diff < this.sensorTimeDifference this.accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: motionDetected ? 1 : 0 From 394dcd5b7cc9ebc184529ec0ad25898d0db04934 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 4 Nov 2020 13:00:12 +0000 Subject: [PATCH 0662/3183] Update package.json --- package.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/package.json b/package.json index 2c7708b5..44b29e96 100644 --- a/package.json +++ b/package.json @@ -71,5 +71,10 @@ "node-dns-sd": "0.4.2", "websocket-as-promised": "1.1.0", "ws": "7.3.1" + }, + "standard": { + "ignore": [ + "/lib/fakegato/" + ] } } From a0fbcdebe60e75381295578e25365c28be57e20b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 4 Nov 2020 13:41:48 +0000 Subject: [PATCH 0663/3183] 3.11.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 825e6c59..f894ce79 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.0-4", + "version": "3.11.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 44b29e96..489ced8f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.0-4", + "version": "3.11.0", "author": "bwp91", "contributors": [ "gbro115", From 4096c20277d007b525e5ab85ebbcf954fd9c5f23 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 4 Nov 2020 19:17:28 +0000 Subject: [PATCH 0664/3183] diffuser - skeletal support --- lib/device/diffuser.js | 35 +++++++++++++++++++++++++++++++++++ lib/ewelink-platform.js | 10 ++++++++++ lib/helpers.js | 3 ++- 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 lib/device/diffuser.js diff --git a/lib/device/diffuser.js b/lib/device/diffuser.js new file mode 100644 index 00000000..a16abdae --- /dev/null +++ b/lib/device/diffuser.js @@ -0,0 +1,35 @@ +/* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ +'use strict' +const helpers = require('./../helpers') +module.exports = class deviceDiffuser { + constructor (platform, accessory) { + this.platform = platform + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + const service = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) + service + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalSwitchUpdate(value, callback)) + this.accessory = accessory + } + + async internalSwitchUpdate (value, callback) { + callback() + try { + const params = { switch: value ? 'on' : 'off' } + await this.platform.sendDeviceUpdate(this.accessory, params) + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async externalUpdate (params) { + try { + if (!helpers.hasProperty(params, 'switch')) return + this.accessory.getService(this.Service.Lightbulb).updateCharacteristic(this.Characteristic.On, params.switch === 'on') + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, false) + } + } +} diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index a085a52a..8ae35653 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -11,6 +11,7 @@ const deviceLock = require('./device/lock') const deviceValve = require('./device/valve') const deviceSensor = require('./device/sensor') const deviceFan = require('./device/fan') +const deviceDiffuser = require('./device/diffuser') const deviceThermostat = require('./device/thermostat') const deviceOutlet = require('./device/outlet') const deviceUSB = require('./device/usb') @@ -245,6 +246,15 @@ module.exports = class eWeLinkPlatform { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new deviceFan(this, accessory) /**/ + } else if (helpers.devicesDiffuser.includes(device.extra.uiid)) { + /******** + DIFFUSERS + ********/ + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new deviceDiffuser(this, accessory) + /**/ } else if (helpers.devicesThermostat.includes(device.extra.uiid)) { /********** THERMOSTATS diff --git a/lib/helpers.js b/lib/helpers.js index 2cdc67b1..47bd7483 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -25,6 +25,7 @@ module.exports = { devicesSensor: [102], devicesThermostat: [15], devicesFan: [34], + devicesDiffuser: [25], devicesOutlet: [32], devicesCamera: [87], devicesUSB: [77], @@ -123,7 +124,7 @@ module.exports = { 22: 1, // "RGB_BALL_LIGHT" \\ B1, B1_R2 23: 0, // "NEST_THERMOSTAT" \\ 24: 1, // "GSM_SOCKET" \\ - 25: 0, // "AROMATHERAPY", \\ Diffuser + 25: 0, // "AROMATHERAPY", \\ Diffuser, Komeito 1515-X 26: 0, // "RuiMiTeWenKongQi" \\ 27: 1, // "GSM_UNLIMIT_SOCKET" \\ 28: 1, // "RF_BRIDGE" \\ RFBridge, RF_Bridge From eb3ed14f7b013db91de0c584f5adca6556ed68b6 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 4 Nov 2020 19:18:32 +0000 Subject: [PATCH 0665/3183] 3.11.1-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f894ce79..da43220f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.0", + "version": "3.11.1-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 489ced8f..707103bd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.0", + "version": "3.11.1-0", "author": "bwp91", "contributors": [ "gbro115", From 09726764d225b0b49641ea2d5c03abaf96f6a497 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 5 Nov 2020 11:03:54 +0000 Subject: [PATCH 0666/3183] diffuser more support --- lib/device/diffuser.js | 120 ++++++++++++++++++++++++++++++++++++++--- lib/helpers.js | 10 ++-- 2 files changed, 120 insertions(+), 10 deletions(-) diff --git a/lib/device/diffuser.js b/lib/device/diffuser.js index a16abdae..966cf348 100644 --- a/lib/device/diffuser.js +++ b/lib/device/diffuser.js @@ -1,20 +1,41 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' +const convert = require('color-convert') const helpers = require('./../helpers') module.exports = class deviceDiffuser { constructor (platform, accessory) { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic - const service = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) - service + const onOffService = accessory.getService('Diffuser') || accessory.addService(this.Service.Fan, 'Diffuser', 'diffuser') + const lightService = accessory.getService('Light') || accessory.addService(this.Service.Lightbulb, 'Light', 'light') + onOffService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalSwitchUpdate(value, callback)) + .on('set', (value, callback) => this.internalDiffuserOnOffUpdate(value, callback)) + this.accessory = accessory + onOffService + .getCharacteristic(this.Characteristic.RotationSpeed) + .on('set', (value, callback) => this.internalDiffuserStateUpdate(value, callback)) + .setProps({ + minStep: 50 + }) + lightService + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalLightOnOffUpdate(value, callback)) + lightService + .getCharacteristic(this.Characteristic.Brightness) + .on('set', (value, callback) => this.internalLightBrightnessUpdate(value, callback)) + lightService + .getCharacteristic(this.Characteristic.Hue) + .on('set', (value, callback) => this.internalLightColourUpdate(value, callback)) + lightService + .getCharacteristic(this.Characteristic.Saturation) + .on('set', (value, callback) => callback()) this.accessory = accessory } - async internalSwitchUpdate (value, callback) { + async internalDiffuserOnOffUpdate (value, callback) { callback() try { const params = { switch: value ? 'on' : 'off' } @@ -24,10 +45,97 @@ module.exports = class deviceDiffuser { } } + async internalDiffuserStateUpdate (value, callback) { + try { + await helpers.sleep(1000) + callback() + if (value === 0) return + const value = value <= 75 ? 50 : 100 + const params = { state: value / 2 } + this.accessory.context.cacheState = value + await this.platform.sendDeviceUpdate(this.accessory, params) + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async internalLightOnOffUpdate (value, callback) { + try { + callback() + const params = { lightswitch: value ? 1 : 0 } + await this.platform.sendDeviceUpdate(this.accessory, params) + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async internalLightBrightnessUpdate (value, callback) { + try { + await helpers.sleep(1000) + callback() + const updateKeyBright = Math.random().toString(36).substr(2, 8) + this.accessory.context.updateKeyBright = updateKeyBright + const params = { + lightbright: value + } + await helpers.sleep(500) + if (updateKeyBright !== this.accessory.context.updateKeyBright) return + await this.platform.sendDeviceUpdate(this.accessory, params) + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async internalLightColourUpdate (value, callback) { + callback() + try { + const updateKeyColour = Math.random().toString(36).substr(2, 8) + this.accessory.context.updateKeyColour = updateKeyColour + const newRGB = convert.hsv.rgb(value, this.accessory.getService('Light') + .getCharacteristic(this.Characteristic.Saturation).value, 100) + const params = { + lightRcolor: newRGB[0], + lightGcolor: newRGB[1], + lightBcolor: newRGB[2] + } + await helpers.sleep(500) + if (updateKeyColour !== this.accessory.context.updateKeyColour) return + await this.platform.sendDeviceUpdate(this.accessory, params) + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + async externalUpdate (params) { try { - if (!helpers.hasProperty(params, 'switch')) return - this.accessory.getService(this.Service.Lightbulb).updateCharacteristic(this.Characteristic.On, params.switch === 'on') + if (helpers.hasProperty(params, 'switch')) { + this.accessory.getService('Diffuser').updateCharacteristic(this.Characteristic.On, params.switch === 'on') + if (!helpers.hasProperty(params, 'state')) { + this.accessory.getService('Diffuser').updateCharacteristic(this.Characteristic.RotationSpeed, this.accessory.context.cacheState) + } + } + if (helpers.hasProperty(params, 'state')) { + this.accessory.getService('Diffuser').updateCharacteristic(this.Characteristic.RotationSpeed, params.state * 50) + this.accessory.context.cacheState = params.state * 50 + } + if (helpers.hasProperty(params, 'lightswitch')) { + this.accessory.getService('Light') + .updateCharacteristic(this.Characteristic.On, params.lightswitch === 1) + } + if (helpers.hasProperty(params, 'lightbright')) { + this.accessory.getService('Light') + .updateCharacteristic(this.Characteristic.Brightness, params.lightbright) + } + if ( + helpers.hasProperty(params, 'lightRcolor') && + helpers.hasProperty(params, 'lightGcolor') && + helpers.hasProperty(params, 'lightBcolor') + ) { + const newColour = convert.rgb.hsv(params.lightRcolor, params.lightGcolor, params.lightBcolor) + this.accessory.getService('Light') + .updateCharacteristic(this.Characteristic.Hue, newColour[0]) + .updateCharacteristic(this.Characteristic.Saturation, 100) + } } catch (err) { this.platform.deviceUpdateError(this.accessory, err, false) } diff --git a/lib/helpers.js b/lib/helpers.js index 47bd7483..2efccb01 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -38,10 +38,12 @@ module.exports = { 'channel', 'cmd', 'color', 'colorB', 'colorG', 'colorR', 'current', 'currentHumidity', 'currentTemperature', - 'humidity', 'key', 'lock', 'ltype', - 'mainSwitch', 'mode', 'motion', 'online', - 'power', 'rfChl', 'rfList', 'rfTrig', - 'sensorType', 'setclose', 'state', + 'humidity', 'key', 'lightbright', + 'lightswitch', 'lightRcolor', + 'lightGcolor', 'lightBcolor', 'lock', + 'ltype', 'mainSwitch', 'mode', 'motion', + 'online', 'power', 'rfChl', 'rfList', + 'rfTrig', 'sensorType', 'setclose', 'state', 'switch', 'switches', 'temperature', 'trigTime', 'type', 'voltage', 'zyx_mode' ], From d6ad61be7a730b04a8a8901dad39f4891d275972 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 5 Nov 2020 11:05:29 +0000 Subject: [PATCH 0667/3183] diffuser fix --- lib/device/diffuser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/diffuser.js b/lib/device/diffuser.js index 966cf348..90b6594f 100644 --- a/lib/device/diffuser.js +++ b/lib/device/diffuser.js @@ -50,7 +50,7 @@ module.exports = class deviceDiffuser { await helpers.sleep(1000) callback() if (value === 0) return - const value = value <= 75 ? 50 : 100 + value = value <= 75 ? 50 : 100 const params = { state: value / 2 } this.accessory.context.cacheState = value await this.platform.sendDeviceUpdate(this.accessory, params) From cc29c9597c694b1dff5c1313c8d68c7f268a4542 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 5 Nov 2020 11:06:05 +0000 Subject: [PATCH 0668/3183] 3.11.1-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index da43220f..06296a1e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.1-0", + "version": "3.11.1-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 707103bd..3f7b8ba8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.1-0", + "version": "3.11.1-1", "author": "bwp91", "contributors": [ "gbro115", From 13bcfbb4db537e617ec48dd353988720ac3281e7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 5 Nov 2020 12:12:46 +0000 Subject: [PATCH 0669/3183] colour improvements --- lib/device/diffuser.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/device/diffuser.js b/lib/device/diffuser.js index 90b6594f..ae8bcf86 100644 --- a/lib/device/diffuser.js +++ b/lib/device/diffuser.js @@ -71,7 +71,7 @@ module.exports = class deviceDiffuser { async internalLightBrightnessUpdate (value, callback) { try { - await helpers.sleep(1000) + await helpers.sleep(2000) callback() const updateKeyBright = Math.random().toString(36).substr(2, 8) this.accessory.context.updateKeyBright = updateKeyBright @@ -87,12 +87,16 @@ module.exports = class deviceDiffuser { } async internalLightColourUpdate (value, callback) { - callback() try { + await helpers.sleep(2000) + callback() const updateKeyColour = Math.random().toString(36).substr(2, 8) this.accessory.context.updateKeyColour = updateKeyColour - const newRGB = convert.hsv.rgb(value, this.accessory.getService('Light') - .getCharacteristic(this.Characteristic.Saturation).value, 100) + const newRGB = convert.hsv.rgb( + value, + this.accessory.getService('Light').getCharacteristic(this.Characteristic.Saturation).value, + 100 + ) const params = { lightRcolor: newRGB[0], lightGcolor: newRGB[1], From d01c81aeafd9a9af70d849e9d4a652d7bc8fbab4 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 5 Nov 2020 12:13:29 +0000 Subject: [PATCH 0670/3183] 3.11.1-2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 06296a1e..7e4cba17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.1-1", + "version": "3.11.1-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 3f7b8ba8..560f6e08 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.1-1", + "version": "3.11.1-2", "author": "bwp91", "contributors": [ "gbro115", From dd4d10c5bc5a6d0b99fd6d4630fc80f8ac72a6f4 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 5 Nov 2020 12:46:06 +0000 Subject: [PATCH 0671/3183] send update last --- lib/device/switch-multi.js | 32 +++++++++----------------------- lib/device/valve.js | 2 +- 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/lib/device/switch-multi.js b/lib/device/switch-multi.js index 4722b0d9..11c7c193 100644 --- a/lib/device/switch-multi.js +++ b/lib/device/switch-multi.js @@ -31,6 +31,7 @@ module.exports = class deviceSwitch { callback() try { let oAccessory + let masterState = 'off' const params = {} switch (this.accessory.context.switchNumber) { case '0': @@ -39,6 +40,11 @@ module.exports = class deviceSwitch { params.switches[1].switch = value ? 'on' : 'off' params.switches[2].switch = value ? 'on' : 'off' params.switches[3].switch = value ? 'on' : 'off' + for (let i = 0; i <= 4; i++) { + if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { + oAccessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, value) + } + } break case '1': case '2': @@ -55,28 +61,8 @@ module.exports = class deviceSwitch { } else { params.switches[i - 1].switch = 'off' } - } - break - } - await this.platform.sendDeviceUpdate(this.accessory, params) - switch (this.accessory.context.switchNumber) { - case '0': - for (let i = 0; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { - oAccessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, value) - } - } - break - case '1': - case '2': - case '3': - case '4': { - let masterState = 'off' - for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { - if (oAccessory.getService(this.Service.Switch).getCharacteristic(this.Characteristic.On).value) { - masterState = 'on' - } + if (oAccessory.getService(this.Service.Switch).getCharacteristic(this.Characteristic.On).value) { + masterState = 'on' } } if (!this.platform.hiddenMasters.includes(this.accessory.context.eweDeviceId)) { @@ -84,8 +70,8 @@ module.exports = class deviceSwitch { oAccessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, masterState === 'on') } break - } } + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) } diff --git a/lib/device/valve.js b/lib/device/valve.js index e5bc5633..9cb81422 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -65,7 +65,6 @@ module.exports = class deviceValve { params.switches[1].switch = value ? 'on' : 'off' break } - await this.platform.sendDeviceUpdate(this.accessory, params) serviceValve .updateCharacteristic(this.Characteristic.InUse, value) switch (value) { @@ -80,6 +79,7 @@ module.exports = class deviceValve { break } } + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) } From c22ca651c2d29bf4f975147bd44a8dd5332449f3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 5 Nov 2020 12:46:11 +0000 Subject: [PATCH 0672/3183] template device --- lib/device/template.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 lib/device/template.js diff --git a/lib/device/template.js b/lib/device/template.js new file mode 100644 index 00000000..96b3e25d --- /dev/null +++ b/lib/device/template.js @@ -0,0 +1,32 @@ +/* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ +'use strict' +module.exports = class deviceTemplate { + constructor (platform, accessory) { + this.platform = platform + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + const service = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) + service + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(value, callback)) + this.accessory = accessory + } + + async internalUpdate (value, callback) { + callback() + try { + + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async externalUpdate (params) { + try { + + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, false) + } + } +} From c628e9be4b9695c17e68413184789c0b196a5584 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 5 Nov 2020 12:47:23 +0000 Subject: [PATCH 0673/3183] 3.11.1-3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7e4cba17..3df90786 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.1-2", + "version": "3.11.1-3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 560f6e08..945ac85c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.1-2", + "version": "3.11.1-3", "author": "bwp91", "contributors": [ "gbro115", From 404977b90adaedf11bc3f2957f2059194b645f30 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 5 Nov 2020 12:53:22 +0000 Subject: [PATCH 0674/3183] Update switch-multi.js --- lib/device/switch-multi.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/device/switch-multi.js b/lib/device/switch-multi.js index 11c7c193..1163cb0c 100644 --- a/lib/device/switch-multi.js +++ b/lib/device/switch-multi.js @@ -53,6 +53,9 @@ module.exports = class deviceSwitch { params.switches = helpers.defaultMultiSwitchOff for (let i = 1; i <= 4; i++) { if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { + if (oAccessory.getService(this.Service.Switch).getCharacteristic(this.Characteristic.On).value) { + masterState = 'on' + } if (i === parseInt(this.accessory.context.switchNumber)) { params.switches[i - 1].switch = value ? 'on' : 'off' } else { @@ -61,9 +64,6 @@ module.exports = class deviceSwitch { } else { params.switches[i - 1].switch = 'off' } - if (oAccessory.getService(this.Service.Switch).getCharacteristic(this.Characteristic.On).value) { - masterState = 'on' - } } if (!this.platform.hiddenMasters.includes(this.accessory.context.eweDeviceId)) { oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW0') From c2c224bebf7e9187d0996678cb5b42737219f58d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 5 Nov 2020 13:23:45 +0000 Subject: [PATCH 0675/3183] 3.11.1-4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3df90786..48cba590 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.1-3", + "version": "3.11.1-4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 945ac85c..882facbb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.1-3", + "version": "3.11.1-4", "author": "bwp91", "contributors": [ "gbro115", From ad1eec9047cef002424f3811762274196b75f7c5 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 6 Nov 2020 10:23:17 +0000 Subject: [PATCH 0676/3183] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f73a85c9..941872f3 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ To use this plugin, you will need to already have [Homebridge](https://homebridg * [Beta Version](https://github.com/bwp91/homebridge-ewelink/wiki/Beta-Version) ### Features * [Supported Devices](https://github.com/bwp91/homebridge-ewelink/wiki/Supported-Devices) +* [Multi Channel Devices](https://github.com/bwp91/homebridge-ewelink/wiki/Multi-Channel-Devices) * [Accessory Simulations](https://github.com/bwp91/homebridge-ewelink/wiki/Accessory-Simulations) * [Connection Methods](https://github.com/bwp91/homebridge-ewelink/wiki/Connection-Methods) ### How-to Guides From 0ffddea69f785fcde431cb78dff18cb19e42a79c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 6 Nov 2020 10:43:10 +0000 Subject: [PATCH 0677/3183] L1 hk scene fix? --- lib/device/light-colour.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/device/light-colour.js b/lib/device/light-colour.js index 92a7d0c2..fe68041a 100644 --- a/lib/device/light-colour.js +++ b/lib/device/light-colour.js @@ -49,8 +49,8 @@ module.exports = class deviceLightColour { await this.platform.sendDeviceUpdate(this.accessory, params) break case 'brightness': { - const updateKey = Math.random().toString(36).substr(2, 8) - this.accessory.context.updateKey = updateKey + const updateKeyBright = Math.random().toString(36).substr(2, 8) + this.accessory.context.updateKeyBright = updateKeyBright switch (this.accessory.context.eweUIID) { case 22: // *** B1 doesn't support brightness *** \\ @@ -76,13 +76,13 @@ module.exports = class deviceLightColour { break } await helpers.sleep(500) - if (updateKey !== this.accessory.context.updateKey) return + if (updateKeyBright !== this.accessory.context.updateKeyBright) return await this.platform.sendDeviceUpdate(this.accessory, params) break } case 'hue': { - const updateKey = Math.random().toString(36).substr(2, 8) - this.accessory.context.updateKey = updateKey + const updateKeyColour = Math.random().toString(36).substr(2, 8) + this.accessory.context.updateKeyColour = updateKeyColour newRGB = convert.hsv.rgb(value, lightService.getCharacteristic(this.Characteristic.Saturation).value, 100) switch (this.accessory.context.eweUIID) { case 22: @@ -122,8 +122,8 @@ module.exports = class deviceLightColour { this.accessory.context.cacheB = newRGB[2] break } - await helpers.sleep(500) - if (updateKey !== this.accessory.context.updateKey) return + await helpers.sleep(1000) + if (updateKeyColour !== this.accessory.context.updateKeyColour) return await this.platform.sendDeviceUpdate(this.accessory, params) break } From 660d5188820248df4ea26eb62c13fca1b3f02f70 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 6 Nov 2020 10:44:15 +0000 Subject: [PATCH 0678/3183] 3.11.1-5 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 48cba590..4661b466 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.1-4", + "version": "3.11.1-5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 882facbb..114783d4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.1-4", + "version": "3.11.1-5", "author": "bwp91", "contributors": [ "gbro115", From e65cb7b5f896c9015fde3aff807e5294d3ecf5be Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 6 Nov 2020 12:04:41 +0000 Subject: [PATCH 0679/3183] Update light-colour.js --- lib/device/light-colour.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/device/light-colour.js b/lib/device/light-colour.js index fe68041a..a4c7320f 100644 --- a/lib/device/light-colour.js +++ b/lib/device/light-colour.js @@ -75,7 +75,7 @@ module.exports = class deviceLightColour { } break } - await helpers.sleep(500) + await helpers.sleep(1000) if (updateKeyBright !== this.accessory.context.updateKeyBright) return await this.platform.sendDeviceUpdate(this.accessory, params) break @@ -122,7 +122,7 @@ module.exports = class deviceLightColour { this.accessory.context.cacheB = newRGB[2] break } - await helpers.sleep(1000) + await helpers.sleep(2000) if (updateKeyColour !== this.accessory.context.updateKeyColour) return await this.platform.sendDeviceUpdate(this.accessory, params) break From 707731cb2433350da60a9a2f8345ad499bb0af76 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 6 Nov 2020 12:05:20 +0000 Subject: [PATCH 0680/3183] 3.11.1-6 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4661b466..018015d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.1-5", + "version": "3.11.1-6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 114783d4..de3e7886 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.1-5", + "version": "3.11.1-6", "author": "bwp91", "contributors": [ "gbro115", From 9b89f3a01aa5b82b93f51cc5b4cbe7e4a967832d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 6 Nov 2020 12:31:27 +0000 Subject: [PATCH 0681/3183] Update light-colour.js --- lib/device/light-colour.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/device/light-colour.js b/lib/device/light-colour.js index a4c7320f..fe68041a 100644 --- a/lib/device/light-colour.js +++ b/lib/device/light-colour.js @@ -75,7 +75,7 @@ module.exports = class deviceLightColour { } break } - await helpers.sleep(1000) + await helpers.sleep(500) if (updateKeyBright !== this.accessory.context.updateKeyBright) return await this.platform.sendDeviceUpdate(this.accessory, params) break @@ -122,7 +122,7 @@ module.exports = class deviceLightColour { this.accessory.context.cacheB = newRGB[2] break } - await helpers.sleep(2000) + await helpers.sleep(1000) if (updateKeyColour !== this.accessory.context.updateKeyColour) return await this.platform.sendDeviceUpdate(this.accessory, params) break From f6dc92a68cd61ecd3fe35f8330a1bd465bc890ac Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 6 Nov 2020 12:55:10 +0000 Subject: [PATCH 0682/3183] remove duplicate error check --- lib/ewelink-platform.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 8ae35653..30a6adf9 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -74,7 +74,6 @@ module.exports = class eWeLinkPlatform { this.httpClient = new eWeLinkHTTP(this.config, this.log) await this.httpClient.getHost() this.authData = await this.httpClient.login() - if (this.authData === undefined) throw new Error('No auth data received from eWeLink.') const deviceList = await this.httpClient.getDevices() deviceList.forEach(device => this.devicesInEW.set(device.deviceid, device)) this.wsClient = new eWeLinkWS(this.config, this.log, this.authData) From 004deeee757eba97100cc3725885616a6caea584 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 6 Nov 2020 13:52:57 +0000 Subject: [PATCH 0683/3183] 3.11.1-7 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 018015d0..754f0c99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.1-6", + "version": "3.11.1-7", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index de3e7886..0522db14 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.1-6", + "version": "3.11.1-7", "author": "bwp91", "contributors": [ "gbro115", From 00f3e286704167fbb402f64f5d0080a58151c94c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 6 Nov 2020 13:54:15 +0000 Subject: [PATCH 0684/3183] 3.11.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 754f0c99..51d79aff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.1-7", + "version": "3.11.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 0522db14..bfcd25fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.1-7", + "version": "3.11.1", "author": "bwp91", "contributors": [ "gbro115", From 84f4c18f1fbaac3c23e92c13be8ea3408b31bb2b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 7 Nov 2020 09:54:23 +0000 Subject: [PATCH 0685/3183] fix for valves #137 --- lib/device/valve.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/device/valve.js b/lib/device/valve.js index 9cb81422..0179331a 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -9,16 +9,16 @@ module.exports = class deviceValve { this.Characteristic = platform.api.hap.Characteristic ;['A', 'B'].forEach(v => { let valveService - const valveConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId) - if (!(valveService = this.accessory.getService('Valve ' + v))) { - this.accessory + const valveConfig = this.platform.cusG.get(accessory.context.hbDeviceId) + if (!(valveService = accessory.getService('Valve ' + v))) { + accessory .addService(this.Service.Valve, 'Valve ' + v, 'valve' + v.toLowerCase()) .setCharacteristic(this.Characteristic.Active, 0) .setCharacteristic(this.Characteristic.InUse, 0) .setCharacteristic(this.Characteristic.ValveType, 1) .setCharacteristic(this.Characteristic.SetDuration, Math.round((valveConfig.operationTime || 1200) / 10)) .addCharacteristic(this.Characteristic.RemainingDuration) - valveService = this.accessory.getService('Valve ' + v) + valveService = accessory.getService('Valve ' + v) } valveService .getCharacteristic(this.Characteristic.Active) From 3c7ba5bf33bca54cc9023437b284875ce9d0bb1e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 7 Nov 2020 10:14:20 +0000 Subject: [PATCH 0686/3183] update cache on switch update --- lib/device/switch-multi.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/device/switch-multi.js b/lib/device/switch-multi.js index 1163cb0c..0845e1ca 100644 --- a/lib/device/switch-multi.js +++ b/lib/device/switch-multi.js @@ -58,6 +58,7 @@ module.exports = class deviceSwitch { } if (i === parseInt(this.accessory.context.switchNumber)) { params.switches[i - 1].switch = value ? 'on' : 'off' + oAccessory.context.cacheOn = value } else { params.switches[i - 1].switch = oAccessory.context.cacheOn ? 'on' : 'off' } From 465bdae359de61046ab1490262591f4315c4e0ec Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 7 Nov 2020 11:14:18 +0000 Subject: [PATCH 0687/3183] 3.11.2-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 51d79aff..ab5e7b7f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.1", + "version": "3.11.2-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index bfcd25fb..00bbee34 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.1", + "version": "3.11.2-0", "author": "bwp91", "contributors": [ "gbro115", From 5d0d3d474604021a98f290c80eca424192fedb4f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 7 Nov 2020 21:44:35 +0000 Subject: [PATCH 0688/3183] clarify numbers --- config.schema.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config.schema.json b/config.schema.json index 4d770c92..871adb6e 100644 --- a/config.schema.json +++ b/config.schema.json @@ -157,19 +157,19 @@ ] }, { - "title": "Window Blind (using multi-channel device)", + "title": "1 Window Blind (using multi-channel device)", "enum": [ "blind" ] }, { - "title": "Lock (using single channel device)", + "title": "1 Lock (using single channel device)", "enum": [ "lock" ] }, { - "title": "Irrigation/Sprinkler (using multi-channel device)", + "title": "2 Irrigation Valves (using multi-channel device)", "enum": [ "valve" ] From 198478800ed4d33697f3ce56d976ba1713b3eb55 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 7 Nov 2020 21:45:04 +0000 Subject: [PATCH 0689/3183] =?UTF-8?q?=E2=9A=A0=EF=B8=8F=20valve=20to=20val?= =?UTF-8?q?ve=5Ftwo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.schema.json | 2 +- lib/device/{valve.js => valve-two.js} | 2 +- lib/ewelink-platform.js | 12 ++++++------ lib/helpers.js | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) rename lib/device/{valve.js => valve-two.js} (99%) diff --git a/config.schema.json b/config.schema.json index 871adb6e..adf13ec7 100644 --- a/config.schema.json +++ b/config.schema.json @@ -171,7 +171,7 @@ { "title": "2 Irrigation Valves (using multi-channel device)", "enum": [ - "valve" + "valve_two" ] } ] diff --git a/lib/device/valve.js b/lib/device/valve-two.js similarity index 99% rename from lib/device/valve.js rename to lib/device/valve-two.js index 0179331a..893738e7 100644 --- a/lib/device/valve.js +++ b/lib/device/valve-two.js @@ -2,7 +2,7 @@ /* eslint-disable new-cap */ 'use strict' const helpers = require('./../helpers') -module.exports = class deviceValve { +module.exports = class deviceValveTwo { constructor (platform, accessory) { this.platform = platform this.Service = platform.api.hap.Service diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 30a6adf9..c3c74ad3 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -8,7 +8,7 @@ const deviceGarageTwo = require('./device/garage-two') const deviceGarageFour = require('./device/garage-four') const deviceGarageEachen = require('./device/garage-eachen') const deviceLock = require('./device/lock') -const deviceValve = require('./device/valve') +const deviceValveTwo = require('./device/valve-two') const deviceSensor = require('./device/sensor') const deviceFan = require('./device/fan') const deviceDiffuser = require('./device/diffuser') @@ -218,14 +218,14 @@ module.exports = class eWeLinkPlatform { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new deviceLock(this, accessory) /**************************/ - } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'valve') { - /**************************** - VALVES [ACCESSORY SIMULATION] - ****************************/ + } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'valve_two') { + /********************************** + VALVES [TWO] [ACCESSORY SIMULATION] + **********************************/ accessory = this.devicesInHB.has(device.deviceid + 'SWX') ? this.devicesInHB.get(device.deviceid + 'SWX') : this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new deviceValve(this, accessory) + accessory.control = new deviceValveTwo(this, accessory) /***************************/ } else if (helpers.devicesSensor.includes(device.extra.uiid)) { /******************* diff --git a/lib/helpers.js b/lib/helpers.js index 2efccb01..878aae37 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -7,7 +7,7 @@ module.exports = { appId: 'oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq', appSecret: '6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM', httpRetryCodes: ['ENOTFOUND', 'ETIMEDOUT', 'EAI_AGAIN'], - allowedGroups: ['blind', 'garage', 'garage_two', 'garage_four', 'garage_eachen', 'lock', 'valve'], + allowedGroups: ['blind', 'garage', 'garage_two', 'garage_four', 'garage_eachen', 'lock', 'valve_two'], defaults: { inUsePowerThreshold: 0, lowBattThreshold: 25, From 65077d0421224ea4d57cb07f0049617eb48cbc3e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 7 Nov 2020 21:47:17 +0000 Subject: [PATCH 0690/3183] clarify for valves --- config.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.schema.json b/config.schema.json index adf13ec7..a27d5f72 100644 --- a/config.schema.json +++ b/config.schema.json @@ -201,7 +201,7 @@ "operationTime": { "type": "integer", "title": "Operation Time (Deciseconds)", - "description": "Blinds/garage doors: the time to fully open/close the device. Locks: the time to show as unlocked. Irrigation: the time the valves will open for. This setting is in deciseconds - count the time in seconds and multiply by 10, for example 100 for 10 seconds or 75 for 7.5 seconds.", + "description": "Blinds/garage doors: the time to fully open/close the device. Locks: the time to show as unlocked. Irrigation: an initial default time for HomeKit. This setting is in deciseconds - count the time in seconds and multiply by 10, for example 100 for 10 seconds or 75 for 7.5 seconds.", "default": 100, "minimum": 10, "maximum": 600 From 2786a1a17fe18cbdcf3e1bc9c738474fa5625971 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 7 Nov 2020 21:51:58 +0000 Subject: [PATCH 0691/3183] building blocks for valve (one) --- config.schema.json | 6 ++++++ lib/device/valve.js | 32 ++++++++++++++++++++++++++++++++ lib/ewelink-platform.js | 10 ++++++++++ lib/helpers.js | 2 +- 4 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 lib/device/valve.js diff --git a/config.schema.json b/config.schema.json index a27d5f72..608c3a36 100644 --- a/config.schema.json +++ b/config.schema.json @@ -168,6 +168,12 @@ "lock" ] }, + { + "title": "1 Irrigation Valve (using single-channel device)", + "enum": [ + "valve" + ] + }, { "title": "2 Irrigation Valves (using multi-channel device)", "enum": [ diff --git a/lib/device/valve.js b/lib/device/valve.js new file mode 100644 index 00000000..be54a971 --- /dev/null +++ b/lib/device/valve.js @@ -0,0 +1,32 @@ +/* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ +'use strict' +module.exports = class deviceValve { + constructor (platform, accessory) { + this.platform = platform + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + const service = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) + service + .getCharacteristic(this.Characteristic.On) + .on('set', (value, callback) => this.internalUpdate(value, callback)) + this.accessory = accessory + } + + async internalUpdate (value, callback) { + callback() + try { + + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async externalUpdate (params) { + try { + + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, false) + } + } +} diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index c3c74ad3..e71119f6 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -8,6 +8,7 @@ const deviceGarageTwo = require('./device/garage-two') const deviceGarageFour = require('./device/garage-four') const deviceGarageEachen = require('./device/garage-eachen') const deviceLock = require('./device/lock') +const deviceValve = require('./device/valve') const deviceValveTwo = require('./device/valve-two') const deviceSensor = require('./device/sensor') const deviceFan = require('./device/fan') @@ -218,6 +219,15 @@ module.exports = class eWeLinkPlatform { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new deviceLock(this, accessory) /**************************/ + } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'valve') { + /********************************** + VALVES [ONE] [ACCESSORY SIMULATION] + **********************************/ + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new deviceValve(this, accessory) + /***************************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'valve_two') { /********************************** VALVES [TWO] [ACCESSORY SIMULATION] diff --git a/lib/helpers.js b/lib/helpers.js index 878aae37..bcb3f2b0 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -7,7 +7,7 @@ module.exports = { appId: 'oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq', appSecret: '6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM', httpRetryCodes: ['ENOTFOUND', 'ETIMEDOUT', 'EAI_AGAIN'], - allowedGroups: ['blind', 'garage', 'garage_two', 'garage_four', 'garage_eachen', 'lock', 'valve_two'], + allowedGroups: ['blind', 'garage', 'garage_two', 'garage_four', 'garage_eachen', 'lock', 'valve', 'valve_two'], defaults: { inUsePowerThreshold: 0, lowBattThreshold: 25, From dff49eb79ce5998d27861ac09e6287e8cceddec6 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 7 Nov 2020 22:00:53 +0000 Subject: [PATCH 0692/3183] formatting --- lib/device/valve-two.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/device/valve-two.js b/lib/device/valve-two.js index 893738e7..c4d014b9 100644 --- a/lib/device/valve-two.js +++ b/lib/device/valve-two.js @@ -29,9 +29,7 @@ module.exports = class deviceValveTwo { if (valveService.getCharacteristic(this.Characteristic.InUse).value) { valveService.updateCharacteristic(this.Characteristic.RemainingDuration, value) clearTimeout(valveService.timer) - valveService.timer = setTimeout(() => { - valveService.setCharacteristic(this.Characteristic.Active, 0) - }, value * 1000) + valveService.timer = setTimeout(() => valveService.setCharacteristic(this.Characteristic.Active, 0), value * 1000) } callback() }) From de296e7d5c23739ebabed6513e6c0455d805534b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 7 Nov 2020 22:01:14 +0000 Subject: [PATCH 0693/3183] valve one initial attempt --- lib/device/valve.js | 57 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/lib/device/valve.js b/lib/device/valve.js index be54a971..8ca7e0b7 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -6,17 +6,52 @@ module.exports = class deviceValve { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic - const service = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) - service - .getCharacteristic(this.Characteristic.On) + let valveService + const valveConfig = this.platform.cusG.get(accessory.context.hbDeviceId) + if (!(valveService = accessory.getService(this.Service.Valve) { + accessory + .addService(this.Service.Valve) + .setCharacteristic(this.Characteristic.Active, 0) + .setCharacteristic(this.Characteristic.InUse, 0) + .setCharacteristic(this.Characteristic.ValveType, 1) + .setCharacteristic(this.Characteristic.SetDuration, Math.round((valveConfig.operationTime || 1200) / 10)) + .addCharacteristic(this.Characteristic.RemainingDuration) + valveService = accessory.getService(this.Service.Valve) + } + valveService + .getCharacteristic(this.Characteristic.Active) .on('set', (value, callback) => this.internalUpdate(value, callback)) + valveService + .getCharacteristic(this.Characteristic.SetDuration) + .on('set', (value, callback) => { + if (valveService.getCharacteristic(this.Characteristic.InUse).value) { + valveService.updateCharacteristic(this.Characteristic.RemainingDuration, value) + clearTimeout(valveService.timer) + valveService.timer = setTimeout(() => valveService.setCharacteristic(this.Characteristic.Active, 0), value * 1000) + } + callback() + }) this.accessory = accessory } async internalUpdate (value, callback) { callback() try { - + const serviceValve = this.accessory.getService(this.Service.Valve) + serviceValve.updateCharacteristic(this.Characteristic.InUse, value) + switch (value) { + case 0: + serviceValve.updateCharacteristic(this.Characteristic.RemainingDuration, 0) + clearTimeout(this.accessory.getService(valve).timer) + break + case 1: { + const timer = serviceValve.getCharacteristic(this.Characteristic.SetDuration).value + serviceValve.updateCharacteristic(this.Characteristic.RemainingDuration, timer) + serviceValve.timer = setTimeout(() => serviceValve.setCharacteristic(this.Characteristic.Active, 0), timer * 1000) + break + } + } + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) } @@ -24,7 +59,19 @@ module.exports = class deviceValve { async externalUpdate (params) { try { - + if (!helpers.hasProperty(params, 'switch')) return + const valveService = this.accessory.getService(this.Service.Valve) + valveService + .updateCharacteristic(this.Characteristic.Active, params.switch === 'on') + .updateCharacteristic(this.Characteristic.InUse, params.switch === 'on') + if (params.switch === 'on') { + const timer = valveService.getCharacteristic(this.Characteristic.SetDuration).value + valveService.updateCharacteristic(this.Characteristic.RemainingDuration, timer) + valveService.timer = setTimeout(() => valveService.setCharacteristic(this.Characteristic.Active, 0), timer * 1000) + } else { + valveService.updateCharacteristic(this.Characteristic.RemainingDuration, 0) + clearTimeout(valveService.timer) + } } catch (err) { this.platform.deviceUpdateError(this.accessory, err, false) } From 7259b581e7a94d222e0deb31b4341e474958a045 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 7 Nov 2020 22:02:28 +0000 Subject: [PATCH 0694/3183] remove unnecessary check --- lib/device/valve-two.js | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/lib/device/valve-two.js b/lib/device/valve-two.js index c4d014b9..63b501f0 100644 --- a/lib/device/valve-two.js +++ b/lib/device/valve-two.js @@ -40,14 +40,6 @@ module.exports = class deviceValveTwo { async internalUpdate (valve, value, callback) { callback() try { - let valveConfig - const params = { switches: helpers.defaultMultiSwitchOff } - if (!(valveConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { - throw new Error('group config missing') - } - if (valveConfig.type !== 'valve') { - throw new Error('improper configuration') - } const serviceValve = this.accessory.getService(valve) switch (valve) { case 'Valve A': @@ -63,8 +55,7 @@ module.exports = class deviceValveTwo { params.switches[1].switch = value ? 'on' : 'off' break } - serviceValve - .updateCharacteristic(this.Characteristic.InUse, value) + serviceValve.updateCharacteristic(this.Characteristic.InUse, value) switch (value) { case 0: serviceValve.updateCharacteristic(this.Characteristic.RemainingDuration, 0) @@ -86,13 +77,6 @@ module.exports = class deviceValveTwo { async externalUpdate (params) { try { if (!helpers.hasProperty(params, 'switches')) return - let valveConfig - if (!(valveConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { - throw new Error('group config missing') - } - if (valveConfig.type !== 'valve') { - throw new Error('improper configuration') - } ;['A', 'B'].forEach((v, k) => { const valveService = this.accessory.getService('Valve ' + v) valveService From 9739a48fd05fc867e7cba7bd1237312a9163de2b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 7 Nov 2020 22:06:26 +0000 Subject: [PATCH 0695/3183] syntax errors to valve and valvetwo --- lib/device/valve-two.js | 1 + lib/device/valve.js | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/device/valve-two.js b/lib/device/valve-two.js index 63b501f0..4e53ebff 100644 --- a/lib/device/valve-two.js +++ b/lib/device/valve-two.js @@ -40,6 +40,7 @@ module.exports = class deviceValveTwo { async internalUpdate (valve, value, callback) { callback() try { + const params = { switches: helpers.defaultMultiSwitchOff } const serviceValve = this.accessory.getService(valve) switch (valve) { case 'Valve A': diff --git a/lib/device/valve.js b/lib/device/valve.js index 8ca7e0b7..ac142ff3 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -1,6 +1,7 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' +const helpers = require('./../helpers') module.exports = class deviceValve { constructor (platform, accessory) { this.platform = platform @@ -8,7 +9,7 @@ module.exports = class deviceValve { this.Characteristic = platform.api.hap.Characteristic let valveService const valveConfig = this.platform.cusG.get(accessory.context.hbDeviceId) - if (!(valveService = accessory.getService(this.Service.Valve) { + if (!(valveService = accessory.getService(this.Service.Valve))) { accessory .addService(this.Service.Valve) .setCharacteristic(this.Characteristic.Active, 0) @@ -37,12 +38,13 @@ module.exports = class deviceValve { async internalUpdate (value, callback) { callback() try { + const params = { switch: value ? 'on' : 'off' } const serviceValve = this.accessory.getService(this.Service.Valve) serviceValve.updateCharacteristic(this.Characteristic.InUse, value) switch (value) { case 0: serviceValve.updateCharacteristic(this.Characteristic.RemainingDuration, 0) - clearTimeout(this.accessory.getService(valve).timer) + clearTimeout(this.accessory.getService(this.Service.Valve).timer) break case 1: { const timer = serviceValve.getCharacteristic(this.Characteristic.SetDuration).value From 6740e8d48a563304ba27da98418955f7f619c2a7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 7 Nov 2020 22:09:41 +0000 Subject: [PATCH 0696/3183] 3.12.0-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index ab5e7b7f..9cc4dc99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.2-0", + "version": "3.12.0-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 00bbee34..bfe28921 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.11.2-0", + "version": "3.12.0-0", "author": "bwp91", "contributors": [ "gbro115", From 562b210c68631254bd0cd35feeca7bcb675055fc Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 10:02:07 +0000 Subject: [PATCH 0697/3183] add 1009 to chan list --- lib/helpers.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/helpers.js b/lib/helpers.js index bcb3f2b0..8bfa21c7 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -190,6 +190,7 @@ module.exports = { 1001: 0, // "BLADELESS_FAN" \\ 1002: 0, // "NEW_HUMIDIFIER" \\ 1003: 0, // "WARM_AIR_BLOWER" \\ + 1009: 1, // "" \\ Some sort of single switch device 1256: 1, // "ZIGBEE_SINGLE_SWITCH" \\ 1770: 1, // "ZIGBEE_TEMPERATURE_SENSOR" \\ 2026: 1, // "ZIGBEE_MOBILE_SENSOR" \\ @@ -197,6 +198,6 @@ module.exports = { 3026: 1, // "ZIGBEE_DOOR_AND_WINDOW_SENSOR" \\ 3256: 3, // "ZIGBEE_SWITCH_3" \\ 4026: 1, // "ZIGBEE_WATER_SENSOR" \\ - 4256: 4 // "ZIGBEE_SWITCH_4" \\ + 4256: 4 // "ZIGBEE_SWITCH_4" \\ } } From c8176171edb6ecf087376ccc0853427c090c3ef7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 10:27:17 +0000 Subject: [PATCH 0698/3183] bump ws dependency --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9cc4dc99..f8c907be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -256,9 +256,9 @@ } }, "ws": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz", - "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==" + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.0.tgz", + "integrity": "sha512-kyFwXuV/5ymf+IXhS6f0+eAFvydbaBW3zjpT6hUdAh/hbVjTIB5EHBGi0bPoCLSK2wcuz3BrEkB9LrYv1Nm4NQ==" } } } diff --git a/package.json b/package.json index bfe28921..3ab65e24 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "interval-promise": "1.4.0", "node-dns-sd": "0.4.2", "websocket-as-promised": "1.1.0", - "ws": "7.3.1" + "ws": "7.4.0" }, "standard": { "ignore": [ From 1f08586c47693b84923c0cfc63e56f35d3d1c3d1 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 11:01:17 +0000 Subject: [PATCH 0699/3183] no change, code formatting --- lib/ewelink-platform.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index e71119f6..94d73fdc 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -574,7 +574,8 @@ module.exports = class eWeLinkPlatform { } async sendDeviceUpdate (accessory, params) { - await helpers.sleep(Math.floor(Math.random() * (100 - 10 + 1) + 10)) + // *** generates a random number in the range [10, 100] *** \\ + await helpers.sleep(Math.floor(Math.random() * 91 + 10)) if (this.updateInProgress) { await helpers.sleep(400) return await this.sendDeviceUpdate(accessory, params) From e24ad7fedbe878851a1fd63197fc9febf484006e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 11:01:37 +0000 Subject: [PATCH 0700/3183] split simultaneous updates try --- lib/device/switch-multi.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/device/switch-multi.js b/lib/device/switch-multi.js index 0845e1ca..ae1c3f7d 100644 --- a/lib/device/switch-multi.js +++ b/lib/device/switch-multi.js @@ -9,6 +9,7 @@ module.exports = class deviceSwitch { this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic this.EveHistoryService = fakegato(platform.api) + this.updateInProgress = false const switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) switchService .getCharacteristic(this.Characteristic.On) @@ -28,6 +29,14 @@ module.exports = class deviceSwitch { } async internalUpdate (value, callback) { + // *** generates a random number in the range [10, 100] *** \\ + await helpers.sleep(Math.floor(Math.random() * 91 + 10)) + if (this.updateInProgress) { + await helpers.sleep(300) + return await this.internalUpdate(value, callback) + } + this.updateInProgress = true + setTimeout(() => (this.updateInProgress = false), 250) callback() try { let oAccessory From 714ab1a25a13b744da7f74519c5030d32c902633 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 11:08:20 +0000 Subject: [PATCH 0701/3183] 3.12.0-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f8c907be..02229e1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0-0", + "version": "3.12.0-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 3ab65e24..41af04f9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0-0", + "version": "3.12.0-1", "author": "bwp91", "contributors": [ "gbro115", From 28dd566074024bcbbe3c333b6a275cf931cc89b4 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 13:10:48 +0000 Subject: [PATCH 0702/3183] don't use this.accessory --- lib/device/blind.js | 43 +++++++++++----------- lib/device/curtain.js | 21 ++++++----- lib/device/diffuser.js | 72 ++++++++++++++++++------------------- lib/device/fan.js | 25 +++++++------ lib/device/garage-eachen.js | 35 +++++++++--------- lib/device/garage-four.js | 49 +++++++++++++------------ lib/device/garage-two.js | 67 +++++++++++++++++----------------- lib/device/garage.js | 55 ++++++++++++++-------------- lib/device/light-colour.js | 63 ++++++++++++++++---------------- lib/device/light-ctemp.js | 13 ++++--- lib/device/light-dimmer.js | 27 +++++++------- lib/device/lock.js | 34 +++++++++--------- lib/device/outlet.js | 27 +++++++------- lib/device/rf-bridge.js | 19 +++++----- lib/device/scm.js | 18 +++++----- lib/device/sensor.js | 11 +++--- lib/device/switch-multi.js | 46 ++++++++++-------------- lib/device/switch-single.js | 18 +++++----- lib/device/template.js | 12 +++---- lib/device/thermostat.js | 27 +++++++------- lib/device/usb.js | 17 +++++---- lib/device/valve-two.js | 23 ++++++------ lib/device/valve.js | 19 +++++----- lib/device/zb-dev.js | 42 +++++++++++----------- lib/ewelink-platform.js | 4 +-- 25 files changed, 380 insertions(+), 407 deletions(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index b481d65e..aae2d48f 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -18,21 +18,20 @@ module.exports = class deviceBlind { } wcService .getCharacteristic(this.Characteristic.TargetPosition) - .on('set', (value, callback) => this.internalUpdate(value, callback)) - this.accessory = accessory + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) } - async internalUpdate (value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { let blindConfig const params = {} - const wcService = this.accessory.getService(this.Service.WindowCovering) - const prevState = this.accessory.context.cachePositionState - let prevPosition = this.accessory.context.cacheCurrentPosition + const wcService = accessory.getService(this.Service.WindowCovering) + const prevState = accessory.context.cachePositionState + let prevPosition = accessory.context.cacheCurrentPosition const newTarget = value const updateKey = Math.random().toString(36).substr(2, 8) - if (!(blindConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { + if (!(blindConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (blindConfig.type !== 'blind') { @@ -40,11 +39,11 @@ module.exports = class deviceBlind { } if (newTarget === prevPosition) return params.switches = helpers.defaultMultiSwitchOff - this.accessory.context.updateKey = updateKey + accessory.context.updateKey = updateKey const percentStepPerDecisecond = blindConfig.operationTime / 100 if (prevState !== 2) { - await this.platform.sendDeviceUpdate(this.accessory, params) - let positionPercentChange = Math.floor(Date.now() / 100) - this.accessory.context.cacheLastStartTime + await this.platform.sendDeviceUpdate(accessory, params) + let positionPercentChange = Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime positionPercentChange = Math.floor(percentStepPerDecisecond * positionPercentChange) if (prevState === 0) { prevPosition -= positionPercentChange @@ -52,33 +51,33 @@ module.exports = class deviceBlind { prevPosition += positionPercentChange } wcService.updateCharacteristic(this.Characteristic.CurrentPosition, prevPosition) - this.accessory.context.cacheCurrentPosition = prevPosition + accessory.context.cacheCurrentPosition = prevPosition } const diffPosition = newTarget - prevPosition const setToMoveUp = diffPosition > 0 const decisecondsToMove = Math.round(Math.abs(diffPosition) * percentStepPerDecisecond) params.switches[0].switch = setToMoveUp ? 'on' : 'off' params.switches[1].switch = setToMoveUp ? 'off' : 'on' - await this.platform.sendDeviceUpdate(this.accessory, params) - this.accessory.context.cacheTargetPosition = newTarget - this.accessory.context.cachePositionState = setToMoveUp ? 1 : 0 - this.accessory.context.cacheLastStartTime = Math.floor(Date.now() / 100) - if (this.accessory.context.updateKey !== updateKey) return + await this.platform.sendDeviceUpdate(accessory, params) + accessory.context.cacheTargetPosition = newTarget + accessory.context.cachePositionState = setToMoveUp ? 1 : 0 + accessory.context.cacheLastStartTime = Math.floor(Date.now() / 100) + if (accessory.context.updateKey !== updateKey) return await helpers.sleep(decisecondsToMove * 100) - if (this.accessory.context.updateKey !== updateKey) return + if (accessory.context.updateKey !== updateKey) return params.switches[0].switch = 'off' params.switches[1].switch = 'off' - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(accessory, params) wcService.updateCharacteristic(this.Characteristic.PositionState, 2) wcService.updateCharacteristic(this.Characteristic.CurrentPosition, newTarget) - this.accessory.context.cachePositionState = 2 - this.accessory.context.cacheCurrentPosition = newTarget + accessory.context.cachePositionState = 2 + accessory.context.cacheCurrentPosition = newTarget } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { } } diff --git a/lib/device/curtain.js b/lib/device/curtain.js index 67ca977b..d2fafcb4 100644 --- a/lib/device/curtain.js +++ b/lib/device/curtain.js @@ -18,15 +18,14 @@ module.exports = class deviceCurtain { } cService .getCharacteristic(this.Characteristic.TargetPosition) - .on('set', (value, callback) => this.internalUpdate(value, callback)) - this.accessory = accessory + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) } - async internalUpdate (value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { let params - const prevPos = this.accessory.context.cacheCurrentPosition + const prevPos = accessory.context.cacheCurrentPosition const newPos = value if (newPos === prevPos) return if (newPos === 0 || newPos === 100) { @@ -34,16 +33,16 @@ module.exports = class deviceCurtain { } else { params = { setclose: Math.abs(100 - newPos) } } - this.accessory.context.cacheCurrentPosition = newPos - await this.platform.sendDeviceUpdate(this.accessory, params) + accessory.context.cacheCurrentPosition = newPos + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { - const cService = this.accessory.getService(this.Service.WindowCovering) + const cService = accessory.getService(this.Service.WindowCovering) if (!helpers.hasProperty(params, 'switch') && !helpers.hasProperty(params, 'setclose')) { return } @@ -52,10 +51,10 @@ module.exports = class deviceCurtain { .updateCharacteristic(this.Characteristic.TargetPosition, newPos) .updateCharacteristic(this.Characteristic.CurrentPosition, newPos) .updateCharacteristic(this.Characteristic.PositionState, 2) - this.accessory.context.cacheCurrentPosition = newPos + accessory.context.cacheCurrentPosition = newPos return } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/diffuser.js b/lib/device/diffuser.js index ae8bcf86..47a1739b 100644 --- a/lib/device/diffuser.js +++ b/lib/device/diffuser.js @@ -12,89 +12,87 @@ module.exports = class deviceDiffuser { const lightService = accessory.getService('Light') || accessory.addService(this.Service.Lightbulb, 'Light', 'light') onOffService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalDiffuserOnOffUpdate(value, callback)) - this.accessory = accessory + .on('set', (value, callback) => this.internalDiffuserOnOffUpdate(accessory, value, callback)) onOffService .getCharacteristic(this.Characteristic.RotationSpeed) - .on('set', (value, callback) => this.internalDiffuserStateUpdate(value, callback)) + .on('set', (value, callback) => this.internalDiffuserStateUpdate(accessory, value, callback)) .setProps({ minStep: 50 }) lightService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalLightOnOffUpdate(value, callback)) + .on('set', (value, callback) => this.internalLightOnOffUpdate(accessory, value, callback)) lightService .getCharacteristic(this.Characteristic.Brightness) - .on('set', (value, callback) => this.internalLightBrightnessUpdate(value, callback)) + .on('set', (value, callback) => this.internalLightBrightnessUpdate(accessory, value, callback)) lightService .getCharacteristic(this.Characteristic.Hue) - .on('set', (value, callback) => this.internalLightColourUpdate(value, callback)) + .on('set', (value, callback) => this.internalLightColourUpdate(accessory, value, callback)) lightService .getCharacteristic(this.Characteristic.Saturation) .on('set', (value, callback) => callback()) - this.accessory = accessory } - async internalDiffuserOnOffUpdate (value, callback) { + async internalDiffuserOnOffUpdate (accessory, value, callback) { callback() try { const params = { switch: value ? 'on' : 'off' } - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async internalDiffuserStateUpdate (value, callback) { + async internalDiffuserStateUpdate (accessory, value, callback) { try { await helpers.sleep(1000) callback() if (value === 0) return value = value <= 75 ? 50 : 100 const params = { state: value / 2 } - this.accessory.context.cacheState = value - await this.platform.sendDeviceUpdate(this.accessory, params) + accessory.context.cacheState = value + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async internalLightOnOffUpdate (value, callback) { + async internalLightOnOffUpdate (accessory, value, callback) { try { callback() const params = { lightswitch: value ? 1 : 0 } - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async internalLightBrightnessUpdate (value, callback) { + async internalLightBrightnessUpdate (accessory, value, callback) { try { await helpers.sleep(2000) callback() const updateKeyBright = Math.random().toString(36).substr(2, 8) - this.accessory.context.updateKeyBright = updateKeyBright + accessory.context.updateKeyBright = updateKeyBright const params = { lightbright: value } await helpers.sleep(500) - if (updateKeyBright !== this.accessory.context.updateKeyBright) return - await this.platform.sendDeviceUpdate(this.accessory, params) + if (updateKeyBright !== accessory.context.updateKeyBright) return + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async internalLightColourUpdate (value, callback) { + async internalLightColourUpdate (accessory, value, callback) { try { await helpers.sleep(2000) callback() const updateKeyColour = Math.random().toString(36).substr(2, 8) - this.accessory.context.updateKeyColour = updateKeyColour + accessory.context.updateKeyColour = updateKeyColour const newRGB = convert.hsv.rgb( value, - this.accessory.getService('Light').getCharacteristic(this.Characteristic.Saturation).value, + accessory.getService('Light').getCharacteristic(this.Characteristic.Saturation).value, 100 ) const params = { @@ -103,31 +101,31 @@ module.exports = class deviceDiffuser { lightBcolor: newRGB[2] } await helpers.sleep(500) - if (updateKeyColour !== this.accessory.context.updateKeyColour) return - await this.platform.sendDeviceUpdate(this.accessory, params) + if (updateKeyColour !== accessory.context.updateKeyColour) return + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { if (helpers.hasProperty(params, 'switch')) { - this.accessory.getService('Diffuser').updateCharacteristic(this.Characteristic.On, params.switch === 'on') + accessory.getService('Diffuser').updateCharacteristic(this.Characteristic.On, params.switch === 'on') if (!helpers.hasProperty(params, 'state')) { - this.accessory.getService('Diffuser').updateCharacteristic(this.Characteristic.RotationSpeed, this.accessory.context.cacheState) + accessory.getService('Diffuser').updateCharacteristic(this.Characteristic.RotationSpeed, accessory.context.cacheState) } } if (helpers.hasProperty(params, 'state')) { - this.accessory.getService('Diffuser').updateCharacteristic(this.Characteristic.RotationSpeed, params.state * 50) - this.accessory.context.cacheState = params.state * 50 + accessory.getService('Diffuser').updateCharacteristic(this.Characteristic.RotationSpeed, params.state * 50) + accessory.context.cacheState = params.state * 50 } if (helpers.hasProperty(params, 'lightswitch')) { - this.accessory.getService('Light') + accessory.getService('Light') .updateCharacteristic(this.Characteristic.On, params.lightswitch === 1) } if (helpers.hasProperty(params, 'lightbright')) { - this.accessory.getService('Light') + accessory.getService('Light') .updateCharacteristic(this.Characteristic.Brightness, params.lightbright) } if ( @@ -136,12 +134,12 @@ module.exports = class deviceDiffuser { helpers.hasProperty(params, 'lightBcolor') ) { const newColour = convert.rgb.hsv(params.lightRcolor, params.lightGcolor, params.lightBcolor) - this.accessory.getService('Light') + accessory.getService('Light') .updateCharacteristic(this.Characteristic.Hue, newColour[0]) .updateCharacteristic(this.Characteristic.Saturation, 100) } } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/fan.js b/lib/device/fan.js index baeaaf4a..bb1a55dc 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -15,13 +15,13 @@ module.exports = class deviceFan { const fanService = accessory.getService(this.Service.Fan) || accessory.addService(this.Service.Fan) fanService .getCharacteristic(this.Characteristic.On) - .on('set', async (value, callback) => { + .on('set', (value, callback) => { callback() if (!value) fanService.setCharacteristic(this.Characteristic.RotationSpeed, 0) }) fanService .getCharacteristic(this.Characteristic.RotationSpeed) - .on('set', (value, callback) => this.internalUpdate('speed', value, callback)) + .on('set', (value, callback) => this.internalUpdate(accessory, 'speed', value, callback)) .setProps({ minStep: 33 }) @@ -34,20 +34,19 @@ module.exports = class deviceFan { const fanLightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) fanLightService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate('light', value, callback)) + .on('set', (value, callback) => this.internalUpdate(accessory, 'light', value, callback)) } - this.accessory = accessory } - async internalUpdate (type, value, callback) { + async internalUpdate (accessory, type, value, callback) { callback() try { let newPower let newSpeed let newLight let lightService - if (this.visibleLight) lightService = this.accessory.getService(this.Service.Lightbulb) - const fanService = this.accessory.getService(this.Service.Fan) + if (this.visibleLight) lightService = accessory.getService(this.Service.Lightbulb) + const fanService = accessory.getService(this.Service.Fan) const params = { switches: helpers.defaultMultiSwitchOff } switch (type) { case 'speed': @@ -65,19 +64,19 @@ module.exports = class deviceFan { params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? 'on' : 'off' params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? 'on' : 'off' params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? 'on' : 'off' - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { if (helpers.hasProperty(params, 'updateSource') && params.updateSource === 'LAN') return if (params.switches && Array.isArray(params.switches)) { let lightService - if (this.visibleLight) lightService = this.accessory.getService(this.Service.Lightbulb) - const fanService = this.accessory.getService(this.Service.Fan) + if (this.visibleLight) lightService = accessory.getService(this.Service.Lightbulb) + const fanService = accessory.getService(this.Service.Fan) const light = params.switches[0].switch === 'on' let status let speed @@ -104,7 +103,7 @@ module.exports = class deviceFan { .updateCharacteristic(this.Characteristic.RotationSpeed, speed) } } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 1c7fb8bf..ddba1e03 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -18,59 +18,58 @@ module.exports = class deviceGarageEachen { } gdeService .getCharacteristic(this.Characteristic.TargetDoorState) - .on('set', (value, callback) => this.internalUpdate(value, callback)) - this.accessory = accessory + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) } - async internalUpdate (value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { let garageConfig - if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage_eachen') { throw new Error('improper configuration') } const params = { switch: value === 0 ? 'on' : 'off' } - const gdService = this.accessory.getService(this.Service.GarageDoorOpener) + const gdService = accessory.getService(this.Service.GarageDoorOpener) if (value === gdService.getCharacteristic(this.Characteristic.CurrentDoorState).value % 2) return - this.accessory.context.inUse = true - await this.platform.sendDeviceUpdate(this.accessory, params) + accessory.context.inUse = true + await this.platform.sendDeviceUpdate(accessory, params) gdService .updateCharacteristic(this.Characteristic.TargetDoorState, value) .updateCharacteristic(this.Characteristic.CurrentDoorState, value + 2) await helpers.sleep(2000) - this.accessory.context.inUse = false + accessory.context.inUse = false if (value === 0) { await helpers.sleep(Math.max((garageConfig.operationTime - 20) * 100, 0)) gdService.updateCharacteristic(this.Characteristic.CurrentDoorState, 0) } } catch (err) { - this.accessory.context.inUse = false - this.platform.deviceUpdateError(this.accessory, err, true) + accessory.context.inUse = false + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { - if (!helpers.hasProperty(params, 'switch') || this.accessory.context.inUse) return + if (!helpers.hasProperty(params, 'switch') || accessory.context.inUse) return let garageConfig - if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage_eachen') { throw new Error('improper configuration') } - this.accessory.context.inUse = true - const gdService = this.accessory.getService(this.Service.GarageDoorOpener) + accessory.context.inUse = true + const gdService = accessory.getService(this.Service.GarageDoorOpener) gdService .updateCharacteristic(this.Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) .updateCharacteristic(this.Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) - this.accessory.context.inUse = false + accessory.context.inUse = false } catch (err) { - this.accessory.context.inUse = false - this.platform.deviceUpdateError(this.accessory, err, false) + accessory.context.inUse = false + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/garage-four.js b/lib/device/garage-four.js index f21f1e4d..85b30124 100644 --- a/lib/device/garage-four.js +++ b/lib/device/garage-four.js @@ -19,16 +19,15 @@ module.exports = class deviceGarageFour { } gdService .getCharacteristic(this.Characteristic.TargetDoorState) - .on('set', (value, callback) => this.internalUpdate(v, value, callback)) + .on('set', (value, callback) => this.internalUpdate(accessory, v, value, callback)) }) - this.accessory = accessory } - async internalUpdate (garage, value, callback) { + async internalUpdate (accessory, garage, value, callback) { callback() try { let garageConfig - if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage_four') { @@ -65,45 +64,45 @@ module.exports = class deviceGarageFour { ? sAccessory.getService(this.Service.ContactSensor).getCharacteristic(this.Characteristic.ContactSensorState).value === 0 ? 1 : 0 - : this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState + : accessory.context.cacheStates[garageChannel].cacheCurrentDoorState if (value === prevState % 2) return - const gdService = this.accessory.getService('Garage ' + garage) - this.accessory.context.inUse = true + const gdService = accessory.getService('Garage ' + garage) + accessory.context.inUse = true const updateKey = Math.random().toString(36).substr(2, 8) - this.accessory.context.updateKey = updateKey + accessory.context.updateKey = updateKey gdService .updateCharacteristic(this.Characteristic.TargetDoorState, value) .updateCharacteristic(this.Characteristic.CurrentDoorState, value + 2) - this.accessory.context.cacheStates[garageChannel].cacheTargetDoorState = value - this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = value + 2 + accessory.context.cacheStates[garageChannel].cacheTargetDoorState = value + accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = value + 2 const params = { switches: helpers.defaultMultiSwitchOff } ;[0, 1, 2, 3].forEach(i => (params.switches[i].switch = garageChannel === i ? 'on' : 'off')) - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(accessory, params) await helpers.sleep(1000) - this.accessory.context.inUse = false + accessory.context.inUse = false await helpers.sleep(Math.max((garageConfig.operationTime - 10) * 100, 0)) - if (this.accessory.context.updateKey !== updateKey || sAccessory) return + if (accessory.context.updateKey !== updateKey || sAccessory) return if (!sAccessory) { gdService.updateCharacteristic(this.Characteristic.CurrentDoorState, value) - this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = value + accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = value } } catch (err) { - this.accessory.context.inUse = false - this.platform.deviceUpdateError(this.accessory, err, true) + accessory.context.inUse = false + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { - if (!helpers.hasProperty(params, 'switches') || this.accessory.context.inUse) return + if (!helpers.hasProperty(params, 'switches') || accessory.context.inUse) return let garageConfig - if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage_four') { throw new Error('improper configuration') } - if (this.accessory.context.inUse) return + if (accessory.context.inUse) return ;['A', 'B', 'C', 'D'].forEach(async v => { let garageChannel switch (v) { @@ -133,16 +132,16 @@ module.exports = class deviceGarageFour { throw new Error("defined DW2 sensor isn't a sensor") } if (sensorDefinition) return - const gcService = this.accessory.getService('Garage ' + v) - const prevState = this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState + const gcService = accessory.getService('Garage ' + v) + const prevState = accessory.context.cacheStates[garageChannel].cacheCurrentDoorState const newPos = [0, 2].includes(prevState) ? 1 : 0 if (params.switches[garageChannel].switch === 'off') return gcService.updateCharacteristic(this.Characteristic.CurrentDoorState, newPos) - this.accessory.context.cacheStates[garageChannel].cacheTargetDoorState = newPos - this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = newPos + accessory.context.cacheStates[garageChannel].cacheTargetDoorState = newPos + accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = newPos }) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/garage-two.js b/lib/device/garage-two.js index fa02653c..d23ac1d5 100644 --- a/lib/device/garage-two.js +++ b/lib/device/garage-two.js @@ -19,16 +19,15 @@ module.exports = class deviceGarageTwo { } gdService .getCharacteristic(this.Characteristic.TargetDoorState) - .on('set', (value, callback) => this.internalUpdate('Garage' + v, value, callback)) + .on('set', (value, callback) => this.internalUpdate(accessory, 'Garage' + v, value, callback)) }) - this.accessory = accessory } - async internalUpdate (garage, value, callback) { + async internalUpdate (accessory, garage, value, callback) { callback() try { let garageConfig - if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage_two') { @@ -50,8 +49,8 @@ module.exports = class deviceGarageTwo { } let sAccessory = false const newPos = value - const params = { switches: this.accessory.context.switchState } - const gdService = this.accessory.getService(garage) + const params = { switches: accessory.context.switchState } + const gdService = accessory.getService(garage) if (sensorDefinition && !(sAccessory = this.platform.devicesInHB.get(garageConfig.sensorId + 'SWX'))) { throw new Error("defined DW2 sensor doesn't exist") } @@ -63,69 +62,69 @@ module.exports = class deviceGarageTwo { ? 1 : 0 : garage === 'Garage 1' - ? this.accessory.context.cacheOneCurrentDoorState - : this.accessory.context.cacheTwoCurrentDoorState + ? accessory.context.cacheOneCurrentDoorState + : accessory.context.cacheTwoCurrentDoorState if (newPos === prevState % 2) return - this.accessory.context.inUse = true + accessory.context.inUse = true gdService .updateCharacteristic(this.Characteristic.TargetDoorState, newPos) .updateCharacteristic(this.Characteristic.CurrentDoorState, newPos + 2) switch (garage) { case 'Garage 1': { - this.accessory.context.cacheOneTargetDoorState = newPos - this.accessory.context.cacheOneCurrentDoorState = newPos + 2 + accessory.context.cacheOneTargetDoorState = newPos + accessory.context.cacheOneCurrentDoorState = newPos + 2 params.switches[0].switch = newPos === 0 ? 'on' : 'off' params.switches[1].switch = newPos === 1 ? 'on' : 'off' break } case 'Garage 2': { - this.accessory.context.cacheTwoTargetDoorState = newPos - this.accessory.context.cacheTwoCurrentDoorState = newPos + 2 + accessory.context.cacheTwoTargetDoorState = newPos + accessory.context.cacheTwoCurrentDoorState = newPos + 2 params.switches[2].switch = newPos === 0 ? 'on' : 'off' params.switches[3].switch = newPos === 1 ? 'on' : 'off' break } } - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(accessory, params) await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) if (!sAccessory) { gdService.updateCharacteristic(this.Characteristic.CurrentDoorState, newPos) switch (garage) { case 'Garage 1': { - this.accessory.context.cacheOneCurrentDoorState = newPos + accessory.context.cacheOneCurrentDoorState = newPos break } case 'Garage 2': { - this.accessory.context.cacheTwoCurrentDoorState = newPos + accessory.context.cacheTwoCurrentDoorState = newPos break } } } - this.accessory.context.inUse = false + accessory.context.inUse = false } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - externalUpdate (params) { + externalUpdate (accessory, params) { try { if (!helpers.hasProperty(params, 'switches')) { return } let garageConfig - if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage_two') { throw new Error('improper configuration') } - if (this.accessory.context.inUse || garageConfig.sensorId) return - this.accessory.context.switchState = params.switches + if (accessory.context.inUse || garageConfig.sensorId) return + accessory.context.switchState = params.switches ;['1', '2'].forEach(async v => { - const gcService = this.accessory.getService('Garage ' + v) + const gcService = accessory.getService('Garage ' + v) const prevState = v === '1' - ? this.accessory.context.cacheOneCurrentDoorState - : this.accessory.context.cacheTwoCurrentDoorState + ? accessory.context.cacheOneCurrentDoorState + : accessory.context.cacheTwoCurrentDoorState const newPos = [0, 2].includes(prevState) ? 3 : 2 switch (v) { case '1': @@ -145,7 +144,7 @@ module.exports = class deviceGarageTwo { } break } - this.accessory.context.inUse = true + accessory.context.inUse = true if (garageConfig.sensorId) { await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) } else { @@ -154,29 +153,29 @@ module.exports = class deviceGarageTwo { .updateCharacteristic(this.Characteristic.CurrentDoorState, newPos) switch (v) { case '1': - this.accessory.context.cacheOneCurrentDoorState = newPos - this.accessory.context.cacheTwoTargetDoorState = newPos - 2 + accessory.context.cacheOneCurrentDoorState = newPos + accessory.context.cacheTwoTargetDoorState = newPos - 2 break case '2': - this.accessory.context.cacheTwoCurrentDoorState = newPos - this.accessory.context.cacheTwoTargetDoorState = newPos - 2 + accessory.context.cacheTwoCurrentDoorState = newPos + accessory.context.cacheTwoTargetDoorState = newPos - 2 break } await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) gcService.updateCharacteristic(this.Characteristic.CurrentDoorState, newPos - 2) switch (v) { case '1': - this.accessory.context.cacheOneCurrentDoorState = newPos - 2 + accessory.context.cacheOneCurrentDoorState = newPos - 2 break case '2': - this.accessory.context.cacheTwoCurrentDoorState = newPos - 2 + accessory.context.cacheTwoCurrentDoorState = newPos - 2 break } } }) - this.accessory.context.inUse = false + accessory.context.inUse = false } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/garage.js b/lib/device/garage.js index 38d31896..ebee6eb5 100644 --- a/lib/device/garage.js +++ b/lib/device/garage.js @@ -18,15 +18,14 @@ module.exports = class deviceGarage { } gdService .getCharacteristic(this.Characteristic.TargetDoorState) - .on('set', (value, callback) => this.internalUpdate(value, callback)) - this.accessory = accessory + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) } - async internalUpdate (value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { let garageConfig - if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage' || !['oneSwitch', 'twoSwitch'].includes(garageConfig.setup)) { @@ -37,7 +36,7 @@ module.exports = class deviceGarage { const newPos = value const params = {} let delay = 0 - const gdService = this.accessory.getService(this.Service.GarageDoorOpener) + const gdService = accessory.getService(this.Service.GarageDoorOpener) if (sensorDefinition && !(sAccessory = this.platform.devicesInHB.get(garageConfig.sensorId + 'SWX'))) { throw new Error("defined DW2 sensor doesn't exist") } @@ -48,22 +47,22 @@ module.exports = class deviceGarage { ? sAccessory.getService(this.Service.ContactSensor).getCharacteristic(this.Characteristic.ContactSensorState).value === 0 ? 1 : 0 - : this.accessory.context.cacheCurrentDoorState + : accessory.context.cacheCurrentDoorState if (newPos === prevState % 2) return - this.accessory.context.inUse = true - this.accessory.context.state = value + accessory.context.inUse = true + accessory.context.state = value if (garageConfig.setup === 'oneSwitch' && [2, 3].includes(prevState)) { gdService.updateCharacteristic(this.Characteristic.CurrentDoorState, ((prevState * 2) % 3) + 2) - this.accessory.context.cacheCurrentDoorState = ((prevState * 2) % 3) + 2 + accessory.context.cacheCurrentDoorState = ((prevState * 2) % 3) + 2 delay = 1500 } - if (this.accessory.context.state !== newPos) return + if (accessory.context.state !== newPos) return await helpers.sleep(delay) gdService .updateCharacteristic(this.Characteristic.TargetDoorState, newPos) .updateCharacteristic(this.Characteristic.CurrentDoorState, newPos + 2) - this.accessory.context.cacheTargetDoorState = newPos - this.accessory.context.cacheCurrentDoorState = newPos + 2 + accessory.context.cacheTargetDoorState = newPos + accessory.context.cacheCurrentDoorState = newPos + 2 switch (garageConfig.setup) { case 'oneSwitch': params.switch = 'on' @@ -74,34 +73,34 @@ module.exports = class deviceGarage { params.switches[1].switch = newPos === 1 ? 'on' : 'off' break } - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(accessory, params) await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) if (!sAccessory) { gdService.updateCharacteristic(this.Characteristic.CurrentDoorState, newPos) - this.accessory.context.cacheCurrentDoorState = newPos + accessory.context.cacheCurrentDoorState = newPos } - this.accessory.context.inUse = false + accessory.context.inUse = false } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { if (!helpers.hasProperty(params, 'switch') && !helpers.hasProperty(params, 'switches')) { return } let garageConfig - const gcService = this.accessory.getService(this.Service.GarageDoorOpener) - const prevState = this.accessory.context.cacheCurrentDoorState + const gcService = accessory.getService(this.Service.GarageDoorOpener) + const prevState = accessory.context.cacheCurrentDoorState const newPos = [0, 2].includes(prevState) ? 3 : 2 - if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage' || !['oneSwitch', 'twoSwitch'].includes(garageConfig.setup)) { throw new Error('improper configuration') } - if (this.accessory.context.inUse || garageConfig.sensorId) return + if (accessory.context.inUse || garageConfig.sensorId) return switch (garageConfig.setup) { case 'oneSwitch': if (params.switch === 'off') { @@ -117,23 +116,23 @@ module.exports = class deviceGarage { } break } - this.accessory.context.inUse = true + accessory.context.inUse = true if (garageConfig.sensorId) { await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) } else { gcService .updateCharacteristic(this.Characteristic.TargetDoorState, newPos - 2) .updateCharacteristic(this.Characteristic.CurrentDoorState, newPos) - this.accessory.context.cacheCurrentDoorState = newPos - this.accessory.context.cacheTargetDoorState = newPos - 2 + accessory.context.cacheCurrentDoorState = newPos + accessory.context.cacheTargetDoorState = newPos - 2 await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) gcService.updateCharacteristic(this.Characteristic.CurrentDoorState, newPos - 2) - this.accessory.context.cacheCurrentDoorState = newPos - 2 + accessory.context.cacheCurrentDoorState = newPos - 2 } - this.accessory.context.inUse = false + accessory.context.inUse = false } catch (err) { - this.accessory.context.inUse = false - this.platform.deviceUpdateError(this.accessory, err, false) + accessory.context.inUse = false + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/light-colour.js b/lib/device/light-colour.js index fe68041a..487356a3 100644 --- a/lib/device/light-colour.js +++ b/lib/device/light-colour.js @@ -11,13 +11,13 @@ module.exports = class deviceLightColour { const lightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) lightService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate('onoff', value, callback)) + .on('set', (value, callback) => this.internalUpdate(accessory, 'onoff', value, callback)) lightService .getCharacteristic(this.Characteristic.Brightness) - .on('set', (value, callback) => this.internalUpdate('brightness', value, callback)) + .on('set', (value, callback) => this.internalUpdate(accessory, 'brightness', value, callback)) lightService .getCharacteristic(this.Characteristic.Hue) - .on('set', (value, callback) => this.internalUpdate('hue', value, callback)) + .on('set', (value, callback) => this.internalUpdate(accessory, 'hue', value, callback)) lightService .getCharacteristic(this.Characteristic.Saturation) .on('set', (value, callback) => callback()) @@ -29,29 +29,28 @@ module.exports = class deviceLightColour { minStep: 100 }) } - this.accessory = accessory } - async internalUpdate (type, value, callback) { + async internalUpdate (accessory, type, value, callback) { callback() try { let newRGB let params = {} - const lightService = this.accessory.getService(this.Service.Lightbulb) + const lightService = accessory.getService(this.Service.Lightbulb) switch (type) { case 'onoff': - if (this.accessory.context.eweUIID === 22) { + if (accessory.context.eweUIID === 22) { // **** B1 uses state rather than switch *** \\ params.state = value ? 'on' : 'off' } else { params.switch = value ? 'on' : 'off' } - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(accessory, params) break case 'brightness': { const updateKeyBright = Math.random().toString(36).substr(2, 8) - this.accessory.context.updateKeyBright = updateKeyBright - switch (this.accessory.context.eweUIID) { + accessory.context.updateKeyBright = updateKeyBright + switch (accessory.context.eweUIID) { case 22: // *** B1 doesn't support brightness *** \\ return @@ -68,23 +67,23 @@ module.exports = class deviceLightColour { ltype: 'color', color: { br: value, - r: this.accessory.context.cacheR, - g: this.accessory.context.cacheG, - b: this.accessory.context.cacheB + r: accessory.context.cacheR, + g: accessory.context.cacheG, + b: accessory.context.cacheB } } break } await helpers.sleep(500) - if (updateKeyBright !== this.accessory.context.updateKeyBright) return - await this.platform.sendDeviceUpdate(this.accessory, params) + if (updateKeyBright !== accessory.context.updateKeyBright) return + await this.platform.sendDeviceUpdate(accessory, params) break } case 'hue': { const updateKeyColour = Math.random().toString(36).substr(2, 8) - this.accessory.context.updateKeyColour = updateKeyColour + accessory.context.updateKeyColour = updateKeyColour newRGB = convert.hsv.rgb(value, lightService.getCharacteristic(this.Characteristic.Saturation).value, 100) - switch (this.accessory.context.eweUIID) { + switch (accessory.context.eweUIID) { case 22: // *** B1 *** \\ params = { @@ -117,38 +116,38 @@ module.exports = class deviceLightColour { br: lightService.getCharacteristic(this.Characteristic.Brightness).value } } - this.accessory.context.cacheR = newRGB[0] - this.accessory.context.cacheG = newRGB[1] - this.accessory.context.cacheB = newRGB[2] + accessory.context.cacheR = newRGB[0] + accessory.context.cacheG = newRGB[1] + accessory.context.cacheB = newRGB[2] break } await helpers.sleep(1000) - if (updateKeyColour !== this.accessory.context.updateKeyColour) return - await this.platform.sendDeviceUpdate(this.accessory, params) + if (updateKeyColour !== accessory.context.updateKeyColour) return + await this.platform.sendDeviceUpdate(accessory, params) break } } } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { let newColour let mode let isOn = false - const lightService = this.accessory.getService(this.Service.Lightbulb) - if (this.accessory.context.eweUIID === 22 && helpers.hasProperty(params, 'state')) { + const lightService = accessory.getService(this.Service.Lightbulb) + if (accessory.context.eweUIID === 22 && helpers.hasProperty(params, 'state')) { isOn = params.state === 'on' - } else if (this.accessory.context.eweUIID !== 22 && helpers.hasProperty(params, 'switch')) { + } else if (accessory.context.eweUIID !== 22 && helpers.hasProperty(params, 'switch')) { isOn = params.switch === 'on' } else { isOn = lightService.getCharacteristic(this.Characteristic.On).value } if (isOn) { lightService.updateCharacteristic(this.Characteristic.On, true) - switch (this.accessory.context.eweUIID) { + switch (accessory.context.eweUIID) { case 22: // *** B1 *** \\ if (helpers.hasProperty(params, 'zyx_mode')) { @@ -204,9 +203,9 @@ module.exports = class deviceLightColour { lightService .updateCharacteristic(this.Characteristic.Hue, newColour[0]) .updateCharacteristic(this.Characteristic.Saturation, 100) - this.accessory.context.cacheR = params.color.r - this.accessory.context.cacheG = params.color.g - this.accessory.context.cacheB = params.color.b + accessory.context.cacheR = params.color.r + accessory.context.cacheG = params.color.g + accessory.context.cacheB = params.color.b } } } @@ -216,7 +215,7 @@ module.exports = class deviceLightColour { lightService.updateCharacteristic(this.Characteristic.On, false) } } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/light-ctemp.js b/lib/device/light-ctemp.js index 66fa2e25..f9450a4e 100644 --- a/lib/device/light-ctemp.js +++ b/lib/device/light-ctemp.js @@ -9,27 +9,26 @@ module.exports = class deviceLightCTemp { const lightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) lightService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate('onoff', value, callback)) + .on('set', (value, callback) => this.internalUpdate(accessory, 'onoff', value, callback)) lightService .getCharacteristic(this.Characteristic.Brightness) - .on('set', (value, callback) => this.internalUpdate('brightness', value, callback)) - this.accessory = accessory + .on('set', (value, callback) => this.internalUpdate(accessory, 'brightness', value, callback)) } - async internalUpdate (type, value, callback) { + async internalUpdate (accessory, type, value, callback) { callback() try { } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/light-dimmer.js b/lib/device/light-dimmer.js index b7c30db4..94da5b67 100644 --- a/lib/device/light-dimmer.js +++ b/lib/device/light-dimmer.js @@ -10,25 +10,24 @@ module.exports = class deviceLightDimmer { const lightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) lightService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate('onoff', value, callback)) + .on('set', (value, callback) => this.internalUpdate(accessory, 'onoff', value, callback)) lightService.getCharacteristic(this.Characteristic.Brightness) - .on('set', (value, callback) => this.internalUpdate('brightness', value, callback)) - this.accessory = accessory + .on('set', (value, callback) => this.internalUpdate(accessory, 'brightness', value, callback)) } - async internalUpdate (type, value, callback) { + async internalUpdate (accessory, type, value, callback) { callback() try { const params = {} switch (type) { case 'onoff': params.switch = value ? 'on' : 'off' - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(accessory, params) break case 'brightness': { const updateKey = Math.random().toString(36).substr(2, 8) - this.accessory.context.updateKey = updateKey - switch (this.accessory.context.eweUIID) { + accessory.context.updateKey = updateKey + switch (accessory.context.eweUIID) { case 36: // *** KING-M4 eWeLink scale is 10-100 and HomeKit scale is 0-100. *** \\ params.bright = Math.round((value * 9) / 10 + 10) @@ -40,25 +39,25 @@ module.exports = class deviceLightDimmer { break } await helpers.sleep(500) - if (updateKey !== this.accessory.context.updateKey) return - await this.platform.sendDeviceUpdate(this.accessory, params) + if (updateKey !== accessory.context.updateKey) return + await this.platform.sendDeviceUpdate(accessory, params) break } } } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { - const lightService = this.accessory.getService(this.Service.Lightbulb) + const lightService = accessory.getService(this.Service.Lightbulb) const isOn = helpers.hasProperty(params, 'switch') ? params.switch === 'on' : lightService.getCharacteristic(this.Characteristic.On).value if (isOn) { lightService.updateCharacteristic(this.Characteristic.On, true) - switch (this.accessory.context.eweUIID) { + switch (accessory.context.eweUIID) { case 36: // *** KING-M4 eWeLink scale is 10-100 and HomeKit scale is 0-100. *** \\ if (helpers.hasProperty(params, 'bright')) { @@ -77,7 +76,7 @@ module.exports = class deviceLightDimmer { lightService.updateCharacteristic(this.Characteristic.On, false) } } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/lock.js b/lib/device/lock.js index b69ea0cc..6804242f 100644 --- a/lib/device/lock.js +++ b/lib/device/lock.js @@ -10,49 +10,49 @@ module.exports = class deviceLock { const lmService = accessory.getService(this.Service.LockMechanism) || accessory.addService(this.Service.LockMechanism) lmService .getCharacteristic(this.Characteristic.LockTargetState) - .on('set', (value, callback) => this.internalUpdate(value, callback)) - this.accessory = accessory + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + accessory = accessory } - async internalUpdate (value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { let lockConfig const params = { switch: 'on' } - const lmService = this.accessory.getService(this.Service.LockMechanism) - if (!(lockConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { + const lmService = accessory.getService(this.Service.LockMechanism) + if (!(lockConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (lockConfig.type !== 'lock') { throw new Error('improper configuration') } - this.accessory.context.inUse = true - await this.platform.sendDeviceUpdate(this.accessory, params) + accessory.context.inUse = true + await this.platform.sendDeviceUpdate(accessory, params) await helpers.sleep(Math.max(lockConfig.operationTime * 100, 1000)) lmService .updateCharacteristic(this.Characteristic.LockTargetState, 1) .updateCharacteristic(this.Characteristic.LockCurrentState, 1) - this.accessory.context.inUse = false + accessory.context.inUse = false } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { if (!helpers.hasProperty(params, 'switch')) return let lockConfig - const lmService = this.accessory.getService(this.Service.LockMechanism) - if (!(lockConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { + const lmService = accessory.getService(this.Service.LockMechanism) + if (!(lockConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (lockConfig.type !== 'lock') { throw new Error('improper configuration') } - if (params.switch === 'off' || this.accessory.context.inUse) { + if (params.switch === 'off' || accessory.context.inUse) { return } - this.accessory.context.inUse = true + accessory.context.inUse = true lmService .updateCharacteristic(this.Characteristic.LockCurrentState, 0) .updateCharacteristic(this.Characteristic.LockTargetState, 0) @@ -60,10 +60,10 @@ module.exports = class deviceLock { lmService .updateCharacteristic(this.Characteristic.LockCurrentState, 1) .updateCharacteristic(this.Characteristic.LockTargetState, 1) - this.accessory.context.inUse = false + accessory.context.inUse = false } catch (err) { - this.accessory.context.inUse = false - this.platform.deviceUpdateError(this.accessory, err, false) + accessory.context.inUse = false + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/outlet.js b/lib/device/outlet.js index 72339905..3992c9e0 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -100,10 +100,10 @@ module.exports = class deviceOutlet { } outletService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(value, callback)) + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) outletService .getCharacteristic(this.eveResetTotal) - .on('set', (value, callback) => { + .on('set', (accessory, value, callback) => { callback() accessory.context.energyReadings = [] accessory.context.energyReadingTotal = 0 @@ -126,38 +126,37 @@ module.exports = class deviceOutlet { accessory.context.energyReadings = [] outletService.updateCharacteristic(this.eveTotalConsumption, accessory.context.energyReadingTotal) }, 300000) - this.accessory = accessory } - async internalUpdate (value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { const params = { switch: value ? 'on' : 'off' } - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { - const outletService = this.accessory.getService(this.Service.Outlet) + const outletService = accessory.getService(this.Service.Outlet) if (helpers.hasProperty(params, 'switch')) { outletService.updateCharacteristic(this.Characteristic.On, params.switch === 'on') - if (!this.accessory.context.powerReadings) { + if (!accessory.context.powerReadings) { outletService.updateCharacteristic(this.Characteristic.OutletInUse, params.switch === 'on') } } if (helpers.hasProperty(params, 'power')) { - this.accessory.context.powerReadings = true + accessory.context.powerReadings = true outletService.updateCharacteristic(this.Characteristic.OutletInUse, parseFloat(params.power) > this.inUsePowerThreshold) outletService.updateCharacteristic(this.eveCurrentConsumption, parseFloat(params.power)) - const isOn = this.accessory.getService(this.Service.Outlet).getCharacteristic(this.Characteristic.On).value - this.accessory.eveLogger.addEntry({ + const isOn = accessory.getService(this.Service.Outlet).getCharacteristic(this.Characteristic.On).value + accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), power: isOn ? parseFloat(params.power) : 0 }) - this.accessory.context.energyReadings.push(parseFloat(params.power)) + accessory.context.energyReadings.push(parseFloat(params.power)) } if (helpers.hasProperty(params, 'voltage')) { outletService.updateCharacteristic(this.eveVoltage, parseFloat(params.voltage)) @@ -166,7 +165,7 @@ module.exports = class deviceOutlet { outletService.updateCharacteristic(this.eveElectricCurrent, parseFloat(params.current)) } } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index f5f61a00..e9fe4f13 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -21,7 +21,7 @@ module.exports = class deviceRFBridge { accessory.getService(name).updateCharacteristic(this.Characteristic.On, false) accessory.getService(name) .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(chan, name, value, callback)) + .on('set', (value, callback) => this.internalUpdate(accessory, chan, name, value, callback)) }) } else { let serv @@ -73,10 +73,9 @@ module.exports = class deviceRFBridge { path: this.platform.eveLogPath }) } - this.accessory = accessory } - async internalUpdate (rfChl, service, value, callback) { + async internalUpdate (accessory, rfChl, service, value, callback) { callback() try { if (!value) return @@ -85,14 +84,14 @@ module.exports = class deviceRFBridge { rfChl: parseInt(rfChl) } await helpers.sleep(1000) - this.accessory.getService(service).updateCharacteristic(this.Characteristic.On, false) - await this.platform.sendDeviceUpdate(this.accessory, params) + accessory.getService(service).updateCharacteristic(this.Characteristic.On, false) + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { if (!helpers.hasProperty(params, 'updateSource')) return const timeNow = new Date() @@ -100,7 +99,7 @@ module.exports = class deviceRFBridge { if (helpers.hasProperty(params, 'cmd') && params.cmd === 'transmit' && helpers.hasProperty(params, 'rfChl')) { this.platform.devicesInHB.forEach(acc => { if ( - acc.context.eweDeviceId === this.accessory.context.eweDeviceId && + acc.context.eweDeviceId === accessory.context.eweDeviceId && helpers.hasProperty(acc.context, 'buttons') && helpers.hasProperty(acc.context.buttons, params.rfChl.toString()) ) { @@ -121,7 +120,7 @@ module.exports = class deviceRFBridge { .forEach(async chan => { this.platform.devicesInHB.forEach(acc => { if ( - acc.context.eweDeviceId === this.accessory.context.eweDeviceId && + acc.context.eweDeviceId === accessory.context.eweDeviceId && helpers.hasProperty(acc.context, 'buttons') && helpers.hasProperty(acc.context.buttons, chan.split('g')[1].toString()) ) { @@ -198,7 +197,7 @@ module.exports = class deviceRFBridge { }) } } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/scm.js b/lib/device/scm.js index fc8c339c..c952e154 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -12,36 +12,36 @@ module.exports = class deviceSCM { const scmService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) scmService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(value, callback)) + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('switch', accessory, { storage: 'fs', path: this.platform.eveLogPath }) - this.accessory = accessory + accessory = accessory } - async internalUpdate (value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { const params = { switches: helpers.defaultMultiSwitchOff } params.switches[0].switch = value ? 'on' : 'off' - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { if (!helpers.hasProperty(params, 'switches')) return - this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, params.switches[0].switch === 'on') - this.accessory.eveLogger.addEntry({ + accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, params.switches[0].switch === 'on') + accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: params.switches[0].switch === 'on' ? 1 : 0 }) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/sensor.js b/lib/device/sensor.js index 50c5816e..c1592391 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -22,14 +22,13 @@ module.exports = class deviceSensor { storage: 'fs', path: this.platform.eveLogPath }) - this.accessory = accessory } async externalUpdate (params) { try { if (helpers.hasProperty(params, 'battery')) { const batteryService = - this.accessory.getService(this.Service.BatteryService) || this.accessory.addService(this.Service.BatteryService) + accessory.getService(this.Service.BatteryService) || accessory.addService(this.Service.BatteryService) const scaledBattery = Math.round(params.battery * 33.3) batteryService.updateCharacteristic(this.Characteristic.BatteryLevel, scaledBattery) batteryService.updateCharacteristic( @@ -40,14 +39,14 @@ module.exports = class deviceSensor { if (!helpers.hasProperty(params, 'switch')) return const newState = params.switch === 'on' ? 1 : 0 let oAccessory = false - const contactService = this.accessory.getService(this.Service.ContactSensor) + const contactService = accessory.getService(this.Service.ContactSensor) contactService.updateCharacteristic(this.Characteristic.ContactSensorState, newState) - this.accessory.eveLogger.addEntry({ + accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: newState }) this.platform.cusG.forEach(async group => { - if (group.sensorId === this.accessory.context.eweDeviceId && group.type === 'garage') { + if (group.sensorId === accessory.context.eweDeviceId && group.type === 'garage') { if ((oAccessory = this.platform.devicesInHB.get(group.deviceId + 'SWX'))) { switch (newState) { case 0: @@ -68,7 +67,7 @@ module.exports = class deviceSensor { } }) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/switch-multi.js b/lib/device/switch-multi.js index ae1c3f7d..c4caf414 100644 --- a/lib/device/switch-multi.js +++ b/lib/device/switch-multi.js @@ -13,7 +13,7 @@ module.exports = class deviceSwitch { const switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) switchService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(value, callback)) + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) if (accessory.getService(this.Service.Outlet)) { accessory.removeService(accessory.getService(this.Service.Outlet)) } @@ -25,24 +25,15 @@ module.exports = class deviceSwitch { storage: 'fs', path: this.platform.eveLogPath }) - this.accessory = accessory } - async internalUpdate (value, callback) { - // *** generates a random number in the range [10, 100] *** \\ - await helpers.sleep(Math.floor(Math.random() * 91 + 10)) - if (this.updateInProgress) { - await helpers.sleep(300) - return await this.internalUpdate(value, callback) - } - this.updateInProgress = true - setTimeout(() => (this.updateInProgress = false), 250) - callback() + async internalUpdate (accessory, value, callback) { try { + callback() let oAccessory let masterState = 'off' const params = {} - switch (this.accessory.context.switchNumber) { + switch (accessory.context.switchNumber) { case '0': params.switches = helpers.defaultMultiSwitchOff params.switches[0].switch = value ? 'on' : 'off' @@ -50,8 +41,9 @@ module.exports = class deviceSwitch { params.switches[2].switch = value ? 'on' : 'off' params.switches[3].switch = value ? 'on' : 'off' for (let i = 0; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { + if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { oAccessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, value) + oAccessory.context.cacheOn = value } } break @@ -61,11 +53,11 @@ module.exports = class deviceSwitch { case '4': params.switches = helpers.defaultMultiSwitchOff for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { + if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { if (oAccessory.getService(this.Service.Switch).getCharacteristic(this.Characteristic.On).value) { masterState = 'on' } - if (i === parseInt(this.accessory.context.switchNumber)) { + if (i === parseInt(accessory.context.switchNumber)) { params.switches[i - 1].switch = value ? 'on' : 'off' oAccessory.context.cacheOn = value } else { @@ -75,24 +67,24 @@ module.exports = class deviceSwitch { params.switches[i - 1].switch = 'off' } } - if (!this.platform.hiddenMasters.includes(this.accessory.context.eweDeviceId)) { - oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW0') + if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { + oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW0') oAccessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, masterState === 'on') } break } - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { if (!helpers.hasProperty(params, 'switches')) return - const idToCheck = this.accessory.context.hbDeviceId.slice(0, -1) + const idToCheck = accessory.context.hbDeviceId.slice(0, -1) let primaryState = false - for (let i = 1; i <= this.accessory.context.channelCount; i++) { + for (let i = 1; i <= accessory.context.channelCount; i++) { if (params.switches[i - 1].switch === 'on') { primaryState = true } @@ -108,15 +100,15 @@ module.exports = class deviceSwitch { }) } } - if (!this.platform.hiddenMasters.includes(this.accessory.context.eweDeviceId)) { - this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, primaryState) - this.accessory.eveLogger.addEntry({ + if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { + accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, primaryState) + accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: primaryState ? 1 : 0 }) } } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/switch-single.js b/lib/device/switch-single.js index 90c7cbf6..1b106754 100644 --- a/lib/device/switch-single.js +++ b/lib/device/switch-single.js @@ -12,7 +12,7 @@ module.exports = class deviceSwitchSingle { const switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) switchService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(value, callback)) + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) if (accessory.getService(this.Service.Outlet)) { accessory.removeService(accessory.getService(this.Service.Outlet)) } @@ -24,29 +24,29 @@ module.exports = class deviceSwitchSingle { storage: 'fs', path: this.platform.eveLogPath }) - this.accessory = accessory + accessory = accessory } - async internalUpdate (value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { const params = { switch: value ? 'on' : 'off' } - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { if (!helpers.hasProperty(params, 'switch')) return - this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, params.switch === 'on') - this.accessory.eveLogger.addEntry({ + accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, params.switch === 'on') + accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: params.switch === 'on' ? 1 : 0 }) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/template.js b/lib/device/template.js index 96b3e25d..640ac76d 100644 --- a/lib/device/template.js +++ b/lib/device/template.js @@ -9,24 +9,24 @@ module.exports = class deviceTemplate { const service = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) service .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(value, callback)) - this.accessory = accessory + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + accessory = accessory } - async internalUpdate (value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index 2f2216d7..f8ebc126 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -17,63 +17,62 @@ module.exports = class deviceThermostat { const switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) switchService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(value, callback)) + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) } accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('custom', accessory, { storage: 'fs', path: this.platform.eveLogPath }) - this.accessory = accessory } - async internalUpdate (value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { const params = { switch: value ? 'on' : 'off', mainSwitch: value ? 'on' : 'off' } - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { if ( !this.platform.config.hideTHSwitch && (helpers.hasProperty(params, 'switch') || helpers.hasProperty(params, 'mainSwitch')) ) { const newState = helpers.hasProperty(params, 'switch') ? params.switch === 'on' : params.mainSwitch === 'on' - const switchService = this.accessory.getService(this.Service.Switch) + const switchService = accessory.getService(this.Service.Switch) switchService.updateCharacteristic(this.Characteristic.On, newState) - this.accessory.eveLogger.addEntry({ + accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: newState ? 1 : 0 }) } const eveLog = { time: Math.round(new Date().valueOf() / 1000) } - if (helpers.hasProperty(params, 'currentTemperature') && this.accessory.getService(this.Service.TemperatureSensor)) { + if (helpers.hasProperty(params, 'currentTemperature') && accessory.getService(this.Service.TemperatureSensor)) { const currentTemp = parseFloat(params.currentTemperature !== 'unavailable' ? params.currentTemperature : 0) - this.accessory + accessory .getService(this.Service.TemperatureSensor) .updateCharacteristic(this.Characteristic.CurrentTemperature, currentTemp) eveLog.temp = currentTemp } - if (helpers.hasProperty(params, 'currentHumidity') && this.accessory.getService(this.Service.HumiditySensor)) { + if (helpers.hasProperty(params, 'currentHumidity') && accessory.getService(this.Service.HumiditySensor)) { const currentHumi = parseFloat(params.currentHumidity !== 'unavailable' ? params.currentHumidity : 0) - this.accessory + accessory .getService(this.Service.HumiditySensor) .updateCharacteristic(this.Characteristic.CurrentRelativeHumidity, currentHumi) eveLog.humidity = currentHumi } if (helpers.hasProperty(eveLog, 'temp') || helpers.hasProperty(eveLog, 'humidity')) { - this.accessory.eveLogger.addEntry(eveLog) + accessory.eveLogger.addEntry(eveLog) } } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/usb.js b/lib/device/usb.js index ccc96e56..b43f90c0 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -12,36 +12,35 @@ module.exports = class deviceUSB { const usbService = accessory.getService(this.Service.Outlet) || accessory.addService(this.Service.Outlet) usbService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(value, callback)) + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('switch', accessory, { storage: 'fs', path: this.platform.eveLogPath }) - this.accessory = accessory } - async internalUpdate (value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { const params = { switches: helpers.defaultMultiSwitchOff } params.switches[0].switch = value ? 'on' : 'off' - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { if (!helpers.hasProperty(params, 'switches')) return - this.accessory.getService(this.Service.Outlet).updateCharacteristic(this.Characteristic.On, params.switches[0].switch === 'on') - this.accessory.eveLogger.addEntry({ + accessory.getService(this.Service.Outlet).updateCharacteristic(this.Characteristic.On, params.switches[0].switch === 'on') + accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: params.switches[0].switch === 'on' ? 1 : 0 }) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/valve-two.js b/lib/device/valve-two.js index 4e53ebff..b49cabb2 100644 --- a/lib/device/valve-two.js +++ b/lib/device/valve-two.js @@ -22,7 +22,7 @@ module.exports = class deviceValveTwo { } valveService .getCharacteristic(this.Characteristic.Active) - .on('set', (value, callback) => this.internalUpdate('Valve ' + v, value, callback)) + .on('set', (value, callback) => this.internalUpdate(accessory, 'Valve ' + v, value, callback)) valveService .getCharacteristic(this.Characteristic.SetDuration) .on('set', (value, callback) => { @@ -34,23 +34,22 @@ module.exports = class deviceValveTwo { callback() }) }) - this.accessory = accessory } - async internalUpdate (valve, value, callback) { + async internalUpdate (accessory, valve, value, callback) { callback() try { const params = { switches: helpers.defaultMultiSwitchOff } - const serviceValve = this.accessory.getService(valve) + const serviceValve = accessory.getService(valve) switch (valve) { case 'Valve A': params.switches[0].switch = value ? 'on' : 'off' - params.switches[1].switch = this.accessory.getService('Valve B').getCharacteristic(this.Characteristic.Active).value + params.switches[1].switch = accessory.getService('Valve B').getCharacteristic(this.Characteristic.Active).value ? 'on' : 'off' break case 'Valve B': - params.switches[0].switch = this.accessory.getService('Valve A').getCharacteristic(this.Characteristic.Active).value + params.switches[0].switch = accessory.getService('Valve A').getCharacteristic(this.Characteristic.Active).value ? 'on' : 'off' params.switches[1].switch = value ? 'on' : 'off' @@ -60,7 +59,7 @@ module.exports = class deviceValveTwo { switch (value) { case 0: serviceValve.updateCharacteristic(this.Characteristic.RemainingDuration, 0) - clearTimeout(this.accessory.getService(valve).timer) + clearTimeout(accessory.getService(valve).timer) break case 1: { const timer = serviceValve.getCharacteristic(this.Characteristic.SetDuration).value @@ -69,17 +68,17 @@ module.exports = class deviceValveTwo { break } } - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { if (!helpers.hasProperty(params, 'switches')) return ;['A', 'B'].forEach((v, k) => { - const valveService = this.accessory.getService('Valve ' + v) + const valveService = accessory.getService('Valve ' + v) valveService .updateCharacteristic(this.Characteristic.Active, params.switches[k].switch === 'on') .updateCharacteristic(this.Characteristic.InUse, params.switches[k].switch === 'on') @@ -93,7 +92,7 @@ module.exports = class deviceValveTwo { } }) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/valve.js b/lib/device/valve.js index ac142ff3..e03b17a9 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -21,7 +21,7 @@ module.exports = class deviceValve { } valveService .getCharacteristic(this.Characteristic.Active) - .on('set', (value, callback) => this.internalUpdate(value, callback)) + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) valveService .getCharacteristic(this.Characteristic.SetDuration) .on('set', (value, callback) => { @@ -32,19 +32,18 @@ module.exports = class deviceValve { } callback() }) - this.accessory = accessory } - async internalUpdate (value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { const params = { switch: value ? 'on' : 'off' } - const serviceValve = this.accessory.getService(this.Service.Valve) + const serviceValve = accessory.getService(this.Service.Valve) serviceValve.updateCharacteristic(this.Characteristic.InUse, value) switch (value) { case 0: serviceValve.updateCharacteristic(this.Characteristic.RemainingDuration, 0) - clearTimeout(this.accessory.getService(this.Service.Valve).timer) + clearTimeout(accessory.getService(this.Service.Valve).timer) break case 1: { const timer = serviceValve.getCharacteristic(this.Characteristic.SetDuration).value @@ -53,16 +52,16 @@ module.exports = class deviceValve { break } } - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { if (!helpers.hasProperty(params, 'switch')) return - const valveService = this.accessory.getService(this.Service.Valve) + const valveService = accessory.getService(this.Service.Valve) valveService .updateCharacteristic(this.Characteristic.Active, params.switch === 'on') .updateCharacteristic(this.Characteristic.InUse, params.switch === 'on') @@ -75,7 +74,7 @@ module.exports = class deviceValve { clearTimeout(valveService.timer) } } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index a7514131..40f9914f 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -45,7 +45,7 @@ module.exports = class deviceZBDev { }) accessory.getService(this.Service.Switch) .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(value, callback)) + .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) break case 1770: if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) @@ -76,38 +76,38 @@ module.exports = class deviceZBDev { }) break } - this.accessory = accessory + accessory = accessory } - async internalUpdate (value, callback) { + async internalUpdate (accessory, value, callback) { callback() try { const params = { switch: value ? 'on' : 'off' } - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) + this.platform.deviceUpdateError(accessory, err, true) } } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { //* ** credit @tasict ***\\ if (helpers.hasProperty(params, 'battery')) { - if (this.accessory.context.eweUIID === 3026 && this.platform.config.ZBDWBatt) { + if (accessory.context.eweUIID === 3026 && this.platform.config.ZBDWBatt) { params.battery *= 10 } const batteryService = - this.accessory.getService(this.Service.BatteryService) || this.accessory.addService(this.Service.BatteryService) + accessory.getService(this.Service.BatteryService) || accessory.addService(this.Service.BatteryService) batteryService.updateCharacteristic(this.Characteristic.BatteryLevel, params.battery) batteryService.updateCharacteristic( this.Characteristic.StatusLowBattery, params.battery < this.lowBattThreshold ) } - switch (this.accessory.context.eweUIID) { + switch (accessory.context.eweUIID) { case 1000: if (helpers.hasProperty(params, 'key') && [0, 1, 2].includes(params.key)) { - this.accessory + accessory .getService(this.Service.StatelessProgrammableSwitch) .updateCharacteristic(this.Characteristic.ProgrammableSwitchEvent, params.key) } @@ -115,10 +115,10 @@ module.exports = class deviceZBDev { case 1009: case 1256: if (helpers.hasProperty(params, 'switch') && ['off', 'on'].includes(params.switch)) { - this.accessory + accessory .getService(this.Service.Switch) .updateCharacteristic(this.Characteristic.On, params.switch === 'on') - this.accessory.eveLogger.addEntry({ + accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: params.switch === 'on' ? 1 : 0 }) @@ -128,20 +128,20 @@ module.exports = class deviceZBDev { const eveLog = { time: Math.round(new Date().valueOf() / 1000) } if (helpers.hasProperty(params, 'temperature')) { const currentTemp = parseInt(params.temperature) / 100 - this.accessory + accessory .getService(this.Service.TemperatureSensor) .updateCharacteristic(this.Characteristic.CurrentTemperature, currentTemp) eveLog.temp = parseFloat(currentTemp) } if (helpers.hasProperty(params, 'humidity')) { const currentHumi = parseInt(params.humidity) / 100 - this.accessory + accessory .getService(this.Service.HumiditySensor) .updateCharacteristic(this.Characteristic.CurrentRelativeHumidity, currentHumi) eveLog.humidity = parseFloat(currentHumi) } if (helpers.hasProperty(eveLog, 'temp') || helpers.hasProperty(eveLog, 'humidity')) { - this.accessory.eveLogger.addEntry(eveLog) + accessory.eveLogger.addEntry(eveLog) } break } @@ -153,30 +153,30 @@ module.exports = class deviceZBDev { helpers.hasProperty(params, 'updateSource') && params.motion === 1 && diff < this.sensorTimeDifference - this.accessory.eveLogger.addEntry({ + accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: motionDetected ? 1 : 0 }) - this.accessory.getService(this.Service.MotionSensor).updateCharacteristic(this.Characteristic.MotionDetected, motionDetected) + accessory.getService(this.Service.MotionSensor).updateCharacteristic(this.Characteristic.MotionDetected, motionDetected) break } break case 3026: if (helpers.hasProperty(params, 'lock') && [0, 1].includes(params.lock)) { - this.accessory + accessory .getService(this.Service.ContactSensor) .updateCharacteristic(this.Characteristic.ContactSensorState, params.lock) - this.accessory.eveLogger.addEntry({ + accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: params.lock }) } break default: - throw new Error('Zigbee device type not supported [uiid ' + this.accessory.context.eweUIID + ']') + throw new Error('Zigbee device type not supported [uiid ' + accessory.context.eweUIID + ']') } } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) + this.platform.deviceUpdateError(accessory, err, false) } } } diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 94d73fdc..bb5f0913 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -504,7 +504,7 @@ module.exports = class eWeLinkPlatform { str += 'is unreachable' } } - if (!this.config.disableHTTPRefresh) accessory.control.externalUpdate(device.params) + if (!this.config.disableHTTPRefresh) accessory.control.externalUpdate(accessory, device.params) this.devicesInHB.set(accessory.context.hbDeviceId, accessory) this.log(' → [%s] initialised %s.', device.name, str) } catch (err) { @@ -648,7 +648,7 @@ module.exports = class eWeLinkPlatform { this.log('[%s] %s update received and will be refreshed.', accessory.displayName, device.params.updateSource) } try { - accessory.control.externalUpdate(device.params) + accessory.control.externalUpdate(accessory, device.params) } catch (err) { this.log.warn('[%s] could not be refreshed as %s.', accessory.displayName, this.debug ? err : err.message) } From a8bcf8311e8a2e0e4286553677ba2daf9a89de51 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 13:17:55 +0000 Subject: [PATCH 0703/3183] callback inside try --- lib/device/blind.js | 2 +- lib/device/curtain.js | 2 +- lib/device/diffuser.js | 4 ++-- lib/device/fan.js | 2 +- lib/device/garage-eachen.js | 2 +- lib/device/garage-four.js | 2 +- lib/device/garage-two.js | 2 +- lib/device/garage.js | 2 +- lib/device/light-colour.js | 2 +- lib/device/light-ctemp.js | 2 +- lib/device/light-dimmer.js | 2 +- lib/device/lock.js | 2 +- lib/device/outlet.js | 2 +- lib/device/rf-bridge.js | 2 +- lib/device/scm.js | 2 +- lib/device/switch-single.js | 2 +- lib/device/template.js | 2 +- lib/device/thermostat.js | 2 +- lib/device/usb.js | 2 +- lib/device/valve-two.js | 2 +- lib/device/valve.js | 2 +- lib/device/zb-dev.js | 2 +- 22 files changed, 23 insertions(+), 23 deletions(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index aae2d48f..1b28ce47 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -22,8 +22,8 @@ module.exports = class deviceBlind { } async internalUpdate (accessory, value, callback) { - callback() try { + callback() let blindConfig const params = {} const wcService = accessory.getService(this.Service.WindowCovering) diff --git a/lib/device/curtain.js b/lib/device/curtain.js index d2fafcb4..26b0de3b 100644 --- a/lib/device/curtain.js +++ b/lib/device/curtain.js @@ -22,8 +22,8 @@ module.exports = class deviceCurtain { } async internalUpdate (accessory, value, callback) { - callback() try { + callback() let params const prevPos = accessory.context.cacheCurrentPosition const newPos = value diff --git a/lib/device/diffuser.js b/lib/device/diffuser.js index 47a1739b..a5a34858 100644 --- a/lib/device/diffuser.js +++ b/lib/device/diffuser.js @@ -34,8 +34,8 @@ module.exports = class deviceDiffuser { } async internalDiffuserOnOffUpdate (accessory, value, callback) { - callback() try { + callback() const params = { switch: value ? 'on' : 'off' } await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { @@ -100,7 +100,7 @@ module.exports = class deviceDiffuser { lightGcolor: newRGB[1], lightBcolor: newRGB[2] } - await helpers.sleep(500) + await helpers.sleep(1000) if (updateKeyColour !== accessory.context.updateKeyColour) return await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { diff --git a/lib/device/fan.js b/lib/device/fan.js index bb1a55dc..963d7da8 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -39,8 +39,8 @@ module.exports = class deviceFan { } async internalUpdate (accessory, type, value, callback) { - callback() try { + callback() let newPower let newSpeed let newLight diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index ddba1e03..53431d1c 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -22,8 +22,8 @@ module.exports = class deviceGarageEachen { } async internalUpdate (accessory, value, callback) { - callback() try { + callback() let garageConfig if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') diff --git a/lib/device/garage-four.js b/lib/device/garage-four.js index 85b30124..499ce08e 100644 --- a/lib/device/garage-four.js +++ b/lib/device/garage-four.js @@ -24,8 +24,8 @@ module.exports = class deviceGarageFour { } async internalUpdate (accessory, garage, value, callback) { - callback() try { + callback() let garageConfig if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') diff --git a/lib/device/garage-two.js b/lib/device/garage-two.js index d23ac1d5..96fb08f1 100644 --- a/lib/device/garage-two.js +++ b/lib/device/garage-two.js @@ -24,8 +24,8 @@ module.exports = class deviceGarageTwo { } async internalUpdate (accessory, garage, value, callback) { - callback() try { + callback() let garageConfig if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') diff --git a/lib/device/garage.js b/lib/device/garage.js index ebee6eb5..898b075e 100644 --- a/lib/device/garage.js +++ b/lib/device/garage.js @@ -22,8 +22,8 @@ module.exports = class deviceGarage { } async internalUpdate (accessory, value, callback) { - callback() try { + callback() let garageConfig if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') diff --git a/lib/device/light-colour.js b/lib/device/light-colour.js index 487356a3..1b63dd5f 100644 --- a/lib/device/light-colour.js +++ b/lib/device/light-colour.js @@ -32,8 +32,8 @@ module.exports = class deviceLightColour { } async internalUpdate (accessory, type, value, callback) { - callback() try { + callback() let newRGB let params = {} const lightService = accessory.getService(this.Service.Lightbulb) diff --git a/lib/device/light-ctemp.js b/lib/device/light-ctemp.js index f9450a4e..d82bea02 100644 --- a/lib/device/light-ctemp.js +++ b/lib/device/light-ctemp.js @@ -16,8 +16,8 @@ module.exports = class deviceLightCTemp { } async internalUpdate (accessory, type, value, callback) { - callback() try { + callback() } catch (err) { this.platform.deviceUpdateError(accessory, err, true) diff --git a/lib/device/light-dimmer.js b/lib/device/light-dimmer.js index 94da5b67..4567e26a 100644 --- a/lib/device/light-dimmer.js +++ b/lib/device/light-dimmer.js @@ -16,8 +16,8 @@ module.exports = class deviceLightDimmer { } async internalUpdate (accessory, type, value, callback) { - callback() try { + callback() const params = {} switch (type) { case 'onoff': diff --git a/lib/device/lock.js b/lib/device/lock.js index 6804242f..d0a6b8b3 100644 --- a/lib/device/lock.js +++ b/lib/device/lock.js @@ -15,8 +15,8 @@ module.exports = class deviceLock { } async internalUpdate (accessory, value, callback) { - callback() try { + callback() let lockConfig const params = { switch: 'on' } const lmService = accessory.getService(this.Service.LockMechanism) diff --git a/lib/device/outlet.js b/lib/device/outlet.js index 3992c9e0..fba94b09 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -129,8 +129,8 @@ module.exports = class deviceOutlet { } async internalUpdate (accessory, value, callback) { - callback() try { + callback() const params = { switch: value ? 'on' : 'off' } await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index e9fe4f13..1adb89f4 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -76,8 +76,8 @@ module.exports = class deviceRFBridge { } async internalUpdate (accessory, rfChl, service, value, callback) { - callback() try { + callback() if (!value) return const params = { cmd: 'transmit', diff --git a/lib/device/scm.js b/lib/device/scm.js index c952e154..3b784fda 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -22,8 +22,8 @@ module.exports = class deviceSCM { } async internalUpdate (accessory, value, callback) { - callback() try { + callback() const params = { switches: helpers.defaultMultiSwitchOff } params.switches[0].switch = value ? 'on' : 'off' await this.platform.sendDeviceUpdate(accessory, params) diff --git a/lib/device/switch-single.js b/lib/device/switch-single.js index 1b106754..e5e840ca 100644 --- a/lib/device/switch-single.js +++ b/lib/device/switch-single.js @@ -28,8 +28,8 @@ module.exports = class deviceSwitchSingle { } async internalUpdate (accessory, value, callback) { - callback() try { + callback() const params = { switch: value ? 'on' : 'off' } await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { diff --git a/lib/device/template.js b/lib/device/template.js index 640ac76d..a55ee11f 100644 --- a/lib/device/template.js +++ b/lib/device/template.js @@ -14,8 +14,8 @@ module.exports = class deviceTemplate { } async internalUpdate (accessory, value, callback) { - callback() try { + callback() } catch (err) { this.platform.deviceUpdateError(accessory, err, true) diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index f8ebc126..fbea99d1 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -27,8 +27,8 @@ module.exports = class deviceThermostat { } async internalUpdate (accessory, value, callback) { - callback() try { + callback() const params = { switch: value ? 'on' : 'off', mainSwitch: value ? 'on' : 'off' diff --git a/lib/device/usb.js b/lib/device/usb.js index b43f90c0..c9ad71e7 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -21,8 +21,8 @@ module.exports = class deviceUSB { } async internalUpdate (accessory, value, callback) { - callback() try { + callback() const params = { switches: helpers.defaultMultiSwitchOff } params.switches[0].switch = value ? 'on' : 'off' await this.platform.sendDeviceUpdate(accessory, params) diff --git a/lib/device/valve-two.js b/lib/device/valve-two.js index b49cabb2..bd487adc 100644 --- a/lib/device/valve-two.js +++ b/lib/device/valve-two.js @@ -37,8 +37,8 @@ module.exports = class deviceValveTwo { } async internalUpdate (accessory, valve, value, callback) { - callback() try { + callback() const params = { switches: helpers.defaultMultiSwitchOff } const serviceValve = accessory.getService(valve) switch (valve) { diff --git a/lib/device/valve.js b/lib/device/valve.js index e03b17a9..4e8d0457 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -35,8 +35,8 @@ module.exports = class deviceValve { } async internalUpdate (accessory, value, callback) { - callback() try { + callback() const params = { switch: value ? 'on' : 'off' } const serviceValve = accessory.getService(this.Service.Valve) serviceValve.updateCharacteristic(this.Characteristic.InUse, value) diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index 40f9914f..3a5fbcc3 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -80,8 +80,8 @@ module.exports = class deviceZBDev { } async internalUpdate (accessory, value, callback) { - callback() try { + callback() const params = { switch: value ? 'on' : 'off' } await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { From c25e32572b996b2c40f2a776c5ad7661867d95a3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 13:25:37 +0000 Subject: [PATCH 0704/3183] tidying up/formatting --- lib/device/light-ctemp.js | 1 - lib/device/lock.js | 1 - lib/device/scm.js | 1 - lib/device/sensor.js | 2 +- lib/device/switch-single.js | 1 - lib/device/template.js | 2 -- lib/device/zb-dev.js | 1 - 7 files changed, 1 insertion(+), 8 deletions(-) diff --git a/lib/device/light-ctemp.js b/lib/device/light-ctemp.js index d82bea02..295f77e0 100644 --- a/lib/device/light-ctemp.js +++ b/lib/device/light-ctemp.js @@ -18,7 +18,6 @@ module.exports = class deviceLightCTemp { async internalUpdate (accessory, type, value, callback) { try { callback() - } catch (err) { this.platform.deviceUpdateError(accessory, err, true) } diff --git a/lib/device/lock.js b/lib/device/lock.js index d0a6b8b3..a5cd43ba 100644 --- a/lib/device/lock.js +++ b/lib/device/lock.js @@ -11,7 +11,6 @@ module.exports = class deviceLock { lmService .getCharacteristic(this.Characteristic.LockTargetState) .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) - accessory = accessory } async internalUpdate (accessory, value, callback) { diff --git a/lib/device/scm.js b/lib/device/scm.js index 3b784fda..906f294b 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -18,7 +18,6 @@ module.exports = class deviceSCM { storage: 'fs', path: this.platform.eveLogPath }) - accessory = accessory } async internalUpdate (accessory, value, callback) { diff --git a/lib/device/sensor.js b/lib/device/sensor.js index c1592391..66467a1a 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -24,7 +24,7 @@ module.exports = class deviceSensor { }) } - async externalUpdate (params) { + async externalUpdate (accessory, params) { try { if (helpers.hasProperty(params, 'battery')) { const batteryService = diff --git a/lib/device/switch-single.js b/lib/device/switch-single.js index e5e840ca..62ff4ecc 100644 --- a/lib/device/switch-single.js +++ b/lib/device/switch-single.js @@ -24,7 +24,6 @@ module.exports = class deviceSwitchSingle { storage: 'fs', path: this.platform.eveLogPath }) - accessory = accessory } async internalUpdate (accessory, value, callback) { diff --git a/lib/device/template.js b/lib/device/template.js index a55ee11f..7c980a3c 100644 --- a/lib/device/template.js +++ b/lib/device/template.js @@ -10,13 +10,11 @@ module.exports = class deviceTemplate { service .getCharacteristic(this.Characteristic.On) .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) - accessory = accessory } async internalUpdate (accessory, value, callback) { try { callback() - } catch (err) { this.platform.deviceUpdateError(accessory, err, true) } diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index 3a5fbcc3..433071e4 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -76,7 +76,6 @@ module.exports = class deviceZBDev { }) break } - accessory = accessory } async internalUpdate (accessory, value, callback) { From dc20502a00e7090400b2770ad81a7ef6d6145398 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 13:27:46 +0000 Subject: [PATCH 0705/3183] 3.12.0-2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 02229e1b..032b820d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0-1", + "version": "3.12.0-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 41af04f9..91ec9975 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0-1", + "version": "3.12.0-2", "author": "bwp91", "contributors": [ "gbro115", From de005bb9f80cc2f1f3549c577315c67096b7d51f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 13:58:37 +0000 Subject: [PATCH 0706/3183] Revert "3.12.0-2" This reverts commit dc20502a00e7090400b2770ad81a7ef6d6145398. --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 032b820d..02229e1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0-2", + "version": "3.12.0-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 91ec9975..41af04f9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0-2", + "version": "3.12.0-1", "author": "bwp91", "contributors": [ "gbro115", From cfd99b12be13125311b3d7424a2393e1af9537d3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 13:58:53 +0000 Subject: [PATCH 0707/3183] Revert "tidying up/formatting" This reverts commit c25e32572b996b2c40f2a776c5ad7661867d95a3. --- lib/device/light-ctemp.js | 1 + lib/device/lock.js | 1 + lib/device/scm.js | 1 + lib/device/sensor.js | 2 +- lib/device/switch-single.js | 1 + lib/device/template.js | 2 ++ lib/device/zb-dev.js | 1 + 7 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/device/light-ctemp.js b/lib/device/light-ctemp.js index 295f77e0..d82bea02 100644 --- a/lib/device/light-ctemp.js +++ b/lib/device/light-ctemp.js @@ -18,6 +18,7 @@ module.exports = class deviceLightCTemp { async internalUpdate (accessory, type, value, callback) { try { callback() + } catch (err) { this.platform.deviceUpdateError(accessory, err, true) } diff --git a/lib/device/lock.js b/lib/device/lock.js index a5cd43ba..d0a6b8b3 100644 --- a/lib/device/lock.js +++ b/lib/device/lock.js @@ -11,6 +11,7 @@ module.exports = class deviceLock { lmService .getCharacteristic(this.Characteristic.LockTargetState) .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + accessory = accessory } async internalUpdate (accessory, value, callback) { diff --git a/lib/device/scm.js b/lib/device/scm.js index 906f294b..3b784fda 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -18,6 +18,7 @@ module.exports = class deviceSCM { storage: 'fs', path: this.platform.eveLogPath }) + accessory = accessory } async internalUpdate (accessory, value, callback) { diff --git a/lib/device/sensor.js b/lib/device/sensor.js index 66467a1a..c1592391 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -24,7 +24,7 @@ module.exports = class deviceSensor { }) } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (helpers.hasProperty(params, 'battery')) { const batteryService = diff --git a/lib/device/switch-single.js b/lib/device/switch-single.js index 62ff4ecc..e5e840ca 100644 --- a/lib/device/switch-single.js +++ b/lib/device/switch-single.js @@ -24,6 +24,7 @@ module.exports = class deviceSwitchSingle { storage: 'fs', path: this.platform.eveLogPath }) + accessory = accessory } async internalUpdate (accessory, value, callback) { diff --git a/lib/device/template.js b/lib/device/template.js index 7c980a3c..a55ee11f 100644 --- a/lib/device/template.js +++ b/lib/device/template.js @@ -10,11 +10,13 @@ module.exports = class deviceTemplate { service .getCharacteristic(this.Characteristic.On) .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + accessory = accessory } async internalUpdate (accessory, value, callback) { try { callback() + } catch (err) { this.platform.deviceUpdateError(accessory, err, true) } diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index 433071e4..3a5fbcc3 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -76,6 +76,7 @@ module.exports = class deviceZBDev { }) break } + accessory = accessory } async internalUpdate (accessory, value, callback) { From 29f5910d513858174d611b6b7a28a7e69678e52c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 13:58:57 +0000 Subject: [PATCH 0708/3183] Revert "callback inside try" This reverts commit a8bcf8311e8a2e0e4286553677ba2daf9a89de51. --- lib/device/blind.js | 2 +- lib/device/curtain.js | 2 +- lib/device/diffuser.js | 4 ++-- lib/device/fan.js | 2 +- lib/device/garage-eachen.js | 2 +- lib/device/garage-four.js | 2 +- lib/device/garage-two.js | 2 +- lib/device/garage.js | 2 +- lib/device/light-colour.js | 2 +- lib/device/light-ctemp.js | 2 +- lib/device/light-dimmer.js | 2 +- lib/device/lock.js | 2 +- lib/device/outlet.js | 2 +- lib/device/rf-bridge.js | 2 +- lib/device/scm.js | 2 +- lib/device/switch-single.js | 2 +- lib/device/template.js | 2 +- lib/device/thermostat.js | 2 +- lib/device/usb.js | 2 +- lib/device/valve-two.js | 2 +- lib/device/valve.js | 2 +- lib/device/zb-dev.js | 2 +- 22 files changed, 23 insertions(+), 23 deletions(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index 1b28ce47..aae2d48f 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -22,8 +22,8 @@ module.exports = class deviceBlind { } async internalUpdate (accessory, value, callback) { + callback() try { - callback() let blindConfig const params = {} const wcService = accessory.getService(this.Service.WindowCovering) diff --git a/lib/device/curtain.js b/lib/device/curtain.js index 26b0de3b..d2fafcb4 100644 --- a/lib/device/curtain.js +++ b/lib/device/curtain.js @@ -22,8 +22,8 @@ module.exports = class deviceCurtain { } async internalUpdate (accessory, value, callback) { + callback() try { - callback() let params const prevPos = accessory.context.cacheCurrentPosition const newPos = value diff --git a/lib/device/diffuser.js b/lib/device/diffuser.js index a5a34858..47a1739b 100644 --- a/lib/device/diffuser.js +++ b/lib/device/diffuser.js @@ -34,8 +34,8 @@ module.exports = class deviceDiffuser { } async internalDiffuserOnOffUpdate (accessory, value, callback) { + callback() try { - callback() const params = { switch: value ? 'on' : 'off' } await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { @@ -100,7 +100,7 @@ module.exports = class deviceDiffuser { lightGcolor: newRGB[1], lightBcolor: newRGB[2] } - await helpers.sleep(1000) + await helpers.sleep(500) if (updateKeyColour !== accessory.context.updateKeyColour) return await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { diff --git a/lib/device/fan.js b/lib/device/fan.js index 963d7da8..bb1a55dc 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -39,8 +39,8 @@ module.exports = class deviceFan { } async internalUpdate (accessory, type, value, callback) { + callback() try { - callback() let newPower let newSpeed let newLight diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 53431d1c..ddba1e03 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -22,8 +22,8 @@ module.exports = class deviceGarageEachen { } async internalUpdate (accessory, value, callback) { + callback() try { - callback() let garageConfig if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') diff --git a/lib/device/garage-four.js b/lib/device/garage-four.js index 499ce08e..85b30124 100644 --- a/lib/device/garage-four.js +++ b/lib/device/garage-four.js @@ -24,8 +24,8 @@ module.exports = class deviceGarageFour { } async internalUpdate (accessory, garage, value, callback) { + callback() try { - callback() let garageConfig if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') diff --git a/lib/device/garage-two.js b/lib/device/garage-two.js index 96fb08f1..d23ac1d5 100644 --- a/lib/device/garage-two.js +++ b/lib/device/garage-two.js @@ -24,8 +24,8 @@ module.exports = class deviceGarageTwo { } async internalUpdate (accessory, garage, value, callback) { + callback() try { - callback() let garageConfig if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') diff --git a/lib/device/garage.js b/lib/device/garage.js index 898b075e..ebee6eb5 100644 --- a/lib/device/garage.js +++ b/lib/device/garage.js @@ -22,8 +22,8 @@ module.exports = class deviceGarage { } async internalUpdate (accessory, value, callback) { + callback() try { - callback() let garageConfig if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { throw new Error('group config missing') diff --git a/lib/device/light-colour.js b/lib/device/light-colour.js index 1b63dd5f..487356a3 100644 --- a/lib/device/light-colour.js +++ b/lib/device/light-colour.js @@ -32,8 +32,8 @@ module.exports = class deviceLightColour { } async internalUpdate (accessory, type, value, callback) { + callback() try { - callback() let newRGB let params = {} const lightService = accessory.getService(this.Service.Lightbulb) diff --git a/lib/device/light-ctemp.js b/lib/device/light-ctemp.js index d82bea02..f9450a4e 100644 --- a/lib/device/light-ctemp.js +++ b/lib/device/light-ctemp.js @@ -16,8 +16,8 @@ module.exports = class deviceLightCTemp { } async internalUpdate (accessory, type, value, callback) { + callback() try { - callback() } catch (err) { this.platform.deviceUpdateError(accessory, err, true) diff --git a/lib/device/light-dimmer.js b/lib/device/light-dimmer.js index 4567e26a..94da5b67 100644 --- a/lib/device/light-dimmer.js +++ b/lib/device/light-dimmer.js @@ -16,8 +16,8 @@ module.exports = class deviceLightDimmer { } async internalUpdate (accessory, type, value, callback) { + callback() try { - callback() const params = {} switch (type) { case 'onoff': diff --git a/lib/device/lock.js b/lib/device/lock.js index d0a6b8b3..6804242f 100644 --- a/lib/device/lock.js +++ b/lib/device/lock.js @@ -15,8 +15,8 @@ module.exports = class deviceLock { } async internalUpdate (accessory, value, callback) { + callback() try { - callback() let lockConfig const params = { switch: 'on' } const lmService = accessory.getService(this.Service.LockMechanism) diff --git a/lib/device/outlet.js b/lib/device/outlet.js index fba94b09..3992c9e0 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -129,8 +129,8 @@ module.exports = class deviceOutlet { } async internalUpdate (accessory, value, callback) { + callback() try { - callback() const params = { switch: value ? 'on' : 'off' } await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index 1adb89f4..e9fe4f13 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -76,8 +76,8 @@ module.exports = class deviceRFBridge { } async internalUpdate (accessory, rfChl, service, value, callback) { + callback() try { - callback() if (!value) return const params = { cmd: 'transmit', diff --git a/lib/device/scm.js b/lib/device/scm.js index 3b784fda..c952e154 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -22,8 +22,8 @@ module.exports = class deviceSCM { } async internalUpdate (accessory, value, callback) { + callback() try { - callback() const params = { switches: helpers.defaultMultiSwitchOff } params.switches[0].switch = value ? 'on' : 'off' await this.platform.sendDeviceUpdate(accessory, params) diff --git a/lib/device/switch-single.js b/lib/device/switch-single.js index e5e840ca..1b106754 100644 --- a/lib/device/switch-single.js +++ b/lib/device/switch-single.js @@ -28,8 +28,8 @@ module.exports = class deviceSwitchSingle { } async internalUpdate (accessory, value, callback) { + callback() try { - callback() const params = { switch: value ? 'on' : 'off' } await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { diff --git a/lib/device/template.js b/lib/device/template.js index a55ee11f..640ac76d 100644 --- a/lib/device/template.js +++ b/lib/device/template.js @@ -14,8 +14,8 @@ module.exports = class deviceTemplate { } async internalUpdate (accessory, value, callback) { + callback() try { - callback() } catch (err) { this.platform.deviceUpdateError(accessory, err, true) diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index fbea99d1..f8ebc126 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -27,8 +27,8 @@ module.exports = class deviceThermostat { } async internalUpdate (accessory, value, callback) { + callback() try { - callback() const params = { switch: value ? 'on' : 'off', mainSwitch: value ? 'on' : 'off' diff --git a/lib/device/usb.js b/lib/device/usb.js index c9ad71e7..b43f90c0 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -21,8 +21,8 @@ module.exports = class deviceUSB { } async internalUpdate (accessory, value, callback) { + callback() try { - callback() const params = { switches: helpers.defaultMultiSwitchOff } params.switches[0].switch = value ? 'on' : 'off' await this.platform.sendDeviceUpdate(accessory, params) diff --git a/lib/device/valve-two.js b/lib/device/valve-two.js index bd487adc..b49cabb2 100644 --- a/lib/device/valve-two.js +++ b/lib/device/valve-two.js @@ -37,8 +37,8 @@ module.exports = class deviceValveTwo { } async internalUpdate (accessory, valve, value, callback) { + callback() try { - callback() const params = { switches: helpers.defaultMultiSwitchOff } const serviceValve = accessory.getService(valve) switch (valve) { diff --git a/lib/device/valve.js b/lib/device/valve.js index 4e8d0457..e03b17a9 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -35,8 +35,8 @@ module.exports = class deviceValve { } async internalUpdate (accessory, value, callback) { + callback() try { - callback() const params = { switch: value ? 'on' : 'off' } const serviceValve = accessory.getService(this.Service.Valve) serviceValve.updateCharacteristic(this.Characteristic.InUse, value) diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index 3a5fbcc3..40f9914f 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -80,8 +80,8 @@ module.exports = class deviceZBDev { } async internalUpdate (accessory, value, callback) { + callback() try { - callback() const params = { switch: value ? 'on' : 'off' } await this.platform.sendDeviceUpdate(accessory, params) } catch (err) { From 0439ff5a00f34273a4ce7fb3a42f06b63e1b398b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 13:59:00 +0000 Subject: [PATCH 0709/3183] Revert "don't use this.accessory" This reverts commit 28dd566074024bcbbe3c333b6a275cf931cc89b4. --- lib/device/blind.js | 43 +++++++++++----------- lib/device/curtain.js | 21 +++++------ lib/device/diffuser.js | 72 +++++++++++++++++++------------------ lib/device/fan.js | 25 ++++++------- lib/device/garage-eachen.js | 35 +++++++++--------- lib/device/garage-four.js | 49 ++++++++++++------------- lib/device/garage-two.js | 67 +++++++++++++++++----------------- lib/device/garage.js | 55 ++++++++++++++-------------- lib/device/light-colour.js | 63 ++++++++++++++++---------------- lib/device/light-ctemp.js | 13 +++---- lib/device/light-dimmer.js | 27 +++++++------- lib/device/lock.js | 34 +++++++++--------- lib/device/outlet.js | 27 +++++++------- lib/device/rf-bridge.js | 19 +++++----- lib/device/scm.js | 18 +++++----- lib/device/sensor.js | 11 +++--- lib/device/switch-multi.js | 46 ++++++++++++++---------- lib/device/switch-single.js | 18 +++++----- lib/device/template.js | 12 +++---- lib/device/thermostat.js | 27 +++++++------- lib/device/usb.js | 17 ++++----- lib/device/valve-two.js | 23 ++++++------ lib/device/valve.js | 19 +++++----- lib/device/zb-dev.js | 42 +++++++++++----------- lib/ewelink-platform.js | 4 +-- 25 files changed, 407 insertions(+), 380 deletions(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index aae2d48f..b481d65e 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -18,20 +18,21 @@ module.exports = class deviceBlind { } wcService .getCharacteristic(this.Characteristic.TargetPosition) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .on('set', (value, callback) => this.internalUpdate(value, callback)) + this.accessory = accessory } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { let blindConfig const params = {} - const wcService = accessory.getService(this.Service.WindowCovering) - const prevState = accessory.context.cachePositionState - let prevPosition = accessory.context.cacheCurrentPosition + const wcService = this.accessory.getService(this.Service.WindowCovering) + const prevState = this.accessory.context.cachePositionState + let prevPosition = this.accessory.context.cacheCurrentPosition const newTarget = value const updateKey = Math.random().toString(36).substr(2, 8) - if (!(blindConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + if (!(blindConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (blindConfig.type !== 'blind') { @@ -39,11 +40,11 @@ module.exports = class deviceBlind { } if (newTarget === prevPosition) return params.switches = helpers.defaultMultiSwitchOff - accessory.context.updateKey = updateKey + this.accessory.context.updateKey = updateKey const percentStepPerDecisecond = blindConfig.operationTime / 100 if (prevState !== 2) { - await this.platform.sendDeviceUpdate(accessory, params) - let positionPercentChange = Math.floor(Date.now() / 100) - accessory.context.cacheLastStartTime + await this.platform.sendDeviceUpdate(this.accessory, params) + let positionPercentChange = Math.floor(Date.now() / 100) - this.accessory.context.cacheLastStartTime positionPercentChange = Math.floor(percentStepPerDecisecond * positionPercentChange) if (prevState === 0) { prevPosition -= positionPercentChange @@ -51,33 +52,33 @@ module.exports = class deviceBlind { prevPosition += positionPercentChange } wcService.updateCharacteristic(this.Characteristic.CurrentPosition, prevPosition) - accessory.context.cacheCurrentPosition = prevPosition + this.accessory.context.cacheCurrentPosition = prevPosition } const diffPosition = newTarget - prevPosition const setToMoveUp = diffPosition > 0 const decisecondsToMove = Math.round(Math.abs(diffPosition) * percentStepPerDecisecond) params.switches[0].switch = setToMoveUp ? 'on' : 'off' params.switches[1].switch = setToMoveUp ? 'off' : 'on' - await this.platform.sendDeviceUpdate(accessory, params) - accessory.context.cacheTargetPosition = newTarget - accessory.context.cachePositionState = setToMoveUp ? 1 : 0 - accessory.context.cacheLastStartTime = Math.floor(Date.now() / 100) - if (accessory.context.updateKey !== updateKey) return + await this.platform.sendDeviceUpdate(this.accessory, params) + this.accessory.context.cacheTargetPosition = newTarget + this.accessory.context.cachePositionState = setToMoveUp ? 1 : 0 + this.accessory.context.cacheLastStartTime = Math.floor(Date.now() / 100) + if (this.accessory.context.updateKey !== updateKey) return await helpers.sleep(decisecondsToMove * 100) - if (accessory.context.updateKey !== updateKey) return + if (this.accessory.context.updateKey !== updateKey) return params.switches[0].switch = 'off' params.switches[1].switch = 'off' - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) wcService.updateCharacteristic(this.Characteristic.PositionState, 2) wcService.updateCharacteristic(this.Characteristic.CurrentPosition, newTarget) - accessory.context.cachePositionState = 2 - accessory.context.cacheCurrentPosition = newTarget + this.accessory.context.cachePositionState = 2 + this.accessory.context.cacheCurrentPosition = newTarget } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { } } diff --git a/lib/device/curtain.js b/lib/device/curtain.js index d2fafcb4..67ca977b 100644 --- a/lib/device/curtain.js +++ b/lib/device/curtain.js @@ -18,14 +18,15 @@ module.exports = class deviceCurtain { } cService .getCharacteristic(this.Characteristic.TargetPosition) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .on('set', (value, callback) => this.internalUpdate(value, callback)) + this.accessory = accessory } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { let params - const prevPos = accessory.context.cacheCurrentPosition + const prevPos = this.accessory.context.cacheCurrentPosition const newPos = value if (newPos === prevPos) return if (newPos === 0 || newPos === 100) { @@ -33,16 +34,16 @@ module.exports = class deviceCurtain { } else { params = { setclose: Math.abs(100 - newPos) } } - accessory.context.cacheCurrentPosition = newPos - await this.platform.sendDeviceUpdate(accessory, params) + this.accessory.context.cacheCurrentPosition = newPos + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { - const cService = accessory.getService(this.Service.WindowCovering) + const cService = this.accessory.getService(this.Service.WindowCovering) if (!helpers.hasProperty(params, 'switch') && !helpers.hasProperty(params, 'setclose')) { return } @@ -51,10 +52,10 @@ module.exports = class deviceCurtain { .updateCharacteristic(this.Characteristic.TargetPosition, newPos) .updateCharacteristic(this.Characteristic.CurrentPosition, newPos) .updateCharacteristic(this.Characteristic.PositionState, 2) - accessory.context.cacheCurrentPosition = newPos + this.accessory.context.cacheCurrentPosition = newPos return } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/diffuser.js b/lib/device/diffuser.js index 47a1739b..ae8bcf86 100644 --- a/lib/device/diffuser.js +++ b/lib/device/diffuser.js @@ -12,87 +12,89 @@ module.exports = class deviceDiffuser { const lightService = accessory.getService('Light') || accessory.addService(this.Service.Lightbulb, 'Light', 'light') onOffService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalDiffuserOnOffUpdate(accessory, value, callback)) + .on('set', (value, callback) => this.internalDiffuserOnOffUpdate(value, callback)) + this.accessory = accessory onOffService .getCharacteristic(this.Characteristic.RotationSpeed) - .on('set', (value, callback) => this.internalDiffuserStateUpdate(accessory, value, callback)) + .on('set', (value, callback) => this.internalDiffuserStateUpdate(value, callback)) .setProps({ minStep: 50 }) lightService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalLightOnOffUpdate(accessory, value, callback)) + .on('set', (value, callback) => this.internalLightOnOffUpdate(value, callback)) lightService .getCharacteristic(this.Characteristic.Brightness) - .on('set', (value, callback) => this.internalLightBrightnessUpdate(accessory, value, callback)) + .on('set', (value, callback) => this.internalLightBrightnessUpdate(value, callback)) lightService .getCharacteristic(this.Characteristic.Hue) - .on('set', (value, callback) => this.internalLightColourUpdate(accessory, value, callback)) + .on('set', (value, callback) => this.internalLightColourUpdate(value, callback)) lightService .getCharacteristic(this.Characteristic.Saturation) .on('set', (value, callback) => callback()) + this.accessory = accessory } - async internalDiffuserOnOffUpdate (accessory, value, callback) { + async internalDiffuserOnOffUpdate (value, callback) { callback() try { const params = { switch: value ? 'on' : 'off' } - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async internalDiffuserStateUpdate (accessory, value, callback) { + async internalDiffuserStateUpdate (value, callback) { try { await helpers.sleep(1000) callback() if (value === 0) return value = value <= 75 ? 50 : 100 const params = { state: value / 2 } - accessory.context.cacheState = value - await this.platform.sendDeviceUpdate(accessory, params) + this.accessory.context.cacheState = value + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async internalLightOnOffUpdate (accessory, value, callback) { + async internalLightOnOffUpdate (value, callback) { try { callback() const params = { lightswitch: value ? 1 : 0 } - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async internalLightBrightnessUpdate (accessory, value, callback) { + async internalLightBrightnessUpdate (value, callback) { try { await helpers.sleep(2000) callback() const updateKeyBright = Math.random().toString(36).substr(2, 8) - accessory.context.updateKeyBright = updateKeyBright + this.accessory.context.updateKeyBright = updateKeyBright const params = { lightbright: value } await helpers.sleep(500) - if (updateKeyBright !== accessory.context.updateKeyBright) return - await this.platform.sendDeviceUpdate(accessory, params) + if (updateKeyBright !== this.accessory.context.updateKeyBright) return + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async internalLightColourUpdate (accessory, value, callback) { + async internalLightColourUpdate (value, callback) { try { await helpers.sleep(2000) callback() const updateKeyColour = Math.random().toString(36).substr(2, 8) - accessory.context.updateKeyColour = updateKeyColour + this.accessory.context.updateKeyColour = updateKeyColour const newRGB = convert.hsv.rgb( value, - accessory.getService('Light').getCharacteristic(this.Characteristic.Saturation).value, + this.accessory.getService('Light').getCharacteristic(this.Characteristic.Saturation).value, 100 ) const params = { @@ -101,31 +103,31 @@ module.exports = class deviceDiffuser { lightBcolor: newRGB[2] } await helpers.sleep(500) - if (updateKeyColour !== accessory.context.updateKeyColour) return - await this.platform.sendDeviceUpdate(accessory, params) + if (updateKeyColour !== this.accessory.context.updateKeyColour) return + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (helpers.hasProperty(params, 'switch')) { - accessory.getService('Diffuser').updateCharacteristic(this.Characteristic.On, params.switch === 'on') + this.accessory.getService('Diffuser').updateCharacteristic(this.Characteristic.On, params.switch === 'on') if (!helpers.hasProperty(params, 'state')) { - accessory.getService('Diffuser').updateCharacteristic(this.Characteristic.RotationSpeed, accessory.context.cacheState) + this.accessory.getService('Diffuser').updateCharacteristic(this.Characteristic.RotationSpeed, this.accessory.context.cacheState) } } if (helpers.hasProperty(params, 'state')) { - accessory.getService('Diffuser').updateCharacteristic(this.Characteristic.RotationSpeed, params.state * 50) - accessory.context.cacheState = params.state * 50 + this.accessory.getService('Diffuser').updateCharacteristic(this.Characteristic.RotationSpeed, params.state * 50) + this.accessory.context.cacheState = params.state * 50 } if (helpers.hasProperty(params, 'lightswitch')) { - accessory.getService('Light') + this.accessory.getService('Light') .updateCharacteristic(this.Characteristic.On, params.lightswitch === 1) } if (helpers.hasProperty(params, 'lightbright')) { - accessory.getService('Light') + this.accessory.getService('Light') .updateCharacteristic(this.Characteristic.Brightness, params.lightbright) } if ( @@ -134,12 +136,12 @@ module.exports = class deviceDiffuser { helpers.hasProperty(params, 'lightBcolor') ) { const newColour = convert.rgb.hsv(params.lightRcolor, params.lightGcolor, params.lightBcolor) - accessory.getService('Light') + this.accessory.getService('Light') .updateCharacteristic(this.Characteristic.Hue, newColour[0]) .updateCharacteristic(this.Characteristic.Saturation, 100) } } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/fan.js b/lib/device/fan.js index bb1a55dc..baeaaf4a 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -15,13 +15,13 @@ module.exports = class deviceFan { const fanService = accessory.getService(this.Service.Fan) || accessory.addService(this.Service.Fan) fanService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => { + .on('set', async (value, callback) => { callback() if (!value) fanService.setCharacteristic(this.Characteristic.RotationSpeed, 0) }) fanService .getCharacteristic(this.Characteristic.RotationSpeed) - .on('set', (value, callback) => this.internalUpdate(accessory, 'speed', value, callback)) + .on('set', (value, callback) => this.internalUpdate('speed', value, callback)) .setProps({ minStep: 33 }) @@ -34,19 +34,20 @@ module.exports = class deviceFan { const fanLightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) fanLightService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, 'light', value, callback)) + .on('set', (value, callback) => this.internalUpdate('light', value, callback)) } + this.accessory = accessory } - async internalUpdate (accessory, type, value, callback) { + async internalUpdate (type, value, callback) { callback() try { let newPower let newSpeed let newLight let lightService - if (this.visibleLight) lightService = accessory.getService(this.Service.Lightbulb) - const fanService = accessory.getService(this.Service.Fan) + if (this.visibleLight) lightService = this.accessory.getService(this.Service.Lightbulb) + const fanService = this.accessory.getService(this.Service.Fan) const params = { switches: helpers.defaultMultiSwitchOff } switch (type) { case 'speed': @@ -64,19 +65,19 @@ module.exports = class deviceFan { params.switches[1].switch = newPower === 1 && newSpeed >= 33 ? 'on' : 'off' params.switches[2].switch = newPower === 1 && newSpeed >= 66 && newSpeed < 99 ? 'on' : 'off' params.switches[3].switch = newPower === 1 && newSpeed >= 99 ? 'on' : 'off' - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (helpers.hasProperty(params, 'updateSource') && params.updateSource === 'LAN') return if (params.switches && Array.isArray(params.switches)) { let lightService - if (this.visibleLight) lightService = accessory.getService(this.Service.Lightbulb) - const fanService = accessory.getService(this.Service.Fan) + if (this.visibleLight) lightService = this.accessory.getService(this.Service.Lightbulb) + const fanService = this.accessory.getService(this.Service.Fan) const light = params.switches[0].switch === 'on' let status let speed @@ -103,7 +104,7 @@ module.exports = class deviceFan { .updateCharacteristic(this.Characteristic.RotationSpeed, speed) } } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index ddba1e03..1c7fb8bf 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -18,58 +18,59 @@ module.exports = class deviceGarageEachen { } gdeService .getCharacteristic(this.Characteristic.TargetDoorState) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .on('set', (value, callback) => this.internalUpdate(value, callback)) + this.accessory = accessory } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { let garageConfig - if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage_eachen') { throw new Error('improper configuration') } const params = { switch: value === 0 ? 'on' : 'off' } - const gdService = accessory.getService(this.Service.GarageDoorOpener) + const gdService = this.accessory.getService(this.Service.GarageDoorOpener) if (value === gdService.getCharacteristic(this.Characteristic.CurrentDoorState).value % 2) return - accessory.context.inUse = true - await this.platform.sendDeviceUpdate(accessory, params) + this.accessory.context.inUse = true + await this.platform.sendDeviceUpdate(this.accessory, params) gdService .updateCharacteristic(this.Characteristic.TargetDoorState, value) .updateCharacteristic(this.Characteristic.CurrentDoorState, value + 2) await helpers.sleep(2000) - accessory.context.inUse = false + this.accessory.context.inUse = false if (value === 0) { await helpers.sleep(Math.max((garageConfig.operationTime - 20) * 100, 0)) gdService.updateCharacteristic(this.Characteristic.CurrentDoorState, 0) } } catch (err) { - accessory.context.inUse = false - this.platform.deviceUpdateError(accessory, err, true) + this.accessory.context.inUse = false + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { - if (!helpers.hasProperty(params, 'switch') || accessory.context.inUse) return + if (!helpers.hasProperty(params, 'switch') || this.accessory.context.inUse) return let garageConfig - if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage_eachen') { throw new Error('improper configuration') } - accessory.context.inUse = true - const gdService = accessory.getService(this.Service.GarageDoorOpener) + this.accessory.context.inUse = true + const gdService = this.accessory.getService(this.Service.GarageDoorOpener) gdService .updateCharacteristic(this.Characteristic.TargetDoorState, params.switch === 'on' ? 0 : 1) .updateCharacteristic(this.Characteristic.CurrentDoorState, params.switch === 'on' ? 0 : 1) - accessory.context.inUse = false + this.accessory.context.inUse = false } catch (err) { - accessory.context.inUse = false - this.platform.deviceUpdateError(accessory, err, false) + this.accessory.context.inUse = false + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/garage-four.js b/lib/device/garage-four.js index 85b30124..f21f1e4d 100644 --- a/lib/device/garage-four.js +++ b/lib/device/garage-four.js @@ -19,15 +19,16 @@ module.exports = class deviceGarageFour { } gdService .getCharacteristic(this.Characteristic.TargetDoorState) - .on('set', (value, callback) => this.internalUpdate(accessory, v, value, callback)) + .on('set', (value, callback) => this.internalUpdate(v, value, callback)) }) + this.accessory = accessory } - async internalUpdate (accessory, garage, value, callback) { + async internalUpdate (garage, value, callback) { callback() try { let garageConfig - if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage_four') { @@ -64,45 +65,45 @@ module.exports = class deviceGarageFour { ? sAccessory.getService(this.Service.ContactSensor).getCharacteristic(this.Characteristic.ContactSensorState).value === 0 ? 1 : 0 - : accessory.context.cacheStates[garageChannel].cacheCurrentDoorState + : this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState if (value === prevState % 2) return - const gdService = accessory.getService('Garage ' + garage) - accessory.context.inUse = true + const gdService = this.accessory.getService('Garage ' + garage) + this.accessory.context.inUse = true const updateKey = Math.random().toString(36).substr(2, 8) - accessory.context.updateKey = updateKey + this.accessory.context.updateKey = updateKey gdService .updateCharacteristic(this.Characteristic.TargetDoorState, value) .updateCharacteristic(this.Characteristic.CurrentDoorState, value + 2) - accessory.context.cacheStates[garageChannel].cacheTargetDoorState = value - accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = value + 2 + this.accessory.context.cacheStates[garageChannel].cacheTargetDoorState = value + this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = value + 2 const params = { switches: helpers.defaultMultiSwitchOff } ;[0, 1, 2, 3].forEach(i => (params.switches[i].switch = garageChannel === i ? 'on' : 'off')) - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) await helpers.sleep(1000) - accessory.context.inUse = false + this.accessory.context.inUse = false await helpers.sleep(Math.max((garageConfig.operationTime - 10) * 100, 0)) - if (accessory.context.updateKey !== updateKey || sAccessory) return + if (this.accessory.context.updateKey !== updateKey || sAccessory) return if (!sAccessory) { gdService.updateCharacteristic(this.Characteristic.CurrentDoorState, value) - accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = value + this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = value } } catch (err) { - accessory.context.inUse = false - this.platform.deviceUpdateError(accessory, err, true) + this.accessory.context.inUse = false + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { - if (!helpers.hasProperty(params, 'switches') || accessory.context.inUse) return + if (!helpers.hasProperty(params, 'switches') || this.accessory.context.inUse) return let garageConfig - if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage_four') { throw new Error('improper configuration') } - if (accessory.context.inUse) return + if (this.accessory.context.inUse) return ;['A', 'B', 'C', 'D'].forEach(async v => { let garageChannel switch (v) { @@ -132,16 +133,16 @@ module.exports = class deviceGarageFour { throw new Error("defined DW2 sensor isn't a sensor") } if (sensorDefinition) return - const gcService = accessory.getService('Garage ' + v) - const prevState = accessory.context.cacheStates[garageChannel].cacheCurrentDoorState + const gcService = this.accessory.getService('Garage ' + v) + const prevState = this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState const newPos = [0, 2].includes(prevState) ? 1 : 0 if (params.switches[garageChannel].switch === 'off') return gcService.updateCharacteristic(this.Characteristic.CurrentDoorState, newPos) - accessory.context.cacheStates[garageChannel].cacheTargetDoorState = newPos - accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = newPos + this.accessory.context.cacheStates[garageChannel].cacheTargetDoorState = newPos + this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = newPos }) } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/garage-two.js b/lib/device/garage-two.js index d23ac1d5..fa02653c 100644 --- a/lib/device/garage-two.js +++ b/lib/device/garage-two.js @@ -19,15 +19,16 @@ module.exports = class deviceGarageTwo { } gdService .getCharacteristic(this.Characteristic.TargetDoorState) - .on('set', (value, callback) => this.internalUpdate(accessory, 'Garage' + v, value, callback)) + .on('set', (value, callback) => this.internalUpdate('Garage' + v, value, callback)) }) + this.accessory = accessory } - async internalUpdate (accessory, garage, value, callback) { + async internalUpdate (garage, value, callback) { callback() try { let garageConfig - if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage_two') { @@ -49,8 +50,8 @@ module.exports = class deviceGarageTwo { } let sAccessory = false const newPos = value - const params = { switches: accessory.context.switchState } - const gdService = accessory.getService(garage) + const params = { switches: this.accessory.context.switchState } + const gdService = this.accessory.getService(garage) if (sensorDefinition && !(sAccessory = this.platform.devicesInHB.get(garageConfig.sensorId + 'SWX'))) { throw new Error("defined DW2 sensor doesn't exist") } @@ -62,69 +63,69 @@ module.exports = class deviceGarageTwo { ? 1 : 0 : garage === 'Garage 1' - ? accessory.context.cacheOneCurrentDoorState - : accessory.context.cacheTwoCurrentDoorState + ? this.accessory.context.cacheOneCurrentDoorState + : this.accessory.context.cacheTwoCurrentDoorState if (newPos === prevState % 2) return - accessory.context.inUse = true + this.accessory.context.inUse = true gdService .updateCharacteristic(this.Characteristic.TargetDoorState, newPos) .updateCharacteristic(this.Characteristic.CurrentDoorState, newPos + 2) switch (garage) { case 'Garage 1': { - accessory.context.cacheOneTargetDoorState = newPos - accessory.context.cacheOneCurrentDoorState = newPos + 2 + this.accessory.context.cacheOneTargetDoorState = newPos + this.accessory.context.cacheOneCurrentDoorState = newPos + 2 params.switches[0].switch = newPos === 0 ? 'on' : 'off' params.switches[1].switch = newPos === 1 ? 'on' : 'off' break } case 'Garage 2': { - accessory.context.cacheTwoTargetDoorState = newPos - accessory.context.cacheTwoCurrentDoorState = newPos + 2 + this.accessory.context.cacheTwoTargetDoorState = newPos + this.accessory.context.cacheTwoCurrentDoorState = newPos + 2 params.switches[2].switch = newPos === 0 ? 'on' : 'off' params.switches[3].switch = newPos === 1 ? 'on' : 'off' break } } - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) if (!sAccessory) { gdService.updateCharacteristic(this.Characteristic.CurrentDoorState, newPos) switch (garage) { case 'Garage 1': { - accessory.context.cacheOneCurrentDoorState = newPos + this.accessory.context.cacheOneCurrentDoorState = newPos break } case 'Garage 2': { - accessory.context.cacheTwoCurrentDoorState = newPos + this.accessory.context.cacheTwoCurrentDoorState = newPos break } } } - accessory.context.inUse = false + this.accessory.context.inUse = false } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - externalUpdate (accessory, params) { + externalUpdate (params) { try { if (!helpers.hasProperty(params, 'switches')) { return } let garageConfig - if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage_two') { throw new Error('improper configuration') } - if (accessory.context.inUse || garageConfig.sensorId) return - accessory.context.switchState = params.switches + if (this.accessory.context.inUse || garageConfig.sensorId) return + this.accessory.context.switchState = params.switches ;['1', '2'].forEach(async v => { - const gcService = accessory.getService('Garage ' + v) + const gcService = this.accessory.getService('Garage ' + v) const prevState = v === '1' - ? accessory.context.cacheOneCurrentDoorState - : accessory.context.cacheTwoCurrentDoorState + ? this.accessory.context.cacheOneCurrentDoorState + : this.accessory.context.cacheTwoCurrentDoorState const newPos = [0, 2].includes(prevState) ? 3 : 2 switch (v) { case '1': @@ -144,7 +145,7 @@ module.exports = class deviceGarageTwo { } break } - accessory.context.inUse = true + this.accessory.context.inUse = true if (garageConfig.sensorId) { await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) } else { @@ -153,29 +154,29 @@ module.exports = class deviceGarageTwo { .updateCharacteristic(this.Characteristic.CurrentDoorState, newPos) switch (v) { case '1': - accessory.context.cacheOneCurrentDoorState = newPos - accessory.context.cacheTwoTargetDoorState = newPos - 2 + this.accessory.context.cacheOneCurrentDoorState = newPos + this.accessory.context.cacheTwoTargetDoorState = newPos - 2 break case '2': - accessory.context.cacheTwoCurrentDoorState = newPos - accessory.context.cacheTwoTargetDoorState = newPos - 2 + this.accessory.context.cacheTwoCurrentDoorState = newPos + this.accessory.context.cacheTwoTargetDoorState = newPos - 2 break } await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) gcService.updateCharacteristic(this.Characteristic.CurrentDoorState, newPos - 2) switch (v) { case '1': - accessory.context.cacheOneCurrentDoorState = newPos - 2 + this.accessory.context.cacheOneCurrentDoorState = newPos - 2 break case '2': - accessory.context.cacheTwoCurrentDoorState = newPos - 2 + this.accessory.context.cacheTwoCurrentDoorState = newPos - 2 break } } }) - accessory.context.inUse = false + this.accessory.context.inUse = false } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/garage.js b/lib/device/garage.js index ebee6eb5..38d31896 100644 --- a/lib/device/garage.js +++ b/lib/device/garage.js @@ -18,14 +18,15 @@ module.exports = class deviceGarage { } gdService .getCharacteristic(this.Characteristic.TargetDoorState) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .on('set', (value, callback) => this.internalUpdate(value, callback)) + this.accessory = accessory } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { let garageConfig - if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage' || !['oneSwitch', 'twoSwitch'].includes(garageConfig.setup)) { @@ -36,7 +37,7 @@ module.exports = class deviceGarage { const newPos = value const params = {} let delay = 0 - const gdService = accessory.getService(this.Service.GarageDoorOpener) + const gdService = this.accessory.getService(this.Service.GarageDoorOpener) if (sensorDefinition && !(sAccessory = this.platform.devicesInHB.get(garageConfig.sensorId + 'SWX'))) { throw new Error("defined DW2 sensor doesn't exist") } @@ -47,22 +48,22 @@ module.exports = class deviceGarage { ? sAccessory.getService(this.Service.ContactSensor).getCharacteristic(this.Characteristic.ContactSensorState).value === 0 ? 1 : 0 - : accessory.context.cacheCurrentDoorState + : this.accessory.context.cacheCurrentDoorState if (newPos === prevState % 2) return - accessory.context.inUse = true - accessory.context.state = value + this.accessory.context.inUse = true + this.accessory.context.state = value if (garageConfig.setup === 'oneSwitch' && [2, 3].includes(prevState)) { gdService.updateCharacteristic(this.Characteristic.CurrentDoorState, ((prevState * 2) % 3) + 2) - accessory.context.cacheCurrentDoorState = ((prevState * 2) % 3) + 2 + this.accessory.context.cacheCurrentDoorState = ((prevState * 2) % 3) + 2 delay = 1500 } - if (accessory.context.state !== newPos) return + if (this.accessory.context.state !== newPos) return await helpers.sleep(delay) gdService .updateCharacteristic(this.Characteristic.TargetDoorState, newPos) .updateCharacteristic(this.Characteristic.CurrentDoorState, newPos + 2) - accessory.context.cacheTargetDoorState = newPos - accessory.context.cacheCurrentDoorState = newPos + 2 + this.accessory.context.cacheTargetDoorState = newPos + this.accessory.context.cacheCurrentDoorState = newPos + 2 switch (garageConfig.setup) { case 'oneSwitch': params.switch = 'on' @@ -73,34 +74,34 @@ module.exports = class deviceGarage { params.switches[1].switch = newPos === 1 ? 'on' : 'off' break } - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) if (!sAccessory) { gdService.updateCharacteristic(this.Characteristic.CurrentDoorState, newPos) - accessory.context.cacheCurrentDoorState = newPos + this.accessory.context.cacheCurrentDoorState = newPos } - accessory.context.inUse = false + this.accessory.context.inUse = false } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (!helpers.hasProperty(params, 'switch') && !helpers.hasProperty(params, 'switches')) { return } let garageConfig - const gcService = accessory.getService(this.Service.GarageDoorOpener) - const prevState = accessory.context.cacheCurrentDoorState + const gcService = this.accessory.getService(this.Service.GarageDoorOpener) + const prevState = this.accessory.context.cacheCurrentDoorState const newPos = [0, 2].includes(prevState) ? 3 : 2 - if (!(garageConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (garageConfig.type !== 'garage' || !['oneSwitch', 'twoSwitch'].includes(garageConfig.setup)) { throw new Error('improper configuration') } - if (accessory.context.inUse || garageConfig.sensorId) return + if (this.accessory.context.inUse || garageConfig.sensorId) return switch (garageConfig.setup) { case 'oneSwitch': if (params.switch === 'off') { @@ -116,23 +117,23 @@ module.exports = class deviceGarage { } break } - accessory.context.inUse = true + this.accessory.context.inUse = true if (garageConfig.sensorId) { await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) } else { gcService .updateCharacteristic(this.Characteristic.TargetDoorState, newPos - 2) .updateCharacteristic(this.Characteristic.CurrentDoorState, newPos) - accessory.context.cacheCurrentDoorState = newPos - accessory.context.cacheTargetDoorState = newPos - 2 + this.accessory.context.cacheCurrentDoorState = newPos + this.accessory.context.cacheTargetDoorState = newPos - 2 await helpers.sleep(Math.max(garageConfig.operationTime * 100, 1000)) gcService.updateCharacteristic(this.Characteristic.CurrentDoorState, newPos - 2) - accessory.context.cacheCurrentDoorState = newPos - 2 + this.accessory.context.cacheCurrentDoorState = newPos - 2 } - accessory.context.inUse = false + this.accessory.context.inUse = false } catch (err) { - accessory.context.inUse = false - this.platform.deviceUpdateError(accessory, err, false) + this.accessory.context.inUse = false + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/light-colour.js b/lib/device/light-colour.js index 487356a3..fe68041a 100644 --- a/lib/device/light-colour.js +++ b/lib/device/light-colour.js @@ -11,13 +11,13 @@ module.exports = class deviceLightColour { const lightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) lightService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, 'onoff', value, callback)) + .on('set', (value, callback) => this.internalUpdate('onoff', value, callback)) lightService .getCharacteristic(this.Characteristic.Brightness) - .on('set', (value, callback) => this.internalUpdate(accessory, 'brightness', value, callback)) + .on('set', (value, callback) => this.internalUpdate('brightness', value, callback)) lightService .getCharacteristic(this.Characteristic.Hue) - .on('set', (value, callback) => this.internalUpdate(accessory, 'hue', value, callback)) + .on('set', (value, callback) => this.internalUpdate('hue', value, callback)) lightService .getCharacteristic(this.Characteristic.Saturation) .on('set', (value, callback) => callback()) @@ -29,28 +29,29 @@ module.exports = class deviceLightColour { minStep: 100 }) } + this.accessory = accessory } - async internalUpdate (accessory, type, value, callback) { + async internalUpdate (type, value, callback) { callback() try { let newRGB let params = {} - const lightService = accessory.getService(this.Service.Lightbulb) + const lightService = this.accessory.getService(this.Service.Lightbulb) switch (type) { case 'onoff': - if (accessory.context.eweUIID === 22) { + if (this.accessory.context.eweUIID === 22) { // **** B1 uses state rather than switch *** \\ params.state = value ? 'on' : 'off' } else { params.switch = value ? 'on' : 'off' } - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) break case 'brightness': { const updateKeyBright = Math.random().toString(36).substr(2, 8) - accessory.context.updateKeyBright = updateKeyBright - switch (accessory.context.eweUIID) { + this.accessory.context.updateKeyBright = updateKeyBright + switch (this.accessory.context.eweUIID) { case 22: // *** B1 doesn't support brightness *** \\ return @@ -67,23 +68,23 @@ module.exports = class deviceLightColour { ltype: 'color', color: { br: value, - r: accessory.context.cacheR, - g: accessory.context.cacheG, - b: accessory.context.cacheB + r: this.accessory.context.cacheR, + g: this.accessory.context.cacheG, + b: this.accessory.context.cacheB } } break } await helpers.sleep(500) - if (updateKeyBright !== accessory.context.updateKeyBright) return - await this.platform.sendDeviceUpdate(accessory, params) + if (updateKeyBright !== this.accessory.context.updateKeyBright) return + await this.platform.sendDeviceUpdate(this.accessory, params) break } case 'hue': { const updateKeyColour = Math.random().toString(36).substr(2, 8) - accessory.context.updateKeyColour = updateKeyColour + this.accessory.context.updateKeyColour = updateKeyColour newRGB = convert.hsv.rgb(value, lightService.getCharacteristic(this.Characteristic.Saturation).value, 100) - switch (accessory.context.eweUIID) { + switch (this.accessory.context.eweUIID) { case 22: // *** B1 *** \\ params = { @@ -116,38 +117,38 @@ module.exports = class deviceLightColour { br: lightService.getCharacteristic(this.Characteristic.Brightness).value } } - accessory.context.cacheR = newRGB[0] - accessory.context.cacheG = newRGB[1] - accessory.context.cacheB = newRGB[2] + this.accessory.context.cacheR = newRGB[0] + this.accessory.context.cacheG = newRGB[1] + this.accessory.context.cacheB = newRGB[2] break } await helpers.sleep(1000) - if (updateKeyColour !== accessory.context.updateKeyColour) return - await this.platform.sendDeviceUpdate(accessory, params) + if (updateKeyColour !== this.accessory.context.updateKeyColour) return + await this.platform.sendDeviceUpdate(this.accessory, params) break } } } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { let newColour let mode let isOn = false - const lightService = accessory.getService(this.Service.Lightbulb) - if (accessory.context.eweUIID === 22 && helpers.hasProperty(params, 'state')) { + const lightService = this.accessory.getService(this.Service.Lightbulb) + if (this.accessory.context.eweUIID === 22 && helpers.hasProperty(params, 'state')) { isOn = params.state === 'on' - } else if (accessory.context.eweUIID !== 22 && helpers.hasProperty(params, 'switch')) { + } else if (this.accessory.context.eweUIID !== 22 && helpers.hasProperty(params, 'switch')) { isOn = params.switch === 'on' } else { isOn = lightService.getCharacteristic(this.Characteristic.On).value } if (isOn) { lightService.updateCharacteristic(this.Characteristic.On, true) - switch (accessory.context.eweUIID) { + switch (this.accessory.context.eweUIID) { case 22: // *** B1 *** \\ if (helpers.hasProperty(params, 'zyx_mode')) { @@ -203,9 +204,9 @@ module.exports = class deviceLightColour { lightService .updateCharacteristic(this.Characteristic.Hue, newColour[0]) .updateCharacteristic(this.Characteristic.Saturation, 100) - accessory.context.cacheR = params.color.r - accessory.context.cacheG = params.color.g - accessory.context.cacheB = params.color.b + this.accessory.context.cacheR = params.color.r + this.accessory.context.cacheG = params.color.g + this.accessory.context.cacheB = params.color.b } } } @@ -215,7 +216,7 @@ module.exports = class deviceLightColour { lightService.updateCharacteristic(this.Characteristic.On, false) } } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/light-ctemp.js b/lib/device/light-ctemp.js index f9450a4e..66fa2e25 100644 --- a/lib/device/light-ctemp.js +++ b/lib/device/light-ctemp.js @@ -9,26 +9,27 @@ module.exports = class deviceLightCTemp { const lightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) lightService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, 'onoff', value, callback)) + .on('set', (value, callback) => this.internalUpdate('onoff', value, callback)) lightService .getCharacteristic(this.Characteristic.Brightness) - .on('set', (value, callback) => this.internalUpdate(accessory, 'brightness', value, callback)) + .on('set', (value, callback) => this.internalUpdate('brightness', value, callback)) + this.accessory = accessory } - async internalUpdate (accessory, type, value, callback) { + async internalUpdate (type, value, callback) { callback() try { } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/light-dimmer.js b/lib/device/light-dimmer.js index 94da5b67..b7c30db4 100644 --- a/lib/device/light-dimmer.js +++ b/lib/device/light-dimmer.js @@ -10,24 +10,25 @@ module.exports = class deviceLightDimmer { const lightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) lightService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, 'onoff', value, callback)) + .on('set', (value, callback) => this.internalUpdate('onoff', value, callback)) lightService.getCharacteristic(this.Characteristic.Brightness) - .on('set', (value, callback) => this.internalUpdate(accessory, 'brightness', value, callback)) + .on('set', (value, callback) => this.internalUpdate('brightness', value, callback)) + this.accessory = accessory } - async internalUpdate (accessory, type, value, callback) { + async internalUpdate (type, value, callback) { callback() try { const params = {} switch (type) { case 'onoff': params.switch = value ? 'on' : 'off' - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) break case 'brightness': { const updateKey = Math.random().toString(36).substr(2, 8) - accessory.context.updateKey = updateKey - switch (accessory.context.eweUIID) { + this.accessory.context.updateKey = updateKey + switch (this.accessory.context.eweUIID) { case 36: // *** KING-M4 eWeLink scale is 10-100 and HomeKit scale is 0-100. *** \\ params.bright = Math.round((value * 9) / 10 + 10) @@ -39,25 +40,25 @@ module.exports = class deviceLightDimmer { break } await helpers.sleep(500) - if (updateKey !== accessory.context.updateKey) return - await this.platform.sendDeviceUpdate(accessory, params) + if (updateKey !== this.accessory.context.updateKey) return + await this.platform.sendDeviceUpdate(this.accessory, params) break } } } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { - const lightService = accessory.getService(this.Service.Lightbulb) + const lightService = this.accessory.getService(this.Service.Lightbulb) const isOn = helpers.hasProperty(params, 'switch') ? params.switch === 'on' : lightService.getCharacteristic(this.Characteristic.On).value if (isOn) { lightService.updateCharacteristic(this.Characteristic.On, true) - switch (accessory.context.eweUIID) { + switch (this.accessory.context.eweUIID) { case 36: // *** KING-M4 eWeLink scale is 10-100 and HomeKit scale is 0-100. *** \\ if (helpers.hasProperty(params, 'bright')) { @@ -76,7 +77,7 @@ module.exports = class deviceLightDimmer { lightService.updateCharacteristic(this.Characteristic.On, false) } } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/lock.js b/lib/device/lock.js index 6804242f..b69ea0cc 100644 --- a/lib/device/lock.js +++ b/lib/device/lock.js @@ -10,49 +10,49 @@ module.exports = class deviceLock { const lmService = accessory.getService(this.Service.LockMechanism) || accessory.addService(this.Service.LockMechanism) lmService .getCharacteristic(this.Characteristic.LockTargetState) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) - accessory = accessory + .on('set', (value, callback) => this.internalUpdate(value, callback)) + this.accessory = accessory } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { let lockConfig const params = { switch: 'on' } - const lmService = accessory.getService(this.Service.LockMechanism) - if (!(lockConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + const lmService = this.accessory.getService(this.Service.LockMechanism) + if (!(lockConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (lockConfig.type !== 'lock') { throw new Error('improper configuration') } - accessory.context.inUse = true - await this.platform.sendDeviceUpdate(accessory, params) + this.accessory.context.inUse = true + await this.platform.sendDeviceUpdate(this.accessory, params) await helpers.sleep(Math.max(lockConfig.operationTime * 100, 1000)) lmService .updateCharacteristic(this.Characteristic.LockTargetState, 1) .updateCharacteristic(this.Characteristic.LockCurrentState, 1) - accessory.context.inUse = false + this.accessory.context.inUse = false } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (!helpers.hasProperty(params, 'switch')) return let lockConfig - const lmService = accessory.getService(this.Service.LockMechanism) - if (!(lockConfig = this.platform.cusG.get(accessory.context.hbDeviceId))) { + const lmService = this.accessory.getService(this.Service.LockMechanism) + if (!(lockConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') } if (lockConfig.type !== 'lock') { throw new Error('improper configuration') } - if (params.switch === 'off' || accessory.context.inUse) { + if (params.switch === 'off' || this.accessory.context.inUse) { return } - accessory.context.inUse = true + this.accessory.context.inUse = true lmService .updateCharacteristic(this.Characteristic.LockCurrentState, 0) .updateCharacteristic(this.Characteristic.LockTargetState, 0) @@ -60,10 +60,10 @@ module.exports = class deviceLock { lmService .updateCharacteristic(this.Characteristic.LockCurrentState, 1) .updateCharacteristic(this.Characteristic.LockTargetState, 1) - accessory.context.inUse = false + this.accessory.context.inUse = false } catch (err) { - accessory.context.inUse = false - this.platform.deviceUpdateError(accessory, err, false) + this.accessory.context.inUse = false + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/outlet.js b/lib/device/outlet.js index 3992c9e0..72339905 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -100,10 +100,10 @@ module.exports = class deviceOutlet { } outletService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .on('set', (value, callback) => this.internalUpdate(value, callback)) outletService .getCharacteristic(this.eveResetTotal) - .on('set', (accessory, value, callback) => { + .on('set', (value, callback) => { callback() accessory.context.energyReadings = [] accessory.context.energyReadingTotal = 0 @@ -126,37 +126,38 @@ module.exports = class deviceOutlet { accessory.context.energyReadings = [] outletService.updateCharacteristic(this.eveTotalConsumption, accessory.context.energyReadingTotal) }, 300000) + this.accessory = accessory } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { const params = { switch: value ? 'on' : 'off' } - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { - const outletService = accessory.getService(this.Service.Outlet) + const outletService = this.accessory.getService(this.Service.Outlet) if (helpers.hasProperty(params, 'switch')) { outletService.updateCharacteristic(this.Characteristic.On, params.switch === 'on') - if (!accessory.context.powerReadings) { + if (!this.accessory.context.powerReadings) { outletService.updateCharacteristic(this.Characteristic.OutletInUse, params.switch === 'on') } } if (helpers.hasProperty(params, 'power')) { - accessory.context.powerReadings = true + this.accessory.context.powerReadings = true outletService.updateCharacteristic(this.Characteristic.OutletInUse, parseFloat(params.power) > this.inUsePowerThreshold) outletService.updateCharacteristic(this.eveCurrentConsumption, parseFloat(params.power)) - const isOn = accessory.getService(this.Service.Outlet).getCharacteristic(this.Characteristic.On).value - accessory.eveLogger.addEntry({ + const isOn = this.accessory.getService(this.Service.Outlet).getCharacteristic(this.Characteristic.On).value + this.accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), power: isOn ? parseFloat(params.power) : 0 }) - accessory.context.energyReadings.push(parseFloat(params.power)) + this.accessory.context.energyReadings.push(parseFloat(params.power)) } if (helpers.hasProperty(params, 'voltage')) { outletService.updateCharacteristic(this.eveVoltage, parseFloat(params.voltage)) @@ -165,7 +166,7 @@ module.exports = class deviceOutlet { outletService.updateCharacteristic(this.eveElectricCurrent, parseFloat(params.current)) } } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index e9fe4f13..f5f61a00 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -21,7 +21,7 @@ module.exports = class deviceRFBridge { accessory.getService(name).updateCharacteristic(this.Characteristic.On, false) accessory.getService(name) .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, chan, name, value, callback)) + .on('set', (value, callback) => this.internalUpdate(chan, name, value, callback)) }) } else { let serv @@ -73,9 +73,10 @@ module.exports = class deviceRFBridge { path: this.platform.eveLogPath }) } + this.accessory = accessory } - async internalUpdate (accessory, rfChl, service, value, callback) { + async internalUpdate (rfChl, service, value, callback) { callback() try { if (!value) return @@ -84,14 +85,14 @@ module.exports = class deviceRFBridge { rfChl: parseInt(rfChl) } await helpers.sleep(1000) - accessory.getService(service).updateCharacteristic(this.Characteristic.On, false) - await this.platform.sendDeviceUpdate(accessory, params) + this.accessory.getService(service).updateCharacteristic(this.Characteristic.On, false) + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (!helpers.hasProperty(params, 'updateSource')) return const timeNow = new Date() @@ -99,7 +100,7 @@ module.exports = class deviceRFBridge { if (helpers.hasProperty(params, 'cmd') && params.cmd === 'transmit' && helpers.hasProperty(params, 'rfChl')) { this.platform.devicesInHB.forEach(acc => { if ( - acc.context.eweDeviceId === accessory.context.eweDeviceId && + acc.context.eweDeviceId === this.accessory.context.eweDeviceId && helpers.hasProperty(acc.context, 'buttons') && helpers.hasProperty(acc.context.buttons, params.rfChl.toString()) ) { @@ -120,7 +121,7 @@ module.exports = class deviceRFBridge { .forEach(async chan => { this.platform.devicesInHB.forEach(acc => { if ( - acc.context.eweDeviceId === accessory.context.eweDeviceId && + acc.context.eweDeviceId === this.accessory.context.eweDeviceId && helpers.hasProperty(acc.context, 'buttons') && helpers.hasProperty(acc.context.buttons, chan.split('g')[1].toString()) ) { @@ -197,7 +198,7 @@ module.exports = class deviceRFBridge { }) } } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/scm.js b/lib/device/scm.js index c952e154..fc8c339c 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -12,36 +12,36 @@ module.exports = class deviceSCM { const scmService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) scmService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .on('set', (value, callback) => this.internalUpdate(value, callback)) accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('switch', accessory, { storage: 'fs', path: this.platform.eveLogPath }) - accessory = accessory + this.accessory = accessory } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { const params = { switches: helpers.defaultMultiSwitchOff } params.switches[0].switch = value ? 'on' : 'off' - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (!helpers.hasProperty(params, 'switches')) return - accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, params.switches[0].switch === 'on') - accessory.eveLogger.addEntry({ + this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, params.switches[0].switch === 'on') + this.accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: params.switches[0].switch === 'on' ? 1 : 0 }) } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/sensor.js b/lib/device/sensor.js index c1592391..50c5816e 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -22,13 +22,14 @@ module.exports = class deviceSensor { storage: 'fs', path: this.platform.eveLogPath }) + this.accessory = accessory } async externalUpdate (params) { try { if (helpers.hasProperty(params, 'battery')) { const batteryService = - accessory.getService(this.Service.BatteryService) || accessory.addService(this.Service.BatteryService) + this.accessory.getService(this.Service.BatteryService) || this.accessory.addService(this.Service.BatteryService) const scaledBattery = Math.round(params.battery * 33.3) batteryService.updateCharacteristic(this.Characteristic.BatteryLevel, scaledBattery) batteryService.updateCharacteristic( @@ -39,14 +40,14 @@ module.exports = class deviceSensor { if (!helpers.hasProperty(params, 'switch')) return const newState = params.switch === 'on' ? 1 : 0 let oAccessory = false - const contactService = accessory.getService(this.Service.ContactSensor) + const contactService = this.accessory.getService(this.Service.ContactSensor) contactService.updateCharacteristic(this.Characteristic.ContactSensorState, newState) - accessory.eveLogger.addEntry({ + this.accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: newState }) this.platform.cusG.forEach(async group => { - if (group.sensorId === accessory.context.eweDeviceId && group.type === 'garage') { + if (group.sensorId === this.accessory.context.eweDeviceId && group.type === 'garage') { if ((oAccessory = this.platform.devicesInHB.get(group.deviceId + 'SWX'))) { switch (newState) { case 0: @@ -67,7 +68,7 @@ module.exports = class deviceSensor { } }) } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/switch-multi.js b/lib/device/switch-multi.js index c4caf414..ae1c3f7d 100644 --- a/lib/device/switch-multi.js +++ b/lib/device/switch-multi.js @@ -13,7 +13,7 @@ module.exports = class deviceSwitch { const switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) switchService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .on('set', (value, callback) => this.internalUpdate(value, callback)) if (accessory.getService(this.Service.Outlet)) { accessory.removeService(accessory.getService(this.Service.Outlet)) } @@ -25,15 +25,24 @@ module.exports = class deviceSwitch { storage: 'fs', path: this.platform.eveLogPath }) + this.accessory = accessory } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { + // *** generates a random number in the range [10, 100] *** \\ + await helpers.sleep(Math.floor(Math.random() * 91 + 10)) + if (this.updateInProgress) { + await helpers.sleep(300) + return await this.internalUpdate(value, callback) + } + this.updateInProgress = true + setTimeout(() => (this.updateInProgress = false), 250) + callback() try { - callback() let oAccessory let masterState = 'off' const params = {} - switch (accessory.context.switchNumber) { + switch (this.accessory.context.switchNumber) { case '0': params.switches = helpers.defaultMultiSwitchOff params.switches[0].switch = value ? 'on' : 'off' @@ -41,9 +50,8 @@ module.exports = class deviceSwitch { params.switches[2].switch = value ? 'on' : 'off' params.switches[3].switch = value ? 'on' : 'off' for (let i = 0; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { + if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { oAccessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, value) - oAccessory.context.cacheOn = value } } break @@ -53,11 +61,11 @@ module.exports = class deviceSwitch { case '4': params.switches = helpers.defaultMultiSwitchOff for (let i = 1; i <= 4; i++) { - if ((oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW' + i))) { + if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { if (oAccessory.getService(this.Service.Switch).getCharacteristic(this.Characteristic.On).value) { masterState = 'on' } - if (i === parseInt(accessory.context.switchNumber)) { + if (i === parseInt(this.accessory.context.switchNumber)) { params.switches[i - 1].switch = value ? 'on' : 'off' oAccessory.context.cacheOn = value } else { @@ -67,24 +75,24 @@ module.exports = class deviceSwitch { params.switches[i - 1].switch = 'off' } } - if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { - oAccessory = this.platform.devicesInHB.get(accessory.context.eweDeviceId + 'SW0') + if (!this.platform.hiddenMasters.includes(this.accessory.context.eweDeviceId)) { + oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW0') oAccessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, masterState === 'on') } break } - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (!helpers.hasProperty(params, 'switches')) return - const idToCheck = accessory.context.hbDeviceId.slice(0, -1) + const idToCheck = this.accessory.context.hbDeviceId.slice(0, -1) let primaryState = false - for (let i = 1; i <= accessory.context.channelCount; i++) { + for (let i = 1; i <= this.accessory.context.channelCount; i++) { if (params.switches[i - 1].switch === 'on') { primaryState = true } @@ -100,15 +108,15 @@ module.exports = class deviceSwitch { }) } } - if (!this.platform.hiddenMasters.includes(accessory.context.eweDeviceId)) { - accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, primaryState) - accessory.eveLogger.addEntry({ + if (!this.platform.hiddenMasters.includes(this.accessory.context.eweDeviceId)) { + this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, primaryState) + this.accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: primaryState ? 1 : 0 }) } } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/switch-single.js b/lib/device/switch-single.js index 1b106754..90c7cbf6 100644 --- a/lib/device/switch-single.js +++ b/lib/device/switch-single.js @@ -12,7 +12,7 @@ module.exports = class deviceSwitchSingle { const switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) switchService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .on('set', (value, callback) => this.internalUpdate(value, callback)) if (accessory.getService(this.Service.Outlet)) { accessory.removeService(accessory.getService(this.Service.Outlet)) } @@ -24,29 +24,29 @@ module.exports = class deviceSwitchSingle { storage: 'fs', path: this.platform.eveLogPath }) - accessory = accessory + this.accessory = accessory } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { const params = { switch: value ? 'on' : 'off' } - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (!helpers.hasProperty(params, 'switch')) return - accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, params.switch === 'on') - accessory.eveLogger.addEntry({ + this.accessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, params.switch === 'on') + this.accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: params.switch === 'on' ? 1 : 0 }) } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/template.js b/lib/device/template.js index 640ac76d..96b3e25d 100644 --- a/lib/device/template.js +++ b/lib/device/template.js @@ -9,24 +9,24 @@ module.exports = class deviceTemplate { const service = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) service .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) - accessory = accessory + .on('set', (value, callback) => this.internalUpdate(value, callback)) + this.accessory = accessory } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index f8ebc126..2f2216d7 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -17,62 +17,63 @@ module.exports = class deviceThermostat { const switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) switchService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .on('set', (value, callback) => this.internalUpdate(value, callback)) } accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('custom', accessory, { storage: 'fs', path: this.platform.eveLogPath }) + this.accessory = accessory } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { const params = { switch: value ? 'on' : 'off', mainSwitch: value ? 'on' : 'off' } - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if ( !this.platform.config.hideTHSwitch && (helpers.hasProperty(params, 'switch') || helpers.hasProperty(params, 'mainSwitch')) ) { const newState = helpers.hasProperty(params, 'switch') ? params.switch === 'on' : params.mainSwitch === 'on' - const switchService = accessory.getService(this.Service.Switch) + const switchService = this.accessory.getService(this.Service.Switch) switchService.updateCharacteristic(this.Characteristic.On, newState) - accessory.eveLogger.addEntry({ + this.accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: newState ? 1 : 0 }) } const eveLog = { time: Math.round(new Date().valueOf() / 1000) } - if (helpers.hasProperty(params, 'currentTemperature') && accessory.getService(this.Service.TemperatureSensor)) { + if (helpers.hasProperty(params, 'currentTemperature') && this.accessory.getService(this.Service.TemperatureSensor)) { const currentTemp = parseFloat(params.currentTemperature !== 'unavailable' ? params.currentTemperature : 0) - accessory + this.accessory .getService(this.Service.TemperatureSensor) .updateCharacteristic(this.Characteristic.CurrentTemperature, currentTemp) eveLog.temp = currentTemp } - if (helpers.hasProperty(params, 'currentHumidity') && accessory.getService(this.Service.HumiditySensor)) { + if (helpers.hasProperty(params, 'currentHumidity') && this.accessory.getService(this.Service.HumiditySensor)) { const currentHumi = parseFloat(params.currentHumidity !== 'unavailable' ? params.currentHumidity : 0) - accessory + this.accessory .getService(this.Service.HumiditySensor) .updateCharacteristic(this.Characteristic.CurrentRelativeHumidity, currentHumi) eveLog.humidity = currentHumi } if (helpers.hasProperty(eveLog, 'temp') || helpers.hasProperty(eveLog, 'humidity')) { - accessory.eveLogger.addEntry(eveLog) + this.accessory.eveLogger.addEntry(eveLog) } } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/usb.js b/lib/device/usb.js index b43f90c0..ccc96e56 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -12,35 +12,36 @@ module.exports = class deviceUSB { const usbService = accessory.getService(this.Service.Outlet) || accessory.addService(this.Service.Outlet) usbService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .on('set', (value, callback) => this.internalUpdate(value, callback)) accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('switch', accessory, { storage: 'fs', path: this.platform.eveLogPath }) + this.accessory = accessory } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { const params = { switches: helpers.defaultMultiSwitchOff } params.switches[0].switch = value ? 'on' : 'off' - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (!helpers.hasProperty(params, 'switches')) return - accessory.getService(this.Service.Outlet).updateCharacteristic(this.Characteristic.On, params.switches[0].switch === 'on') - accessory.eveLogger.addEntry({ + this.accessory.getService(this.Service.Outlet).updateCharacteristic(this.Characteristic.On, params.switches[0].switch === 'on') + this.accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: params.switches[0].switch === 'on' ? 1 : 0 }) } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/valve-two.js b/lib/device/valve-two.js index b49cabb2..4e53ebff 100644 --- a/lib/device/valve-two.js +++ b/lib/device/valve-two.js @@ -22,7 +22,7 @@ module.exports = class deviceValveTwo { } valveService .getCharacteristic(this.Characteristic.Active) - .on('set', (value, callback) => this.internalUpdate(accessory, 'Valve ' + v, value, callback)) + .on('set', (value, callback) => this.internalUpdate('Valve ' + v, value, callback)) valveService .getCharacteristic(this.Characteristic.SetDuration) .on('set', (value, callback) => { @@ -34,22 +34,23 @@ module.exports = class deviceValveTwo { callback() }) }) + this.accessory = accessory } - async internalUpdate (accessory, valve, value, callback) { + async internalUpdate (valve, value, callback) { callback() try { const params = { switches: helpers.defaultMultiSwitchOff } - const serviceValve = accessory.getService(valve) + const serviceValve = this.accessory.getService(valve) switch (valve) { case 'Valve A': params.switches[0].switch = value ? 'on' : 'off' - params.switches[1].switch = accessory.getService('Valve B').getCharacteristic(this.Characteristic.Active).value + params.switches[1].switch = this.accessory.getService('Valve B').getCharacteristic(this.Characteristic.Active).value ? 'on' : 'off' break case 'Valve B': - params.switches[0].switch = accessory.getService('Valve A').getCharacteristic(this.Characteristic.Active).value + params.switches[0].switch = this.accessory.getService('Valve A').getCharacteristic(this.Characteristic.Active).value ? 'on' : 'off' params.switches[1].switch = value ? 'on' : 'off' @@ -59,7 +60,7 @@ module.exports = class deviceValveTwo { switch (value) { case 0: serviceValve.updateCharacteristic(this.Characteristic.RemainingDuration, 0) - clearTimeout(accessory.getService(valve).timer) + clearTimeout(this.accessory.getService(valve).timer) break case 1: { const timer = serviceValve.getCharacteristic(this.Characteristic.SetDuration).value @@ -68,17 +69,17 @@ module.exports = class deviceValveTwo { break } } - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (!helpers.hasProperty(params, 'switches')) return ;['A', 'B'].forEach((v, k) => { - const valveService = accessory.getService('Valve ' + v) + const valveService = this.accessory.getService('Valve ' + v) valveService .updateCharacteristic(this.Characteristic.Active, params.switches[k].switch === 'on') .updateCharacteristic(this.Characteristic.InUse, params.switches[k].switch === 'on') @@ -92,7 +93,7 @@ module.exports = class deviceValveTwo { } }) } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/valve.js b/lib/device/valve.js index e03b17a9..ac142ff3 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -21,7 +21,7 @@ module.exports = class deviceValve { } valveService .getCharacteristic(this.Characteristic.Active) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .on('set', (value, callback) => this.internalUpdate(value, callback)) valveService .getCharacteristic(this.Characteristic.SetDuration) .on('set', (value, callback) => { @@ -32,18 +32,19 @@ module.exports = class deviceValve { } callback() }) + this.accessory = accessory } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { const params = { switch: value ? 'on' : 'off' } - const serviceValve = accessory.getService(this.Service.Valve) + const serviceValve = this.accessory.getService(this.Service.Valve) serviceValve.updateCharacteristic(this.Characteristic.InUse, value) switch (value) { case 0: serviceValve.updateCharacteristic(this.Characteristic.RemainingDuration, 0) - clearTimeout(accessory.getService(this.Service.Valve).timer) + clearTimeout(this.accessory.getService(this.Service.Valve).timer) break case 1: { const timer = serviceValve.getCharacteristic(this.Characteristic.SetDuration).value @@ -52,16 +53,16 @@ module.exports = class deviceValve { break } } - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { if (!helpers.hasProperty(params, 'switch')) return - const valveService = accessory.getService(this.Service.Valve) + const valveService = this.accessory.getService(this.Service.Valve) valveService .updateCharacteristic(this.Characteristic.Active, params.switch === 'on') .updateCharacteristic(this.Characteristic.InUse, params.switch === 'on') @@ -74,7 +75,7 @@ module.exports = class deviceValve { clearTimeout(valveService.timer) } } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index 40f9914f..a7514131 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -45,7 +45,7 @@ module.exports = class deviceZBDev { }) accessory.getService(this.Service.Switch) .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate(accessory, value, callback)) + .on('set', (value, callback) => this.internalUpdate(value, callback)) break case 1770: if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) @@ -76,38 +76,38 @@ module.exports = class deviceZBDev { }) break } - accessory = accessory + this.accessory = accessory } - async internalUpdate (accessory, value, callback) { + async internalUpdate (value, callback) { callback() try { const params = { switch: value ? 'on' : 'off' } - await this.platform.sendDeviceUpdate(accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { - this.platform.deviceUpdateError(accessory, err, true) + this.platform.deviceUpdateError(this.accessory, err, true) } } - async externalUpdate (accessory, params) { + async externalUpdate (params) { try { //* ** credit @tasict ***\\ if (helpers.hasProperty(params, 'battery')) { - if (accessory.context.eweUIID === 3026 && this.platform.config.ZBDWBatt) { + if (this.accessory.context.eweUIID === 3026 && this.platform.config.ZBDWBatt) { params.battery *= 10 } const batteryService = - accessory.getService(this.Service.BatteryService) || accessory.addService(this.Service.BatteryService) + this.accessory.getService(this.Service.BatteryService) || this.accessory.addService(this.Service.BatteryService) batteryService.updateCharacteristic(this.Characteristic.BatteryLevel, params.battery) batteryService.updateCharacteristic( this.Characteristic.StatusLowBattery, params.battery < this.lowBattThreshold ) } - switch (accessory.context.eweUIID) { + switch (this.accessory.context.eweUIID) { case 1000: if (helpers.hasProperty(params, 'key') && [0, 1, 2].includes(params.key)) { - accessory + this.accessory .getService(this.Service.StatelessProgrammableSwitch) .updateCharacteristic(this.Characteristic.ProgrammableSwitchEvent, params.key) } @@ -115,10 +115,10 @@ module.exports = class deviceZBDev { case 1009: case 1256: if (helpers.hasProperty(params, 'switch') && ['off', 'on'].includes(params.switch)) { - accessory + this.accessory .getService(this.Service.Switch) .updateCharacteristic(this.Characteristic.On, params.switch === 'on') - accessory.eveLogger.addEntry({ + this.accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: params.switch === 'on' ? 1 : 0 }) @@ -128,20 +128,20 @@ module.exports = class deviceZBDev { const eveLog = { time: Math.round(new Date().valueOf() / 1000) } if (helpers.hasProperty(params, 'temperature')) { const currentTemp = parseInt(params.temperature) / 100 - accessory + this.accessory .getService(this.Service.TemperatureSensor) .updateCharacteristic(this.Characteristic.CurrentTemperature, currentTemp) eveLog.temp = parseFloat(currentTemp) } if (helpers.hasProperty(params, 'humidity')) { const currentHumi = parseInt(params.humidity) / 100 - accessory + this.accessory .getService(this.Service.HumiditySensor) .updateCharacteristic(this.Characteristic.CurrentRelativeHumidity, currentHumi) eveLog.humidity = parseFloat(currentHumi) } if (helpers.hasProperty(eveLog, 'temp') || helpers.hasProperty(eveLog, 'humidity')) { - accessory.eveLogger.addEntry(eveLog) + this.accessory.eveLogger.addEntry(eveLog) } break } @@ -153,30 +153,30 @@ module.exports = class deviceZBDev { helpers.hasProperty(params, 'updateSource') && params.motion === 1 && diff < this.sensorTimeDifference - accessory.eveLogger.addEntry({ + this.accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: motionDetected ? 1 : 0 }) - accessory.getService(this.Service.MotionSensor).updateCharacteristic(this.Characteristic.MotionDetected, motionDetected) + this.accessory.getService(this.Service.MotionSensor).updateCharacteristic(this.Characteristic.MotionDetected, motionDetected) break } break case 3026: if (helpers.hasProperty(params, 'lock') && [0, 1].includes(params.lock)) { - accessory + this.accessory .getService(this.Service.ContactSensor) .updateCharacteristic(this.Characteristic.ContactSensorState, params.lock) - accessory.eveLogger.addEntry({ + this.accessory.eveLogger.addEntry({ time: Math.round(new Date().valueOf() / 1000), status: params.lock }) } break default: - throw new Error('Zigbee device type not supported [uiid ' + accessory.context.eweUIID + ']') + throw new Error('Zigbee device type not supported [uiid ' + this.accessory.context.eweUIID + ']') } } catch (err) { - this.platform.deviceUpdateError(accessory, err, false) + this.platform.deviceUpdateError(this.accessory, err, false) } } } diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index bb5f0913..94d73fdc 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -504,7 +504,7 @@ module.exports = class eWeLinkPlatform { str += 'is unreachable' } } - if (!this.config.disableHTTPRefresh) accessory.control.externalUpdate(accessory, device.params) + if (!this.config.disableHTTPRefresh) accessory.control.externalUpdate(device.params) this.devicesInHB.set(accessory.context.hbDeviceId, accessory) this.log(' → [%s] initialised %s.', device.name, str) } catch (err) { @@ -648,7 +648,7 @@ module.exports = class eWeLinkPlatform { this.log('[%s] %s update received and will be refreshed.', accessory.displayName, device.params.updateSource) } try { - accessory.control.externalUpdate(accessory, device.params) + accessory.control.externalUpdate(device.params) } catch (err) { this.log.warn('[%s] could not be refreshed as %s.', accessory.displayName, this.debug ? err : err.message) } From 788911c072d0ab907258a6016aab20c52023143a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 14:02:33 +0000 Subject: [PATCH 0710/3183] revert recent changes --- lib/device/blind.js | 2 +- lib/device/curtain.js | 2 +- lib/device/diffuser.js | 2 +- lib/device/fan.js | 4 ++-- lib/device/garage-eachen.js | 2 +- lib/device/garage-four.js | 2 +- lib/device/garage-two.js | 2 +- lib/device/garage.js | 2 +- lib/device/light-colour.js | 2 +- lib/device/light-ctemp.js | 3 +-- lib/device/light-dimmer.js | 2 +- lib/device/lock.js | 2 +- lib/device/outlet.js | 2 +- lib/device/rf-bridge.js | 2 +- lib/device/scm.js | 2 +- lib/device/switch-multi.js | 10 +--------- lib/device/switch-single.js | 2 +- lib/device/template.js | 3 +-- lib/device/thermostat.js | 2 +- lib/device/usb.js | 2 +- lib/device/valve-two.js | 2 +- lib/device/valve.js | 2 +- lib/device/zb-dev.js | 2 +- package-lock.json | 2 +- package.json | 2 +- 25 files changed, 26 insertions(+), 36 deletions(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index b481d65e..d0191a2f 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -23,8 +23,8 @@ module.exports = class deviceBlind { } async internalUpdate (value, callback) { - callback() try { + callback() let blindConfig const params = {} const wcService = this.accessory.getService(this.Service.WindowCovering) diff --git a/lib/device/curtain.js b/lib/device/curtain.js index 67ca977b..02e3758d 100644 --- a/lib/device/curtain.js +++ b/lib/device/curtain.js @@ -23,8 +23,8 @@ module.exports = class deviceCurtain { } async internalUpdate (value, callback) { - callback() try { + callback() let params const prevPos = this.accessory.context.cacheCurrentPosition const newPos = value diff --git a/lib/device/diffuser.js b/lib/device/diffuser.js index ae8bcf86..95b1d1d8 100644 --- a/lib/device/diffuser.js +++ b/lib/device/diffuser.js @@ -36,8 +36,8 @@ module.exports = class deviceDiffuser { } async internalDiffuserOnOffUpdate (value, callback) { - callback() try { + callback() const params = { switch: value ? 'on' : 'off' } await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { diff --git a/lib/device/fan.js b/lib/device/fan.js index baeaaf4a..1569f0e8 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -15,7 +15,7 @@ module.exports = class deviceFan { const fanService = accessory.getService(this.Service.Fan) || accessory.addService(this.Service.Fan) fanService .getCharacteristic(this.Characteristic.On) - .on('set', async (value, callback) => { + .on('set', (value, callback) => { callback() if (!value) fanService.setCharacteristic(this.Characteristic.RotationSpeed, 0) }) @@ -40,8 +40,8 @@ module.exports = class deviceFan { } async internalUpdate (type, value, callback) { - callback() try { + callback() let newPower let newSpeed let newLight diff --git a/lib/device/garage-eachen.js b/lib/device/garage-eachen.js index 1c7fb8bf..6f4ef86d 100644 --- a/lib/device/garage-eachen.js +++ b/lib/device/garage-eachen.js @@ -23,8 +23,8 @@ module.exports = class deviceGarageEachen { } async internalUpdate (value, callback) { - callback() try { + callback() let garageConfig if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') diff --git a/lib/device/garage-four.js b/lib/device/garage-four.js index f21f1e4d..40247d9e 100644 --- a/lib/device/garage-four.js +++ b/lib/device/garage-four.js @@ -25,8 +25,8 @@ module.exports = class deviceGarageFour { } async internalUpdate (garage, value, callback) { - callback() try { + callback() let garageConfig if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') diff --git a/lib/device/garage-two.js b/lib/device/garage-two.js index fa02653c..e534d59a 100644 --- a/lib/device/garage-two.js +++ b/lib/device/garage-two.js @@ -25,8 +25,8 @@ module.exports = class deviceGarageTwo { } async internalUpdate (garage, value, callback) { - callback() try { + callback() let garageConfig if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') diff --git a/lib/device/garage.js b/lib/device/garage.js index 38d31896..2e69359c 100644 --- a/lib/device/garage.js +++ b/lib/device/garage.js @@ -23,8 +23,8 @@ module.exports = class deviceGarage { } async internalUpdate (value, callback) { - callback() try { + callback() let garageConfig if (!(garageConfig = this.platform.cusG.get(this.accessory.context.hbDeviceId))) { throw new Error('group config missing') diff --git a/lib/device/light-colour.js b/lib/device/light-colour.js index fe68041a..4d9581c6 100644 --- a/lib/device/light-colour.js +++ b/lib/device/light-colour.js @@ -33,8 +33,8 @@ module.exports = class deviceLightColour { } async internalUpdate (type, value, callback) { - callback() try { + callback() let newRGB let params = {} const lightService = this.accessory.getService(this.Service.Lightbulb) diff --git a/lib/device/light-ctemp.js b/lib/device/light-ctemp.js index 66fa2e25..2874f653 100644 --- a/lib/device/light-ctemp.js +++ b/lib/device/light-ctemp.js @@ -17,9 +17,8 @@ module.exports = class deviceLightCTemp { } async internalUpdate (type, value, callback) { - callback() try { - + callback() } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) } diff --git a/lib/device/light-dimmer.js b/lib/device/light-dimmer.js index b7c30db4..734bb4ff 100644 --- a/lib/device/light-dimmer.js +++ b/lib/device/light-dimmer.js @@ -17,8 +17,8 @@ module.exports = class deviceLightDimmer { } async internalUpdate (type, value, callback) { - callback() try { + callback() const params = {} switch (type) { case 'onoff': diff --git a/lib/device/lock.js b/lib/device/lock.js index b69ea0cc..25730813 100644 --- a/lib/device/lock.js +++ b/lib/device/lock.js @@ -15,8 +15,8 @@ module.exports = class deviceLock { } async internalUpdate (value, callback) { - callback() try { + callback() let lockConfig const params = { switch: 'on' } const lmService = this.accessory.getService(this.Service.LockMechanism) diff --git a/lib/device/outlet.js b/lib/device/outlet.js index 72339905..fdbcfea8 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -130,8 +130,8 @@ module.exports = class deviceOutlet { } async internalUpdate (value, callback) { - callback() try { + callback() const params = { switch: value ? 'on' : 'off' } await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index f5f61a00..3701aa9e 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -77,8 +77,8 @@ module.exports = class deviceRFBridge { } async internalUpdate (rfChl, service, value, callback) { - callback() try { + callback() if (!value) return const params = { cmd: 'transmit', diff --git a/lib/device/scm.js b/lib/device/scm.js index fc8c339c..72313bf9 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -22,8 +22,8 @@ module.exports = class deviceSCM { } async internalUpdate (value, callback) { - callback() try { + callback() const params = { switches: helpers.defaultMultiSwitchOff } params.switches[0].switch = value ? 'on' : 'off' await this.platform.sendDeviceUpdate(this.accessory, params) diff --git a/lib/device/switch-multi.js b/lib/device/switch-multi.js index ae1c3f7d..e333541a 100644 --- a/lib/device/switch-multi.js +++ b/lib/device/switch-multi.js @@ -29,16 +29,8 @@ module.exports = class deviceSwitch { } async internalUpdate (value, callback) { - // *** generates a random number in the range [10, 100] *** \\ - await helpers.sleep(Math.floor(Math.random() * 91 + 10)) - if (this.updateInProgress) { - await helpers.sleep(300) - return await this.internalUpdate(value, callback) - } - this.updateInProgress = true - setTimeout(() => (this.updateInProgress = false), 250) - callback() try { + callback() let oAccessory let masterState = 'off' const params = {} diff --git a/lib/device/switch-single.js b/lib/device/switch-single.js index 90c7cbf6..ba9ab10e 100644 --- a/lib/device/switch-single.js +++ b/lib/device/switch-single.js @@ -28,8 +28,8 @@ module.exports = class deviceSwitchSingle { } async internalUpdate (value, callback) { - callback() try { + callback() const params = { switch: value ? 'on' : 'off' } await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { diff --git a/lib/device/template.js b/lib/device/template.js index 96b3e25d..728469c0 100644 --- a/lib/device/template.js +++ b/lib/device/template.js @@ -14,9 +14,8 @@ module.exports = class deviceTemplate { } async internalUpdate (value, callback) { - callback() try { - + callback() } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) } diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index 2f2216d7..f1c4c085 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -28,8 +28,8 @@ module.exports = class deviceThermostat { } async internalUpdate (value, callback) { - callback() try { + callback() const params = { switch: value ? 'on' : 'off', mainSwitch: value ? 'on' : 'off' diff --git a/lib/device/usb.js b/lib/device/usb.js index ccc96e56..b4928a2f 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -22,8 +22,8 @@ module.exports = class deviceUSB { } async internalUpdate (value, callback) { - callback() try { + callback() const params = { switches: helpers.defaultMultiSwitchOff } params.switches[0].switch = value ? 'on' : 'off' await this.platform.sendDeviceUpdate(this.accessory, params) diff --git a/lib/device/valve-two.js b/lib/device/valve-two.js index 4e53ebff..7cb2348d 100644 --- a/lib/device/valve-two.js +++ b/lib/device/valve-two.js @@ -38,8 +38,8 @@ module.exports = class deviceValveTwo { } async internalUpdate (valve, value, callback) { - callback() try { + callback() const params = { switches: helpers.defaultMultiSwitchOff } const serviceValve = this.accessory.getService(valve) switch (valve) { diff --git a/lib/device/valve.js b/lib/device/valve.js index ac142ff3..bf514311 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -36,8 +36,8 @@ module.exports = class deviceValve { } async internalUpdate (value, callback) { - callback() try { + callback() const params = { switch: value ? 'on' : 'off' } const serviceValve = this.accessory.getService(this.Service.Valve) serviceValve.updateCharacteristic(this.Characteristic.InUse, value) diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index a7514131..3a4c0aa7 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -80,8 +80,8 @@ module.exports = class deviceZBDev { } async internalUpdate (value, callback) { - callback() try { + callback() const params = { switch: value ? 'on' : 'off' } await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { diff --git a/package-lock.json b/package-lock.json index 02229e1b..032b820d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0-1", + "version": "3.12.0-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 41af04f9..91ec9975 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0-1", + "version": "3.12.0-2", "author": "bwp91", "contributors": [ "gbro115", From c0027fecc386cd1c006cec3a6da6b265d6c2bbd9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 14:45:43 +0000 Subject: [PATCH 0711/3183] unnecessary var --- lib/device/switch-multi.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/device/switch-multi.js b/lib/device/switch-multi.js index e333541a..52ee75c3 100644 --- a/lib/device/switch-multi.js +++ b/lib/device/switch-multi.js @@ -9,7 +9,6 @@ module.exports = class deviceSwitch { this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic this.EveHistoryService = fakegato(platform.api) - this.updateInProgress = false const switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) switchService .getCharacteristic(this.Characteristic.On) From 9483f1f720b52d6476a1b5e8fb12e45af4c3d2ef Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 14:45:58 +0000 Subject: [PATCH 0712/3183] increase await --- lib/device/diffuser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/diffuser.js b/lib/device/diffuser.js index 95b1d1d8..d275f9b3 100644 --- a/lib/device/diffuser.js +++ b/lib/device/diffuser.js @@ -102,7 +102,7 @@ module.exports = class deviceDiffuser { lightGcolor: newRGB[1], lightBcolor: newRGB[2] } - await helpers.sleep(500) + await helpers.sleep(1000) if (updateKeyColour !== this.accessory.context.updateKeyColour) return await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { From 31f99d74c300a83173b794b8ef4551730e51cf62 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 14:46:23 +0000 Subject: [PATCH 0713/3183] change logic in sendDeviceUpdate --- lib/ewelink-platform.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 94d73fdc..703ef140 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -56,7 +56,6 @@ module.exports = class eWeLinkPlatform { this.config.nameOverride = this.nameOverrideTmp this.config.ipOverride = this.ipOverrideTmp this.wsRefreshFlag = true - this.updateInProgress = false this.eveLogPath = this.api.user.storagePath() + '/persist/' this.api .on('didFinishLaunching', () => this.eWeLinkSetup()) @@ -573,15 +572,11 @@ module.exports = class eWeLinkPlatform { } } - async sendDeviceUpdate (accessory, params) { - // *** generates a random number in the range [10, 100] *** \\ - await helpers.sleep(Math.floor(Math.random() * 91 + 10)) - if (this.updateInProgress) { - await helpers.sleep(400) - return await this.sendDeviceUpdate(accessory, params) + async sendDeviceUpdate (accessory, params, doAwait = true) { + if (doAwait) { + // *** generates a random number in the range [10, 1000] *** \\ + await helpers.sleep(Math.floor(Math.random() * (991) + 10)) } - this.updateInProgress = true - setTimeout(() => (this.updateInProgress = false), 350) const payload = { apikey: accessory.context.eweApiKey, deviceid: accessory.context.eweDeviceId, From 7fc82439d61aa207b2e29dfc40829ba47589a54f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 14:46:40 +0000 Subject: [PATCH 0714/3183] skip await time for blinds --- lib/device/blind.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index d0191a2f..278323ae 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -43,7 +43,7 @@ module.exports = class deviceBlind { this.accessory.context.updateKey = updateKey const percentStepPerDecisecond = blindConfig.operationTime / 100 if (prevState !== 2) { - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params, false) let positionPercentChange = Math.floor(Date.now() / 100) - this.accessory.context.cacheLastStartTime positionPercentChange = Math.floor(percentStepPerDecisecond * positionPercentChange) if (prevState === 0) { @@ -59,7 +59,7 @@ module.exports = class deviceBlind { const decisecondsToMove = Math.round(Math.abs(diffPosition) * percentStepPerDecisecond) params.switches[0].switch = setToMoveUp ? 'on' : 'off' params.switches[1].switch = setToMoveUp ? 'off' : 'on' - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params, false) this.accessory.context.cacheTargetPosition = newTarget this.accessory.context.cachePositionState = setToMoveUp ? 1 : 0 this.accessory.context.cacheLastStartTime = Math.floor(Date.now() / 100) @@ -68,7 +68,7 @@ module.exports = class deviceBlind { if (this.accessory.context.updateKey !== updateKey) return params.switches[0].switch = 'off' params.switches[1].switch = 'off' - await this.platform.sendDeviceUpdate(this.accessory, params) + await this.platform.sendDeviceUpdate(this.accessory, params, false) wcService.updateCharacteristic(this.Characteristic.PositionState, 2) wcService.updateCharacteristic(this.Characteristic.CurrentPosition, newTarget) this.accessory.context.cachePositionState = 2 From fc33a99082868735197ab0bb8bb71f9427ee8197 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 14:48:24 +0000 Subject: [PATCH 0715/3183] 3.12.0-3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 032b820d..09da7301 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0-2", + "version": "3.12.0-3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 91ec9975..8f9769e4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0-2", + "version": "3.12.0-3", "author": "bwp91", "contributors": [ "gbro115", From 671b3e8d6800ee87d7f43cc059717b3f6e9316f4 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 16:16:20 +0000 Subject: [PATCH 0716/3183] switches ongoing fix --- lib/device/blind.js | 6 +++--- lib/device/switch-multi.js | 2 ++ lib/ewelink-platform.js | 6 +----- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/device/blind.js b/lib/device/blind.js index 278323ae..d0191a2f 100644 --- a/lib/device/blind.js +++ b/lib/device/blind.js @@ -43,7 +43,7 @@ module.exports = class deviceBlind { this.accessory.context.updateKey = updateKey const percentStepPerDecisecond = blindConfig.operationTime / 100 if (prevState !== 2) { - await this.platform.sendDeviceUpdate(this.accessory, params, false) + await this.platform.sendDeviceUpdate(this.accessory, params) let positionPercentChange = Math.floor(Date.now() / 100) - this.accessory.context.cacheLastStartTime positionPercentChange = Math.floor(percentStepPerDecisecond * positionPercentChange) if (prevState === 0) { @@ -59,7 +59,7 @@ module.exports = class deviceBlind { const decisecondsToMove = Math.round(Math.abs(diffPosition) * percentStepPerDecisecond) params.switches[0].switch = setToMoveUp ? 'on' : 'off' params.switches[1].switch = setToMoveUp ? 'off' : 'on' - await this.platform.sendDeviceUpdate(this.accessory, params, false) + await this.platform.sendDeviceUpdate(this.accessory, params) this.accessory.context.cacheTargetPosition = newTarget this.accessory.context.cachePositionState = setToMoveUp ? 1 : 0 this.accessory.context.cacheLastStartTime = Math.floor(Date.now() / 100) @@ -68,7 +68,7 @@ module.exports = class deviceBlind { if (this.accessory.context.updateKey !== updateKey) return params.switches[0].switch = 'off' params.switches[1].switch = 'off' - await this.platform.sendDeviceUpdate(this.accessory, params, false) + await this.platform.sendDeviceUpdate(this.accessory, params) wcService.updateCharacteristic(this.Characteristic.PositionState, 2) wcService.updateCharacteristic(this.Characteristic.CurrentPosition, newTarget) this.accessory.context.cachePositionState = 2 diff --git a/lib/device/switch-multi.js b/lib/device/switch-multi.js index 52ee75c3..f7d468d8 100644 --- a/lib/device/switch-multi.js +++ b/lib/device/switch-multi.js @@ -28,6 +28,7 @@ module.exports = class deviceSwitch { } async internalUpdate (value, callback) { + await helpers.sleep(Math.floor(Math.random() * (991) + 10)) try { callback() let oAccessory @@ -43,6 +44,7 @@ module.exports = class deviceSwitch { for (let i = 0; i <= 4; i++) { if ((oAccessory = this.platform.devicesInHB.get(this.accessory.context.eweDeviceId + 'SW' + i))) { oAccessory.getService(this.Service.Switch).updateCharacteristic(this.Characteristic.On, value) + oAccessory.context.cacheOn = value } } break diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 703ef140..396cd161 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -572,11 +572,7 @@ module.exports = class eWeLinkPlatform { } } - async sendDeviceUpdate (accessory, params, doAwait = true) { - if (doAwait) { - // *** generates a random number in the range [10, 1000] *** \\ - await helpers.sleep(Math.floor(Math.random() * (991) + 10)) - } + async sendDeviceUpdate (accessory, params) { const payload = { apikey: accessory.context.eweApiKey, deviceid: accessory.context.eweDeviceId, From 26b7fe5b6be473903e2b67258c34c14f6a69bee4 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 16:18:43 +0000 Subject: [PATCH 0717/3183] 3.12.0-4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 09da7301..7c7f7789 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0-3", + "version": "3.12.0-4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 8f9769e4..9d1f2d22 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0-3", + "version": "3.12.0-4", "author": "bwp91", "contributors": [ "gbro115", From 467355868438d34c39b07a0d407fe83da83c673f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 17:55:48 +0000 Subject: [PATCH 0718/3183] await inside try --- lib/device/switch-multi.js | 2 +- lib/device/switch-single.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/device/switch-multi.js b/lib/device/switch-multi.js index f7d468d8..30446c7e 100644 --- a/lib/device/switch-multi.js +++ b/lib/device/switch-multi.js @@ -28,8 +28,8 @@ module.exports = class deviceSwitch { } async internalUpdate (value, callback) { - await helpers.sleep(Math.floor(Math.random() * (991) + 10)) try { + await helpers.sleep(Math.floor(Math.random() * (991) + 10)) callback() let oAccessory let masterState = 'off' diff --git a/lib/device/switch-single.js b/lib/device/switch-single.js index ba9ab10e..061e19e6 100644 --- a/lib/device/switch-single.js +++ b/lib/device/switch-single.js @@ -29,6 +29,7 @@ module.exports = class deviceSwitchSingle { async internalUpdate (value, callback) { try { + await helpers.sleep(Math.floor(Math.random() * (991) + 10)) callback() const params = { switch: value ? 'on' : 'off' } await this.platform.sendDeviceUpdate(this.accessory, params) From 98f30d37cf0f9089e9e62dcb40a777a8b37b4722 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 18:32:41 +0000 Subject: [PATCH 0719/3183] 3.12.0-5 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7c7f7789..bcc20dd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0-4", + "version": "3.12.0-5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 9d1f2d22..ea7eb8be 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0-4", + "version": "3.12.0-5", "author": "bwp91", "contributors": [ "gbro115", From e0568a852e2b04342ab8ec7e3e12cfe9107a28d2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 20:48:34 +0000 Subject: [PATCH 0720/3183] ignore info folder --- .gitignore | 1 + .npmignore | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 45fb205e..3f1189f6 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ .nova .github .npm +info/ node_modules/ \ No newline at end of file diff --git a/.npmignore b/.npmignore index 45fb205e..3f1189f6 100644 --- a/.npmignore +++ b/.npmignore @@ -2,4 +2,5 @@ .nova .github .npm +info/ node_modules/ \ No newline at end of file From 7962a6874d6b2001109c203417e735ba6a807f13 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Nov 2020 21:04:09 +0000 Subject: [PATCH 0721/3183] Update .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3f1189f6..a5ad5d79 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ .DS_Store .nova -.github .npm info/ node_modules/ \ No newline at end of file From 92825354c4d4038e1180d7e70936ed32098b329b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 9 Nov 2020 06:47:57 +0000 Subject: [PATCH 0722/3183] Update ewelink-platform.js --- lib/ewelink-platform.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 396cd161..30fb67cd 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -374,8 +374,8 @@ module.exports = class eWeLinkPlatform { } oAccessory.context.reachableWAN = device.online oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false - this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) oAccessory.control = new deviceSwitchMulti(this, oAccessory) + this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) } /**********************/ } else if (helpers.devicesRFBridge.includes(device.extra.uiid)) { From effe4f9ead38821b3a12b5ed53d6abcffdd441fa Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 9 Nov 2020 08:38:06 +0000 Subject: [PATCH 0723/3183] no brackets needed --- lib/device/switch-multi.js | 2 +- lib/device/switch-single.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/device/switch-multi.js b/lib/device/switch-multi.js index 30446c7e..a9a8d36f 100644 --- a/lib/device/switch-multi.js +++ b/lib/device/switch-multi.js @@ -29,7 +29,7 @@ module.exports = class deviceSwitch { async internalUpdate (value, callback) { try { - await helpers.sleep(Math.floor(Math.random() * (991) + 10)) + await helpers.sleep(Math.floor(Math.random() * 991 + 10)) callback() let oAccessory let masterState = 'off' diff --git a/lib/device/switch-single.js b/lib/device/switch-single.js index 061e19e6..28b7aaab 100644 --- a/lib/device/switch-single.js +++ b/lib/device/switch-single.js @@ -29,7 +29,7 @@ module.exports = class deviceSwitchSingle { async internalUpdate (value, callback) { try { - await helpers.sleep(Math.floor(Math.random() * (991) + 10)) + await helpers.sleep(Math.floor(Math.random() * 991 + 10)) callback() const params = { switch: value ? 'on' : 'off' } await this.platform.sendDeviceUpdate(this.accessory, params) From 4218fa748ff1d6dc1981514e0aa3545f976cf686 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 9 Nov 2020 08:43:15 +0000 Subject: [PATCH 0724/3183] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 941872f3..465daba4 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ To use this plugin, you will need to already have [Homebridge](https://homebridg * [How to copy Homebridge logs](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-copy-Homebridge-logs) * [How to enable/disable plugin extended logging](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-enable-disable-plugin-extended-logging) * [How to remove an accessory from the cache](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-remove-an-accessory-from-the-cache) +* [How to update node](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-update-node) ### About * [About Me](https://github.com/sponsors/bwp91) * [Support Request](https://github.com/bwp91/homebridge-ewelink/issues/new/choose) From 1e92b651e02cd4d1f8e85344ee836a0649669eaa Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 9 Nov 2020 09:24:53 +0000 Subject: [PATCH 0725/3183] add local wiki links --- config.schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.schema.json b/config.schema.json index 608c3a36..916ba357 100644 --- a/config.schema.json +++ b/config.schema.json @@ -118,7 +118,7 @@ "groups": { "type": "array", "title": "Accessory Simulations", - "description": "You can use this setting to set up custom simulated HomeKit accessories from a generic single/multi-switch device. For more information please see the wiki.", + "description": "You can use this setting to set up custom simulated HomeKit accessories from a generic single/multi-switch device. Please see this wiki article for more information.", "items": { "type": "object", "properties": { @@ -226,7 +226,7 @@ "bridgeSensors": { "type": "array", "title": "Sensors", - "description": "You can expose different types of sensors connected to your RF Bridge in HomeKit.", + "description": "You can expose different types of sensors connected to your RF Bridge in HomeKit. Please see this wiki article for more information.", "items": { "type": "object", "properties": { From f3a3fa7f1279ef0c2616a63d52501cbb03ca1010 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 9 Nov 2020 09:26:42 +0000 Subject: [PATCH 0726/3183] add header logo, remove footer --- config.schema.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config.schema.json b/config.schema.json index 916ba357..722655c7 100644 --- a/config.schema.json +++ b/config.schema.json @@ -2,8 +2,7 @@ "pluginAlias": "eWeLink", "pluginType": "platform", "singular": true, - "headerDisplay": "Homebridge/HOOBS plugin to control eWeLink devices with original firmware.", - "footerDisplay": "For help and support please visit our [GitHub Wiki](https://github.com/bwp91/homebridge-ewelink/wiki).", + "headerDisplay": "

For help and support please visit our GitHub Wiki. We hope you find this plugin useful!

", "schema": { "type": "object", "properties": { From 5ef84cbc9bccbbca091a4604b46107a10985c649 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 9 Nov 2020 10:43:47 +0000 Subject: [PATCH 0727/3183] enable support for B02-F --- lib/helpers.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/helpers.js b/lib/helpers.js index 8bfa21c7..65ee950a 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -20,7 +20,7 @@ module.exports = { devicesSingleSwitchOutlet: ['Sonoff Pow', 'S20', 'S26', 'S55'], devicesBrightable: [36, 44], devicesColourable: [22, 59, 104], - devicesCTempable: [], + devicesCTempable: [103], devicesCurtain: [11], devicesSensor: [102], devicesThermostat: [15], @@ -45,7 +45,8 @@ module.exports = { 'online', 'power', 'rfChl', 'rfList', 'rfTrig', 'sensorType', 'setclose', 'state', 'switch', 'switches', 'temperature', - 'trigTime', 'type', 'voltage', 'zyx_mode' + 'trigTime', 'type', 'voltage', 'ltype', + 'zyx_mode' ], defaultMultiSwitchOff: [ { @@ -182,7 +183,7 @@ module.exports = { 94: 0, // "YIAN_ELECTRIC_PROTECT" \\ 98: 0, // "DOORBELL_RFBRIDGE" \\ 102: 1, // "DOOR_MAGNETIC" \\ OPL-DMA, DW2 - 103: 0, // "WOTEWODE_TEM_LIGHT" \\ + 103: 1, // "WOTEWODE_TEM_LIGHT" \\ B02-F 104: 1, // "WOTEWODE_RGB_TEM_LIGHT" \\ 107: 0, // "GSM_SOCKET_NO_FLOW" \\ 109: 0, // "YK_INFRARED_2" \\ From 2cb40d69e9d2ff3640ab5634ead947c60e47600f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 9 Nov 2020 12:15:23 +0000 Subject: [PATCH 0728/3183] colourTemp support for B02-F --- lib/device/light-colour.js | 8 +++- lib/device/light-ctemp.js | 89 +++++++++++++++++++++++++++++++++++++- lib/helpers.js | 4 +- 3 files changed, 95 insertions(+), 6 deletions(-) diff --git a/lib/device/light-colour.js b/lib/device/light-colour.js index 4d9581c6..fba478c3 100644 --- a/lib/device/light-colour.js +++ b/lib/device/light-colour.js @@ -34,12 +34,12 @@ module.exports = class deviceLightColour { async internalUpdate (type, value, callback) { try { - callback() let newRGB let params = {} const lightService = this.accessory.getService(this.Service.Lightbulb) switch (type) { case 'onoff': + callback() if (this.accessory.context.eweUIID === 22) { // **** B1 uses state rather than switch *** \\ params.state = value ? 'on' : 'off' @@ -49,6 +49,8 @@ module.exports = class deviceLightColour { await this.platform.sendDeviceUpdate(this.accessory, params) break case 'brightness': { + await helpers.sleep(1000) + callback() const updateKeyBright = Math.random().toString(36).substr(2, 8) this.accessory.context.updateKeyBright = updateKeyBright switch (this.accessory.context.eweUIID) { @@ -81,6 +83,8 @@ module.exports = class deviceLightColour { break } case 'hue': { + await helpers.sleep(2000) + callback() const updateKeyColour = Math.random().toString(36).substr(2, 8) this.accessory.context.updateKeyColour = updateKeyColour newRGB = convert.hsv.rgb(value, lightService.getCharacteristic(this.Characteristic.Saturation).value, 100) @@ -135,6 +139,7 @@ module.exports = class deviceLightColour { async externalUpdate (params) { try { + if (helpers.hasProperty(params, 'updateSource') && params.updateSource === 'LAN') return let newColour let mode let isOn = false @@ -184,7 +189,6 @@ module.exports = class deviceLightColour { break case 104: // *** GTLC104 *** \\ - if (helpers.hasProperty(params, 'updateSource') && params.updateSource === 'LAN') return if (helpers.hasProperty(params, 'ltype')) { mode = params.ltype if (mode === 'color' && helpers.hasProperty(params, 'color')) { diff --git a/lib/device/light-ctemp.js b/lib/device/light-ctemp.js index 2874f653..317e5d91 100644 --- a/lib/device/light-ctemp.js +++ b/lib/device/light-ctemp.js @@ -1,7 +1,8 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -module.exports = class deviceLightCTemp { +const helpers = require('./../helpers') +module.exports = class deviceLightColour { constructor (platform, accessory) { this.platform = platform this.Service = platform.api.hap.Service @@ -13,12 +14,65 @@ module.exports = class deviceLightCTemp { lightService .getCharacteristic(this.Characteristic.Brightness) .on('set', (value, callback) => this.internalUpdate('brightness', value, callback)) + lightService + .getCharacteristic(this.Characteristic.ColorTemperature) + .on('set', (value, callback) => this.internalUpdate('colour', value, callback)) this.accessory = accessory } async internalUpdate (type, value, callback) { try { - callback() + let params = {} + const lightService = this.accessory.getService(this.Service.Lightbulb) + switch (type) { + case 'onoff': + callback() + params.switch = value ? 'on' : 'off' + await this.platform.sendDeviceUpdate(this.accessory, params) + break + case 'brightness': { + await helpers.sleep(1000) + callback() + const updateKeyBright = Math.random().toString(36).substr(2, 8) + this.accessory.context.updateKeyBright = updateKeyBright + // *** Device needs the current ct value sent too *** \\ + params = { + ltype: 'white', + white: { + br: value, + ct: this.accessory.context.cacheCT + } + } + await helpers.sleep(500) + if (updateKeyBright !== this.accessory.context.updateKeyBright) return + await this.platform.sendDeviceUpdate(this.accessory, params) + break + } + case 'colour': { + await helpers.sleep(2000) + callback() + const updateKeyColour = Math.random().toString(36).substr(2, 8) + this.accessory.context.updateKeyColour = updateKeyColour + // HomeKit has a ct range of 140-500 corresponding to 2000-7143K + // B02-F-A60 has a range of 2200K-6500K corresponding to ct: 0-255 + let mToK = Math.round(1000000 / value) + if (mToK < 2200) mToK = 2200 + if (mToK > 6500) mToK = 6500 + const kToCT = Math.round(((mToK - 2200) / 4300) * 255) + params = { + ltype: 'white', + white: { + ct: kToCT, + br: lightService.getCharacteristic(this.Characteristic.Brightness).value + } + } + this.accessory.context.cacheCT = kToCT + await helpers.sleep(1000) + if (updateKeyColour !== this.accessory.context.updateKeyColour) return + await this.platform.sendDeviceUpdate(this.accessory, params) + break + } + } } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) } @@ -26,7 +80,38 @@ module.exports = class deviceLightCTemp { async externalUpdate (params) { try { + if (helpers.hasProperty(params, 'updateSource') && params.updateSource === 'LAN') return + let mode + let isOn = false + const lightService = this.accessory.getService(this.Service.Lightbulb) + if (helpers.hasProperty(params, 'switch')) { + isOn = params.switch === 'on' + } else { + isOn = lightService.getCharacteristic(this.Characteristic.On).value + } + if (isOn) { + lightService.updateCharacteristic(this.Characteristic.On, true) + if (helpers.hasProperty(params, 'ltype')) { + mode = params.ltype + if (mode === 'white' && helpers.hasProperty(params, 'white')) { + if (helpers.hasProperty(params.white, 'br')) { + lightService.updateCharacteristic(this.Characteristic.Brightness, params.white.br) + } + if (helpers.hasProperty(params.white, 'ct')) { + // B02-F-A60 has a range of 2200K-6500K corresponding to ct: 0-255 + // HomeKit has a ct range of 140-500 corresponding to 2000-7143K + + const ctToK = Math.round(params.white.ct / 255 * 4300 + 2200) + const kToMired = Math.round(1000000 / ctToK) + lightService.updateCharacteristic(this.Characteristic.ColorTemperature, kToMired) + this.accessory.context.cacheCT = params.white.ct + } + } + } + } else { + lightService.updateCharacteristic(this.Characteristic.On, false) + } } catch (err) { this.platform.deviceUpdateError(this.accessory, err, false) } diff --git a/lib/helpers.js b/lib/helpers.js index 65ee950a..ced67c70 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -14,7 +14,7 @@ module.exports = { sensorTimeLength: 60, sensorTimeDifference: 120 }, - devicesNonLAN: [22, 28, 34, 59, 102, 104], + devicesNonLAN: [22, 28, 34, 59, 102, 103, 104], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59, 104], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], devicesSingleSwitchOutlet: ['Sonoff Pow', 'S20', 'S26', 'S55'], @@ -45,7 +45,7 @@ module.exports = { 'online', 'power', 'rfChl', 'rfList', 'rfTrig', 'sensorType', 'setclose', 'state', 'switch', 'switches', 'temperature', - 'trigTime', 'type', 'voltage', 'ltype', + 'trigTime', 'type', 'voltage', 'white', 'zyx_mode' ], defaultMultiSwitchOff: [ From b08c3c0fcd5d89b539d615e76c01d26332b097b8 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 9 Nov 2020 15:31:07 +0000 Subject: [PATCH 0729/3183] add switch first --- lib/device/thermostat.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index f1c4c085..8cd4a93a 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -9,16 +9,16 @@ module.exports = class deviceThermostat { this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic this.EveHistoryService = fakegato(platform.api) - if (!accessory.getService(this.Service.TemperatureSensor)) accessory.addService(this.Service.TemperatureSensor) - if (accessory.context.sensorType !== 'DS18B20') { - if (!accessory.getService(this.Service.HumiditySensor)) accessory.addService(this.Service.HumiditySensor) - } if (!this.platform.config.hideTHSwitch) { const switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) switchService .getCharacteristic(this.Characteristic.On) .on('set', (value, callback) => this.internalUpdate(value, callback)) } + if (!accessory.getService(this.Service.TemperatureSensor)) accessory.addService(this.Service.TemperatureSensor) + if (accessory.context.sensorType !== 'DS18B20') { + if (!accessory.getService(this.Service.HumiditySensor)) accessory.addService(this.Service.HumiditySensor) + } accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('custom', accessory, { storage: 'fs', From 32af34499a9a229d3138083d87c6f7f6248e4cbe Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 9 Nov 2020 15:34:40 +0000 Subject: [PATCH 0730/3183] remove switch of config hidden --- lib/device/thermostat.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index 8cd4a93a..0f0658e4 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -9,7 +9,11 @@ module.exports = class deviceThermostat { this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic this.EveHistoryService = fakegato(platform.api) - if (!this.platform.config.hideTHSwitch) { + if (this.platform.config.hideTHSwitch) { + if (accessory.getService(this.Service.Switch)) { + accessory.removeService(accessory.getService(this.Service.Switch)) + } + } else { const switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) switchService .getCharacteristic(this.Characteristic.On) From 6ee04c6f0c3299d85a91a8f1275c83eec8ed5969 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 9 Nov 2020 15:45:15 +0000 Subject: [PATCH 0731/3183] 3.12.0-6 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index bcc20dd9..b6c5d5f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0-5", + "version": "3.12.0-6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index ea7eb8be..2afad660 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0-5", + "version": "3.12.0-6", "author": "bwp91", "contributors": [ "gbro115", From ea1bc7ed84397076fed41eaad1c36e289a963773 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 9 Nov 2020 19:56:01 +0000 Subject: [PATCH 0732/3183] Update switch-multi.js --- lib/device/switch-multi.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/switch-multi.js b/lib/device/switch-multi.js index a9a8d36f..20f9a9f2 100644 --- a/lib/device/switch-multi.js +++ b/lib/device/switch-multi.js @@ -3,7 +3,7 @@ 'use strict' const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') -module.exports = class deviceSwitch { +module.exports = class deviceSwitchMulti { constructor (platform, accessory) { this.platform = platform this.Service = platform.api.hap.Service From 7a06c0dfec210eeb2eb98704d55fa008b666dc8b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 11 Nov 2020 13:54:10 +0000 Subject: [PATCH 0733/3183] reduce delay --- lib/device/switch-multi.js | 2 +- lib/device/switch-single.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/device/switch-multi.js b/lib/device/switch-multi.js index 20f9a9f2..2b5df947 100644 --- a/lib/device/switch-multi.js +++ b/lib/device/switch-multi.js @@ -29,7 +29,7 @@ module.exports = class deviceSwitchMulti { async internalUpdate (value, callback) { try { - await helpers.sleep(Math.floor(Math.random() * 991 + 10)) + await helpers.sleep(Math.floor(Math.random() * 491 + 10)) callback() let oAccessory let masterState = 'off' diff --git a/lib/device/switch-single.js b/lib/device/switch-single.js index 28b7aaab..4fdcb5e2 100644 --- a/lib/device/switch-single.js +++ b/lib/device/switch-single.js @@ -29,7 +29,7 @@ module.exports = class deviceSwitchSingle { async internalUpdate (value, callback) { try { - await helpers.sleep(Math.floor(Math.random() * 991 + 10)) + await helpers.sleep(Math.floor(Math.random() * 491 + 10)) callback() const params = { switch: value ? 'on' : 'off' } await this.platform.sendDeviceUpdate(this.accessory, params) From d34f88009bc6ff2863d2d39bdcca8f4bfca8e022 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 11 Nov 2020 14:03:14 +0000 Subject: [PATCH 0734/3183] 3.12.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index b6c5d5f4..1afcf81a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0-6", + "version": "3.12.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 2afad660..73fe3a48 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0-6", + "version": "3.12.0", "author": "bwp91", "contributors": [ "gbro115", From b349722bce94dadfb9870af3a91ba5df7e6a73b7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 11 Nov 2020 21:49:59 +0000 Subject: [PATCH 0735/3183] increase range slightly --- lib/device/switch-multi.js | 2 +- lib/device/switch-single.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/device/switch-multi.js b/lib/device/switch-multi.js index 2b5df947..19b71595 100644 --- a/lib/device/switch-multi.js +++ b/lib/device/switch-multi.js @@ -29,7 +29,7 @@ module.exports = class deviceSwitchMulti { async internalUpdate (value, callback) { try { - await helpers.sleep(Math.floor(Math.random() * 491 + 10)) + await helpers.sleep(Math.floor(Math.random() * 741 + 10)) callback() let oAccessory let masterState = 'off' diff --git a/lib/device/switch-single.js b/lib/device/switch-single.js index 4fdcb5e2..b1902f91 100644 --- a/lib/device/switch-single.js +++ b/lib/device/switch-single.js @@ -29,7 +29,7 @@ module.exports = class deviceSwitchSingle { async internalUpdate (value, callback) { try { - await helpers.sleep(Math.floor(Math.random() * 491 + 10)) + await helpers.sleep(Math.floor(Math.random() * 741 + 10)) callback() const params = { switch: value ? 'on' : 'off' } await this.platform.sendDeviceUpdate(this.accessory, params) From f7bd0d736a0fccc23a8f0ad4b51174372dfe8be8 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 11 Nov 2020 22:02:18 +0000 Subject: [PATCH 0736/3183] S55R1 to outlet list --- lib/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers.js b/lib/helpers.js index ced67c70..cb2a0fc2 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -17,7 +17,7 @@ module.exports = { devicesNonLAN: [22, 28, 34, 59, 102, 103, 104], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59, 104], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], - devicesSingleSwitchOutlet: ['Sonoff Pow', 'S20', 'S26', 'S55'], + devicesSingleSwitchOutlet: ['Sonoff Pow', 'S20', 'S26', 'S55', 'S55R1'], devicesBrightable: [36, 44], devicesColourable: [22, 59, 104], devicesCTempable: [103], From 37933dca1af06135a5722e24f10965e092e20bfb Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 11 Nov 2020 22:04:16 +0000 Subject: [PATCH 0737/3183] 3.12.1-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1afcf81a..76daf946 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0", + "version": "3.12.1-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 73fe3a48..dcd0223d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.12.0", + "version": "3.12.1-0", "author": "bwp91", "contributors": [ "gbro115", From b2a1e0b4b27f822979ea1a15f9a0b77c3f61c68e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 12 Nov 2020 08:53:09 +0000 Subject: [PATCH 0738/3183] hide TH switch per device basis --- config.schema.json | 13 ++++++------- lib/device/thermostat.js | 4 ++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/config.schema.json b/config.schema.json index 722655c7..b829f930 100644 --- a/config.schema.json +++ b/config.schema.json @@ -78,13 +78,12 @@ "hideLightFromFan": { "type": "string", "title": "Hide Fan Lights", - "description": "A list of eWeLink iFan devices for which the light will be hidden from Homebridge. For example '10009553c8' or multiple separated with a comma '10009553c8,10009553c9'" + "description": "A list of eWeLink iFan devices for which the light will be hidden from Homebridge. For example '10009553c8' or multiple separated with a comma '10009553c8,10009553c9'." }, - "hideTHSwitch": { - "title": "Hide TH10/TH16 Switch", - "type": "boolean", - "description": "If checked, the switch for the TH10/TH16 devices will be hidden from Homebridge.", - "default": false + "hideSwitchFromTH": { + "type": "string", + "title": "Hide Fan Lights", + "description": "A list of TH10/TH16 devices for which the switch will be hidden from Homebridge. For example '10009553c8' or multiple separated with a comma '10009553c8,10009553c9'." }, "lowBattThreshold": { "type": "integer", @@ -375,7 +374,7 @@ "outletAsSwitch", "inUsePowerThreshold", "hideLightFromFan", - "hideTHSwitch", + "hideSwitchFromTH", "lowBattThreshold", "sensorTimeDifference", "hideZBLDPress", diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index 0f0658e4..9400a497 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -9,7 +9,7 @@ module.exports = class deviceThermostat { this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic this.EveHistoryService = fakegato(platform.api) - if (this.platform.config.hideTHSwitch) { + if ((this.platform.config.hideSwitchFromTH || '').includes(accessory.context.eweDeviceId)) { if (accessory.getService(this.Service.Switch)) { accessory.removeService(accessory.getService(this.Service.Switch)) } @@ -47,7 +47,7 @@ module.exports = class deviceThermostat { async externalUpdate (params) { try { if ( - !this.platform.config.hideTHSwitch && + !(this.platform.config.hideSwitchFromTH || '').includes(this.accessory.context.eweDeviceId) && (helpers.hasProperty(params, 'switch') || helpers.hasProperty(params, 'mainSwitch')) ) { const newState = helpers.hasProperty(params, 'switch') ? params.switch === 'on' : params.mainSwitch === 'on' From 5d7d294d49a0fb2704a808e2bef6683de0a99301 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 12 Nov 2020 15:07:42 +0000 Subject: [PATCH 0739/3183] config rf bridge per device --- config.schema.json | 15 +++++++-------- lib/ewelink-platform.js | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/config.schema.json b/config.schema.json index b829f930..0161e91e 100644 --- a/config.schema.json +++ b/config.schema.json @@ -85,6 +85,11 @@ "title": "Hide Fan Lights", "description": "A list of TH10/TH16 devices for which the switch will be hidden from Homebridge. For example '10009553c8' or multiple separated with a comma '10009553c8,10009553c9'." }, + "resetRFBridge": { + "title": "Reset RF Bridges", + "type": "string", + "description": "If checked, the plugin will remove and re-add these RF Bridges on Homebridge restart. This is needed when adding/removed sub-devices from the RF Bridge. For example '10009553c8' or multiple separated with a comma '10009553c8,10009553c9'." + }, "lowBattThreshold": { "type": "integer", "title": "Low Battery Threshold", @@ -107,12 +112,6 @@ "description": "If checked, double and long press options will be hidden for the ZigBee button.", "default": false }, - "resetRFBridge": { - "title": "Reset RF Bridges", - "type": "boolean", - "description": "If checked, the plugin will remove and re-add all RF Bridges on Homebridge restart. This is needed when adding/removed sub-devices from the RF Bridge.", - "default": false - }, "groups": { "type": "array", "title": "Accessory Simulations", @@ -375,10 +374,10 @@ "inUsePowerThreshold", "hideLightFromFan", "hideSwitchFromTH", + "resetRFBridge", "lowBattThreshold", "sensorTimeDifference", - "hideZBLDPress", - "resetRFBridge" + "hideZBLDPress" ] }, { diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 30fb67cd..c7a73a01 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -425,7 +425,7 @@ module.exports = class eWeLinkPlatform { } if ((oAccessory = this.devicesInHB.get(device.deviceid + 'SW' + swNumber))) { if ( - this.config.resetRFBridge || + (this.config.resetRFBridge || '').includes(device.deviceid) || oAccessory.context.subType !== subType || oAccessory.context.sensorTimeLength !== sensorTimeLength || oAccessory.context.swNumber !== swNumber From c346f8a09c5ef88d9be988cc8f62a9865b9e5756 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Thu, 12 Nov 2020 19:57:58 +0000 Subject: [PATCH 0740/3183] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 465daba4..d2c3dd64 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- Homebridge Verified + Homebridge Verified

From 8bf5fb68f69019770a52ab5c9c3124cfd9946aa3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 12 Nov 2020 20:01:19 +0000 Subject: [PATCH 0741/3183] reduce image size --- config.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.schema.json b/config.schema.json index 0161e91e..77bebb1f 100644 --- a/config.schema.json +++ b/config.schema.json @@ -2,7 +2,7 @@ "pluginAlias": "eWeLink", "pluginType": "platform", "singular": true, - "headerDisplay": "

For help and support please visit our GitHub Wiki. We hope you find this plugin useful!

", + "headerDisplay": "

For help and support please visit our GitHub Wiki. We hope you find this plugin useful!

", "schema": { "type": "object", "properties": { From 1d5f90f4a7dd02d674f7ce487c6f1a09995ff049 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 13 Nov 2020 13:32:53 +0000 Subject: [PATCH 0742/3183] capitalisation --- lib/ewelink-platform.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index c7a73a01..81270cf1 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -650,7 +650,7 @@ module.exports = class eWeLinkPlatform { this.initialiseDevice(newDevice) this.lanClient.addDeviceToMap(newDevice) } catch (err) { - this.log.warn('[%s] Restart Homebridge to add new device, failed to add automatically as %s.', deviceId, err.message) + this.log.warn('[%s] restart Homebridge to add new device, failed to add automatically as %s.', deviceId, err.message) } } } From c3f9c9809e77d237fff04cae5d2e57212a400f2d Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 13 Nov 2020 13:36:11 +0000 Subject: [PATCH 0743/3183] Update README.md --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d2c3dd64..b13d4ae9 100644 --- a/README.md +++ b/README.md @@ -18,18 +18,22 @@ Homebridge/HOOBS plugin to control eWeLink devices with original firmware.
### Prerequisites -To use this plugin, you will need to already have [Homebridge](https://homebridge.io) or [HOOBS](https://hoobs.org) installed. Please refer to the links for more information and installation instructions. +* To use this plugin, you will need to already have [Homebridge](https://homebridge.io) or [HOOBS](https://hoobs.org) installed. Please refer to the links for more information and installation instructions. + +### Plugin Information ### Setup * [Installation (Homebridge)](https://github.com/bwp91/homebridge-ewelink/wiki/Installation-(Homebridge)) * [Installation (HOOBS)](https://github.com/bwp91/homebridge-ewelink/wiki/Installation-(HOOBS)) * [Configuration](https://github.com/bwp91/homebridge-ewelink/wiki/Configuration) * [Beta Version](https://github.com/bwp91/homebridge-ewelink/wiki/Beta-Version) + ### Features * [Supported Devices](https://github.com/bwp91/homebridge-ewelink/wiki/Supported-Devices) * [Multi Channel Devices](https://github.com/bwp91/homebridge-ewelink/wiki/Multi-Channel-Devices) * [Accessory Simulations](https://github.com/bwp91/homebridge-ewelink/wiki/Accessory-Simulations) * [Connection Methods](https://github.com/bwp91/homebridge-ewelink/wiki/Connection-Methods) + ### How-to Guides * [How to set up RF Bridge sensors](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-RF-Bridge-sensors) * [How to set up Sonoff Camera (GK-200MP2-B)](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-Sonoff-Camera) @@ -37,9 +41,11 @@ To use this plugin, you will need to already have [Homebridge](https://homebridg * [How to enable/disable plugin extended logging](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-enable-disable-plugin-extended-logging) * [How to remove an accessory from the cache](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-remove-an-accessory-from-the-cache) * [How to update node](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-update-node) + ### About * [About Me](https://github.com/sponsors/bwp91) * [Support Request](https://github.com/bwp91/homebridge-ewelink/issues/new/choose) * [Credits](https://github.com/bwp91/homebridge-ewelink/wiki/Credits) + ### Disclaimer -I am in no way affiliated with eWeLink nor any of the device brands (like Sonoff) and this plugin is a personal project that I maintain in my free time. +* I am in no way affiliated with eWeLink nor any of the device brands (like Sonoff) and this plugin is a personal project that I maintain in my free time. From 139d83a185f363e709e52d6e0c1a3534011247b7 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 13 Nov 2020 13:36:57 +0000 Subject: [PATCH 0744/3183] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b13d4ae9..9ac72c70 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ Homebridge/HOOBS plugin to control eWeLink devices with original firmware. ### About * [About Me](https://github.com/sponsors/bwp91) +* [Changelog](https://github.com/bwp91/homebridge-ewelink/releases) * [Support Request](https://github.com/bwp91/homebridge-ewelink/issues/new/choose) * [Credits](https://github.com/bwp91/homebridge-ewelink/wiki/Credits) From a8d3cf7483cb79a930811e05e370a57906b053b8 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 13 Nov 2020 16:12:28 +0000 Subject: [PATCH 0745/3183] Update feature-request.md --- .github/ISSUE_TEMPLATE/feature-request.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md index 5ba9ddfc..0619afdd 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -7,14 +7,17 @@ assignees: '' --- -**Please explain your feature request in one sentence.** -... +**Please explain your feature request in a one or two sentences.** + + **Is your feature request related to a problem? Please describe.** -... -**Any particular Sonoff devices that this relates to?** -... + + +**Any particular eWeLink devices that this relates to?** + + **Anything else?** -... + From 857ae7deffd33bff6e64e1a39c01b9594d085c4b Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 13 Nov 2020 16:14:20 +0000 Subject: [PATCH 0746/3183] Update feature-request.md --- .github/ISSUE_TEMPLATE/feature-request.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md index 0619afdd..2726831a 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -1,23 +1,24 @@ --- name: Feature Request -about: I have an idea for the package or have a device that isn't supported. +about: I have an idea for the package or a device that isn't supported. title: '' labels: '' assignees: '' --- -**Please explain your feature request in a one or two sentences.** +* **Please explain your feature request in a one or two sentences.** -**Is your feature request related to a problem? Please describe.** +* **Is your feature request related to a problem? Please describe.** -**Any particular eWeLink devices that this relates to?** +* **Any particular eWeLink devices that this relates to?** -**Anything else?** +* **Anything else?** + From 6f6bb87d9c83e646d2000738da1122d09b190d9c Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 13 Nov 2020 16:19:42 +0000 Subject: [PATCH 0747/3183] Update feedback.md --- .github/ISSUE_TEMPLATE/feedback.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feedback.md b/.github/ISSUE_TEMPLATE/feedback.md index 31941559..26dacc4c 100644 --- a/.github/ISSUE_TEMPLATE/feedback.md +++ b/.github/ISSUE_TEMPLATE/feedback.md @@ -1,6 +1,6 @@ --- -name: Feedback -about: Give feedback that I might have asked for. +name: Information/Feedback +about: General information request or plugin feedback title: '' labels: '' assignees: '' From 270c8531933e90b84bf97962714f3efb2481b934 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 13 Nov 2020 16:24:11 +0000 Subject: [PATCH 0748/3183] Update feedback.md --- .github/ISSUE_TEMPLATE/feedback.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feedback.md b/.github/ISSUE_TEMPLATE/feedback.md index 26dacc4c..a4d6059a 100644 --- a/.github/ISSUE_TEMPLATE/feedback.md +++ b/.github/ISSUE_TEMPLATE/feedback.md @@ -1,6 +1,6 @@ --- -name: Information/Feedback -about: General information request or plugin feedback +name: Information Request/Feedback +about: Ask general information about this plugin or give valuable feedback title: '' labels: '' assignees: '' From b4c84265ce1167e0f082b8b11af1f3e6ca1ec0e9 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 13 Nov 2020 16:25:02 +0000 Subject: [PATCH 0749/3183] Update feature-request.md --- .github/ISSUE_TEMPLATE/feature-request.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md index 2726831a..b8ac8ae0 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -1,5 +1,5 @@ --- -name: Feature Request +name: Device/Feature Request about: I have an idea for the package or a device that isn't supported. title: '' labels: '' From e1b48f061d374eb95d8bed6d92976a9592fdde1f Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 13 Nov 2020 16:25:36 +0000 Subject: [PATCH 0750/3183] Update feedback.md --- .github/ISSUE_TEMPLATE/feedback.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/feedback.md b/.github/ISSUE_TEMPLATE/feedback.md index a4d6059a..aad5e776 100644 --- a/.github/ISSUE_TEMPLATE/feedback.md +++ b/.github/ISSUE_TEMPLATE/feedback.md @@ -1,5 +1,5 @@ --- -name: Information Request/Feedback +name: Information/Feedback Request about: Ask general information about this plugin or give valuable feedback title: '' labels: '' From 69d09ba68f13770ef2216ee154f55d20903256eb Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 13 Nov 2020 16:27:36 +0000 Subject: [PATCH 0751/3183] Update new-issue.md --- .github/ISSUE_TEMPLATE/new-issue.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/new-issue.md b/.github/ISSUE_TEMPLATE/new-issue.md index fb970abc..9fc6f8a6 100644 --- a/.github/ISSUE_TEMPLATE/new-issue.md +++ b/.github/ISSUE_TEMPLATE/new-issue.md @@ -1,6 +1,6 @@ --- -name: New Issue -about: I have a problem with the package or it's showing an error. +name: Problem/Bug Alert +about: The plugin isn't working as you'd expect it to, or it showing an error. title: '' labels: '' assignees: '' From 3461c57d6c22b8c0931de739d045758b3999a65a Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 13 Nov 2020 16:31:38 +0000 Subject: [PATCH 0752/3183] Update feature-request.md --- .github/ISSUE_TEMPLATE/feature-request.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md index b8ac8ae0..bf295a05 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -1,6 +1,6 @@ --- -name: Device/Feature Request -about: I have an idea for the package or a device that isn't supported. +name: 🆕 Device/Feature Request +about: Submit new ideas for the plugin or request support for a new device. title: '' labels: '' assignees: '' From 4aaf5445f5aac48878b15e4d31c96cf32b608942 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 13 Nov 2020 16:32:51 +0000 Subject: [PATCH 0753/3183] Update feedback.md --- .github/ISSUE_TEMPLATE/feedback.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/feedback.md b/.github/ISSUE_TEMPLATE/feedback.md index aad5e776..3589a888 100644 --- a/.github/ISSUE_TEMPLATE/feedback.md +++ b/.github/ISSUE_TEMPLATE/feedback.md @@ -1,5 +1,5 @@ --- -name: Information/Feedback Request +name: ℹī¸ Information/Feedback Request about: Ask general information about this plugin or give valuable feedback title: '' labels: '' From 7fcb621516903cb6299f14824f900dc872256cb9 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 13 Nov 2020 16:33:23 +0000 Subject: [PATCH 0754/3183] Update feedback.md --- .github/ISSUE_TEMPLATE/feedback.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/feedback.md b/.github/ISSUE_TEMPLATE/feedback.md index 3589a888..593bb9f4 100644 --- a/.github/ISSUE_TEMPLATE/feedback.md +++ b/.github/ISSUE_TEMPLATE/feedback.md @@ -1,6 +1,6 @@ --- name: ℹī¸ Information/Feedback Request -about: Ask general information about this plugin or give valuable feedback +about: Ask general information about this plugin or give valuable feedback. title: '' labels: '' assignees: '' From d2838d7d4dfbe8652794ae103b3a7c56c20c0a9b Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 13 Nov 2020 16:34:19 +0000 Subject: [PATCH 0755/3183] Update new-issue.md --- .github/ISSUE_TEMPLATE/new-issue.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/new-issue.md b/.github/ISSUE_TEMPLATE/new-issue.md index 9fc6f8a6..67567e77 100644 --- a/.github/ISSUE_TEMPLATE/new-issue.md +++ b/.github/ISSUE_TEMPLATE/new-issue.md @@ -1,6 +1,6 @@ --- -name: Problem/Bug Alert -about: The plugin isn't working as you'd expect it to, or it showing an error. +name: 🚨 Problem/Bug Alert +about: The plugin isn't working as expected or it's showing an error. title: '' labels: '' assignees: '' From 0348633f1630193e256f89aca1eb2142ba18880b Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 13 Nov 2020 16:35:04 +0000 Subject: [PATCH 0756/3183] Update config.yml --- .github/ISSUE_TEMPLATE/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index f43c4539..aa1e0229 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: false contact_links: - - name: Homebridge Discord + - name: 🌐 Homebridge Discord url: https://discord.gg/7X36mdw about: The Homebridge Discord is a community where you can ask questions and get general help with Homebridge and plugins. You can also message me directly on there - my username is bwp91. From 984ccd845bb6970763ba4c382e769885f66f0861 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Fri, 13 Nov 2020 16:36:07 +0000 Subject: [PATCH 0757/3183] Update config.yml --- .github/ISSUE_TEMPLATE/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index aa1e0229..568f5076 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: false contact_links: - - name: 🌐 Homebridge Discord + - name: 🌍 Homebridge Discord url: https://discord.gg/7X36mdw about: The Homebridge Discord is a community where you can ask questions and get general help with Homebridge and plugins. You can also message me directly on there - my username is bwp91. From 0b049d8764450d2d9e0e00179e0aad249d101553 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 14 Nov 2020 13:20:13 +0000 Subject: [PATCH 0758/3183] Update ewelink-platform.js --- lib/ewelink-platform.js | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 81270cf1..cd7f2ccd 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -346,23 +346,12 @@ module.exports = class eWeLinkPlatform { /*********************** SWITCHES [MULTI CHANNEL] ***********************/ - if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid + 'SW0')) { - if (this.devicesInHB.has(device.deviceid + 'SW0')) { - this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW0')) - } - this.hiddenMasters.push(device.deviceid) - accessory = this.addAccessory(device, device.deviceid + 'SW0', true) - } else { - accessory = this.devicesInHB.has(device.deviceid + 'SW0') - ? this.devicesInHB.get(device.deviceid + 'SW0') - : this.addAccessory(device, device.deviceid + 'SW0') - } - accessory.control = new deviceSwitchMulti(this, accessory) - for (let i = 1; i <= helpers.chansFromUiid[device.extra.uiid]; i++) { + for (let i = 0; i <= helpers.chansFromUiid[device.extra.uiid]; i++) { if ((this.config.hideChanFromHB || '').split(',').includes(device.deviceid + 'SW' + i)) { if (this.devicesInHB.has(device.deviceid + 'SW' + i)) { this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + i)) } + if (i === 0) this.hiddenMasters.push(device.deviceid) oAccessory = this.addAccessory(device, device.deviceid + 'SW' + i, true) } else { oAccessory = this.devicesInHB.has(device.deviceid + 'SW' + i) @@ -376,6 +365,7 @@ module.exports = class eWeLinkPlatform { oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false oAccessory.control = new deviceSwitchMulti(this, oAccessory) this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) + if (i === 0) accessory = oAccessory } /**********************/ } else if (helpers.devicesRFBridge.includes(device.extra.uiid)) { From a43335d20c6ede7ba4746f02cf810ed96f99cc99 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 14 Nov 2020 13:24:42 +0000 Subject: [PATCH 0759/3183] change var name --- lib/ewelink-ws.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/ewelink-ws.js b/lib/ewelink-ws.js index 88c78b84..8392878e 100644 --- a/lib/ewelink-ws.js +++ b/lib/ewelink-ws.js @@ -7,14 +7,14 @@ const helpers = require('./helpers') const ws = require('ws') const wsp = require('websocket-as-promised') module.exports = class eWeLinkWS { - constructor (config, log, res) { + constructor (config, log, authData) { this.config = config this.log = log this.debug = this.config.debug || false this.debugReqRes = this.config.debugReqRes || false - this.httpHost = res.httpHost - this.aToken = res.aToken - this.apiKey = res.apiKey + this.httpHost = authData.httpHost + this.aToken = authData.aToken + this.apiKey = authData.apiKey this.wsIsOpen = false this.emitter = new eventEmitter() } From 75c4a80b19688caa3b773d760b7eadc4b7b8b032 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 14 Nov 2020 14:47:08 +0000 Subject: [PATCH 0760/3183] add comments to file --- lib/ewelink-platform.js | 112 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 103 insertions(+), 9 deletions(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index cd7f2ccd..6e848d06 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -32,12 +32,15 @@ const promInterval = require('interval-promise') const version = require('./../package.json').version module.exports = class eWeLinkPlatform { constructor (log, config, api) { + // *** Disable the plugin if not configured correctly *** \\ if (!log || !api || !config) return if (!config.username || !config.password || !config.countryCode) { log.warn('*** Disabling plugin [v%s] ***', version) log.warn('*** eWeLink credentials missing from configuration ***') return } + + // *** Set up our variables *** \\ this.log = log this.config = config this.api = api @@ -57,50 +60,79 @@ module.exports = class eWeLinkPlatform { this.config.ipOverride = this.ipOverrideTmp this.wsRefreshFlag = true this.eveLogPath = this.api.user.storagePath() + '/persist/' + + // *** Set up Homebridge API events *** \\ this.api - .on('didFinishLaunching', () => this.eWeLinkSetup()) - .on('shutdown', () => this.eWeLinkShutdown()) + .on('didFinishLaunching', this.eWeLinkSetup.bind(this)) + .on('shutdown', this.eWeLinkShutdown.bind(this)) } async eWeLinkSetup () { try { + // *** Check to see if the user has disabled the plugin *** \\ if (this.config.disablePlugin) { this.devicesInHB.forEach(a => this.removeAccessory(a)) this.log.warn('*** Disabling plugin [v%s] ***', version) this.log.warn('*** To change this, set disablePlugin to false ***') return } + + // *** Set up initial sync with eWeLink *** \\ this.log('Plugin [v%s] initialised. Syncing with eWeLink...', version) + + // *** Set up the HTTP client, get the user HTTP host, and login *** \\ this.httpClient = new eWeLinkHTTP(this.config, this.log) await this.httpClient.getHost() this.authData = await this.httpClient.login() + + // *** Get a device list and add to the devicesInEW map *** \\ const deviceList = await this.httpClient.getDevices() deviceList.forEach(device => this.devicesInEW.set(device.deviceid, device)) + + // *** Set up the WS client, get the user WS host, and login *** \\ this.wsClient = new eWeLinkWS(this.config, this.log, this.authData) await this.wsClient.getHost() this.wsClient.login() + + // *** Set up the LAN client, scan for devices and start monitoring *** \\ this.lanClient = new eWeLinkLAN(this.config, this.log, deviceList) this.lanDevices = await this.lanClient.getHosts() await this.lanClient.startMonitor() + + // *** Check for valid Accessory Simulations and add to cusG for later use *** \\ if (Object.keys(this.config.groups || []).length > 0) { this.config.groups .filter(g => helpers.hasProperty(g, 'type') && helpers.allowedGroups.includes(g.type)) .filter(g => helpers.hasProperty(g, 'deviceId') && this.devicesInEW.has(g.deviceId)) .forEach(g => this.cusG.set(g.deviceId + 'SWX', g)) } + + // *** Check for valid custom RF Bridge sensors and add to cusS for later use *** \\ if (Object.keys(this.config.bridgeSensors || []).length > 0) { this.config.bridgeSensors .filter(s => helpers.hasProperty(s, 'deviceId') && this.devicesInEW.has(s.deviceId)) .forEach(s => this.cusS.set(s.fullDeviceId, s)) } + + // *** Logging for informative purposes *** \\ this.log('[%s] eWeLink devices loaded from the Homebridge cache.', this.devicesInHB.size) this.log('[%s] primary devices loaded from your eWeLink account.', this.devicesInEW.size) - this.devicesInHB.forEach(a => { - if (!this.devicesInEW.has(a.context.eweDeviceId)) this.removeAccessory(a) + + // *** Remove HB accessories that are no longer in eWeLink account *** \\ + this.devicesInHB.forEach(accessory => { + if (!this.devicesInEW.has(accessory.context.eweDeviceId)) { + this.removeAccessory(accessory) + } }) - this.devicesInEW.forEach(d => this.initialiseDevice(d)) - this.wsClient.receiveUpdate(d => this.receiveDeviceUpdate(d)) - this.lanClient.receiveUpdate(d => this.receiveDeviceUpdate(d)) + + // *** Initialise each device into HB *** \\ + this.devicesInEW.forEach(device => this.initialiseDevice(device)) + + // *** Set up the WS and LAN listener for device updates *** \\ + this.wsClient.receiveUpdate(device => this.receiveDeviceUpdate(device)) + this.lanClient.receiveUpdate(device => this.receiveDeviceUpdate(device)) + + // *** Refresh the WS connection every 30 minutes *** \\ this.wsRefresh = promInterval(async () => { if (this.wsRefreshFlag) { try { @@ -115,13 +147,18 @@ module.exports = class eWeLinkPlatform { } } }, 1800000, { stopOnError: false }) + + // *** Logging for informative purposes *** \\ this.log("eWeLink sync complete. Don't forget to ⭐ī¸ this plugin on GitHub if you're finding it useful!") if (this.config.debugReqRes) { this.log.warn("Note: 'Request & Response Logging' is not advised for long-term use.") } } catch (err) { + // *** Catch errors at any point during setup *** \\ this.log.warn('*** Disabling plugin [v%s] ***', version) this.log.warn(this.debug ? err : err.message) + + // *** Attempt to close WS (and refresh interval) and stop LAN monitor if this has been setup *** \\ try { if (this.lanClient) this.lanClient.closeConnection() if (this.wsClient) this.wsClient.closeConnection() @@ -133,6 +170,7 @@ module.exports = class eWeLinkPlatform { } eWeLinkShutdown () { + // *** Attempt to close WS (and refresh interval) and stop LAN monitor if this has been setup *** \\ try { if (this.lanClient) this.lanClient.closeConnection() if (this.wsClient) this.wsClient.closeConnection() @@ -145,7 +183,9 @@ module.exports = class eWeLinkPlatform { initialiseDevice (device) { let accessory let oAccessory + try { + // *** Remove old switch services for new Accessory Simulations *** \\ if (this.cusG.has(device.deviceid + 'SWX')) { ;['X', '0', '1', '2', '3', '4'].forEach(sw => { if (this.devicesInHB.has(device.deviceid + 'SW' + sw)) { @@ -155,6 +195,8 @@ module.exports = class eWeLinkPlatform { } }) } + + // *** Set up the correct instance for this particular device *** \\ if (helpers.devicesCurtain.includes(device.extra.uiid)) { /*********************** BLINDS [EWELINK UIID 11] @@ -471,16 +513,22 @@ module.exports = class eWeLinkPlatform { return /*********/ } + + // *** Update the current firmware version *** \\ if (!this.hiddenMasters.includes(device.deviceid)) { accessory .getService(this.Service.AccessoryInformation) .setCharacteristic(this.Characteristic.FirmwareRevision, device.params.fwVersion) } + + // *** Update the reachability values (via WS and LAN) *** \\ accessory.context.reachableWAN = device.online accessory.context.reachableLAN = this.lanDevices.has(device.deviceid) ? this.lanDevices.get(device.deviceid).online : false accessory.context.inUse = false + + // *** Helpful logging for each device *** \\ let str = accessory.context.reachableLAN ? 'and found locally with IP [' + this.lanDevices.get(device.deviceid).ip + ']' : 'but LAN mode unavailable as device ' @@ -493,10 +541,15 @@ module.exports = class eWeLinkPlatform { str += 'is unreachable' } } + + // *** Update accessory characteristics with latest values *** \\ if (!this.config.disableHTTPRefresh) accessory.control.externalUpdate(device.params) + + // *** Update any changes to the device into our devicesInHB map *** \\ this.devicesInHB.set(accessory.context.hbDeviceId, accessory) this.log(' → [%s] initialised %s.', device.name, str) } catch (err) { + // *** Catch errors at any point during device initialisation *** \\ const deviceName = accessory && helpers.hasProperty(accessory, 'displayName') ? accessory.displayName : device.name @@ -505,7 +558,10 @@ module.exports = class eWeLinkPlatform { } addAccessory (device, hbDeviceId, hidden = false, extraContext = {}, type = '') { + // *** Get the switchNumber which can be {X, 0, 1, 2, 3, 4, ...} *** \\ const switchNumber = hbDeviceId.split('SW')[1].toString() + + // *** Set up the device name which can depend on the accessory type *** \\ let newDeviceName = type === 'rf_sub' ? device.tags.zyx_info[switchNumber - 1].name : device.name const channelCount = type === 'rf_pri' ? Object.keys((device.tags && device.tags.zyx_info) || []).length @@ -524,6 +580,8 @@ module.exports = class eWeLinkPlatform { if (helpers.hasProperty(this.config.nameOverride, hbDeviceId)) { newDeviceName = this.config.nameOverride[hbDeviceId] } + + // *** Add the new accessory to Homebridge *** \\ try { const accessory = new this.api.platformAccessory(newDeviceName, this.api.hap.uuid.generate(hbDeviceId).toString()) if (!hidden) { @@ -535,10 +593,12 @@ module.exports = class eWeLinkPlatform { .setCharacteristic(this.Characteristic.FirmwareRevision, device.params.fwVersion || version) .setCharacteristic(this.Characteristic.Identify, true) accessory.on('identify', (paired, callback) => { - this.log('[%s] - identify button pressed.', accessory.displayName) callback() + this.log('[%s] - identify button pressed.', accessory.displayName) }) } + + // *** Add helpful context values to the accessory *** \\ accessory.context = { ...{ hbDeviceId, @@ -551,27 +611,38 @@ module.exports = class eWeLinkPlatform { }, ...extraContext } + + // *** Register the accessory if it hasn't been hidden by the user *** \\ if (!hidden) { this.api.registerPlatformAccessories('homebridge-ewelink', 'eWeLink', [accessory]) this.log(' → [%s] has been added to Homebridge.', newDeviceName) } + + // *** Return the new accessory *** \\ return accessory } catch (err) { + // *** Add helpful context values to the accessory *** \\ this.log.warn(' → [%s] could not be added as %s.', newDeviceName, err) return false } } async sendDeviceUpdate (accessory, params) { + // *** Set up the payload to send via LAN/WS *** \\ const payload = { apikey: accessory.context.eweApiKey, deviceid: accessory.context.eweDeviceId, params } + + // *** Quick check to see if LAN mode is supported *** \\ const res = helpers.devicesNonLAN.includes(accessory.context.eweUIID) ? 'LAN mode is not supported for this device' : await this.lanClient.sendUpdate(payload) + + // *** Revert to WS if LAN mode not possible for whatever reason *** \\ if (res !== 'ok') { + // *** Check to see if the device is online *** \\ if (accessory.context.reachableWAN) { if (this.debug) this.log('[%s] Reverting to web socket as %s.', accessory.displayName, res) await this.wsClient.sendUpdate(payload) @@ -582,12 +653,15 @@ module.exports = class eWeLinkPlatform { } async receiveDeviceUpdate (device) { - let accessory const deviceId = device.deviceid + let accessory let reachableChange = false + + // *** Find our accessory for which the updates relates to *** \\ if ((accessory = this.devicesInHB.get(deviceId + 'SWX') || this.devicesInHB.get(deviceId + 'SW0'))) { const isX = accessory.context.hbDeviceId.substr(-1) === 'X' if (device.params.updateSource === 'WS') { + // *** The update is from WS so update the WS online/offline status *** \\ if (device.params.online !== accessory.context.reachableWAN) { accessory.context.reachableWAN = device.params.online this.devicesInHB.set(accessory.context.hbDeviceId, accessory) @@ -603,6 +677,7 @@ module.exports = class eWeLinkPlatform { } } if (device.params.updateSource === 'LAN' && !accessory.context.reachableLAN) { + // *** The update is from LAN so update the LAN online/offline status *** \\ accessory.context.reachableLAN = true this.devicesInHB.set(accessory.context.hbDeviceId, accessory) reachableChange = true @@ -613,7 +688,10 @@ module.exports = class eWeLinkPlatform { this.log.warn('[%s] update could not be requested as %s', accessory.displayName, this.debug ? err.message : err) } } + + // *** Update this new online/offline status for all switches of multi channel devices (ie not X) *** \\ if (reachableChange && !isX) { + // *** Loop through to see which channels are in HB *** \\ for (let i = 1; i <= accessory.context.channelCount; i++) { if (this.devicesInHB.has(deviceId + 'SW' + i)) { const oAccessory = this.devicesInHB.get(deviceId + 'SW' + i) @@ -629,17 +707,27 @@ module.exports = class eWeLinkPlatform { this.log('[%s] %s update received and will be refreshed.', accessory.displayName, device.params.updateSource) } try { + // *** Update the accessory with the new data *** \\ accessory.control.externalUpdate(device.params) } catch (err) { this.log.warn('[%s] could not be refreshed as %s.', accessory.displayName, this.debug ? err : err.message) } } else { + // *** The device does not existing in HB so let's try to add it *** \\ try { + // *** Check to see it doesn't exist because it's user hidden *** \\ if ((this.config.hideDevFromHB || '').includes(deviceId)) return + + // *** Obtain full device information from the HTTP API *** \\ const newDevice = await this.httpClient.getDevice(deviceId) + + // *** Initialise the device in HB *** \\ this.initialiseDevice(newDevice) + + // *** Add the device to the LAN client map *** \\ this.lanClient.addDeviceToMap(newDevice) } catch (err) { + // *** Automatically adding the new device failed for some reason *** \\ this.log.warn('[%s] restart Homebridge to add new device, failed to add automatically as %s.', deviceId, err.message) } } @@ -647,6 +735,8 @@ module.exports = class eWeLinkPlatform { async deviceUpdateError (accessory, err, requestRefresh) { this.log.warn('[%s] could not be updated as %s.', accessory.displayName, this.debug ? err : err.message) + + // *** We only request a device refresh on failed internal updates (ie with 'set' handlers) *** \\ if (requestRefresh) { if (accessory.context.reachableWAN) { try { @@ -660,12 +750,16 @@ module.exports = class eWeLinkPlatform { } configureAccessory (accessory) { + // *** Function is called for each device on HB start *** \\ if (!this.log) return + + // *** Add each cached device to our devicesInHB map *** \\ this.devicesInHB.set(accessory.context.hbDeviceId, accessory) } removeAccessory (accessory) { try { + // *** Unregister the accessory from HB and remove it from our devicesInHB map *** \\ this.api.unregisterPlatformAccessories('homebridge-ewelink', 'eWeLink', [accessory]) this.devicesInHB.delete(accessory.context.hbDeviceId) this.log(' → [%s] was removed from Homebridge.', accessory.displayName) From 081e364e35e87fdddc2b893a22935738b72920ae Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 14 Nov 2020 14:50:53 +0000 Subject: [PATCH 0761/3183] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 9ac72c70..806afeca 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,9 @@ Homebridge/HOOBS plugin to control eWeLink devices with original firmware. * To use this plugin, you will need to already have [Homebridge](https://homebridge.io) or [HOOBS](https://hoobs.org) installed. Please refer to the links for more information and installation instructions. ### Plugin Information +* This plugin uses your eWeLink credentials to obtain and control your devices +* This plugin uses a web socket for real-time device control and updates +* This plugin also allows LAN control for devices that support it ### Setup * [Installation (Homebridge)](https://github.com/bwp91/homebridge-ewelink/wiki/Installation-(Homebridge)) From f4c527925a66e67175229ab23f923ca431b9fa06 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 14 Nov 2020 14:51:44 +0000 Subject: [PATCH 0762/3183] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 806afeca..653b250d 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,9 @@ Homebridge/HOOBS plugin to control eWeLink devices with original firmware. * To use this plugin, you will need to already have [Homebridge](https://homebridge.io) or [HOOBS](https://hoobs.org) installed. Please refer to the links for more information and installation instructions. ### Plugin Information -* This plugin uses your eWeLink credentials to obtain and control your devices -* This plugin uses a web socket for real-time device control and updates -* This plugin also allows LAN control for devices that support it +* This plugin uses your eWeLink credentials to obtain and control your devices through Homebridge. +* This plugin uses a web socket for real-time device control and updates. +* This plugin also supports LAN control for certain devices that support it. ### Setup * [Installation (Homebridge)](https://github.com/bwp91/homebridge-ewelink/wiki/Installation-(Homebridge)) From c3abd0945b6553c6faa00abfc7779d8d1b54e8a5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 14 Nov 2020 15:00:53 +0000 Subject: [PATCH 0763/3183] Update fakegato-history.js --- lib/fakegato/fakegato-history.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/fakegato/fakegato-history.js b/lib/fakegato/fakegato-history.js index 7b0d19d0..1b9b19db 100644 --- a/lib/fakegato/fakegato-history.js +++ b/lib/fakegato/fakegato-history.js @@ -821,7 +821,7 @@ module.exports = function (pHomebridge) { setCurrentS2W1(val, callback) { - callback(null, val); + callback(null); this.log.debug("Data request %s: %s", this.accessoryName, base64ToHex(val)); var valHex = base64ToHex(val); var substring = valHex.substring(4, 12); @@ -836,7 +836,7 @@ module.exports = function (pHomebridge) { setCurrentS2W2(val, callback) { this.log.debug("Clock adjust %s: %s", this.accessoryName, base64ToHex(val)); - callback(null, val); + callback(null); } } From 9d875606916df3c803f37504ca9510cfed1129e6 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sat, 14 Nov 2020 15:25:06 +0000 Subject: [PATCH 0764/3183] Update new-issue.md --- .github/ISSUE_TEMPLATE/new-issue.md | 41 ++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/new-issue.md b/.github/ISSUE_TEMPLATE/new-issue.md index 67567e77..137d97aa 100644 --- a/.github/ISSUE_TEMPLATE/new-issue.md +++ b/.github/ISSUE_TEMPLATE/new-issue.md @@ -7,24 +7,45 @@ assignees: '' --- + + **What issue do you have? Please be as thorough and explicit as possible.** + -... **Details of your setup.** -Do you use Homebridge or HOOBS? +* Do you use Homebridge (with config-ui?) or HOOBS? + + + +* Which version of Homebridge/HOOBS do you have? + + + +* Which version of this plugin (homebridge-ewelink) do you have? + -... -Which version of Homebridge/HOOBS do you have? +* Which eWeLink devices do you have that are causing issues? -... -Which version of this plugin (homebridge-ewelink) do you have? -... +**Please paste any relevant logs below.** + -**Please paste any relevant logs below. It helps if you can turn `debug` and `debugReqRes` in the package settings for more thorough logging.** -> If you are posting an error then it is helpful for me to also see the previous few lines as this can show the cause of the error. +``` -... +``` From 5dcd3012902f4168e72b50619eee3c21084b66ce Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sat, 14 Nov 2020 15:26:04 +0000 Subject: [PATCH 0765/3183] Update new-issue.md --- .github/ISSUE_TEMPLATE/new-issue.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/new-issue.md b/.github/ISSUE_TEMPLATE/new-issue.md index 137d97aa..88fc799a 100644 --- a/.github/ISSUE_TEMPLATE/new-issue.md +++ b/.github/ISSUE_TEMPLATE/new-issue.md @@ -14,6 +14,8 @@ assignees: '' * This is not the place for issues with the homebridge-ewelink-max plugin. I am not the owner of homebridge-ewelink-max --> + + **What issue do you have? Please be as thorough and explicit as possible.** + **Details of your setup.** * Do you use Homebridge (with config-ui?) or HOOBS? From bafc6e08d1b59d1b550a0ac99a6b596ef2b2f8df Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sat, 14 Nov 2020 15:27:00 +0000 Subject: [PATCH 0766/3183] Update new-issue.md --- .github/ISSUE_TEMPLATE/new-issue.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/new-issue.md b/.github/ISSUE_TEMPLATE/new-issue.md index 88fc799a..7fb6c8ac 100644 --- a/.github/ISSUE_TEMPLATE/new-issue.md +++ b/.github/ISSUE_TEMPLATE/new-issue.md @@ -13,10 +13,7 @@ assignees: '' * Are you using a second eWeLink account for Homebridge? Please try using your main eWeLink account instead. * This is not the place for issues with the homebridge-ewelink-max plugin. I am not the owner of homebridge-ewelink-max --> - - - -**What issue do you have? Please be as thorough and explicit as possible.** +### What issue do you have? Please be as thorough and explicit as possible. + * This is not the place for issues with the homebridge-ewelink-max plugin. I am not the owner of homebridge-ewelink-max --> + ### What issue do you have? Please be as thorough and explicit as possible. - @@ -31,7 +24,7 @@ assignees: '' -* Which version of this plugin (homebridge-ewelink) do you have? +* Which version of this plugin (homebridge-ewelink) do you have? Has the issue started since upgrading from a previous version? @@ -39,6 +32,10 @@ assignees: '' +* Do you use your main eWeLink credentials or do you use a secondary eWeLink account for Homebridge? + + + ### Please paste any relevant logs below. From c0b3b5e75941fbd5f024bebba96bb1d7ead61236 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 15 Nov 2020 13:50:26 +0000 Subject: [PATCH 0780/3183] update in api --- lib/ewelink-platform.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 6e848d06..69f65895 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -406,6 +406,7 @@ module.exports = class eWeLinkPlatform { oAccessory.context.reachableWAN = device.online oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false oAccessory.control = new deviceSwitchMulti(this, oAccessory) + this.api.updatePlatformAccessories('homebridge-ewelink', 'eWeLink', [oAccessory]) this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) if (i === 0) accessory = oAccessory } @@ -473,6 +474,7 @@ module.exports = class eWeLinkPlatform { .setCharacteristic(this.Characteristic.FirmwareRevision, device.params.fwVersion) oAccessory.context.reachableWAN = device.online oAccessory.context.reachableLAN = false + this.api.updatePlatformAccessories('homebridge-ewelink', 'eWeLink', [oAccessory]) this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) oAccessory.control = new deviceRFBridge(this, oAccessory) rfChlCounter += Object.keys(subDevice.buttons || {}).length @@ -546,6 +548,7 @@ module.exports = class eWeLinkPlatform { if (!this.config.disableHTTPRefresh) accessory.control.externalUpdate(device.params) // *** Update any changes to the device into our devicesInHB map *** \\ + this.api.updatePlatformAccessories('homebridge-ewelink', 'eWeLink', [accessory]) this.devicesInHB.set(accessory.context.hbDeviceId, accessory) this.log(' → [%s] initialised %s.', device.name, str) } catch (err) { From 5691401f0badfc4806d17194c9fc6b2d7b8cebe1 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 15 Nov 2020 20:12:38 +0000 Subject: [PATCH 0781/3183] ifan fix --- lib/device/fan.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/fan.js b/lib/device/fan.js index 2cf0d5c4..0d07d565 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -52,7 +52,7 @@ module.exports = class deviceFan { } } - async internalLightUpdate (type, value, callback) { + async internalLightUpdate (value, callback) { try { callback() const params = { switches: helpers.defaultMultiSwitchOff } From e8ce72c9dcdeb15dee0dc41192ba5d0068f5966e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 15 Nov 2020 20:13:40 +0000 Subject: [PATCH 0782/3183] 3.13.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9e4aad0d..1856a69f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.0", + "version": "3.13.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 15b62df7..2637b4fc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.0", + "version": "3.13.1", "author": "bwp91", "contributors": [ "gbro115", From 4b11ec35b825efe6fa0f67281b242a0aba66f34a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 15 Nov 2020 21:32:02 +0000 Subject: [PATCH 0783/3183] S26R1 to outlet list --- lib/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers.js b/lib/helpers.js index c2dd2917..9b8c344d 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -17,7 +17,7 @@ module.exports = { devicesNonLAN: [22, 28, 34, 59, 102, 103, 104], devicesSingleSwitch: [1, 5, 6, 14, 15, 22, 24, 27, 32, 36, 44, 59, 104], devicesMultiSwitch: [2, 3, 4, 7, 8, 9, 29, 30, 31, 34, 41], - devicesSingleSwitchOutlet: ['Sonoff Pow', 'S20', 'S26', 'S55', 'S55R1'], + devicesSingleSwitchOutlet: ['Sonoff Pow', 'S20', 'S26', 'S26R1', 'S55', 'S55R1'], devicesBrightable: [36, 44], devicesColourable: [22, 59, 104], devicesCTempable: [103], From c0b25f4ae1824d559a38e880772ff314c1e41f60 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 15 Nov 2020 21:33:20 +0000 Subject: [PATCH 0784/3183] 3.13.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1856a69f..7ca49bfc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.1", + "version": "3.13.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 2637b4fc..3463f65c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.1", + "version": "3.13.2", "author": "bwp91", "contributors": [ "gbro115", From ac494c4dbce293e10f3c6c74b7d6794d344a33f9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 16 Nov 2020 08:25:27 +0000 Subject: [PATCH 0785/3183] negative celcuis to sensors --- lib/device/thermostat.js | 4 ++++ lib/device/zb-dev.js | 9 +++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index 2c3ac02b..1fb67384 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -20,6 +20,10 @@ module.exports = class deviceThermostat { .on('set', this.internalUpdate.bind(this)) } this.tempService = accessory.getService(this.Service.TemperatureSensor) || accessory.addService(this.Service.TemperatureSensor) + this.tempService.getCharacteristic(this.Characteristic.CurrentTemperature) + .setProps({ + minValue: -100 + }) if (accessory.context.sensorType !== 'DS18B20') { this.humiService = accessory.getService(this.Service.HumiditySensor) || accessory.addService(this.Service.HumiditySensor) } diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index 4f9a2939..e4460cc0 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -47,9 +47,13 @@ module.exports = class deviceZBDev { .getCharacteristic(this.Characteristic.On) .on('set', this.internalUpdate.bind(this)) break - case 1770: + case 1770: { if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) - if (!accessory.getService(this.Service.TemperatureSensor)) accessory.addService(this.Service.TemperatureSensor) + const tempService = accessory.getService(this.Service.TemperatureSensor) || accessory.addService(this.Service.TemperatureSensor) + tempService.getCharacteristic(this.Characteristic.CurrentTemperature) + .setProps({ + minValue: -100 + }) if (!accessory.getService(this.Service.HumiditySensor)) accessory.addService(this.Service.HumiditySensor) accessory.log = this.platform.log accessory.eveLogger = new this.EveHistoryService('weather', accessory, { @@ -57,6 +61,7 @@ module.exports = class deviceZBDev { path: this.platform.eveLogPath }) break + } case 2026: if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) if (!accessory.getService(this.Service.MotionSensor)) accessory.addService(this.Service.MotionSensor) From fe5be1b656aa737d20af4ffaec3ba29fbb529ec9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 16 Nov 2020 08:26:10 +0000 Subject: [PATCH 0786/3183] 3.13.3-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7ca49bfc..160ca629 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.2", + "version": "3.13.3-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 3463f65c..bce95257 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.2", + "version": "3.13.3-0", "author": "bwp91", "contributors": [ "gbro115", From d81b1fa7fa9d11d2a20730cb54d3ab512d561f13 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 16 Nov 2020 09:29:04 +0000 Subject: [PATCH 0787/3183] fix for adding multi switch on the go --- lib/ewelink-platform.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 69f65895..f062a42d 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -404,7 +404,9 @@ module.exports = class eWeLinkPlatform { .setCharacteristic(this.Characteristic.FirmwareRevision, device.params.fwVersion) } oAccessory.context.reachableWAN = device.online - oAccessory.context.reachableLAN = this.lanDevices.get(device.deviceid).online || false + oAccessory.context.reachableLAN = this.lanDevices.has(device.deviceid) + ? this.lanDevices.get(device.deviceid).online + : false oAccessory.control = new deviceSwitchMulti(this, oAccessory) this.api.updatePlatformAccessories('homebridge-ewelink', 'eWeLink', [oAccessory]) this.devicesInHB.set(oAccessory.context.hbDeviceId, oAccessory) From e1c62793fc6534f44d338103c2be87c5839f2b68 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 16 Nov 2020 10:03:36 +0000 Subject: [PATCH 0788/3183] 3.13.3-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 160ca629..89861c70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.3-0", + "version": "3.13.3-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index bce95257..2e15554e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.3-0", + "version": "3.13.3-1", "author": "bwp91", "contributors": [ "gbro115", From 1e98235bc9251ce19343c22f2e6dbeb99458a305 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 16 Nov 2020 13:52:52 +0000 Subject: [PATCH 0789/3183] 3.13.3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 89861c70..82e1afb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.3-1", + "version": "3.13.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 2e15554e..adbd8114 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.3-1", + "version": "3.13.3", "author": "bwp91", "contributors": [ "gbro115", From 8fa1fd8867884c68f696682ba605daa757f58d4e Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 16 Nov 2020 20:28:57 +0000 Subject: [PATCH 0790/3183] Create no-response.yml --- .github/no-response.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .github/no-response.yml diff --git a/.github/no-response.yml b/.github/no-response.yml new file mode 100644 index 00000000..4523097f --- /dev/null +++ b/.github/no-response.yml @@ -0,0 +1,10 @@ +# Number of days of inactivity before an Issue is closed for lack of response +daysUntilClose: 3 +# Label requiring a response +responseRequiredLabel: complete +# Comment to post when closing an Issue for lack of response. Set to `false` to disable +closeComment: > + This issue has been automatically closed as it was marked as complete and has had + no further responses within three days. If you are still experiencing problems related + to the original issue then please reply to this message and the issue will be reopened + if necessary. Thank you. From 6c4623805a0125c65ec5ea1c609b7f651fba8148 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 17 Nov 2020 10:10:48 +0000 Subject: [PATCH 0791/3183] accessory simulation updates --- config.schema.json | 6 ++ lib/device/switch-valve.js | 114 +++++++++++++++++++++++++++++++++++++ lib/device/valve-two.js | 18 +++--- lib/ewelink-platform.js | 22 ++++--- lib/helpers.js | 2 +- 5 files changed, 141 insertions(+), 21 deletions(-) create mode 100644 lib/device/switch-valve.js diff --git a/config.schema.json b/config.schema.json index e88eaa97..effe515e 100644 --- a/config.schema.json +++ b/config.schema.json @@ -176,6 +176,12 @@ "enum": [ "valve_two" ] + }, + { + "title": "1 Switch & 1 Valve (using multi-channel device)", + "enum": [ + "switch_valve" + ] } ] }, diff --git a/lib/device/switch-valve.js b/lib/device/switch-valve.js new file mode 100644 index 00000000..146504f2 --- /dev/null +++ b/lib/device/switch-valve.js @@ -0,0 +1,114 @@ +/* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ +'use strict' +const fakegato = require('./../fakegato/fakegato-history') +const helpers = require('./../helpers') +module.exports = class deviceSwitchValve { + constructor (platform, accessory) { + this.platform = platform + this.Service = platform.api.hap.Service + this.Characteristic = platform.api.hap.Characteristic + this.EveHistoryService = fakegato(platform.api) + const valveConfig = this.platform.cusG.get(accessory.context.hbDeviceId) + this.switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) + if (!(this.valveService = accessory.getService(this.Service.Valve))) { + this.valveService = accessory.addService(this.Service.Valve) + this.valveService + .setCharacteristic(this.Characteristic.Active, 0) + .setCharacteristic(this.Characteristic.InUse, 0) + .setCharacteristic(this.Characteristic.ValveType, 1) + .setCharacteristic(this.Characteristic.SetDuration, Math.round((valveConfig.operationTime || 1200) / 10)) + .addCharacteristic(this.Characteristic.RemainingDuration) + } + this.switchService + .getCharacteristic(this.Characteristic.On) + .on('set', this.internalSwitchUpdate.bind(this)) + this.valveService + .getCharacteristic(this.Characteristic.Active) + .on('set', this.internalValveUpdate.bind(this)) + this.valveService + .getCharacteristic(this.Characteristic.SetDuration) + .on('set', (value, callback) => { + if (this.valveService.getCharacteristic(this.Characteristic.InUse).value) { + this.valveService.updateCharacteristic(this.Characteristic.RemainingDuration, value) + clearTimeout(this.valveService.timer) + this.valveService.timer = setTimeout(() => this.valveService.setCharacteristic(this.Characteristic.Active, 0), value * 1000) + } + callback() + }) + accessory.log = this.platform.log + accessory.eveLogger = new this.EveHistoryService('switch', accessory, { + storage: 'fs', + path: this.platform.eveLogPath + }) + this.accessory = accessory + } + + async internalSwitchUpdate (value, callback) { + try { + callback() + const params = { switches: helpers.defaultMultiSwitchOff } + params.switches[0].switch = value ? 'on' : 'off' + params.switches[1].switch = this.valveService.getCharacteristic(this.Characteristic.Active).value === 1 + ? 'on' + : 'off' + await this.platform.sendDeviceUpdate(this.accessory, params) + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async internalValveUpdate (value, callback) { + try { + callback() + const params = { switches: helpers.defaultMultiSwitchOff } + params.switches[0].switch = this.switchService.getCharacteristic(this.Characteristic.On) ? 'on' : 'off' + params.switches[1].switch = value === 1 ? 'on' : 'off' + this.valveService.updateCharacteristic(this.Characteristic.InUse, value) + switch (value) { + case 0: + this.valveService.updateCharacteristic(this.Characteristic.RemainingDuration, 0) + clearTimeout(this.valveService.timer) + break + case 1: { + const timer = this.valveService.getCharacteristic(this.Characteristic.SetDuration).value + this.valveService.updateCharacteristic(this.Characteristic.RemainingDuration, timer) + this.valveService.timer = setTimeout(() => this.valveService.setCharacteristic(this.Characteristic.Active, 0), timer * 1000) + break + } + } + await this.platform.sendDeviceUpdate(this.accessory, params) + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async externalUpdate (params) { + try { + if (!helpers.hasProperty(params, 'switches')) return + + this.switchService.updateCharacteristic(this.Characteristic.On, params.switches[0].switch === 'on') + this.accessory.eveLogger.addEntry({ + time: Math.round(new Date().valueOf() / 1000), + status: params.switch === 'on' ? 1 : 0 + }) + this.valveService + .updateCharacteristic(this.Characteristic.Active, params.switches[1].switch === 'on' ? 1 : 0) + .updateCharacteristic(this.Characteristic.InUse, params.switches[1].switch === 'on' ? 1 : 0) + if (params.switches[1].switch === 'on') { + if (this.valveService.getCharacteristic(this.Characteristic.Active).value === 0) { + // only start the timer if it isn't on already - we don't want to reset an "already on" timer + // if ewelink sends another update midway ie switch turning on/off + const timer = this.valveService.getCharacteristic(this.Characteristic.SetDuration).value + this.valveService.updateCharacteristic(this.Characteristic.RemainingDuration, timer) + this.valveService.timer = setTimeout(() => this.valveService.setCharacteristic(this.Characteristic.Active, 0), timer * 1000) + } + } else { + this.valveService.updateCharacteristic(this.Characteristic.RemainingDuration, 0) + clearTimeout(this.valveService.timer) + } + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, false) + } + } +} diff --git a/lib/device/valve-two.js b/lib/device/valve-two.js index 7cb2348d..3f3c9499 100644 --- a/lib/device/valve-two.js +++ b/lib/device/valve-two.js @@ -26,7 +26,7 @@ module.exports = class deviceValveTwo { valveService .getCharacteristic(this.Characteristic.SetDuration) .on('set', (value, callback) => { - if (valveService.getCharacteristic(this.Characteristic.InUse).value) { + if (valveService.getCharacteristic(this.Characteristic.InUse).value === 1) { valveService.updateCharacteristic(this.Characteristic.RemainingDuration, value) clearTimeout(valveService.timer) valveService.timer = setTimeout(() => valveService.setCharacteristic(this.Characteristic.Active, 0), value * 1000) @@ -45,12 +45,12 @@ module.exports = class deviceValveTwo { switch (valve) { case 'Valve A': params.switches[0].switch = value ? 'on' : 'off' - params.switches[1].switch = this.accessory.getService('Valve B').getCharacteristic(this.Characteristic.Active).value + params.switches[1].switch = this.accessory.getService('Valve B').getCharacteristic(this.Characteristic.Active).value === 1 ? 'on' : 'off' break case 'Valve B': - params.switches[0].switch = this.accessory.getService('Valve A').getCharacteristic(this.Characteristic.Active).value + params.switches[0].switch = this.accessory.getService('Valve A').getCharacteristic(this.Characteristic.Active).value === 1 ? 'on' : 'off' params.switches[1].switch = value ? 'on' : 'off' @@ -81,12 +81,14 @@ module.exports = class deviceValveTwo { ;['A', 'B'].forEach((v, k) => { const valveService = this.accessory.getService('Valve ' + v) valveService - .updateCharacteristic(this.Characteristic.Active, params.switches[k].switch === 'on') - .updateCharacteristic(this.Characteristic.InUse, params.switches[k].switch === 'on') + .updateCharacteristic(this.Characteristic.Active, params.switches[k].switch === 'on' ? 1 : 0) + .updateCharacteristic(this.Characteristic.InUse, params.switches[k].switch === 'on' ? 1 : 0) if (params.switches[k].switch === 'on') { - const timer = valveService.getCharacteristic(this.Characteristic.SetDuration).value - valveService.updateCharacteristic(this.Characteristic.RemainingDuration, timer) - valveService.timer = setTimeout(() => valveService.setCharacteristic(this.Characteristic.Active, 0), timer * 1000) + if (valveService.getCharacteristic(this.Characteristic.Active).value === 0) { + const timer = valveService.getCharacteristic(this.Characteristic.SetDuration).value + valveService.updateCharacteristic(this.Characteristic.RemainingDuration, timer) + valveService.timer = setTimeout(() => valveService.setCharacteristic(this.Characteristic.Active, 0), timer * 1000) + } } else { valveService.updateCharacteristic(this.Characteristic.RemainingDuration, 0) clearTimeout(valveService.timer) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index f062a42d..ff2dade0 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -22,6 +22,7 @@ const deviceLightCTemp = require('./device/light-ctemp') const deviceLightDimmer = require('./device/light-dimmer') const deviceSwitchMulti = require('./device/switch-multi') const deviceSwitchSingle = require('./device/switch-single') +const deviceSwitchValve = require('./device/switch-valve') const deviceRFBridge = require('./device/rf-bridge') const deviceZBDev = require('./device/zb-dev') const eWeLinkHTTP = require('./ewelink-http') @@ -183,19 +184,7 @@ module.exports = class eWeLinkPlatform { initialiseDevice (device) { let accessory let oAccessory - try { - // *** Remove old switch services for new Accessory Simulations *** \\ - if (this.cusG.has(device.deviceid + 'SWX')) { - ;['X', '0', '1', '2', '3', '4'].forEach(sw => { - if (this.devicesInHB.has(device.deviceid + 'SW' + sw)) { - if (this.devicesInHB.get(device.deviceid + 'SW' + sw).getService(this.Service.Switch)) { - this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + sw)) - } - } - }) - } - // *** Set up the correct instance for this particular device *** \\ if (helpers.devicesCurtain.includes(device.extra.uiid)) { /*********************** @@ -260,6 +249,15 @@ module.exports = class eWeLinkPlatform { : this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new deviceLock(this, accessory) /**************************/ + } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'switch_valve') { + /********************************** + SWITCH-VALVE [ACCESSORY SIMULATION] + **********************************/ + accessory = this.devicesInHB.has(device.deviceid + 'SWX') + ? this.devicesInHB.get(device.deviceid + 'SWX') + : this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new deviceSwitchValve(this, accessory) + /***************************/ } else if (this.cusG.has(device.deviceid + 'SWX') && this.cusG.get(device.deviceid + 'SWX').type === 'valve') { /********************************** VALVES [ONE] [ACCESSORY SIMULATION] diff --git a/lib/helpers.js b/lib/helpers.js index 9b8c344d..1590b916 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -7,7 +7,7 @@ module.exports = { appId: 'oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq', appSecret: '6Nz4n0xA8s8qdxQf2GqurZj2Fs55FUvM', httpRetryCodes: ['ENOTFOUND', 'ETIMEDOUT', 'EAI_AGAIN'], - allowedGroups: ['blind', 'garage', 'garage_two', 'garage_four', 'garage_eachen', 'lock', 'valve', 'valve_two'], + allowedGroups: ['blind', 'garage', 'garage_two', 'garage_four', 'garage_eachen', 'lock', 'switch_valve', 'valve', 'valve_two'], defaults: { inUsePowerThreshold: 0, lowBattThreshold: 25, From 08bf03aeb69b7248826a886f4e20cd0a83264ee3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 17 Nov 2020 10:22:17 +0000 Subject: [PATCH 0792/3183] Update switch-valve.js --- lib/device/switch-valve.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/switch-valve.js b/lib/device/switch-valve.js index 146504f2..42ac19bc 100644 --- a/lib/device/switch-valve.js +++ b/lib/device/switch-valve.js @@ -62,7 +62,7 @@ module.exports = class deviceSwitchValve { try { callback() const params = { switches: helpers.defaultMultiSwitchOff } - params.switches[0].switch = this.switchService.getCharacteristic(this.Characteristic.On) ? 'on' : 'off' + params.switches[0].switch = this.switchService.getCharacteristic(this.Characteristic.On).value ? 'on' : 'off' params.switches[1].switch = value === 1 ? 'on' : 'off' this.valveService.updateCharacteristic(this.Characteristic.InUse, value) switch (value) { From caab1868c3c0aeb3729470ace35222716384beb8 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 17 Nov 2020 10:22:58 +0000 Subject: [PATCH 0793/3183] 3.13.4-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 82e1afb1..51270860 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.3", + "version": "3.13.4-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index adbd8114..3114d367 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.3", + "version": "3.13.4-0", "author": "bwp91", "contributors": [ "gbro115", From 8cb6ac52baca9c4148591f8f9faabbb60fc080e7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 17 Nov 2020 10:47:38 +0000 Subject: [PATCH 0794/3183] reinstate amended check --- lib/ewelink-platform.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index ff2dade0..2081e558 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -185,6 +185,20 @@ module.exports = class eWeLinkPlatform { let accessory let oAccessory try { + // *** Remove old switch services for new Accessory Simulations *** \\ + if (this.cusG.has(device.deviceid + 'SWX')) { + const arrToCheck = this.cusG.has(device.deviceid + 'SWX').type === 'switch_valve' + ? ['0', '1'] + : ['X', '0', '1', '2', '3', '4'] + arrToCheck.forEach(sw => { + if (this.devicesInHB.has(device.deviceid + 'SW' + sw)) { + if (this.devicesInHB.get(device.deviceid + 'SW' + sw).getService(this.Service.Switch)) { + this.removeAccessory(this.devicesInHB.get(device.deviceid + 'SW' + sw)) + } + } + }) + } + // *** Set up the correct instance for this particular device *** \\ if (helpers.devicesCurtain.includes(device.extra.uiid)) { /*********************** From 8f81bf4eb4caf9b580e57fee346a78256aaa8cc1 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 17 Nov 2020 10:48:01 +0000 Subject: [PATCH 0795/3183] formatting --- lib/ewelink-platform.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 2081e558..6bcaabb5 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -198,7 +198,7 @@ module.exports = class eWeLinkPlatform { } }) } - + // *** Set up the correct instance for this particular device *** \\ if (helpers.devicesCurtain.includes(device.extra.uiid)) { /*********************** From 25a5d7a8eb13af964960b3fb4041b098bef4240d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 17 Nov 2020 13:12:00 +0000 Subject: [PATCH 0796/3183] fakegato into main lib --- lib/device/outlet.js | 4 +--- lib/device/rf-bridge.js | 4 +--- lib/device/scm.js | 4 +--- lib/device/sensor.js | 4 +--- lib/device/switch-multi.js | 4 +--- lib/device/switch-single.js | 4 +--- lib/device/switch-valve.js | 4 +--- lib/device/thermostat.js | 4 +--- lib/device/usb.js | 4 +--- lib/device/zb-dev.js | 10 ++++------ lib/ewelink-platform.js | 2 ++ 11 files changed, 15 insertions(+), 33 deletions(-) diff --git a/lib/device/outlet.js b/lib/device/outlet.js index cb04154f..66ca8704 100644 --- a/lib/device/outlet.js +++ b/lib/device/outlet.js @@ -1,7 +1,6 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') const util = require('util') module.exports = class deviceOutlet { @@ -9,7 +8,6 @@ module.exports = class deviceOutlet { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic - this.EveHistoryService = fakegato(platform.api) this.inUsePowerThreshold = parseInt(this.platform.config.inUsePowerThreshold) this.inUsePowerThreshold = isNaN(this.inUsePowerThreshold) ? helpers.defaults.inUsePowerThreshold @@ -108,7 +106,7 @@ module.exports = class deviceOutlet { this.outletService.updateCharacteristic(this.eveTotalConsumption, 0) }) accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('energy', accessory, { + accessory.eveLogger = new this.platform.eveService('energy', accessory, { storage: 'fs', path: this.platform.eveLogPath }) diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index 3701aa9e..1b2ba4ba 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -1,14 +1,12 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') module.exports = class deviceRFBridge { constructor (platform, accessory) { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic - this.EveHistoryService = fakegato(platform.api) this.sensorTimeDifference = parseInt(this.platform.config.sensorTimeDifference) this.sensorTimeDifference = isNaN(this.sensorTimeDifference) ? helpers.defaults.sensorTimeDifference @@ -68,7 +66,7 @@ module.exports = class deviceRFBridge { const service = accessory.getService(serv) || accessory.addService(serv) service.updateCharacteristic(char, 0) accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService(eveType, accessory, { + accessory.eveLogger = new this.platform.eveService(eveType, accessory, { storage: 'fs', path: this.platform.eveLogPath }) diff --git a/lib/device/scm.js b/lib/device/scm.js index 1351e204..e5f1e6a0 100644 --- a/lib/device/scm.js +++ b/lib/device/scm.js @@ -1,20 +1,18 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') module.exports = class deviceSCM { constructor (platform, accessory) { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic - this.EveHistoryService = fakegato(platform.api) this.switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) this.switchService .getCharacteristic(this.Characteristic.On) .on('set', this.internalUpdate.bind(this)) accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('switch', accessory, { + accessory.eveLogger = new this.platform.eveService('switch', accessory, { storage: 'fs', path: this.platform.eveLogPath }) diff --git a/lib/device/sensor.js b/lib/device/sensor.js index e9359085..caa6f93e 100644 --- a/lib/device/sensor.js +++ b/lib/device/sensor.js @@ -1,14 +1,12 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') module.exports = class deviceSensor { constructor (platform, accessory) { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic - this.EveHistoryService = fakegato(platform.api) this.lowBattThreshold = parseInt(this.platform.config.lowBattThreshold) this.lowBattThreshold = isNaN(this.lowBattThreshold) ? helpers.defaults.lowBattThreshold @@ -18,7 +16,7 @@ module.exports = class deviceSensor { this.contactService = accessory.getService(this.Service.ContactSensor) || accessory.addService(this.Service.ContactSensor) this.batteryService = accessory.getService(this.Service.BatteryService) || accessory.addService(this.Service.BatteryService) accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('door', accessory, { + accessory.eveLogger = new this.platform.eveService('door', accessory, { storage: 'fs', path: this.platform.eveLogPath }) diff --git a/lib/device/switch-multi.js b/lib/device/switch-multi.js index a232cc50..337b5c88 100644 --- a/lib/device/switch-multi.js +++ b/lib/device/switch-multi.js @@ -1,14 +1,12 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') module.exports = class deviceSwitchMulti { constructor (platform, accessory) { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic - this.EveHistoryService = fakegato(platform.api) this.switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) this.switchService .getCharacteristic(this.Characteristic.On) @@ -20,7 +18,7 @@ module.exports = class deviceSwitchMulti { accessory.removeService(accessory.getService(this.Service.Lightbulb)) } accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('switch', accessory, { + accessory.eveLogger = new this.platform.eveService('switch', accessory, { storage: 'fs', path: this.platform.eveLogPath }) diff --git a/lib/device/switch-single.js b/lib/device/switch-single.js index 74b6f7eb..c39090a3 100644 --- a/lib/device/switch-single.js +++ b/lib/device/switch-single.js @@ -1,14 +1,12 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') module.exports = class deviceSwitchSingle { constructor (platform, accessory) { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic - this.EveHistoryService = fakegato(platform.api) this.switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) this.switchService .getCharacteristic(this.Characteristic.On) @@ -20,7 +18,7 @@ module.exports = class deviceSwitchSingle { accessory.removeService(accessory.getService(this.Service.Lightbulb)) } accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('switch', accessory, { + accessory.eveLogger = new this.platform.eveService('switch', accessory, { storage: 'fs', path: this.platform.eveLogPath }) diff --git a/lib/device/switch-valve.js b/lib/device/switch-valve.js index 42ac19bc..d0492564 100644 --- a/lib/device/switch-valve.js +++ b/lib/device/switch-valve.js @@ -1,14 +1,12 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') module.exports = class deviceSwitchValve { constructor (platform, accessory) { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic - this.EveHistoryService = fakegato(platform.api) const valveConfig = this.platform.cusG.get(accessory.context.hbDeviceId) this.switchService = accessory.getService(this.Service.Switch) || accessory.addService(this.Service.Switch) if (!(this.valveService = accessory.getService(this.Service.Valve))) { @@ -37,7 +35,7 @@ module.exports = class deviceSwitchValve { callback() }) accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('switch', accessory, { + accessory.eveLogger = new this.platform.eveService('switch', accessory, { storage: 'fs', path: this.platform.eveLogPath }) diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index 1fb67384..5102283a 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -1,14 +1,12 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') module.exports = class deviceThermostat { constructor (platform, accessory) { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic - this.EveHistoryService = fakegato(platform.api) if ((this.platform.config.hideSwitchFromTH || '').includes(accessory.context.eweDeviceId)) { if (accessory.getService(this.Service.Switch)) { accessory.removeService(accessory.getService(this.Service.Switch)) @@ -28,7 +26,7 @@ module.exports = class deviceThermostat { this.humiService = accessory.getService(this.Service.HumiditySensor) || accessory.addService(this.Service.HumiditySensor) } accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('custom', accessory, { + accessory.eveLogger = new this.platform.eveService('custom', accessory, { storage: 'fs', path: this.platform.eveLogPath }) diff --git a/lib/device/usb.js b/lib/device/usb.js index 48de6c45..da0161c8 100644 --- a/lib/device/usb.js +++ b/lib/device/usb.js @@ -1,20 +1,18 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') module.exports = class deviceUSB { constructor (platform, accessory) { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic - this.EveHistoryService = fakegato(platform.api) this.outletService = accessory.getService(this.Service.Outlet) || accessory.addService(this.Service.Outlet) this.outletService .getCharacteristic(this.Characteristic.On) .on('set', this.internalUpdate.bind(this)) accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('switch', accessory, { + accessory.eveLogger = new this.platform.eveService('switch', accessory, { storage: 'fs', path: this.platform.eveLogPath }) diff --git a/lib/device/zb-dev.js b/lib/device/zb-dev.js index e4460cc0..85d73425 100644 --- a/lib/device/zb-dev.js +++ b/lib/device/zb-dev.js @@ -1,14 +1,12 @@ /* jshint -W014, -W033, esversion: 9 */ /* eslint-disable new-cap */ 'use strict' -const fakegato = require('./../fakegato/fakegato-history') const helpers = require('./../helpers') module.exports = class deviceZBDev { constructor (platform, accessory) { this.platform = platform this.Service = platform.api.hap.Service this.Characteristic = platform.api.hap.Characteristic - this.EveHistoryService = fakegato(platform.api) this.lowBattThreshold = parseInt(this.platform.config.lowBattThreshold) this.lowBattThreshold = isNaN(this.lowBattThreshold) ? helpers.defaults.lowBattThreshold @@ -39,7 +37,7 @@ module.exports = class deviceZBDev { if (accessory.getService(this.Service.BatteryService)) accessory.removeService(accessory.getService(this.Service.BatteryService)) if (!accessory.getService(this.Service.Switch)) accessory.addService(this.Service.Switch) accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('switch', accessory, { + accessory.eveLogger = new this.platform.eveService('switch', accessory, { storage: 'fs', path: this.platform.eveLogPath }) @@ -56,7 +54,7 @@ module.exports = class deviceZBDev { }) if (!accessory.getService(this.Service.HumiditySensor)) accessory.addService(this.Service.HumiditySensor) accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('weather', accessory, { + accessory.eveLogger = new this.platform.eveService('weather', accessory, { storage: 'fs', path: this.platform.eveLogPath }) @@ -66,7 +64,7 @@ module.exports = class deviceZBDev { if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) if (!accessory.getService(this.Service.MotionSensor)) accessory.addService(this.Service.MotionSensor) accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('motion', accessory, { + accessory.eveLogger = new this.platform.eveService('motion', accessory, { storage: 'fs', path: this.platform.eveLogPath }) @@ -75,7 +73,7 @@ module.exports = class deviceZBDev { if (!accessory.getService(this.Service.BatteryService)) accessory.addService(this.Service.BatteryService) if (!accessory.getService(this.Service.ContactSensor)) accessory.addService(this.Service.ContactSensor) accessory.log = this.platform.log - accessory.eveLogger = new this.EveHistoryService('door', accessory, { + accessory.eveLogger = new this.platform.eveService('door', accessory, { storage: 'fs', path: this.platform.eveLogPath }) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index 6bcaabb5..b86e9fb4 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -28,6 +28,7 @@ const deviceZBDev = require('./device/zb-dev') const eWeLinkHTTP = require('./ewelink-http') const eWeLinkLAN = require('./ewelink-lan') const eWeLinkWS = require('./ewelink-ws') +const fakegato = require('./fakegato/fakegato-history') const helpers = require('./helpers') const promInterval = require('interval-promise') const version = require('./../package.json').version @@ -47,6 +48,7 @@ module.exports = class eWeLinkPlatform { this.api = api this.Characteristic = api.hap.Characteristic this.Service = api.hap.Service + this.eveService = fakegato(api) this.debug = this.config.debug || false this.devicesInHB = new Map() this.devicesInEW = new Map() From 72540a4485c26ffc77271fd2ab0f3b8c43857bf9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 17 Nov 2020 13:12:18 +0000 Subject: [PATCH 0797/3183] check if timer already running --- lib/device/valve.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/device/valve.js b/lib/device/valve.js index 9ebb3274..175ac295 100644 --- a/lib/device/valve.js +++ b/lib/device/valve.js @@ -23,7 +23,7 @@ module.exports = class deviceValve { this.valveService .getCharacteristic(this.Characteristic.SetDuration) .on('set', (value, callback) => { - if (this.valveService.getCharacteristic(this.Characteristic.InUse).value) { + if (this.valveService.getCharacteristic(this.Characteristic.InUse).value === 1) { this.valveService.updateCharacteristic(this.Characteristic.RemainingDuration, value) clearTimeout(this.valveService.timer) this.valveService.timer = setTimeout( @@ -63,12 +63,14 @@ module.exports = class deviceValve { try { if (!helpers.hasProperty(params, 'switch')) return this.valveService - .updateCharacteristic(this.Characteristic.Active, params.switch === 'on') - .updateCharacteristic(this.Characteristic.InUse, params.switch === 'on') + .updateCharacteristic(this.Characteristic.Active, params.switch === 'on' ? 1 : 0) + .updateCharacteristic(this.Characteristic.InUse, params.switch === 'on' ? 1 : 0) if (params.switch === 'on') { - const timer = this.valveService.getCharacteristic(this.Characteristic.SetDuration).value - this.valveService.updateCharacteristic(this.Characteristic.RemainingDuration, timer) - this.valveService.timer = setTimeout(() => this.valveService.setCharacteristic(this.Characteristic.Active, 0), timer * 1000) + if (this.valveService.getCharacteristic(this.Characteristic.Active).value === 0) { + const timer = this.valveService.getCharacteristic(this.Characteristic.SetDuration).value + this.valveService.updateCharacteristic(this.Characteristic.RemainingDuration, timer) + this.valveService.timer = setTimeout(() => this.valveService.setCharacteristic(this.Characteristic.Active, 0), timer * 1000) + } } else { this.valveService.updateCharacteristic(this.Characteristic.RemainingDuration, 0) clearTimeout(this.valveService.timer) From cc1945f7f7e4cc74ce57ed59f8a5d81dfe0e5531 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 17 Nov 2020 13:13:47 +0000 Subject: [PATCH 0798/3183] 3.13.4-1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 51270860..d5db2f03 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.4-0", + "version": "3.13.4-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 3114d367..468dd186 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.4-0", + "version": "3.13.4-1", "author": "bwp91", "contributors": [ "gbro115", From e0aa28a7c91dd6c6a4c96de0df28fa26c79636be Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 17 Nov 2020 16:14:12 +0000 Subject: [PATCH 0799/3183] bump min hb/node --- package.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 468dd186..9b43d720 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,8 @@ "eachen" ], "engines": { - "homebridge": ">=1.0.0", - "node": ">=12.0.0" + "homebridge": "^1.1.0", + "node": "^14.15.1" }, "repository": { "type": "git", @@ -65,12 +65,12 @@ } ], "dependencies": { - "axios": "0.21.0", - "color-convert": "2.0.1", - "interval-promise": "1.4.0", - "node-dns-sd": "0.4.2", - "websocket-as-promised": "1.1.0", - "ws": "7.4.0" + "axios": "^0.21.0", + "color-convert": "^2.0.1", + "interval-promise": "^1.4.0", + "node-dns-sd": "^0.4.2", + "websocket-as-promised": "^1.1.0", + "ws": "^7.4.0" }, "standard": { "ignore": [ From 10f27e93f7fdeab30abc41178deb570bbea2f5a7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 18 Nov 2020 09:59:33 +0000 Subject: [PATCH 0800/3183] separate functions --- lib/device/light-colour.js | 193 +++++++++++++++++++------------------ lib/device/light-ctemp.js | 105 ++++++++++---------- lib/device/light-dimmer.js | 51 +++++----- 3 files changed, 179 insertions(+), 170 deletions(-) diff --git a/lib/device/light-colour.js b/lib/device/light-colour.js index 032cc295..49bea70a 100644 --- a/lib/device/light-colour.js +++ b/lib/device/light-colour.js @@ -11,13 +11,13 @@ module.exports = class deviceLightColour { this.lightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) this.lightService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate('onoff', value, callback)) + .on('set', this.internalOnOffUpdate.bind(this)) this.lightService .getCharacteristic(this.Characteristic.Brightness) - .on('set', (value, callback) => this.internalUpdate('brightness', value, callback)) + .on('set', this.internalBrightnessUpdate.bind(this)) this.lightService .getCharacteristic(this.Characteristic.Hue) - .on('set', (value, callback) => this.internalUpdate('hue', value, callback)) + .on('set', this.internalHueUpdate.bind(this)) this.lightService .getCharacteristic(this.Characteristic.Saturation) .on('set', (value, callback) => callback()) @@ -32,105 +32,110 @@ module.exports = class deviceLightColour { this.accessory = accessory } - async internalUpdate (type, value, callback) { + async internalOnOffUpdate (value, callback) { try { - let newRGB - let params = {} - switch (type) { - case 'onoff': - callback() - if (this.accessory.context.eweUIID === 22) { - // **** B1 uses state rather than switch *** \\ - params.state = value ? 'on' : 'off' - } else { - params.switch = value ? 'on' : 'off' + callback() + const params = {} + if (this.accessory.context.eweUIID === 22) { + // **** B1 uses state rather than switch *** \\ + params.state = value ? 'on' : 'off' + } else { + params.switch = value ? 'on' : 'off' + } + await this.platform.sendDeviceUpdate(this.accessory, params) + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async internalBrightnessUpdate (value, callback) { + try { + let params + await helpers.sleep(1000) + callback() + const updateKeyBright = Math.random().toString(36).substr(2, 8) + this.accessory.context.updateKeyBright = updateKeyBright + switch (this.accessory.context.eweUIID) { + case 22: + // *** B1 doesn't support brightness *** \\ + return + case 59: + // *** L1 *** \\ + params = { + mode: 1, + bright: value } - await this.platform.sendDeviceUpdate(this.accessory, params) break - case 'brightness': { - await helpers.sleep(1000) - callback() - const updateKeyBright = Math.random().toString(36).substr(2, 8) - this.accessory.context.updateKeyBright = updateKeyBright - switch (this.accessory.context.eweUIID) { - case 22: - // *** B1 doesn't support brightness *** \\ - return - case 59: - // *** L1 *** \\ - params = { - mode: 1, - bright: value - } - break - case 104: - // *** GTLC104 needs the current rgb values sent too *** \\ - params = { - ltype: 'color', - color: { - br: value, - r: this.accessory.context.cacheR, - g: this.accessory.context.cacheG, - b: this.accessory.context.cacheB - } - } - break + case 104: + // *** GTLC104 needs the current rgb values sent too *** \\ + params = { + ltype: 'color', + color: { + br: value, + r: this.accessory.context.cacheR, + g: this.accessory.context.cacheG, + b: this.accessory.context.cacheB + } } - await helpers.sleep(500) - if (updateKeyBright !== this.accessory.context.updateKeyBright) return - await this.platform.sendDeviceUpdate(this.accessory, params) break - } - case 'hue': { - await helpers.sleep(2000) - callback() - const updateKeyColour = Math.random().toString(36).substr(2, 8) - this.accessory.context.updateKeyColour = updateKeyColour - newRGB = convert.hsv.rgb(value, this.lightService.getCharacteristic(this.Characteristic.Saturation).value, 100) - switch (this.accessory.context.eweUIID) { - case 22: - // *** B1 *** \\ - params = { - zyx_mode: 2, - type: 'middle', - channel0: '0', - channel1: '0', - channel2: newRGB[0].toString(), - channel3: newRGB[1].toString(), - channel4: newRGB[2].toString() - } - break - case 59: - // *** L1 *** \\ - params = { - mode: 1, - colorR: newRGB[0], - colorG: newRGB[1], - colorB: newRGB[2] - } - break - case 104: - // *** GTLC104 *** \\ - params = { - ltype: 'color', - color: { - r: newRGB[0], - g: newRGB[1], - b: newRGB[2], - br: this.lightService.getCharacteristic(this.Characteristic.Brightness).value - } - } - this.accessory.context.cacheR = newRGB[0] - this.accessory.context.cacheG = newRGB[1] - this.accessory.context.cacheB = newRGB[2] - break + } + await helpers.sleep(500) + if (updateKeyBright !== this.accessory.context.updateKeyBright) return + await this.platform.sendDeviceUpdate(this.accessory, params) + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async internalHueUpdate (value, callback) { + try { + await helpers.sleep(2000) + callback() + let params + const newRGB = convert.hsv.rgb(value, this.lightService.getCharacteristic(this.Characteristic.Saturation).value, 100) + const updateKeyColour = Math.random().toString(36).substr(2, 8) + this.accessory.context.updateKeyColour = updateKeyColour + switch (this.accessory.context.eweUIID) { + case 22: + // *** B1 *** \\ + params = { + zyx_mode: 2, + type: 'middle', + channel0: '0', + channel1: '0', + channel2: newRGB[0].toString(), + channel3: newRGB[1].toString(), + channel4: newRGB[2].toString() } - await helpers.sleep(1000) - if (updateKeyColour !== this.accessory.context.updateKeyColour) return - await this.platform.sendDeviceUpdate(this.accessory, params) break - } + case 59: + // *** L1 *** \\ + params = { + mode: 1, + colorR: newRGB[0], + colorG: newRGB[1], + colorB: newRGB[2] + } + break + case 104: + // *** GTLC104 *** \\ + params = { + ltype: 'color', + color: { + r: newRGB[0], + g: newRGB[1], + b: newRGB[2], + br: this.lightService.getCharacteristic(this.Characteristic.Brightness).value + } + } + this.accessory.context.cacheR = newRGB[0] + this.accessory.context.cacheG = newRGB[1] + this.accessory.context.cacheB = newRGB[2] + break } + await helpers.sleep(1000) + if (updateKeyColour !== this.accessory.context.updateKeyColour) return + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) } diff --git a/lib/device/light-ctemp.js b/lib/device/light-ctemp.js index 1799f8f2..78b74339 100644 --- a/lib/device/light-ctemp.js +++ b/lib/device/light-ctemp.js @@ -10,68 +10,71 @@ module.exports = class deviceLightColour { this.lightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) this.lightService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate('onoff', value, callback)) + .on('set', this.internalOnOffUpdate.bind(this)) this.lightService .getCharacteristic(this.Characteristic.Brightness) - .on('set', (value, callback) => this.internalUpdate('brightness', value, callback)) + .on('set', this.internalBrightnessUpdate.bind(this)) this.lightService .getCharacteristic(this.Characteristic.ColorTemperature) - .on('set', (value, callback) => this.internalUpdate('colour', value, callback)) + .on('set', this.internalColourTempUpdate.bind(this)) this.accessory = accessory } - async internalUpdate (type, value, callback) { + async internaOnOffUpdate (value, callback) { try { - let params = {} - switch (type) { - case 'onoff': - callback() - params.switch = value ? 'on' : 'off' - await this.platform.sendDeviceUpdate(this.accessory, params) - break - case 'brightness': { - await helpers.sleep(1000) - callback() - const updateKeyBright = Math.random().toString(36).substr(2, 8) - this.accessory.context.updateKeyBright = updateKeyBright - // *** Device needs the current ct value sent too *** \\ - params = { - ltype: 'white', - white: { - br: value, - ct: this.accessory.context.cacheCT - } - } - await helpers.sleep(500) - if (updateKeyBright !== this.accessory.context.updateKeyBright) return - await this.platform.sendDeviceUpdate(this.accessory, params) - break + callback() + const params = { switch: value ? 'on' : 'off' } + await this.platform.sendDeviceUpdate(this.accessory, params) + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async internalBrightnessUpdate (value, callback) { + try { + await helpers.sleep(1000) + callback() + const updateKeyBright = Math.random().toString(36).substr(2, 8) + this.accessory.context.updateKeyBright = updateKeyBright + // *** Device needs the current ct value sent too *** \\ + const params = { + ltype: 'white', + white: { + br: value, + ct: this.accessory.context.cacheCT } - case 'colour': { - await helpers.sleep(2000) - callback() - const updateKeyColour = Math.random().toString(36).substr(2, 8) - this.accessory.context.updateKeyColour = updateKeyColour - // HomeKit has a ct range of 140-500 corresponding to 2000-7143K - // B02-F-A60 has a range of 2200K-6500K corresponding to ct: 0-255 - let mToK = Math.round(1000000 / value) - if (mToK < 2200) mToK = 2200 - if (mToK > 6500) mToK = 6500 - const kToCT = Math.round(((mToK - 2200) / 4300) * 255) - params = { - ltype: 'white', - white: { - ct: kToCT, - br: this.lightService.getCharacteristic(this.Characteristic.Brightness).value - } - } - this.accessory.context.cacheCT = kToCT - await helpers.sleep(1000) - if (updateKeyColour !== this.accessory.context.updateKeyColour) return - await this.platform.sendDeviceUpdate(this.accessory, params) - break + } + await helpers.sleep(500) + if (updateKeyBright !== this.accessory.context.updateKeyBright) return + await this.platform.sendDeviceUpdate(this.accessory, params) + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async internalColourTempUpdate (value, callback) { + try { + await helpers.sleep(2000) + callback() + const updateKeyColour = Math.random().toString(36).substr(2, 8) + this.accessory.context.updateKeyColour = updateKeyColour + // HomeKit has a ct range of 140-500 corresponding to 2000-7143K + // B02-F-A60 has a range of 2200K-6500K corresponding to ct: 0-255 + let mToK = Math.round(1000000 / value) + if (mToK < 2200) mToK = 2200 + if (mToK > 6500) mToK = 6500 + const kToCT = Math.round(((mToK - 2200) / 4300) * 255) + const params = { + ltype: 'white', + white: { + ct: kToCT, + br: this.lightService.getCharacteristic(this.Characteristic.Brightness).value } } + this.accessory.context.cacheCT = kToCT + await helpers.sleep(1000) + if (updateKeyColour !== this.accessory.context.updateKeyColour) return + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) } diff --git a/lib/device/light-dimmer.js b/lib/device/light-dimmer.js index 243903f3..077832cc 100644 --- a/lib/device/light-dimmer.js +++ b/lib/device/light-dimmer.js @@ -10,41 +10,42 @@ module.exports = class deviceLightDimmer { this.lightService = accessory.getService(this.Service.Lightbulb) || accessory.addService(this.Service.Lightbulb) this.lightService .getCharacteristic(this.Characteristic.On) - .on('set', (value, callback) => this.internalUpdate('onoff', value, callback)) + .on('set', this.internalOnOffUpdate.bind(this)) this.lightService.getCharacteristic(this.Characteristic.Brightness) - .on('set', (value, callback) => this.internalUpdate('brightness', value, callback)) + .on('set', this.internalBrightnessUpdate.bind(this)) this.accessory = accessory } - async internalUpdate (type, value, callback) { + async internalOnOffUpdate (value, callback) { + try { + callback() + const params = { switch: value ? 'on' : 'off' } + await this.platform.sendDeviceUpdate(this.accessory, params) + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async internalBrightnessUpdate (value, callback) { try { callback() const params = {} - switch (type) { - case 'onoff': - params.switch = value ? 'on' : 'off' - await this.platform.sendDeviceUpdate(this.accessory, params) + const updateKey = Math.random().toString(36).substr(2, 8) + this.accessory.context.updateKey = updateKey + switch (this.accessory.context.eweUIID) { + case 36: + // *** KING-M4 eWeLink scale is 10-100 and HomeKit scale is 0-100. *** \\ + params.bright = Math.round((value * 9) / 10 + 10) break - case 'brightness': { - const updateKey = Math.random().toString(36).substr(2, 8) - this.accessory.context.updateKey = updateKey - switch (this.accessory.context.eweUIID) { - case 36: - // *** KING-M4 eWeLink scale is 10-100 and HomeKit scale is 0-100. *** \\ - params.bright = Math.round((value * 9) / 10 + 10) - break - case 44: - // *** D1 eWeLink scale matches HomeKit scale of 0-100 *** \\ - params.brightness = value - params.mode = 0 - break - } - await helpers.sleep(500) - if (updateKey !== this.accessory.context.updateKey) return - await this.platform.sendDeviceUpdate(this.accessory, params) + case 44: + // *** D1 eWeLink scale matches HomeKit scale of 0-100 *** \\ + params.brightness = value + params.mode = 0 break - } } + await helpers.sleep(500) + if (updateKey !== this.accessory.context.updateKey) return + await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) } From b9cff978640c3247fc8f43872fa6fef399d3e863 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 18 Nov 2020 12:06:25 +0000 Subject: [PATCH 0801/3183] separate functions tidy up --- lib/device/light-ctemp.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/device/light-ctemp.js b/lib/device/light-ctemp.js index 78b74339..7ef89a20 100644 --- a/lib/device/light-ctemp.js +++ b/lib/device/light-ctemp.js @@ -17,10 +17,15 @@ module.exports = class deviceLightColour { this.lightService .getCharacteristic(this.Characteristic.ColorTemperature) .on('set', this.internalColourTempUpdate.bind(this)) + if (platform.api.version === 2.7 && platform.api.versionGreaterOrEqual('1.3.0-beta.24')) { + // adaptive lighting + this.alController = new platform.api.hap.AdaptiveLightingController(this.lightService) + accessory.configureController(this.alController) + } this.accessory = accessory } - async internaOnOffUpdate (value, callback) { + async internalOnOffUpdate (value, callback) { try { callback() const params = { switch: value ? 'on' : 'off' } @@ -106,6 +111,18 @@ module.exports = class deviceLightColour { const kToMired = Math.round(1000000 / ctToK) this.lightService.updateCharacteristic(this.Characteristic.ColorTemperature, kToMired) + + /* + @TODO + check for any difference in ct and disable Adaptive Lighting + temperature could have been changed by user on the ewelink app + + if (this.accessory.context.cacheCT !== params.white.ct) { + this.alController.disableAdaptiveLighting() + } + + */ + this.accessory.context.cacheCT = params.white.ct } } From d2aea9077b957048bf5451954ee907e8f84238d3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 19 Nov 2020 08:24:56 +0000 Subject: [PATCH 0802/3183] disable AL for now --- lib/device/light-ctemp.js | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/lib/device/light-ctemp.js b/lib/device/light-ctemp.js index 7ef89a20..31b402b7 100644 --- a/lib/device/light-ctemp.js +++ b/lib/device/light-ctemp.js @@ -17,11 +17,13 @@ module.exports = class deviceLightColour { this.lightService .getCharacteristic(this.Characteristic.ColorTemperature) .on('set', this.internalColourTempUpdate.bind(this)) - if (platform.api.version === 2.7 && platform.api.versionGreaterOrEqual('1.3.0-beta.24')) { - // adaptive lighting - this.alController = new platform.api.hap.AdaptiveLightingController(this.lightService) - accessory.configureController(this.alController) - } + /* + @BETA + if (platform.api.version === 2.7 && platform.api.versionGreaterOrEqual('1.3.0-beta.24')) { + this.alController = new platform.api.hap.AdaptiveLightingController(this.lightService) + accessory.configureController(this.alController) + } + */ this.accessory = accessory } @@ -106,23 +108,17 @@ module.exports = class deviceLightColour { if (helpers.hasProperty(params.white, 'ct')) { // B02-F-A60 has a range of 2200K-6500K corresponding to ct: 0-255 // HomeKit has a ct range of 140-500 corresponding to 2000-7143K - const ctToK = Math.round(params.white.ct / 255 * 4300 + 2200) const kToMired = Math.round(1000000 / ctToK) - this.lightService.updateCharacteristic(this.Characteristic.ColorTemperature, kToMired) - /* - @TODO - check for any difference in ct and disable Adaptive Lighting - temperature could have been changed by user on the ewelink app - - if (this.accessory.context.cacheCT !== params.white.ct) { - this.alController.disableAdaptiveLighting() - } - + @BETA + check for any difference in ct and disable Adaptive Lighting + temperature could have been changed by user on the ewelink app + if (this.accessory.context.cacheCT !== params.white.ct) { + this.alController.disableAdaptiveLighting() + } */ - this.accessory.context.cacheCT = params.white.ct } } From 3c3ffd17535dc9cb7c4b3a1b1af0aeb49d609ede Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 19 Nov 2020 08:36:12 +0000 Subject: [PATCH 0803/3183] 3.13.4-2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index d5db2f03..42f82016 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.4-1", + "version": "3.13.4-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 9b43d720..66a7d424 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.4-1", + "version": "3.13.4-2", "author": "bwp91", "contributors": [ "gbro115", From 8c0bd589303c6c6512d528659b70c4a7295b97e8 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 20 Nov 2020 08:20:15 +0000 Subject: [PATCH 0804/3183] remove check for now --- lib/device/light-ctemp.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/device/light-ctemp.js b/lib/device/light-ctemp.js index 31b402b7..376ba21b 100644 --- a/lib/device/light-ctemp.js +++ b/lib/device/light-ctemp.js @@ -111,14 +111,6 @@ module.exports = class deviceLightColour { const ctToK = Math.round(params.white.ct / 255 * 4300 + 2200) const kToMired = Math.round(1000000 / ctToK) this.lightService.updateCharacteristic(this.Characteristic.ColorTemperature, kToMired) - /* - @BETA - check for any difference in ct and disable Adaptive Lighting - temperature could have been changed by user on the ewelink app - if (this.accessory.context.cacheCT !== params.white.ct) { - this.alController.disableAdaptiveLighting() - } - */ this.accessory.context.cacheCT = params.white.ct } } From 5984e9e2638460a60c56154045c5b3f16c5110cf Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 20 Nov 2020 12:30:43 +0000 Subject: [PATCH 0805/3183] Create ISSUE_TEMPLATE.md --- .github/ISSUE_TEMPLATE.md | 41 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..7dab9f26 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,41 @@ + + +### What issue do you have? Please be as thorough and explicit as possible. + + + +### Details of your setup. +* Do you use Homebridge (with config-ui?) or HOOBS? + + + +* Which version of Homebridge/HOOBS do you have? + + + +* Which version of this plugin (homebridge-ewelink) do you have? Has the issue started since upgrading from a previous version? + + + +* Which eWeLink devices do you have that are causing issues? Please include product models if applicable. + + + +* Do you use your main eWeLink credentials or do you use a secondary eWeLink account for Homebridge? + + + +### Please paste any relevant logs below. + + +``` + +``` From 8c049a5c5a28a134c6c8f9a39c277c39483b9e86 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 20 Nov 2020 12:31:47 +0000 Subject: [PATCH 0806/3183] Update ISSUE_TEMPLATE.md --- .github/ISSUE_TEMPLATE.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 7dab9f26..789181de 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,8 +1,7 @@ + * If you are experiencing an issue with the plugin then please use this template as well as you can. + * Things that may seem unimportant to you are often helpful in finding the cause of the issue. --> ### What issue do you have? Please be as thorough and explicit as possible. From 5679744e2ce535171691fe5b88c68600dee5ad57 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 20 Nov 2020 12:35:30 +0000 Subject: [PATCH 0807/3183] Update ISSUE_TEMPLATE.md --- .github/ISSUE_TEMPLATE.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 789181de..4c7d4b18 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,7 +1,7 @@ + → If you are giving feedback or requesting a new feature then feel free to ignore this template. + → If you are experiencing an issue with the plugin then please use this template as well as you can. + → Things that may seem unimportant to you are often helpful in finding the cause of the issue. --> ### What issue do you have? Please be as thorough and explicit as possible. @@ -29,10 +29,13 @@ ### Please paste any relevant logs below. - ``` From b7e1977e7f4620a4418185500edc48e14a9a67ed Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 20 Nov 2020 12:36:43 +0000 Subject: [PATCH 0808/3183] Update ISSUE_TEMPLATE.md --- .github/ISSUE_TEMPLATE.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 4c7d4b18..9fa9f74b 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,7 +1,8 @@ + → Things that may seem unimportant to you are often helpful in finding the cause of the issue. +--> ### What issue do you have? Please be as thorough and explicit as possible. @@ -31,11 +32,11 @@ ### Please paste any relevant logs below. ``` From c7561eb6911b498a5c7bb397ab36cc58bad0dab3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 20 Nov 2020 12:40:54 +0000 Subject: [PATCH 0809/3183] issue templates --- .github/ISSUE_TEMPLATE.md | 6 +++--- .github/ISSUE_TEMPLATE/new-issue.md | 16 ++++++++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 9fa9f74b..26398aae 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -32,11 +32,11 @@ ### Please paste any relevant logs below. ``` diff --git a/.github/ISSUE_TEMPLATE/new-issue.md b/.github/ISSUE_TEMPLATE/new-issue.md index ac949c09..8c485cd1 100644 --- a/.github/ISSUE_TEMPLATE/new-issue.md +++ b/.github/ISSUE_TEMPLATE/new-issue.md @@ -8,8 +8,9 @@ assignees: '' --- + → Please use this template as well as you can. + → Things that may seem unimportant to you are often helpful in finding the cause of the issue. +--> ### What issue do you have? Please be as thorough and explicit as possible. @@ -37,10 +38,13 @@ assignees: '' ### Please paste any relevant logs below. - ``` From 91fc50654a13900d8101bee4ad259b41103fa1d9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 20 Nov 2020 13:18:31 +0000 Subject: [PATCH 0810/3183] Update light-ctemp.js --- lib/device/light-ctemp.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/device/light-ctemp.js b/lib/device/light-ctemp.js index 376ba21b..a5e0a769 100644 --- a/lib/device/light-ctemp.js +++ b/lib/device/light-ctemp.js @@ -18,8 +18,7 @@ module.exports = class deviceLightColour { .getCharacteristic(this.Characteristic.ColorTemperature) .on('set', this.internalColourTempUpdate.bind(this)) /* - @BETA - if (platform.api.version === 2.7 && platform.api.versionGreaterOrEqual('1.3.0-beta.24')) { + if (platform.api.version === 2.7 && platform.api.versionGreaterOrEqual('1.3.0-beta.26')) { this.alController = new platform.api.hap.AdaptiveLightingController(this.lightService) accessory.configureController(this.alController) } From ec9e41774e94d2ee5147c52b25569921fa7967dc Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 20 Nov 2020 14:26:43 +0000 Subject: [PATCH 0811/3183] add some comments to code --- lib/ewelink-http.js | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/lib/ewelink-http.js b/lib/ewelink-http.js index 87df8917..2e6fe055 100644 --- a/lib/ewelink-http.js +++ b/lib/ewelink-http.js @@ -6,6 +6,7 @@ const crypto = require('crypto') const helpers = require('./helpers') module.exports = class eWeLinkHTTP { constructor (config, log) { + // *** Set up our variables *** \\ this.log = log this.debug = config.debug || false this.debugReqRes = config.debugReqRes || false @@ -16,6 +17,7 @@ module.exports = class eWeLinkHTTP { } async getHost () { + // *** Used to get the user's regional (continent) HTTP API host *** \\ const params = { appid: helpers.appId, country_code: this.cCode, @@ -23,6 +25,8 @@ module.exports = class eWeLinkHTTP { ts: Math.floor(new Date().getTime() / 1000), version: 8 } + + // *** Set up the request signature *** \\ let dataToSign = [] try { Object.keys(params).forEach(k => { @@ -34,11 +38,15 @@ module.exports = class eWeLinkHTTP { dataToSign.sort((a, b) => (a.key < b.key ? -1 : 1)) dataToSign = dataToSign.map(k => k.key + '=' + k.value).join('&') dataToSign = crypto.createHmac('sha256', helpers.appSecret).update(dataToSign).digest('base64') + + // *** Log the data depending on the debug setting *** \\ if (this.debugReqRes) { this.log.warn('Sending HTTP getHost() request. This text is yellow for clarity.\n%s', JSON.stringify(params, null, 2)) } else if (this.debug) { this.log('Sending HTTP getHost() request.') } + + // *** Send the request *** \\ const res = await axios.get('https://api.coolkit.cc:8080/api/user/region', { headers: { Authorization: 'Sign ' + dataToSign, @@ -46,6 +54,8 @@ module.exports = class eWeLinkHTTP { }, params }) + + // *** Parse the response *** \\ const body = res.data if (!body.region) { throw new Error('Server did not respond with a region.\n' + JSON.stringify(body, null, 2)) @@ -65,6 +75,7 @@ module.exports = class eWeLinkHTTP { if (this.debug) this.log('HTTP API host received [%s].', this.httpHost) } catch (err) { if (helpers.hasProperty(err, 'code') && helpers.httpRetryCodes.includes(err.code)) { + // *** Retry if another attempt could be successful *** \\ if (this.debug) this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') await helpers.sleep(30000) return await this.getHost() @@ -75,6 +86,7 @@ module.exports = class eWeLinkHTTP { } async login () { + // *** Used to log the user in and obtain the user api key and token *** \\ if (this.httpHost === undefined) this.httpHost = 'eu-apia.coolkit.cc' const data = { countryCode: this.cCode, @@ -85,13 +97,19 @@ module.exports = class eWeLinkHTTP { } else { data.phoneNumber = this.username } + + // *** Log the data depending on the debug setting *** \\ if (this.debugReqRes) { const msg = JSON.stringify(data, null, 2).replace(this.password, '**hidden**').replace(this.username, '**hidden**') this.log.warn('Sending HTTP login() request. This text is yellow for clarity.\n%s', msg) } else if (this.debug) { this.log('Sending HTTP login() request.') } + + // *** Set up the request signature *** \\ const dataToSign = crypto.createHmac('sha256', helpers.appSecret).update(JSON.stringify(data)).digest('base64') + + // *** Send the request *** \\ const res = await axios.post('https://' + this.httpHost + '/v2/user/login', data, { headers: { Authorization: 'Sign ' + dataToSign, @@ -100,6 +118,7 @@ module.exports = class eWeLinkHTTP { 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) } }) + // *** Parse the response *** \\ const body = res.data if ( helpers.hasProperty(body, 'error') && @@ -107,6 +126,7 @@ module.exports = class eWeLinkHTTP { helpers.hasProperty(body, 'data') && helpers.hasProperty(body.data, 'region') ) { + // *** In this case the user has been given a different region so retry login *** \\ const givenRegion = body.data.region switch (givenRegion) { case 'eu': @@ -124,6 +144,7 @@ module.exports = class eWeLinkHTTP { return await this.login() } else { if (body.data.at) { + // *** User api key and token received successfully *** \\ this.aToken = body.data.at this.apiKey = body.data.user.apikey return { @@ -133,6 +154,7 @@ module.exports = class eWeLinkHTTP { } } else { if (body.error === 500) { + // *** Retry if another attempt could be successful *** \\ if (this.debug) this.log.warn('An eWeLink error [500] occured. Retrying in 30 seconds.') await helpers.sleep(30000) return await this.login() @@ -144,7 +166,9 @@ module.exports = class eWeLinkHTTP { } async getDevices () { + // *** Used to get a user's device list *** \\ try { + // *** Send the request *** \\ const res = await axios.get('https://' + this.httpHost + '/v2/device/thing', { headers: { Authorization: 'Bearer ' + this.aToken, @@ -153,6 +177,8 @@ module.exports = class eWeLinkHTTP { 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) } }) + + // *** Parse the response *** \\ const body = res.data if ( !helpers.hasProperty(body, 'data') || @@ -161,16 +187,20 @@ module.exports = class eWeLinkHTTP { ) { throw new Error(JSON.stringify(body, null, 2)) } + + // *** The list also includes scenes so we need to remove them *** \\ const deviceList = [] const sensorList = [] if (body.data.thingList && body.data.thingList.length > 0) { body.data.thingList.forEach(d => { + // *** Check each item is a device and also remove any devices the user has ignored *** \\ if ( helpers.hasProperty(d, 'itemData') && helpers.hasProperty(d.itemData, 'extra') && helpers.hasProperty(d.itemData.extra, 'uiid') && !this.hideDevFromHB.includes(d.itemData.deviceid) ) { + // *** Separate the sensors as these need to be set up first *** \\ if (d.itemData.extra.uiid === 102) { sensorList.push(d.itemData) } else { @@ -179,9 +209,12 @@ module.exports = class eWeLinkHTTP { } }) } + + // *** Sensors need to go first as garages depend on them to exist *** \\ return deviceList.concat(sensorList) } catch (err) { if (helpers.hasProperty(err, 'code') && helpers.httpRetryCodes.includes(err.code)) { + // *** Retry if another attempt could be successful *** \\ if (this.debug) this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') await helpers.sleep(30000) return await this.getDevices() @@ -192,7 +225,9 @@ module.exports = class eWeLinkHTTP { } async getDevice (deviceId) { + // *** Used to get info about a specific device *** \\ try { + // *** Send the request *** \\ const res = await axios.post('https://' + this.httpHost + '/v2/device/thing', { thingList: [{ itemType: 1, @@ -206,6 +241,8 @@ module.exports = class eWeLinkHTTP { 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) } }) + + // *** Parse the response *** \\ const body = res.data if ( !helpers.hasProperty(body, 'data') || @@ -215,12 +252,14 @@ module.exports = class eWeLinkHTTP { throw new Error(JSON.stringify(body, null, 2)) } if (body.data.thingList && body.data.thingList.length === 1) { + // *** Return the device data *** \\ return body.data.thingList[0].itemData } else { throw new Error('device not found in eWeLink') } } catch (err) { if (helpers.hasProperty(err, 'code') && helpers.httpRetryCodes.includes(err.code)) { + // *** Retry if another attempt could be successful *** \\ if (this.debug) this.log.warn('Unable to reach eWeLink. Retrying in 30 seconds.') await helpers.sleep(30000) return await this.getDevice(deviceId) From 206659be4ffe6978bd9cff26e06ad1a1d77c3179 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 20 Nov 2020 14:30:00 +0000 Subject: [PATCH 0812/3183] comments --- lib/ewelink-http.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ewelink-http.js b/lib/ewelink-http.js index 2e6fe055..6a6a48c5 100644 --- a/lib/ewelink-http.js +++ b/lib/ewelink-http.js @@ -200,7 +200,7 @@ module.exports = class eWeLinkHTTP { helpers.hasProperty(d.itemData.extra, 'uiid') && !this.hideDevFromHB.includes(d.itemData.deviceid) ) { - // *** Separate the sensors as these need to be set up first *** \\ + // *** Separate the sensors as these need to be set up last *** \\ if (d.itemData.extra.uiid === 102) { sensorList.push(d.itemData) } else { @@ -210,7 +210,7 @@ module.exports = class eWeLinkHTTP { }) } - // *** Sensors need to go first as garages depend on them to exist *** \\ + // *** Sensors need to go last as they update garages that need to exist already *** \\ return deviceList.concat(sensorList) } catch (err) { if (helpers.hasProperty(err, 'code') && helpers.httpRetryCodes.includes(err.code)) { From 7ca876e4df81353929dfa2bc34bc4a89b7704dbf Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 20 Nov 2020 14:37:36 +0000 Subject: [PATCH 0813/3183] skip matching updates [AL] --- lib/device/light-ctemp.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/device/light-ctemp.js b/lib/device/light-ctemp.js index a5e0a769..57d616d2 100644 --- a/lib/device/light-ctemp.js +++ b/lib/device/light-ctemp.js @@ -40,6 +40,8 @@ module.exports = class deviceLightColour { try { await helpers.sleep(1000) callback() + if (this.lastSentBrightness === value) return + this.lastSentBrightness = value const updateKeyBright = Math.random().toString(36).substr(2, 8) this.accessory.context.updateKeyBright = updateKeyBright // *** Device needs the current ct value sent too *** \\ @@ -62,8 +64,10 @@ module.exports = class deviceLightColour { try { await helpers.sleep(2000) callback() + if (this.lastSentColour === value) return + this.lastSentColour = value const updateKeyColour = Math.random().toString(36).substr(2, 8) - this.accessory.context.updateKeyColour = updateKeyColour + this.updateKeyColour = updateKeyColour // HomeKit has a ct range of 140-500 corresponding to 2000-7143K // B02-F-A60 has a range of 2200K-6500K corresponding to ct: 0-255 let mToK = Math.round(1000000 / value) @@ -79,7 +83,7 @@ module.exports = class deviceLightColour { } this.accessory.context.cacheCT = kToCT await helpers.sleep(1000) - if (updateKeyColour !== this.accessory.context.updateKeyColour) return + if (updateKeyColour !== this.updateKeyColour) return await this.platform.sendDeviceUpdate(this.accessory, params) } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) From 764a760d42ad8d3cb506dbbeb2bb4636991c0908 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 20 Nov 2020 17:37:46 +0000 Subject: [PATCH 0814/3183] 3.13.4-3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 42f82016..0a4dda45 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.4-2", + "version": "3.13.4-3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 66a7d424..9d9256a7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.4-2", + "version": "3.13.4-3", "author": "bwp91", "contributors": [ "gbro115", From 38620147ca051ea4d68bd6875128fe3e0173f71c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 21 Nov 2020 09:58:58 +0000 Subject: [PATCH 0815/3183] Update light-ctemp.js --- lib/device/light-ctemp.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/device/light-ctemp.js b/lib/device/light-ctemp.js index 57d616d2..f962f139 100644 --- a/lib/device/light-ctemp.js +++ b/lib/device/light-ctemp.js @@ -17,12 +17,10 @@ module.exports = class deviceLightColour { this.lightService .getCharacteristic(this.Characteristic.ColorTemperature) .on('set', this.internalColourTempUpdate.bind(this)) - /* - if (platform.api.version === 2.7 && platform.api.versionGreaterOrEqual('1.3.0-beta.26')) { + if (platform.api.version === 2.7 && platform.api.versionGreaterOrEqual('1.3.0-beta.27')) { this.alController = new platform.api.hap.AdaptiveLightingController(this.lightService) accessory.configureController(this.alController) } - */ this.accessory = accessory } From ecc8d099b49145b69f45b3ab97cb4f3ab9ebe51b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 21 Nov 2020 13:25:51 +0000 Subject: [PATCH 0816/3183] Update light-ctemp.js --- lib/device/light-ctemp.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/device/light-ctemp.js b/lib/device/light-ctemp.js index f962f139..42337481 100644 --- a/lib/device/light-ctemp.js +++ b/lib/device/light-ctemp.js @@ -17,10 +17,10 @@ module.exports = class deviceLightColour { this.lightService .getCharacteristic(this.Characteristic.ColorTemperature) .on('set', this.internalColourTempUpdate.bind(this)) - if (platform.api.version === 2.7 && platform.api.versionGreaterOrEqual('1.3.0-beta.27')) { - this.alController = new platform.api.hap.AdaptiveLightingController(this.lightService) - accessory.configureController(this.alController) - } + if (platform.api.version === 2.7 && platform.api.versionGreaterOrEqual('1.3.0-beta.27')) { + this.alController = new platform.api.hap.AdaptiveLightingController(this.lightService) + accessory.configureController(this.alController) + } this.accessory = accessory } From a79fd9b9b866c09ca6986f6a4a390670c18ad8b9 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 21 Nov 2020 18:01:47 +0000 Subject: [PATCH 0817/3183] ws refresh to one hour --- lib/ewelink-platform.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ewelink-platform.js b/lib/ewelink-platform.js index b86e9fb4..f3fa4a83 100644 --- a/lib/ewelink-platform.js +++ b/lib/ewelink-platform.js @@ -149,7 +149,7 @@ module.exports = class eWeLinkPlatform { this.log.warn(this.debug ? err : err.message) } } - }, 1800000, { stopOnError: false }) + }, 3600000, { stopOnError: false }) // *** Logging for informative purposes *** \\ this.log("eWeLink sync complete. Don't forget to ⭐ī¸ this plugin on GitHub if you're finding it useful!") From 4a1916924c54b851cb3994ce37c7d3549b4dd457 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 21 Nov 2020 19:58:28 +0000 Subject: [PATCH 0818/3183] don't update light if off [AL] --- lib/device/light-ctemp.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/device/light-ctemp.js b/lib/device/light-ctemp.js index 42337481..53b9ef23 100644 --- a/lib/device/light-ctemp.js +++ b/lib/device/light-ctemp.js @@ -63,6 +63,7 @@ module.exports = class deviceLightColour { await helpers.sleep(2000) callback() if (this.lastSentColour === value) return + if (!this.lightService.getCharacteristic(this.Characteristic.On).value) return this.lastSentColour = value const updateKeyColour = Math.random().toString(36).substr(2, 8) this.updateKeyColour = updateKeyColour From 36e8f978c4ede3b6f7638cc7a325c15d8952536b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 21 Nov 2020 21:45:11 +0000 Subject: [PATCH 0819/3183] 3.14.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0a4dda45..82469046 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.4-3", + "version": "3.14.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 9d9256a7..178b0aed 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.13.4-3", + "version": "3.14.0", "author": "bwp91", "contributors": [ "gbro115", From 85e9a68c6fed8e3f808f31770738d7121c410c4f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 23 Nov 2020 09:51:52 +0000 Subject: [PATCH 0820/3183] Update light-ctemp.js --- lib/device/light-ctemp.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/device/light-ctemp.js b/lib/device/light-ctemp.js index 53b9ef23..06ee2813 100644 --- a/lib/device/light-ctemp.js +++ b/lib/device/light-ctemp.js @@ -63,7 +63,6 @@ module.exports = class deviceLightColour { await helpers.sleep(2000) callback() if (this.lastSentColour === value) return - if (!this.lightService.getCharacteristic(this.Characteristic.On).value) return this.lastSentColour = value const updateKeyColour = Math.random().toString(36).substr(2, 8) this.updateKeyColour = updateKeyColour @@ -74,6 +73,7 @@ module.exports = class deviceLightColour { if (mToK > 6500) mToK = 6500 const kToCT = Math.round(((mToK - 2200) / 4300) * 255) const params = { + switch: this.lightService.getCharacteristic(this.Characteristic.On).value ? 'on' : 'off', ltype: 'white', white: { ct: kToCT, From 8888c917cfdeb37e0626897a6476a393d5c07219 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 23 Nov 2020 09:52:04 +0000 Subject: [PATCH 0821/3183] Update package-lock.json --- package-lock.json | 67 +++++++---------------------------------------- 1 file changed, 10 insertions(+), 57 deletions(-) diff --git a/package-lock.json b/package-lock.json index 82469046..ad952b7f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -123,11 +123,6 @@ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" }, - "is-negative-zero": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", - "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=" - }, "is-regex": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", @@ -186,63 +181,21 @@ } }, "string.prototype.trimend": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.2.tgz", - "integrity": "sha512-8oAG/hi14Z4nOVP0z6mdiVZ/wqjDtWSLygMigTzAb+7aPEDTleeFf+WrF+alzecxIRkckkJVn+dTlwzJXORATw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", + "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" } }, "string.prototype.trimstart": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.2.tgz", - "integrity": "sha512-7F6CdBTl5zyu30BJFdzSTlSlLPwODC23Od+iLoVH8X6+3fvDPPuBVVj9iaB1GOsSTSIgVfsfm27R2FGrAPznWg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", + "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" } }, "websocket-as-promised": { From a42600540db8e9ffeca4a24711adddab0c670386 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 23 Nov 2020 13:53:26 +0000 Subject: [PATCH 0822/3183] snazzy little ui --- config.schema.json | 1 + homebridge-ui/public/index.html | 169 ++++++++++++++++++++++++++++++++ homebridge-ui/server.js | 34 +++++++ package-lock.json | 5 + package.json | 1 + 5 files changed, 210 insertions(+) create mode 100644 homebridge-ui/public/index.html create mode 100644 homebridge-ui/server.js diff --git a/config.schema.json b/config.schema.json index effe515e..c0f116c8 100644 --- a/config.schema.json +++ b/config.schema.json @@ -2,6 +2,7 @@ "pluginAlias": "eWeLink", "pluginType": "platform", "singular": true, + "customUi": true, "headerDisplay": "

For help and support please visit our GitHub Wiki. We hope you find this plugin useful!

", "schema": { "type": "object", diff --git a/homebridge-ui/public/index.html b/homebridge-ui/public/index.html new file mode 100644 index 00000000..7f0941d7 --- /dev/null +++ b/homebridge-ui/public/index.html @@ -0,0 +1,169 @@ +

+ +

+
+ + + +
+ + + \ No newline at end of file diff --git a/homebridge-ui/server.js b/homebridge-ui/server.js new file mode 100644 index 00000000..a66cb2c8 --- /dev/null +++ b/homebridge-ui/server.js @@ -0,0 +1,34 @@ +const { HomebridgePluginUiServer } = require('@homebridge/plugin-ui-utils') +const fs = require('fs') + +class PluginUiServer extends HomebridgePluginUiServer { + constructor () { + super() + this.onRequest('/getCachedAccessories', async () => { + const devicesToReturn = [] + let cachedAccessories = await fs.promises.readFile(this.homebridgeStoragePath + '/accessories/cachedAccessories') + cachedAccessories = JSON.parse(cachedAccessories) + cachedAccessories + .filter(accessory => accessory.plugin === 'homebridge-ewelink') + .sort((a, b) => { + return a.displayName.toLowerCase() > b.displayName.toLowerCase() + ? 1 + : b.displayName.toLowerCase() > a.displayName.toLowerCase() + ? -1 + : 0 + }) + .forEach(accessory => { + devicesToReturn.push({ + displayName: accessory.displayName, + context: accessory.context + }) + }) + return devicesToReturn + }) + this.ready() + } +} + +(() => { + return new PluginUiServer() +})() diff --git a/package-lock.json b/package-lock.json index ad952b7f..76db033a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,11 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@homebridge/plugin-ui-utils": { + "version": "0.0.17", + "resolved": "https://registry.npmjs.org/@homebridge/plugin-ui-utils/-/plugin-ui-utils-0.0.17.tgz", + "integrity": "sha512-b/36608DrTDgji9tWu126kg+pgS5lXctVwtgUK/t1pH/TsSAWcR7XUe6oDZ364umZm/1CMrVweMlOd+633q8nQ==" + }, "axios": { "version": "0.21.0", "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.0.tgz", diff --git a/package.json b/package.json index 178b0aed..29d80c19 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ } ], "dependencies": { + "@homebridge/plugin-ui-utils": "^0.0.17", "axios": "^0.21.0", "color-convert": "^2.0.1", "interval-promise": "^1.4.0", From f6e97ab98077faa71bc67a6dabd82f723b775b21 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 23 Nov 2020 13:54:06 +0000 Subject: [PATCH 0823/3183] 3.14.1-0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 76db033a..9f004f8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.14.0", + "version": "3.14.1-0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 29d80c19..6f79bac2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "3.14.0", + "version": "3.14.1-0", "author": "bwp91", "contributors": [ "gbro115", From 024dc9e527bced33422c19ea8ba2c05a0dbabac0 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 23 Nov 2020 14:03:04 +0000 Subject: [PATCH 0824/3183] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 653b250d..a4cb08b3 100644 --- a/README.md +++ b/README.md @@ -29,13 +29,13 @@ Homebridge/HOOBS plugin to control eWeLink devices with original firmware. * [Installation (Homebridge)](https://github.com/bwp91/homebridge-ewelink/wiki/Installation-(Homebridge)) * [Installation (HOOBS)](https://github.com/bwp91/homebridge-ewelink/wiki/Installation-(HOOBS)) * [Configuration](https://github.com/bwp91/homebridge-ewelink/wiki/Configuration) -* [Beta Version](https://github.com/bwp91/homebridge-ewelink/wiki/Beta-Version) ### Features * [Supported Devices](https://github.com/bwp91/homebridge-ewelink/wiki/Supported-Devices) * [Multi Channel Devices](https://github.com/bwp91/homebridge-ewelink/wiki/Multi-Channel-Devices) * [Accessory Simulations](https://github.com/bwp91/homebridge-ewelink/wiki/Accessory-Simulations) * [Connection Methods](https://github.com/bwp91/homebridge-ewelink/wiki/Connection-Methods) +* [Beta Version](https://github.com/bwp91/homebridge-ewelink/wiki/Beta-Version) ### How-to Guides * [How to set up RF Bridge sensors](https://github.com/bwp91/homebridge-ewelink/wiki/How-to-set-up-RF-Bridge-sensors) From 1bfa8fc3c64a25843e18b8af736593aa092f79f3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 23 Nov 2020 14:04:13 +0000 Subject: [PATCH 0825/3183] Update index.html --- homebridge-ui/public/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/homebridge-ui/public/index.html b/homebridge-ui/public/index.html index 7f0941d7..a282b3ba 100644 --- a/homebridge-ui/public/index.html +++ b/homebridge-ui/public/index.html @@ -16,6 +16,7 @@

Features

  • Multi Channel Devices
  • Accessory Simulations
  • Connection Methods
  • +
  • Beta Version
  • How-to Guides

    +

    Credits

    + +

    Disclaimer

    -

    I am in no way affiliated with eWeLink nor any of the device brands (like Sonoff) and this plugin is a personal project that I maintain in my free time.

    + + + ` } action (url) { - const nowDate = new Date() - if ((nowDate - this.lastDate) / 1000 < 1) { - throw new Error('Requested too soon') - } - this.lastDate = nowDate const pathParts = url.split('/') const device = pathParts[1] const action = pathParts[2] diff --git a/lib/index.js b/lib/index.js index ac02815c..5905f6a6 100644 --- a/lib/index.js +++ b/lib/index.js @@ -567,6 +567,11 @@ class eWeLinkPlatform { if (this.config.apiPort !== 0) { apiClient = new (require('./connection/api'))(this, devicesInHB) apiServer = http.createServer((req, res) => { + if (req.url === '/') { + res.writeHead(200, { 'Content-Type': 'text/html' }) + res.end(apiClient.showHome()) + return + } res.writeHead(200, { 'Content-Type': 'application/json' }) try { const response = apiClient.action(req.url) From 2bb54b95bb82cac124cad83c99bbbf27523492e7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 14:49:45 +0100 Subject: [PATCH 2013/3183] 6.4.1-beta.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 829b089b..83a4afb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.4.1-beta.0", + "version": "6.4.1-beta.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 7e647dca..a08fd2ce 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.4.1-beta.0", + "version": "6.4.1-beta.1", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From 55c054dadc48a7210f8b64704d5a799b4b7011fc Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 16:54:10 +0100 Subject: [PATCH 2014/3183] add brightness, change api method to updateCharacteristic --- lib/connection/api.js | 120 +++++++++++++++++++++++++++++++++--------- lib/index.js | 4 +- 2 files changed, 96 insertions(+), 28 deletions(-) diff --git a/lib/connection/api.js b/lib/connection/api.js index 6cfbc6bb..9773bfa6 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -76,7 +76,7 @@ module.exports = class connectionAPI { - Query the ON/OFF state.
    + Query the on/off state.
    Example response:
    {"success":true,"response":"on"} @@ -84,7 +84,15 @@ module.exports = class connectionAPI { - Set the state to ON.
    + Query the brightness between 0% and 100%.
    + Example response:
    + {"success":true,"response":34} + + /{hbDeviceId}/get/brightness + + + + Set the state to on.
    Example response:
    {"success":true} @@ -92,7 +100,7 @@ module.exports = class connectionAPI { - Set the state to OFF.
    + Set the state to off.
    Example response:
    {"success":true} @@ -100,12 +108,20 @@ module.exports = class connectionAPI { - Toggle the current state.
    + Switch (toggle) the current state.
    Example response:
    {"success":true} /{hbDeviceId}/set/state/toggle + + + Set the brightness between 0% and 100%.
    + Example response:
    + {"success":true} + + /{hbDeviceId}/set/brightness/54 + @@ -132,7 +148,7 @@ module.exports = class connectionAPI { ` } - action (url) { + async action (url) { const pathParts = url.split('/') const device = pathParts[1] const action = pathParts[2] @@ -154,46 +170,98 @@ module.exports = class connectionAPI { if (!attribute) { throw new Error('No attribute specified') } - if (!['state'].includes(attribute)) { - throw new Error("Action must be 'state'") + if (!['state', 'brightness'].includes(attribute)) { + throw new Error("Attribute must be 'state' or 'brightness'") } if (action === 'set') { if (!newStatus) { throw new Error('No new status specified') } - if (!['on', 'off', 'toggle'].includes(newStatus)) { - throw new Error("New status must be 'on', 'off' or 'toggle' for attribute:state") - } } const accessory = this.devicesInHB.get(uuid) - const service = accessory.getService(this.hapServ.Switch) || - accessory.getService(this.hapServ.Outlet) || - accessory.getService(this.hapServ.Lightbulb) + if (!accessory.control) { + throw new Error('Accessory has not been initialised yet') + } + + let service + let charName - if (!service) { - throw new Error("Accessory is not 'Switch', 'Outlet' or 'Lightbulb'") + switch (attribute) { + case 'state': + service = accessory.getService(this.hapServ.Switch) || + accessory.getService(this.hapServ.Outlet) || + accessory.getService(this.hapServ.Lightbulb) + if (service) { + charName = service.testCharacteristic(this.hapChar.On) + ? this.hapChar.On + : false + } + break + case 'brightness': + service = accessory.getService(this.hapServ.Lightbulb) + if (service) { + charName = service.testCharacteristic(this.hapChar.Brightness) + ? this.hapChar.Brightness + : false + } + break } - const currentHKStatus = service.getCharacteristic(this.hapChar.On).value + if (!charName) { + throw new Error("Accessory does not support attribute '" + attribute + "'") + } + + const currentHKStatus = service.getCharacteristic(charName).value if (action === 'get') { - return currentHKStatus ? 'on' : 'off' + switch (attribute) { + case 'state': + return service.getCharacteristic(charName).value ? 'on' : 'off' + case 'brightness': + return service.getCharacteristic(charName).value + } } if (action === 'set') { let newHKStatus - switch (newStatus) { - case 'on': - newHKStatus = true - break - case 'off': - newHKStatus = false + switch (attribute) { + case 'state': + switch (newStatus) { + case 'on': + newHKStatus = true + break + case 'off': + newHKStatus = false + break + case 'toggle': + newHKStatus = !currentHKStatus + break + default: + throw new Error( + "New status must be 'on', 'off' or 'toggle' for attribute:state" + ) + } + if (!accessory.control.internalStateUpdate) { + throw new Error('Function to control accessory not found') + } + await accessory.control.internalStateUpdate(newHKStatus) break - case 'toggle': - newHKStatus = !currentHKStatus + case 'brightness': { + newHKStatus = parseInt(newStatus) + if (isNaN(newHKStatus) || newHKStatus < 0 || newHKStatus > 100) { + throw new Error( + 'New status must be integer 0-100 for attribute:brightness' + ) + } + if (!accessory.control.internalBrightnessUpdate) { + throw new Error('Function to control accessory not found') + } + await accessory.control.internalBrightnessUpdate(newHKStatus) break + } } - service.setCharacteristic(this.hapChar.On, newHKStatus) + // service.setCharacteristic(charName, newHKStatus) + service.updateCharacteristic(charName, newHKStatus) } } } diff --git a/lib/index.js b/lib/index.js index 5905f6a6..b6db1d6e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -566,7 +566,7 @@ class eWeLinkPlatform { // Set up the listener server for the API if the user has this enabled if (this.config.apiPort !== 0) { apiClient = new (require('./connection/api'))(this, devicesInHB) - apiServer = http.createServer((req, res) => { + apiServer = http.createServer(async (req, res) => { if (req.url === '/') { res.writeHead(200, { 'Content-Type': 'text/html' }) res.end(apiClient.showHome()) @@ -574,7 +574,7 @@ class eWeLinkPlatform { } res.writeHead(200, { 'Content-Type': 'application/json' }) try { - const response = apiClient.action(req.url) + const response = await apiClient.action(req.url) res.end(JSON.stringify({ success: true, response })) } catch (e) { const eText = this.funcs.parseError(e) From bf782dbc182151047faacfd3e6c3bb90e8348a16 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 16:54:45 +0100 Subject: [PATCH 2015/3183] 6.4.1-beta.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 83a4afb1..0bb960dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.4.1-beta.1", + "version": "6.4.1-beta.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a08fd2ce..303dc081 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.4.1-beta.1", + "version": "6.4.1-beta.2", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From 0505494da5c6e14ac8f88a6ab285bd8409c2dc5e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 17:27:29 +0100 Subject: [PATCH 2016/3183] use more caching --- lib/device/outlet-scm.js | 3 +++ lib/device/outlet-single.js | 3 +++ lib/device/sensor-ambient.js | 5 +++-- lib/device/switch-single.js | 3 +++ lib/device/zigbee/switch-single.js | 3 +++ 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/device/outlet-scm.js b/lib/device/outlet-scm.js index 33f92c31..b3ed2845 100644 --- a/lib/device/outlet-scm.js +++ b/lib/device/outlet-scm.js @@ -62,6 +62,9 @@ module.exports = class deviceOutletSCM { async internalStateUpdate (value) { try { const newValue = value ? 'on' : 'off' + if (newValue === this.cacheState) { + return + } const params = { switches: [{ switch: newValue, outlet: 0 }] } diff --git a/lib/device/outlet-single.js b/lib/device/outlet-single.js index 97ce858e..472a48a9 100644 --- a/lib/device/outlet-single.js +++ b/lib/device/outlet-single.js @@ -154,6 +154,9 @@ module.exports = class deviceOutletSingle { async internalStateUpdate (value) { try { const newValue = value ? 'on' : 'off' + if (newValue === this.cacheState) { + return + } await this.platform.sendDeviceUpdate(this.accessory, { switch: newValue }) diff --git a/lib/device/sensor-ambient.js b/lib/device/sensor-ambient.js index 17ea0ec4..c629cf0c 100644 --- a/lib/device/sensor-ambient.js +++ b/lib/device/sensor-ambient.js @@ -95,9 +95,10 @@ module.exports = class deviceSensorAmbient { async internalStateUpdate (value) { try { const newValue = value ? 'on' : 'off' - const params = { - switch: newValue + if (newValue === this.cacheState) { + return } + const params = { switch: newValue } await this.platform.sendDeviceUpdate(this.accessory, params) this.cacheState = newValue if (!this.disableDeviceLogging) { diff --git a/lib/device/switch-single.js b/lib/device/switch-single.js index 8ee1beda..e7df4557 100644 --- a/lib/device/switch-single.js +++ b/lib/device/switch-single.js @@ -51,6 +51,9 @@ module.exports = class deviceSwitchSingle { async internalStateUpdate (value) { try { const newValue = value ? 'on' : 'off' + if (newValue === this.cacheState) { + return + } await this.platform.sendDeviceUpdate(this.accessory, { switch: newValue }) diff --git a/lib/device/zigbee/switch-single.js b/lib/device/zigbee/switch-single.js index 24f71cef..4fe426ab 100644 --- a/lib/device/zigbee/switch-single.js +++ b/lib/device/zigbee/switch-single.js @@ -54,6 +54,9 @@ module.exports = class deviceZBSwitchSingle { async internalStateUpdate (value) { try { const newValue = value ? 'on' : 'off' + if (newValue === this.cacheState) { + return + } await this.platform.sendDeviceUpdate(this.accessory, { switch: newValue }) From e736c13353764de3aa606db29756952be0f723fb Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 17:39:57 +0100 Subject: [PATCH 2017/3183] offline device docs, and more checks for attribute --- lib/connection/api.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/connection/api.js b/lib/connection/api.js index 9773bfa6..03baa3cc 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -63,6 +63,13 @@ module.exports = class connectionAPI {
  • Lights
  • +
  • A note about offline devices: + +
  • Available Commands
    @@ -170,9 +177,6 @@ module.exports = class connectionAPI { if (!attribute) { throw new Error('No attribute specified') } - if (!['state', 'brightness'].includes(attribute)) { - throw new Error("Attribute must be 'state' or 'brightness'") - } if (action === 'set') { if (!newStatus) { throw new Error('No new status specified') @@ -208,7 +212,7 @@ module.exports = class connectionAPI { } if (!charName) { - throw new Error("Accessory does not support attribute '" + attribute + "'") + throw new Error('Accessory does not support attribute:' + attribute) } const currentHKStatus = service.getCharacteristic(charName).value @@ -219,6 +223,8 @@ module.exports = class connectionAPI { return service.getCharacteristic(charName).value ? 'on' : 'off' case 'brightness': return service.getCharacteristic(charName).value + default: + throw new Error("Invalid attribute for action:get'") } } @@ -259,6 +265,8 @@ module.exports = class connectionAPI { await accessory.control.internalBrightnessUpdate(newHKStatus) break } + default: + throw new Error("Invalid attribute for action:set'") } // service.setCharacteristic(charName, newHKStatus) service.updateCharacteristic(charName, newHKStatus) From a9868353e64e686a15c679cf0ec196f4dc4a912e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 17:40:39 +0100 Subject: [PATCH 2018/3183] 6.4.1-beta.3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0bb960dd..5ae0e93c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.4.1-beta.2", + "version": "6.4.1-beta.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 303dc081..df7d9625 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.4.1-beta.2", + "version": "6.4.1-beta.3", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From a47340277e3f5b30a66fe56f435a6e07b06ad047 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 18:14:00 +0100 Subject: [PATCH 2019/3183] code comments --- lib/connection/api.js | 48 +++++++++++++++++++++++++++++++++++++++++-- lib/index.js | 6 ++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/lib/connection/api.js b/lib/connection/api.js index 03baa3cc..c97210a0 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -17,7 +17,7 @@ module.exports = class connectionAPI { } showHome () { - let accList = '' + // This nifty little function creates a map of devices sorted by display name const mapAsc = new Map([...this.devicesInHB.entries()].sort((a, b) => { return a[1].displayName.toLowerCase() > b[1].displayName.toLowerCase() ? 1 @@ -25,12 +25,17 @@ module.exports = class connectionAPI { ? -1 : 0 })) + + // This variable stores the html table rows for displaying the devices + let accList = '' mapAsc.forEach(accessory => { accList += ` ${accessory.displayName} ${accessory.context.hbDeviceId} ` }) + + // Return the home page for the API return ` @@ -156,45 +161,66 @@ module.exports = class connectionAPI { } async action (url) { + // Obtain the parts of the request url const pathParts = url.split('/') const device = pathParts[1] const action = pathParts[2] const attribute = pathParts[3] const newStatus = pathParts[4] + + // Check a device was specified if (!device) { throw new Error('No accessory specified') } + + // Try and find the device in Homebridge const uuid = this.hapUUIDGen(device) if (!this.devicesInHB.has(uuid)) { throw new Error('Accessory not found in Homebridge') } + + // Check an action was specified if (!action) { throw new Error('No action specified') } + + // Check the action is either get or set if (!['get', 'set'].includes(action)) { throw new Error("Action must be 'get' or 'set'") } + + // Check an attribute was specified if (!attribute) { throw new Error('No attribute specified') } + + // Check a new status was supplied if the action is set if (action === 'set') { if (!newStatus) { throw new Error('No new status specified') } } + + // Obtain the corresponding accessory const accessory = this.devicesInHB.get(uuid) + + // Check the device is controllable if (!accessory.control) { throw new Error('Accessory has not been initialised yet') } + // These variables depend on the attribute that was supplied let service let charName switch (attribute) { case 'state': + // This can apply to switches outlets and lights service = accessory.getService(this.hapServ.Switch) || accessory.getService(this.hapServ.Outlet) || accessory.getService(this.hapServ.Lightbulb) + + // Check the accessory has one of these services if (service) { charName = service.testCharacteristic(this.hapChar.On) ? this.hapChar.On @@ -202,7 +228,10 @@ module.exports = class connectionAPI { } break case 'brightness': + // This can apply to lights service = accessory.getService(this.hapServ.Lightbulb) + + // Check the accessory has one of these services if (service) { charName = service.testCharacteristic(this.hapChar.Brightness) ? this.hapChar.Brightness @@ -211,12 +240,15 @@ module.exports = class connectionAPI { break } + // Check that the accessory has the corresponding characteristic for the attribute if (!charName) { throw new Error('Accessory does not support attribute:' + attribute) } + // Obtain the cached value of the accessory-service-characteristic const currentHKStatus = service.getCharacteristic(charName).value + // With a get action we return the cache value from above if (action === 'get') { switch (attribute) { case 'state': @@ -228,10 +260,12 @@ module.exports = class connectionAPI { } } + // With a set action we need to call the set handler for the characteristic if (action === 'set') { let newHKStatus switch (attribute) { case 'state': + // The new status for state must be on, off or toggle switch (newStatus) { case 'on': newHKStatus = true @@ -247,28 +281,38 @@ module.exports = class connectionAPI { "New status must be 'on', 'off' or 'toggle' for attribute:state" ) } + + // Check the accessory has a correct set handler for on/off if (!accessory.control.internalStateUpdate) { throw new Error('Function to control accessory not found') } + + // Call the set handler to send the request to eWeLink await accessory.control.internalStateUpdate(newHKStatus) break case 'brightness': { + // The new status for brightness must be an integer between 0 and 100 newHKStatus = parseInt(newStatus) if (isNaN(newHKStatus) || newHKStatus < 0 || newHKStatus > 100) { throw new Error( 'New status must be integer 0-100 for attribute:brightness' ) } + + // Check the accessory has a correct set handler for on/off if (!accessory.control.internalBrightnessUpdate) { throw new Error('Function to control accessory not found') } + + // Call the set handler to send the request to eWeLink await accessory.control.internalBrightnessUpdate(newHKStatus) break } default: throw new Error("Invalid attribute for action:set'") } - // service.setCharacteristic(charName, newHKStatus) + + // The eWeLink request was successful so update the characteristic in HomeKit service.updateCharacteristic(charName, newHKStatus) } } diff --git a/lib/index.js b/lib/index.js index b6db1d6e..f81bf3d7 100644 --- a/lib/index.js +++ b/lib/index.js @@ -567,16 +567,22 @@ class eWeLinkPlatform { if (this.config.apiPort !== 0) { apiClient = new (require('./connection/api'))(this, devicesInHB) apiServer = http.createServer(async (req, res) => { + // The 'homepage' shows an html document with info about the API if (req.url === '/') { res.writeHead(200, { 'Content-Type': 'text/html' }) res.end(apiClient.showHome()) return } + + // Request is not for the homepage so action appropriately res.writeHead(200, { 'Content-Type': 'application/json' }) try { const response = await apiClient.action(req.url) + + // Actioning the request was successful so respond with a success res.end(JSON.stringify({ success: true, response })) } catch (e) { + // An error occurred actioning the request so respond with the error const eText = this.funcs.parseError(e) res.end(JSON.stringify({ success: false, error: eText })) } From f68633bd22578fa9f918997708e66758160151e5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 18:14:42 +0100 Subject: [PATCH 2020/3183] 6.4.1-beta.4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5ae0e93c..664f9cdd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.4.1-beta.3", + "version": "6.4.1-beta.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index df7d9625..f2109deb 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.4.1-beta.3", + "version": "6.4.1-beta.4", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From 066192d8c4726b8877aea710bc20e7102615a23e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 19:59:37 +0100 Subject: [PATCH 2021/3183] add more endpoints to api --- lib/connection/api.js | 308 +++++++++++++++++++++++++-------- lib/device/light-cct.js | 15 +- lib/device/light-rgb-cct.js | 29 ++-- lib/device/zigbee/light-cct.js | 12 +- 4 files changed, 269 insertions(+), 95 deletions(-) diff --git a/lib/connection/api.js b/lib/connection/api.js index c97210a0..eb910dff 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -66,6 +66,8 @@ module.exports = class connectionAPI {
  • Switches
  • Outlets
  • Lights
  • +
  • Temperature Sensors
  • +
  • Humidity Sensors
  • A note about offline devices: @@ -86,54 +88,110 @@ module.exports = class connectionAPI { - - - Query the on/off state.
    - Example response:
    - {"success":true,"response":"on"} - - /{hbDeviceId}/get/state - - - - Query the brightness between 0% and 100%.
    - Example response:
    - {"success":true,"response":34} - - /{hbDeviceId}/get/brightness - - - - Set the state to on.
    - Example response:
    - {"success":true} - - /{hbDeviceId}/set/state/on - - - - Set the state to off.
    - Example response:
    - {"success":true} - - /{hbDeviceId}/set/state/off - - - - Switch (toggle) the current state.
    - Example response:
    - {"success":true} - - /{hbDeviceId}/set/state/toggle - - - - Set the brightness between 0% and 100%.
    - Example response:
    - {"success":true} - - /{hbDeviceId}/set/brightness/54 - + + + Query the on/off state.
    + Example response:
    + {"success":true,"response":"on"} + + /{hbDeviceId}/get/state + + + + Query the brightness between 0% and 100%.
    + Example response:
    + {"success":true,"response":34} + + /{hbDeviceId}/get/brightness + + + + Query the hue between 0° and 360°.
    + Example response:
    + {"success":true,"response":17} + + /{hbDeviceId}/get/hue + + + + Query the colour temperature between 140 and 500 mired.
    + Example response:
    + {"success":true,"response":345} + + /{hbDeviceId}/get/colourtemperature + + + + Query the Adaptive Lighting on/off state.
    + Example response:
    + {"success":true,"response":"on"} + + /{hbDeviceId}/get/adaptivelighting + + + + Query the temperature as °C.
    + Example response:
    + {"success":true,"response":16.3} + + /{hbDeviceId}/get/temperature + + + + Query the humidity a %.
    + Example response:
    + {"success":true,"response":54} + + /{hbDeviceId}/get/humidity + + + + Set the state to on.
    + Example response:
    + {"success":true} + + /{hbDeviceId}/set/state/on + + + + Set the state to off.
    + Example response:
    + {"success":true} + + /{hbDeviceId}/set/state/off + + + + Switch (toggle) the current state.
    + Example response:
    + {"success":true} + + /{hbDeviceId}/set/state/toggle + + + + Set the brightness between 0% and 100%.
    + Example response:
    + {"success":true} + + /{hbDeviceId}/set/brightness/54 + + + + Set the hue between 0° and 360°.
    + Example response:
    + {"success":true} + + /{hbDeviceId}/set/hue/157 + + + + Set the colour temperature between 140 and 500 mired.
    + Example response:
    + {"success":true} + + /{hbDeviceId}/set/colourtemperature/300 +
  • @@ -214,6 +272,51 @@ module.exports = class connectionAPI { let charName switch (attribute) { + case 'adaptivelighting': + case 'colourtemperature': + // This can apply to lights that support colour + service = accessory.getService(this.hapServ.Lightbulb) + + // Check the accessory has one of these services + if (service) { + charName = service.testCharacteristic(this.hapChar.ColorTemperature) + ? this.hapChar.ColorTemperature + : false + } + break + case 'brightness': + // This can apply to lights + service = accessory.getService(this.hapServ.Lightbulb) + + // Check the accessory has one of these services + if (service) { + charName = service.testCharacteristic(this.hapChar.Brightness) + ? this.hapChar.Brightness + : false + } + break + case 'hue': + // This can apply to lights that support colour + service = accessory.getService(this.hapServ.Lightbulb) + + // Check the accessory has one of these services + if (service) { + charName = service.testCharacteristic(this.hapChar.Hue) + ? this.hapChar.Hue + : false + } + break + case 'humidity': + // This can apply to humidity sensors + service = accessory.getService(this.hapServ.HumiditySensor) + + // Check the accessory has one of these services + if (service) { + charName = service.testCharacteristic(this.hapChar.CurrentRelativeHumidity) + ? this.hapChar.CurrentRelativeHumidity + : false + } + break case 'state': // This can apply to switches outlets and lights service = accessory.getService(this.hapServ.Switch) || @@ -227,17 +330,19 @@ module.exports = class connectionAPI { : false } break - case 'brightness': - // This can apply to lights - service = accessory.getService(this.hapServ.Lightbulb) + case 'temperature': + // This can apply to temperature sensors + service = accessory.getService(this.hapServ.TemperatureSensor) // Check the accessory has one of these services if (service) { - charName = service.testCharacteristic(this.hapChar.Brightness) - ? this.hapChar.Brightness + charName = service.testCharacteristic(this.hapChar.CurrentTemperature) + ? this.hapChar.CurrentTemperature : false } break + default: + throw new Error('Invalid attribute given') } // Check that the accessory has the corresponding characteristic for the attribute @@ -251,10 +356,19 @@ module.exports = class connectionAPI { // With a get action we return the cache value from above if (action === 'get') { switch (attribute) { - case 'state': - return service.getCharacteristic(charName).value ? 'on' : 'off' + case 'adaptivelighting': + return accessory.alController && + accessory.alController.isAdaptiveLightingActive() + ? 'on' + : 'off' case 'brightness': + case 'colourtemperature': + case 'hue': + case 'humidity': + case 'temperature': return service.getCharacteristic(charName).value + case 'state': + return service.getCharacteristic(charName).value ? 'on' : 'off' default: throw new Error("Invalid attribute for action:get'") } @@ -264,6 +378,72 @@ module.exports = class connectionAPI { if (action === 'set') { let newHKStatus switch (attribute) { + case 'brightness': { + // The new status for brightness must be an integer between 0 and 100 + newHKStatus = parseInt(newStatus) + if (isNaN(newHKStatus) || newHKStatus < 0 || newHKStatus > 100) { + throw new Error( + 'New status must be integer 0-100 for attribute:brightness' + ) + } + + // Check the accessory has a correct set handler for on/off + if (!accessory.control.internalBrightnessUpdate) { + throw new Error('Function to control accessory not found') + } + + // Call the set handler to send the request to eWeLink + await accessory.control.internalBrightnessUpdate(newHKStatus) + break + } + case 'colourtemperature': { + // The new status for colour temperature must be an integer between 140 and 500 + newHKStatus = parseInt(newStatus) + if (isNaN(newHKStatus) || newHKStatus < 140 || newHKStatus > 500) { + throw new Error( + 'New status must be integer 140-500 for attribute:colourtemperature' + ) + } + + // Check the accessory has a correct set handler for on/off + if (!accessory.control.internalCTUpdate) { + throw new Error('Function to control accessory not found') + } + + // Call the set handler to send the request to eWeLink + if ( + accessory.alController && + accessory.alController.isAdaptiveLightingActive() + ) { + accessory.alController.disableAdaptiveLighting() + } + await accessory.control.internalCTUpdate(newHKStatus) + break + } + case 'hue': { + // The new status for hue must be an integer between 0 and 360 + newHKStatus = parseInt(newStatus) + if (isNaN(newHKStatus) || newHKStatus < 0 || newHKStatus > 360) { + throw new Error( + 'New status must be integer 0-360 for attribute:hue' + ) + } + + // Check the accessory has a correct set handler for on/off + if (!accessory.control.internalColourUpdate) { + throw new Error('Function to control accessory not found') + } + + // Call the set handler to send the request to eWeLink + if ( + accessory.alController && + accessory.alController.isAdaptiveLightingActive() + ) { + accessory.alController.disableAdaptiveLighting() + } + await accessory.control.internalColourUpdate(newHKStatus) + break + } case 'state': // The new status for state must be on, off or toggle switch (newStatus) { @@ -290,24 +470,6 @@ module.exports = class connectionAPI { // Call the set handler to send the request to eWeLink await accessory.control.internalStateUpdate(newHKStatus) break - case 'brightness': { - // The new status for brightness must be an integer between 0 and 100 - newHKStatus = parseInt(newStatus) - if (isNaN(newHKStatus) || newHKStatus < 0 || newHKStatus > 100) { - throw new Error( - 'New status must be integer 0-100 for attribute:brightness' - ) - } - - // Check the accessory has a correct set handler for on/off - if (!accessory.control.internalBrightnessUpdate) { - throw new Error('Function to control accessory not found') - } - - // Call the set handler to send the request to eWeLink - await accessory.control.internalBrightnessUpdate(newHKStatus) - break - } default: throw new Error("Invalid attribute for action:set'") } diff --git a/lib/device/light-cct.js b/lib/device/light-cct.js index 65fed136..6cb24ebb 100644 --- a/lib/device/light-cct.js +++ b/lib/device/light-cct.js @@ -73,11 +73,11 @@ module.exports = class deviceLightCCT { this.cacheBright = this.service.getCharacteristic(this.hapChar.Brightness).value // Set up the adaptive lighting controller - this.alController = new platform.api.hap.AdaptiveLightingController( + this.accessory.alController = new platform.api.hap.AdaptiveLightingController( this.service, { customTemperatureAdjustment: this.alShift } ) - this.accessory.configureController(this.alController) + this.accessory.configureController(this.accessory.alController) // Output the customised options to the log if in debug mode if (platform.config.debug) { @@ -162,7 +162,7 @@ module.exports = class deviceLightCCT { if (this.cacheMired === value || this.cacheState !== 'on') { return } - if (!this.isOnline && this.alController.isAdaptiveLightingActive()) { + if (!this.isOnline && this.accessory.alController.isAdaptiveLightingActive()) { return } const updateKey = Math.random().toString(36).substr(2, 8) @@ -190,7 +190,10 @@ module.exports = class deviceLightCCT { this.cacheMired = value this.cacheCT = scaledCT if (!this.disableDeviceLogging) { - if (this.alController && this.alController.isAdaptiveLightingActive()) { + if ( + this.accessory.alController && + this.accessory.alController.isAdaptiveLightingActive() + ) { this.log( '[%s] %s [%sK] %s.', this.name, @@ -251,9 +254,9 @@ module.exports = class deviceLightCCT { if (!this.disableDeviceLogging) { this.log('[%s] %s [%sK].', this.name, this.lang.curColour, scaledK) } - if (this.alController.isAdaptiveLightingActive() && ctDiff > 20) { + if (this.accessory.alController.isAdaptiveLightingActive() && ctDiff > 20) { // Look for a variation greater than twenty - this.alController.disableAdaptiveLighting() + this.accessory.alController.disableAdaptiveLighting() if (!this.disableDeviceLogging) { this.log('[%s] %s.', this.name, this.lang.disabledAL) } diff --git a/lib/device/light-rgb-cct.js b/lib/device/light-rgb-cct.js index b403f5cb..887e7ab7 100644 --- a/lib/device/light-rgb-cct.js +++ b/lib/device/light-rgb-cct.js @@ -65,11 +65,11 @@ module.exports = class deviceLightRGBCCT { this.cacheBright = this.service.getCharacteristic(this.hapChar.Brightness).value // Set up the adaptive lighting controller - this.alController = new platform.api.hap.AdaptiveLightingController( + this.accessory.alController = new platform.api.hap.AdaptiveLightingController( this.service, { customTemperatureAdjustment: this.alShift } ) - this.accessory.configureController(this.alController) + this.accessory.configureController(this.accessory.alController) // Output the customised options to the log if in debug mode if (platform.config.debug) { @@ -247,7 +247,7 @@ module.exports = class deviceLightRGBCCT { if (this.cacheMired === value || this.cacheState !== 'on') { return } - if (!this.isOnline && this.alController.isAdaptiveLightingActive()) { + if (!this.isOnline && this.accessory.alController.isAdaptiveLightingActive()) { return } const updateKey = Math.random().toString(36).substr(2, 8) @@ -310,7 +310,7 @@ module.exports = class deviceLightRGBCCT { break } if (!this.disableDeviceLogging) { - if (this.alController.isAdaptiveLightingActive()) { + if (this.accessory.alController.isAdaptiveLightingActive()) { this.log( '[%s] %s [%sK] %s.', this.name, @@ -387,8 +387,11 @@ module.exports = class deviceLightRGBCCT { this.cacheR + ' ' + this.cacheG + ' ' + this.cacheB ) } - if (this.alController.isAdaptiveLightingActive() && rgbDiff > 50) { - this.alController.disableAdaptiveLighting() + if ( + this.accessory.alController.isAdaptiveLightingActive() && + rgbDiff > 50 + ) { + this.accessory.alController.disableAdaptiveLighting() if (!this.disableDeviceLogging) { this.log('[%s] %s.', this.name, this.lang.disabledAL) } @@ -444,8 +447,11 @@ module.exports = class deviceLightRGBCCT { } } } - if (params.updateSource && this.alController.isAdaptiveLightingActive()) { - this.alController.disableAdaptiveLighting() + if ( + params.updateSource && + this.accessory.alController.isAdaptiveLightingActive() + ) { + this.accessory.alController.disableAdaptiveLighting() if (!this.disableDeviceLogging) { this.log('[%s] %s.', this.name, this.lang.disabledAL) } @@ -490,9 +496,12 @@ module.exports = class deviceLightRGBCCT { if (!this.disableDeviceLogging) { this.log('[%s] %s [%sK].', this.name, this.lang.curColour, ctToK) } - if (this.alController.isAdaptiveLightingActive() && ctDiff > 20) { + if ( + this.accessory.alController.isAdaptiveLightingActive() && + ctDiff > 20 + ) { // Look for a variation greater than twenty - this.alController.disableAdaptiveLighting() + this.accessory.alController.disableAdaptiveLighting() if (!this.disableDeviceLogging) { this.log('[%s] %s.', this.name, this.lang.disabledAL) } diff --git a/lib/device/zigbee/light-cct.js b/lib/device/zigbee/light-cct.js index e9a62fe6..07f205e8 100644 --- a/lib/device/zigbee/light-cct.js +++ b/lib/device/zigbee/light-cct.js @@ -66,11 +66,11 @@ module.exports = class deviceZBLightCCT { this.cacheBright = this.service.getCharacteristic(this.hapChar.Brightness).value // Set up the adaptive lighting controller - this.alController = new platform.api.hap.AdaptiveLightingController( + this.accessory.alController = new platform.api.hap.AdaptiveLightingController( this.service, { customTemperatureAdjustment: this.alShift } ) - this.accessory.configureController(this.alController) + this.accessory.configureController(this.accessory.alController) // Output the customised options to the log if in debug mode if (platform.config.debug) { @@ -136,7 +136,7 @@ module.exports = class deviceZBLightCCT { if (this.cacheMired === value || this.cacheState !== 'on') { return } - if (!this.isOnline && this.alController.isAdaptiveLightingActive()) { + if (!this.isOnline && this.accessory.alController.isAdaptiveLightingActive()) { return } const updateKey = Math.random().toString(36).substr(2, 8) @@ -156,7 +156,7 @@ module.exports = class deviceZBLightCCT { this.cacheMired = value this.cacheCT = scaledCT if (!this.disableDeviceLogging) { - if (this.alController.isAdaptiveLightingActive()) { + if (this.accessory.alController.isAdaptiveLightingActive()) { this.log( '[%s] %s [%sK] %s.', this.name, @@ -210,9 +210,9 @@ module.exports = class deviceZBLightCCT { if (!this.disableDeviceLogging) { this.log('[%s] %s [%sK].', this.name, this.lang.curColour, scaledK) } - if (this.alController.isAdaptiveLightingActive() && ctDiff > 20) { + if (this.accessory.alController.isAdaptiveLightingActive() && ctDiff > 20) { // Look for a variation greater than twenty - this.alController.disableAdaptiveLighting() + this.accessory.alController.disableAdaptiveLighting() if (!this.disableDeviceLogging) { this.log('[%s] %s.', this.name, this.lang.disabledAL) } From 476f49e74b97d0fb9a6fd9d753d286447f94e78a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 20:01:09 +0100 Subject: [PATCH 2022/3183] 6.4.1-beta.5 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 664f9cdd..fb2fedb3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.4.1-beta.4", + "version": "6.4.1-beta.5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f2109deb..405431a9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.4.1-beta.4", + "version": "6.4.1-beta.5", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From c2e98910b8651c8a727397303ca86073765f3e13 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 20:46:17 +0100 Subject: [PATCH 2023/3183] more api funcs, docs --- lib/connection/api.js | 55 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/lib/connection/api.js b/lib/connection/api.js index eb910dff..feefa4fb 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -29,9 +29,13 @@ module.exports = class connectionAPI { // This variable stores the html table rows for displaying the devices let accList = '' mapAsc.forEach(accessory => { + const colourWAN = accessory.context.reachableWAN ? '4caf50' : 'f44336' + const colourLAN = accessory.context.reachableLAN ? '4caf50' : 'f44336' accList += ` ${accessory.displayName} ${accessory.context.hbDeviceId} + + ` }) @@ -43,6 +47,7 @@ module.exports = class connectionAPI { homebridge-ewelink API Docs +
    @@ -88,6 +93,22 @@ module.exports = class connectionAPI { + + + Query the online/offline cloud (WAN) state.
    + Example response:
    + {"success":true,"response":"online"} + + /{hbDeviceId}/get/reachablewan + + + + Query the online/offline local (LAN) state.
    + Example response:
    + {"success":true,"response":"offline"} + + /{hbDeviceId}/get/reachablelan + Query the on/off state.
    @@ -197,17 +218,19 @@ module.exports = class connectionAPI {
    Accessory List
    - - - - - - - - - ${accList} - -
    Accessory NameHB Device ID
    + + + + + + + + + + + ${accList} + +
    Accessory NameHB Device IDWANLAN
    @@ -262,6 +285,16 @@ module.exports = class connectionAPI { // Obtain the corresponding accessory const accessory = this.devicesInHB.get(uuid) + // Special case for the reachable WAN and LAN attributes + if (action === 'get') { + if (attribute === 'reachablewan') { + return accessory.context.reachableWAN ? 'online' : 'offline' + } + if (attribute === 'reachablelan') { + return accessory.context.reachableLAN ? 'online' : 'offline' + } + } + // Check the device is controllable if (!accessory.control) { throw new Error('Accessory has not been initialised yet') From ec662a2b268928ae98c496e326386ba37b4f11ed Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 20:46:44 +0100 Subject: [PATCH 2024/3183] 6.4.1-beta.6 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index fb2fedb3..b320ba4b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.4.1-beta.5", + "version": "6.4.1-beta.6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 405431a9..e9828781 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.4.1-beta.5", + "version": "6.4.1-beta.6", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From 578b8779e5db6056c817f74b2698bc40b5350447 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 20:54:11 +0100 Subject: [PATCH 2025/3183] adjust sides and margins --- lib/connection/api.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/connection/api.js b/lib/connection/api.js index feefa4fb..3cc7e1d8 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -50,10 +50,10 @@ module.exports = class connectionAPI { -
    +
    -
    -
    +
    +

    homebridge-ewelink logo

    homebridge-ewelink

    @@ -233,7 +233,7 @@ module.exports = class connectionAPI {
    -
    +
    From bba3723a35a745472ba5ed35cdc87e1ab1a203f5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 20:54:38 +0100 Subject: [PATCH 2026/3183] 6.4.1-beta.7 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index b320ba4b..6bf9eea1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.4.1-beta.6", + "version": "6.4.1-beta.7", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index e9828781..fa96c301 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.4.1-beta.6", + "version": "6.4.1-beta.7", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From 615391cb1d2487586d13a3ae80a97c3de5a45ae2 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 20:58:46 +0100 Subject: [PATCH 2027/3183] rename endpoints --- lib/connection/api.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/connection/api.js b/lib/connection/api.js index 3cc7e1d8..8a3b5d86 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -99,7 +99,7 @@ module.exports = class connectionAPI { Example response:
    {"success":true,"response":"online"} - /{hbDeviceId}/get/reachablewan + /{hbDeviceId}/get/statuswan @@ -107,7 +107,7 @@ module.exports = class connectionAPI { Example response:
    {"success":true,"response":"offline"} - /{hbDeviceId}/get/reachablelan + /{hbDeviceId}/get/statuslan @@ -287,10 +287,10 @@ module.exports = class connectionAPI { // Special case for the reachable WAN and LAN attributes if (action === 'get') { - if (attribute === 'reachablewan') { + if (attribute === 'statuswan') { return accessory.context.reachableWAN ? 'online' : 'offline' } - if (attribute === 'reachablelan') { + if (attribute === 'statuslan') { return accessory.context.reachableLAN ? 'online' : 'offline' } } From e158a29c39d56cbe569f2bd44df3c63944d3611c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 20:59:13 +0100 Subject: [PATCH 2028/3183] 6.4.1-beta.8 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6bf9eea1..ae393bf2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.4.1-beta.7", + "version": "6.4.1-beta.8", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index fa96c301..8e539c48 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.4.1-beta.7", + "version": "6.4.1-beta.8", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From b04f2ca7258878927e1693207d218923ca0e016f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 21:09:05 +0100 Subject: [PATCH 2029/3183] mark wan offline if mode is lan --- lib/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/index.js b/lib/index.js index f81bf3d7..70618dd3 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1035,7 +1035,7 @@ class eWeLinkPlatform { // Add context information to the sub accessory subAccessory.context.firmware = device.params.fwVersion || plugin.version - subAccessory.context.reachableWAN = device.online + subAccessory.context.reachableWAN = wsClient && device.online subAccessory.context.reachableLAN = lanClient && lanDevices.has(device.deviceid) ? lanDevices.get(device.deviceid).ip @@ -1173,7 +1173,7 @@ class eWeLinkPlatform { // Add context information to the sub accessory subAccessory.context.firmware = device.params.fwVersion || plugin.version - subAccessory.context.reachableWAN = device.online + subAccessory.context.reachableWAN = wsClient && device.online subAccessory.context.reachableLAN = false subAccessory.context.eweBrandName = device.brandName subAccessory.context.eweBrandLogo = device.brandLogo @@ -1288,7 +1288,7 @@ class eWeLinkPlatform { // Update the reachability values (via WS and LAN) accessory.context.firmware = device.params.fwVersion || plugin.version - accessory.context.reachableWAN = device.online + accessory.context.reachableWAN = wsClient && device.online accessory.context.reachableLAN = lanClient && lanDevices.has(device.deviceid) ? lanDevices.get(device.deviceid).ip From acbd52ee4d5a1bd5eba4f1aa4326d15cb88fd888 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 21:11:02 +0100 Subject: [PATCH 2030/3183] 6.4.1-beta.9 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index ae393bf2..5a62f00a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.4.1-beta.8", + "version": "6.4.1-beta.9", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 8e539c48..f518e330 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.4.1-beta.8", + "version": "6.4.1-beta.9", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From f4f792cde6d2fe522f4ce08f6d1b764e16b7a25d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 21:15:08 +0100 Subject: [PATCH 2031/3183] don't show hidden accessories on api page --- lib/connection/api.js | 8 ++++++++ lib/index.js | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/connection/api.js b/lib/connection/api.js index 8a3b5d86..62fe52d4 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -29,8 +29,16 @@ module.exports = class connectionAPI { // This variable stores the html table rows for displaying the devices let accList = '' mapAsc.forEach(accessory => { + // Skip if it's a hidden accessory + if (accessory.context.hidden) { + return + } + + // Get the colours for the status icons const colourWAN = accessory.context.reachableWAN ? '4caf50' : 'f44336' const colourLAN = accessory.context.reachableLAN ? '4caf50' : 'f44336' + + // Add the html table row accList += ` ${accessory.displayName} ${accessory.context.hbDeviceId} diff --git a/lib/index.js b/lib/index.js index 70618dd3..088dce31 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1402,7 +1402,8 @@ class eWeLinkPlatform { eweModel: device.productModel, eweApiKey: device.apikey, switchNumber, - channelCount + channelCount, + hidden }, ...extraContext } From 1c0d9d7accd51daa5dddb1799df433ebfc7b0b7b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 21:15:32 +0100 Subject: [PATCH 2032/3183] 6.4.1-beta.10 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5a62f00a..aba18360 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.4.1-beta.9", + "version": "6.4.1-beta.10", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f518e330..2a8e86cb 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.4.1-beta.9", + "version": "6.4.1-beta.10", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From ea22381d0396987156fdcabec6428016c9f8af28 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 5 May 2021 21:16:25 +0100 Subject: [PATCH 2033/3183] spacing --- lib/connection/api.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/connection/api.js b/lib/connection/api.js index 62fe52d4..d11dfed8 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -33,11 +33,11 @@ module.exports = class connectionAPI { if (accessory.context.hidden) { return } - + // Get the colours for the status icons const colourWAN = accessory.context.reachableWAN ? '4caf50' : 'f44336' const colourLAN = accessory.context.reachableLAN ? '4caf50' : 'f44336' - + // Add the html table row accList += ` ${accessory.displayName} From 7ea05b77e45152ef8a699ef54646f47682de6dae Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 6 May 2021 09:16:04 +0100 Subject: [PATCH 2034/3183] Update package-lock.json --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index aba18360..faf5aa97 100644 --- a/package-lock.json +++ b/package-lock.json @@ -134,9 +134,9 @@ "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==" }, "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.3.tgz", + "integrity": "sha512-tDpEUInNcy2Yw3lNSepK3Wdw1RnXLcIVienz6Ou631Acl15cJyRWK4dgA1vCmOEgIbtOV0W7MHg+AR2Gdg1NXQ==" }, "is-negative-zero": { "version": "2.0.1", From 69090250ee99ae5b660cb85f503826737c4f839e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 6 May 2021 09:21:31 +0100 Subject: [PATCH 2035/3183] api auth, remove device list, add devices endpoint --- lib/connection/api.js | 103 ++++++++++++++++++++++-------------------- lib/index.js | 5 +- 2 files changed, 57 insertions(+), 51 deletions(-) diff --git a/lib/connection/api.js b/lib/connection/api.js index d11dfed8..f4cf0cab 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -5,6 +5,7 @@ module.exports = class connectionAPI { constructor (platform, devicesInHB) { // Set up variables from the platform + this.config = platform.config this.consts = platform.consts this.debug = platform.config.debug this.devicesInHB = devicesInHB @@ -17,36 +18,6 @@ module.exports = class connectionAPI { } showHome () { - // This nifty little function creates a map of devices sorted by display name - const mapAsc = new Map([...this.devicesInHB.entries()].sort((a, b) => { - return a[1].displayName.toLowerCase() > b[1].displayName.toLowerCase() - ? 1 - : b[1].displayName.toLowerCase() > a[1].displayName.toLowerCase() - ? -1 - : 0 - })) - - // This variable stores the html table rows for displaying the devices - let accList = '' - mapAsc.forEach(accessory => { - // Skip if it's a hidden accessory - if (accessory.context.hidden) { - return - } - - // Get the colours for the status icons - const colourWAN = accessory.context.reachableWAN ? '4caf50' : 'f44336' - const colourLAN = accessory.context.reachableLAN ? '4caf50' : 'f44336' - - // Add the html table row - accList += ` - ${accessory.displayName} - ${accessory.context.hbDeviceId} - - - ` - }) - // Return the home page for the API return ` @@ -70,6 +41,12 @@ module.exports = class connectionAPI {
    API Docs
    -
    Accessory List
    -
    - - - - - - - - - - - ${accList} - -
    Accessory NameHB Device IDWANLAN
    -
    @@ -249,14 +218,48 @@ module.exports = class connectionAPI { ` } - async action (url) { + async action (req) { + // Authenticate the request + if ( + !req.headers || + !req.headers.authorization || + req.headers.authorization.indexOf('Basic ') === -1 + ) { + throw new Error('Invalid authentication') + } + const encodedCreds = req.headers.authorization.split(' ')[1] + const buff = Buffer.from(encodedCreds, 'base64') + const decodedCreds = buff.toString('utf8').replace(/(\r\n|\n|\r)/gm, '').trim() + const [user, pass] = decodedCreds.split(':') + if (user !== this.config.username || pass !== this.config.password) { + throw new Error('Invalid authentication') + } + // Obtain the parts of the request url - const pathParts = url.split('/') + const pathParts = req.url.split('/') const device = pathParts[1] const action = pathParts[2] const attribute = pathParts[3] const newStatus = pathParts[4] + // Special case for the devicelist + if (device === 'devicelist') { + const deviceList = [] + this.devicesInHB.forEach(accessory => { + if (accessory.context.hidden) { + return + } + deviceList.push({ + name: accessory.displayName, + hbdeviceid: accessory.context.hbDeviceId, + statuswan: !!accessory.context.reachableWAN, + statuslan: !!accessory.context.reachableLAN, + localip: accessory.context.reachableLAN || false + }) + }) + return deviceList + } + // Check a device was specified if (!device) { throw new Error('No accessory specified') @@ -293,6 +296,10 @@ module.exports = class connectionAPI { // Obtain the corresponding accessory const accessory = this.devicesInHB.get(uuid) + if (accessory.context.hidden) { + throw new Error('Accessory not found in Homebridge') + } + // Special case for the reachable WAN and LAN attributes if (action === 'get') { if (attribute === 'statuswan') { diff --git a/lib/index.js b/lib/index.js index 088dce31..e335fbb8 100644 --- a/lib/index.js +++ b/lib/index.js @@ -577,14 +577,13 @@ class eWeLinkPlatform { // Request is not for the homepage so action appropriately res.writeHead(200, { 'Content-Type': 'application/json' }) try { - const response = await apiClient.action(req.url) + const response = await apiClient.action(req) // Actioning the request was successful so respond with a success res.end(JSON.stringify({ success: true, response })) } catch (e) { // An error occurred actioning the request so respond with the error - const eText = this.funcs.parseError(e) - res.end(JSON.stringify({ success: false, error: eText })) + res.end(JSON.stringify({ success: false, error: e.message + '.' })) } }) From cdbac9662b25e9389a6c7b02e08e42c30504578c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 6 May 2021 09:21:54 +0100 Subject: [PATCH 2036/3183] 6.4.1-beta.11 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index faf5aa97..ad00aea9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.4.1-beta.10", + "version": "6.4.1-beta.11", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 2a8e86cb..1c2d36df 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.4.1-beta.10", + "version": "6.4.1-beta.11", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From a2cd8622ed6579893d7dacdb73011d7ab293381b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 6 May 2021 10:26:11 +0100 Subject: [PATCH 2037/3183] change paths, clarify set ranges --- lib/connection/api.js | 139 +++++++++++++++++++++++------------------- 1 file changed, 77 insertions(+), 62 deletions(-) diff --git a/lib/connection/api.js b/lib/connection/api.js index f4cf0cab..69db7e89 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -51,6 +51,7 @@ module.exports = class connectionAPI {
  • All requests will return a JSON response
  • Success or failure of any request can be determined by the success response property which will be true or false
  • Any error will be returned in an error parameter as a string
  • +
  • Replace {hbDeviceId} with the Homebridge ID of the device, e.g. 10000abcdeSWX
  • Supported devices are currently:
  • -
    Available Commands
    +
    Accessory Query Commands
    @@ -84,7 +85,7 @@ module.exports = class connectionAPI { Example response:
    {"success":true,"response":[]} - + - + - + - + - + - + - + - + - + - + + +
    /devicelist/get/devicelist
    @@ -92,7 +93,7 @@ module.exports = class connectionAPI { Example response:
    {"success":true,"response":"online"}
    /{hbDeviceId}/get/statuswan/get/{hbDeviceId}/statuswan
    @@ -100,7 +101,7 @@ module.exports = class connectionAPI { Example response:
    {"success":true,"response":"offline"}
    /{hbDeviceId}/get/statuslan/get/{hbDeviceId}/statuslan
    @@ -108,7 +109,7 @@ module.exports = class connectionAPI { Example response:
    {"success":true,"response":"on"}
    /{hbDeviceId}/get/state/get/{hbDeviceId}/state
    @@ -116,7 +117,7 @@ module.exports = class connectionAPI { Example response:
    {"success":true,"response":34}
    /{hbDeviceId}/get/brightness/get/{hbDeviceId}/brightness
    @@ -124,7 +125,7 @@ module.exports = class connectionAPI { Example response:
    {"success":true,"response":17}
    /{hbDeviceId}/get/hue/get/{hbDeviceId}/hue
    @@ -132,7 +133,7 @@ module.exports = class connectionAPI { Example response:
    {"success":true,"response":345}
    /{hbDeviceId}/get/colourtemperature/get/{hbDeviceId}/colourtemperature
    @@ -140,7 +141,7 @@ module.exports = class connectionAPI { Example response:
    {"success":true,"response":"on"}
    /{hbDeviceId}/get/adaptivelighting/get/{hbDeviceId}/adaptivelighting
    @@ -148,7 +149,7 @@ module.exports = class connectionAPI { Example response:
    {"success":true,"response":16.3}
    /{hbDeviceId}/get/temperature/get/{hbDeviceId}/temperature
    @@ -156,55 +157,68 @@ module.exports = class connectionAPI { Example response:
    {"success":true,"response":54}
    /{hbDeviceId}/get/humidity/get/{hbDeviceId}/humidity
    +
    +
    Accessory Control Commands
    +
    + + + + + + + + - + - + - + - + - + - +
    FunctionPath
    Set the state to on.
    - Example response:
    - {"success":true} + Command range:
    + Must be on.
    /{hbDeviceId}/set/state/on/set/{hbDeviceId}/state/on
    Set the state to off.
    - Example response:
    - {"success":true} + Command range:
    + Must be off.
    /{hbDeviceId}/set/state/off/set/{hbDeviceId}/state/off
    Switch (toggle) the current state.
    - Example response:
    - {"success":true} + Command range:
    + Must be toggle.
    /{hbDeviceId}/set/state/toggle/set/{hbDeviceId}/state/toggle
    - Set the brightness between 0% and 100%.
    - Example response:
    - {"success":true} + Set the to 54%.
    + Command range:
    + Must be between 0 and 100.
    /{hbDeviceId}/set/brightness/54/set/{hbDeviceId}/brightness/54
    - Set the hue between 0° and 360°.
    - Example response:
    - {"success":true} + Set the hue to 157°.
    + Command range:
    + Must be between 0 and 360.
    /{hbDeviceId}/set/hue/157/set/{hbDeviceId}/hue/157
    - Set the colour temperature between 140 and 500 mired.
    - Example response:
    - {"success":true} + Set the colour temperature to 300 mired.
    + Command range:
    + Must be between 140 and 500.
    /{hbDeviceId}/set/colourtemperature/300/set/{hbDeviceId}/colourtemperature/300
    @@ -237,12 +251,27 @@ module.exports = class connectionAPI { // Obtain the parts of the request url const pathParts = req.url.split('/') - const device = pathParts[1] - const action = pathParts[2] + const action = pathParts[1] + const device = pathParts[2] const attribute = pathParts[3] const newStatus = pathParts[4] - // Special case for the devicelist + // Check an action was specified + if (!action) { + throw new Error('No action specified') + } + + // Check the action is either get or set + if (!['get', 'set'].includes(action)) { + throw new Error("Action must be 'get' or 'set'") + } + + // Check a device was specified + if (!device) { + throw new Error('No accessory specified') + } + + // Special case for the device list if (device === 'devicelist') { const deviceList = [] this.devicesInHB.forEach(accessory => { @@ -260,42 +289,16 @@ module.exports = class connectionAPI { return deviceList } - // Check a device was specified - if (!device) { - throw new Error('No accessory specified') - } - // Try and find the device in Homebridge const uuid = this.hapUUIDGen(device) if (!this.devicesInHB.has(uuid)) { throw new Error('Accessory not found in Homebridge') } - // Check an action was specified - if (!action) { - throw new Error('No action specified') - } - - // Check the action is either get or set - if (!['get', 'set'].includes(action)) { - throw new Error("Action must be 'get' or 'set'") - } - - // Check an attribute was specified - if (!attribute) { - throw new Error('No attribute specified') - } - - // Check a new status was supplied if the action is set - if (action === 'set') { - if (!newStatus) { - throw new Error('No new status specified') - } - } - // Obtain the corresponding accessory const accessory = this.devicesInHB.get(uuid) + // Check the accessory isn't hidden from Homebridge if (accessory.context.hidden) { throw new Error('Accessory not found in Homebridge') } @@ -315,6 +318,18 @@ module.exports = class connectionAPI { throw new Error('Accessory has not been initialised yet') } + // Check an attribute was specified + if (!attribute) { + throw new Error('No attribute specified') + } + + // Check a new status was supplied if the action is set + if (action === 'set') { + if (!newStatus) { + throw new Error('No new status specified') + } + } + // These variables depend on the attribute that was supplied let service let charName From cefee0e0225ecc7377b25724c44b368eb29dac33 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 6 May 2021 10:26:49 +0100 Subject: [PATCH 2038/3183] 6.4.1-beta.12 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index ad00aea9..8ec08e20 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.4.1-beta.11", + "version": "6.4.1-beta.12", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1c2d36df..c5ed4a82 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.4.1-beta.11", + "version": "6.4.1-beta.12", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From 671579cfcbd730214daa6260e96ba4acee6134f5 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 6 May 2021 12:57:20 +0100 Subject: [PATCH 2039/3183] bootstrap to 5.0.0-dist, remove fontawesome, add base path banner --- lib/connection/api.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/connection/api.js b/lib/connection/api.js index 69db7e89..fa4603fb 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -24,9 +24,8 @@ module.exports = class connectionAPI { - + homebridge-ewelink API Docs -
    @@ -69,6 +68,7 @@ module.exports = class connectionAPI { +
    Accessory Query Commands
    @@ -227,7 +227,13 @@ module.exports = class connectionAPI {
    - + + ` } From 7e29b3c631c31341859073e1c579152d5a9231ff Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 6 May 2021 13:03:46 +0100 Subject: [PATCH 2040/3183] clean up docs --- lib/connection/api.js | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/lib/connection/api.js b/lib/connection/api.js index fa4603fb..41ac373d 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -39,27 +39,17 @@ module.exports = class connectionAPI {
    API Docs
      -
    • All requests are of type GET
    • +
    • All requests are of type HTTP GET
    • All requests must include a HTTP authentication header in the form:
      • Authorization: "Basic %%%"
      • -
      • Where %%% is a base64 encoded string of your eWeLink username and password in the form username:password
      • +
      • Where %%% is a base64-encoded string of your eWeLink credentials in the form username:password
    • -
    • All requests will return a HTTP 200 OK success code
    • -
    • All requests will return a JSON response
    • +
    • All requests will return a HTTP 200 OK success code with a JSON response
    • Success or failure of any request can be determined by the success response property which will be true or false
    • -
    • Any error will be returned in an error parameter as a string
    • +
    • Error messages will be returned in the error parameter as a string
    • Replace {hbDeviceId} with the Homebridge ID of the device, e.g. 10000abcdeSWX
    • -
    • Supported devices are currently: -
        -
      • Switches
      • -
      • Outlets
      • -
      • Lights
      • -
      • Temperature Sensors
      • -
      • Humidity Sensors
      • -
      -
    • A note about offline devices:
      • Querying any attribute will return the HomeKit cache value
      • From ab6cd5a06ac0d9310317cdad21b10671a9917157 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 6 May 2021 13:19:54 +0100 Subject: [PATCH 2041/3183] Update CHANGELOG.md --- CHANGELOG.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75b2f65c..6a9312ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,18 @@ All notable changes to this homebridge-ewelink will be documented in this file. -## 6.4.0 (2021-05-04) +## 6.5.0 (2021-05-06) + +### Added -**Please Note** +* Internal HTTP API to query/control the state of certain homebridge-ewelink accessories + * Options for new configuration setting `apiPort` are: + * `0` to disable the API (default setting) + * `1` to enable the API with a random available port (port will be shown in the log) + * Any higher integer to enable the API on this fixed port + * Documentation for the API can be seen at the base url (Homebridge IP + API port) -Since it is impossible for me to test *every* device type and all Accessory Simulations, there may be some unexpected issues. A lot of code has changed in this release. If you encounter any issues please let me know on Github or Discord and I will get it sorted as soon as I can :) +## 6.4.0 (2021-05-04) ### Added From c4489e0411b7e068cda3083ae2a907191eb987b6 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 6 May 2021 13:21:15 +0100 Subject: [PATCH 2042/3183] 6.5.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8ec08e20..eed6d47e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.4.1-beta.12", + "version": "6.5.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index c5ed4a82..304f0fda 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.4.1-beta.12", + "version": "6.5.0", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From d8be1bb1202a87cec2f933976a3553c2a83b7d39 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 6 May 2021 19:58:11 +0100 Subject: [PATCH 2043/3183] handle ip change better --- lib/connection/lan.js | 1 + lib/index.js | 72 ++++++++++++++++++++++++++----------------- 2 files changed, 44 insertions(+), 29 deletions(-) diff --git a/lib/connection/lan.js b/lib/connection/lan.js index a571c72a..ced38be3 100644 --- a/lib/connection/lan.js +++ b/lib/connection/lan.js @@ -138,6 +138,7 @@ module.exports = class connectionLAN { if (Object.keys(params).length > 0) { params.online = true params.updateSource = 'LAN' + params.ip = packet.address const returnTemplate = { deviceid: rdata.id, params diff --git a/lib/index.js b/lib/index.js index e335fbb8..b8ba7739 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1035,10 +1035,8 @@ class eWeLinkPlatform { // Add context information to the sub accessory subAccessory.context.firmware = device.params.fwVersion || plugin.version subAccessory.context.reachableWAN = wsClient && device.online - subAccessory.context.reachableLAN = lanClient && - lanDevices.has(device.deviceid) - ? lanDevices.get(device.deviceid).ip - : false + subAccessory.context.reachableLAN = lanClient && lanDevices.has(device.deviceid) && + lanDevices.get(device.deviceid).ip subAccessory.context.eweBrandName = device.brandName subAccessory.context.eweBrandLogo = device.brandLogo subAccessory.context.eweShared = device.sharedBy && device.sharedBy.email @@ -1173,7 +1171,8 @@ class eWeLinkPlatform { // Add context information to the sub accessory subAccessory.context.firmware = device.params.fwVersion || plugin.version subAccessory.context.reachableWAN = wsClient && device.online - subAccessory.context.reachableLAN = false + subAccessory.context.reachableLAN = lanClient && lanDevices.has(device.deviceid) && + lanDevices.get(device.deviceid).ip subAccessory.context.eweBrandName = device.brandName subAccessory.context.eweBrandLogo = device.brandLogo subAccessory.context.eweShared = device.sharedBy && device.sharedBy.email @@ -1288,10 +1287,8 @@ class eWeLinkPlatform { // Update the reachability values (via WS and LAN) accessory.context.firmware = device.params.fwVersion || plugin.version accessory.context.reachableWAN = wsClient && device.online - accessory.context.reachableLAN = lanClient && - lanDevices.has(device.deviceid) - ? lanDevices.get(device.deviceid).ip - : false + accessory.context.reachableLAN = lanClient && lanDevices.has(device.deviceid) && + lanDevices.get(device.deviceid).ip accessory.context.eweBrandName = device.brandName accessory.context.eweBrandLogo = device.brandLogo accessory.context.eweShared = device.sharedBy && device.sharedBy.email @@ -1573,29 +1570,45 @@ class eWeLinkPlatform { } } } - if (device.params.updateSource === 'LAN' && !accessory.context.reachableLAN) { - // The update is from LAN so it must be online - accessory.context.reachableLAN = true - this.api.updatePlatformAccessories(plugin.name, plugin.alias, [accessory]) - devicesInHB.set(accessory.UUID, accessory) + if (device.params.updateSource === 'LAN') { + // Check to see if the IP of the device has changed + if ( + accessory.context.reachableLAN && + device.params.ip && + device.params.ip !== accessory.context.ip + ) { + accessory.context.ip = device.params.ip + this.api.updatePlatformAccessories(plugin.name, plugin.alias, [accessory]) + devicesInHB.set(accessory.UUID, accessory) - // Flag this true to update the sub accessories later - reachableChange = true + // Flag this true to update the sub accessories later + reachableChange = true + } + if (!accessory.context.reachableLAN) { + // The update is from LAN so it must be online + accessory.context.reachableLAN = true + accessory.context.ip = device.params.ip + this.api.updatePlatformAccessories(plugin.name, plugin.alias, [accessory]) + devicesInHB.set(accessory.UUID, accessory) - // Log the new reachability of the device - this.log( - '[%s] %s %s.', - accessory.displayName, - this.lang.repOnline, - this.lang.viaLAN - ) + // Flag this true to update the sub accessories later + reachableChange = true - // Try and request an update through WS if the device has come back online - if (accessory.context.reachableWAN && wsClient) { - try { - wsClient.requestUpdate(accessory) - } catch (err) { - // Suppress any errors here + // Log the new reachability of the device + this.log( + '[%s] %s %s.', + accessory.displayName, + this.lang.repOnline, + this.lang.viaLAN + ) + + // Try and request an update through WS if the device has come back online + if (accessory.context.reachableWAN && wsClient) { + try { + wsClient.requestUpdate(accessory) + } catch (err) { + // Suppress any errors here + } } } } @@ -1615,6 +1628,7 @@ class eWeLinkPlatform { // Update the LAN status if (device.params.updateSource === 'LAN') { subAccessory.context.reachableLAN = true + subAccessory.context.ip = device.params.ip } // Save the sub accessory updates to the platform From 929790dc262d84fa60334785a4907fb91e111ba4 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 6 May 2021 19:58:28 +0100 Subject: [PATCH 2044/3183] create initial currentState func --- lib/device/light-cct.js | 12 ++++++++++++ lib/device/light-dimmer.js | 10 ++++++++++ lib/device/light-rgb-cct.js | 15 +++++++++++++++ lib/device/light-rgb.js | 12 ++++++++++++ lib/device/outlet-double.js | 9 +++++++++ lib/device/outlet-multi.js | 9 +++++++++ lib/device/outlet-scm.js | 10 ++++++++++ lib/device/outlet-single.js | 9 +++++++++ lib/device/switch-double.js | 9 +++++++++ lib/device/switch-multi.js | 9 +++++++++ lib/device/switch-single.js | 9 +++++++++ 11 files changed, 113 insertions(+) diff --git a/lib/device/light-cct.js b/lib/device/light-cct.js index 6cb24ebb..990e935f 100644 --- a/lib/device/light-cct.js +++ b/lib/device/light-cct.js @@ -272,4 +272,16 @@ module.exports = class deviceLightCCT { markStatus (isOnline) { this.isOnline = isOnline } + + currentState () { + const toReturn = {} + toReturn.services = ['light'] + toReturn.light = { + state: this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off', + brightness: this.service.getCharacteristic(this.hapChar.Brightness).value, + colourtemperature: this.service.getCharacteristic(this.hapChar.ColorTemperature).value, + adaptivelighting: this.accessory.alController.isAdaptiveLightingActive() ? 'on' : 'off' + } + return toReturn + } } diff --git a/lib/device/light-dimmer.js b/lib/device/light-dimmer.js index 66b89132..b2f34653 100644 --- a/lib/device/light-dimmer.js +++ b/lib/device/light-dimmer.js @@ -189,4 +189,14 @@ module.exports = class deviceLightDimmer { this.platform.deviceUpdateError(this.accessory, err, false) } } + + currentState () { + const toReturn = {} + toReturn.services = ['light'] + toReturn.light = { + state: this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off', + brightness: this.service.getCharacteristic(this.hapChar.Brightness).value + } + return toReturn + } } diff --git a/lib/device/light-rgb-cct.js b/lib/device/light-rgb-cct.js index 887e7ab7..80683a03 100644 --- a/lib/device/light-rgb-cct.js +++ b/lib/device/light-rgb-cct.js @@ -519,4 +519,19 @@ module.exports = class deviceLightRGBCCT { markStatus (isOnline) { this.isOnline = isOnline } + + currentState () { + const toReturn = {} + toReturn.services = ['light'] + toReturn.light = { + state: this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off', + brightness: this.service.getCharacteristic(this.hapChar.Brightness).value, + colourmode: this.cacheMode === 'white' ? 'colourtemperature' : 'hue', + hue: this.service.getCharacteristic(this.hapChar.Hue).value, + saturation: this.service.getCharacteristic(this.hapChar.Saturation).value, + colourtemperature: this.service.getCharacteristic(this.hapChar.ColorTemperature).value, + adaptivelighting: this.accessory.alController.isAdaptiveLightingActive() ? 'on' : 'off' + } + return toReturn + } } diff --git a/lib/device/light-rgb.js b/lib/device/light-rgb.js index c0d4d971..06258ac9 100644 --- a/lib/device/light-rgb.js +++ b/lib/device/light-rgb.js @@ -208,4 +208,16 @@ module.exports = class deviceLightRGB { this.platform.deviceUpdateError(this.accessory, err, false) } } + + currentState () { + const toReturn = {} + toReturn.services = ['light'] + toReturn.light = { + state: this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off', + brightness: this.service.getCharacteristic(this.hapChar.Brightness).value, + hue: this.service.getCharacteristic(this.hapChar.Hue).value, + saturation: this.service.getCharacteristic(this.hapChar.Saturation).value + } + return toReturn + } } diff --git a/lib/device/outlet-double.js b/lib/device/outlet-double.js index b81512d1..4a9baf8e 100644 --- a/lib/device/outlet-double.js +++ b/lib/device/outlet-double.js @@ -300,4 +300,13 @@ module.exports = class deviceOutletDouble { this.platform.deviceUpdateError(this.accessory, err, false) } } + + currentState () { + const toReturn = {} + toReturn.services = ['outlet'] + toReturn.outlet = { + state: this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off' + } + return toReturn + } } diff --git a/lib/device/outlet-multi.js b/lib/device/outlet-multi.js index cdd3e325..16b80193 100644 --- a/lib/device/outlet-multi.js +++ b/lib/device/outlet-multi.js @@ -196,4 +196,13 @@ module.exports = class deviceOutletMulti { this.platform.deviceUpdateError(this.accessory, err, false) } } + + currentState () { + const toReturn = {} + toReturn.services = ['outlet'] + toReturn.outlet = { + state: this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off' + } + return toReturn + } } diff --git a/lib/device/outlet-scm.js b/lib/device/outlet-scm.js index b3ed2845..b1ff7fbe 100644 --- a/lib/device/outlet-scm.js +++ b/lib/device/outlet-scm.js @@ -97,4 +97,14 @@ module.exports = class deviceOutletSCM { this.platform.deviceUpdateError(this.accessory, err, false) } } + + currentState () { + const toReturn = {} + const service = this.showAsSwitch ? 'switch' : 'outlet' + toReturn.services = [service] + toReturn[service] = { + state: this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off' + } + return toReturn + } } diff --git a/lib/device/outlet-single.js b/lib/device/outlet-single.js index 472a48a9..20c61733 100644 --- a/lib/device/outlet-single.js +++ b/lib/device/outlet-single.js @@ -253,4 +253,13 @@ module.exports = class deviceOutletSingle { this.platform.deviceUpdateError(this.accessory, err, false) } } + + currentState () { + const toReturn = {} + toReturn.services = ['outlet'] + toReturn.outlet = { + state: this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off' + } + return toReturn + } } diff --git a/lib/device/switch-double.js b/lib/device/switch-double.js index 927dd982..6c46449a 100644 --- a/lib/device/switch-double.js +++ b/lib/device/switch-double.js @@ -195,4 +195,13 @@ module.exports = class deviceSwitchDouble { this.platform.deviceUpdateError(this.accessory, err, false) } } + + currentState () { + const toReturn = {} + toReturn.services = ['switch'] + toReturn.switch = { + state: this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off' + } + return toReturn + } } diff --git a/lib/device/switch-multi.js b/lib/device/switch-multi.js index 25e08714..3464597e 100644 --- a/lib/device/switch-multi.js +++ b/lib/device/switch-multi.js @@ -200,4 +200,13 @@ module.exports = class deviceSwitchMulti { this.platform.deviceUpdateError(this.accessory, err, false) } } + + currentState () { + const toReturn = {} + toReturn.services = ['switch'] + toReturn.switch = { + state: this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off' + } + return toReturn + } } diff --git a/lib/device/switch-single.js b/lib/device/switch-single.js index e7df4557..498c89d2 100644 --- a/lib/device/switch-single.js +++ b/lib/device/switch-single.js @@ -87,4 +87,13 @@ module.exports = class deviceSwitchSingle { this.platform.deviceUpdateError(this.accessory, err, false) } } + + currentState () { + const toReturn = {} + toReturn.services = ['switch'] + toReturn.switch = { + state: this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off' + } + return toReturn + } } From 189f881e8faf3ca7336c6e96a517f5673804f9d4 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 6 May 2021 19:58:34 +0100 Subject: [PATCH 2045/3183] changes to api --- lib/connection/api.js | 707 +++++++++++++++++++++--------------------- 1 file changed, 355 insertions(+), 352 deletions(-) diff --git a/lib/connection/api.js b/lib/connection/api.js index 41ac373d..342bb03b 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -52,166 +52,218 @@ module.exports = class connectionAPI {
      • Replace {hbDeviceId} with the Homebridge ID of the device, e.g. 10000abcdeSWX
      • A note about offline devices:
          -
        • Querying any attribute will return the HomeKit cache value
        • -
        • Updating an attribute which matches the HomeKit cache value will return a success:true response
        • -
        • Updating an attribute which does not match the HomeKit cache value will return a success:false with an error:"HAP Status Error: -70402" response
        • +
        • Querying any characteristic will return the HomeKit cache value
        • +
        • Updating an characteristic which matches the HomeKit cache value will return a success:true response
        • +
        • Updating an characteristic which does not match the HomeKit cache value will return a success:false with an error:"HAP Status Error: -70402" response
      Accessory Query Commands
      -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    FunctionPath
    - Obtain a device list as an array.
    - Example response:
    - {"success":true,"response":[]} -
    /get/devicelist
    - Query the online/offline cloud (WAN) state.
    - Example response:
    - {"success":true,"response":"online"} -
    /get/{hbDeviceId}/statuswan
    - Query the online/offline local (LAN) state.
    - Example response:
    - {"success":true,"response":"offline"} -
    /get/{hbDeviceId}/statuslan
    - Query the on/off state.
    - Example response:
    - {"success":true,"response":"on"} -
    /get/{hbDeviceId}/state
    - Query the brightness between 0% and 100%.
    - Example response:
    - {"success":true,"response":34} -
    /get/{hbDeviceId}/brightness
    - Query the hue between 0° and 360°.
    - Example response:
    - {"success":true,"response":17} -
    /get/{hbDeviceId}/hue
    - Query the colour temperature between 140 and 500 mired.
    - Example response:
    - {"success":true,"response":345} -
    /get/{hbDeviceId}/colourtemperature
    - Query the Adaptive Lighting on/off state.
    - Example response:
    - {"success":true,"response":"on"} -
    /get/{hbDeviceId}/adaptivelighting
    - Query the temperature as °C.
    - Example response:
    - {"success":true,"response":16.3} -
    /get/{hbDeviceId}/temperature
    - Query the humidity a %.
    - Example response:
    - {"success":true,"response":54} -
    /get/{hbDeviceId}/humidity
    -
    -
    Accessory Control Commands
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
    FunctionPath
    - Set the state to on.
    - Command range:
    - Must be on. -
    /set/{hbDeviceId}/state/on
    - Set the state to off.
    - Command range:
    - Must be off. -
    /set/{hbDeviceId}/state/off
    - Switch (toggle) the current state.
    - Command range:
    - Must be toggle. -
    /set/{hbDeviceId}/state/toggle
    - Set the to 54%.
    - Command range:
    - Must be between 0 and 100. -
    /set/{hbDeviceId}/brightness/54
    - Set the hue to 157°.
    - Command range:
    - Must be between 0 and 360. -
    /set/{hbDeviceId}/hue/157
    + + + + + + + + + + + + + + + + +
    FunctionPath
    + Obtain a device list as an array.
    + Example response:
    + {"success":true,"response":[]} +
    /get/devicelist
    + Obtain a device's current state as an object.
    + Example response:
    + {"success":true,"response":{}} +
    /get/{hbDeviceId}
    +
    +
    Accessory Control Commands
    +
    + + + + + + + + - - + + - -
    FunctionPath
    - Set the colour temperature to 300 mired.
    - Command range:
    - Must be between 140 and 500. -
    /set/{hbDeviceId}/colourtemperature/300/set/{hbDeviceId}/{service}/{characteristic}/{value}
    + + + Switch: set the state to on.
    + Command range:
    + Must be on. + + /set/{hbDeviceId}/switch/state/on + + + + Switch: set the state to off.
    + Command range:
    + Must be off. + + /set/{hbDeviceId}/switch/state/off + + + + Switch: toggle the current state.
    + Command range:
    + Must be toggle. + + /set/{hbDeviceId}/switch/state/toggle + + + + Outlet: set the state to on.
    + Command range:
    + Must be on. + + /set/{hbDeviceId}/outlet/state/on + + + + Outlet: set the state to off.
    + Command range:
    + Must be off. + + /set/{hbDeviceId}/outlet/state/off + + + + Outlet: toggle the current state.
    + Command range:
    + Must be toggle. + + /set/{hbDeviceId}/outlet/state/toggle + + + + Light: set the state to on.
    + Command range:
    + Must be on. + + /set/{hbDeviceId}/light/state/on + + + + Light: set the state to off.
    + Command range:
    + Must be off. + + /set/{hbDeviceId}/light/state/off + + + + Light: toggle the current state.
    + Command range:
    + Must be toggle. + + /set/{hbDeviceId}/light/state/toggle + + + + Light: set the brightness to 54%.
    + Command range:
    + Must be between 0 and 100. + + /set/{hbDeviceId}/light/brightness/54 + + + + Light: set the hue to 157°.
    + Command range:
    + Must be between 0 and 360. + + /set/{hbDeviceId}/light/hue/157 + + + + Light: set the colour temperature to 300 mired.
    + Command range:
    + Must be between 140 and 500. + + /set/{hbDeviceId}/light/colourtemperature/300 + + + +
    +
    Example Responses
    +
    + + + + + + + + + + + + + +
    Device List ArrayDevice Query Object
    +
    {
    +  "success": true,
    +  "response":[
    +    {
    +      "name": "Bedroom Switch",
    +      "hbdeviceid": "1000aa1a1aSW1",
    +      "status": {
    +        "wan": true,
    +        "lan": true,
    +        "ip": "192.168.1.20"
    +      }
    +    },
    +    {
    +      "name": "Hall Light Bulb",
    +      "hbdeviceid": "1000aa1a1aSWX",
    +      "status": {
    +        "wan": true,
    +        "lan": false,
    +        "ip": false
    +      }
    +    }
    +  ]
    +}
    +
    +
    +
    {
    +  "success": true,
    +  "response": {
    +    "status": {
    +      "wan": true,
    +      "lan": true,
    +      "ip": "192.168.1.20"
    +    },
    +    "services": ["switch"],
    +    "switch": {
    +      "state": "off"
    +    }
    +  }
    +}
    +
    +
      +
    • services is an array of services that the device has
    • +
    • Possible services include switch, outlet and light +
    • Each service will have a corresponding object of characteristics, in this example the service is switch and a characteristic is state
    • +
    • Use the service and characteristic when using the API to control an accessory
    • +
    +
    @@ -230,6 +282,7 @@ module.exports = class connectionAPI { async action (req) { // Authenticate the request + /* if ( !req.headers || !req.headers.authorization || @@ -244,13 +297,15 @@ module.exports = class connectionAPI { if (user !== this.config.username || pass !== this.config.password) { throw new Error('Invalid authentication') } + */ // Obtain the parts of the request url const pathParts = req.url.split('/') const action = pathParts[1] const device = pathParts[2] - const attribute = pathParts[3] - const newStatus = pathParts[4] + const servToUpdate = pathParts[3] + const charToUpdate = pathParts[4] + const newValue = pathParts[5] // Check an action was specified if (!action) { @@ -277,9 +332,11 @@ module.exports = class connectionAPI { deviceList.push({ name: accessory.displayName, hbdeviceid: accessory.context.hbDeviceId, - statuswan: !!accessory.context.reachableWAN, - statuslan: !!accessory.context.reachableLAN, - localip: accessory.context.reachableLAN || false + status: { + wan: !!accessory.context.reachableWAN, + lan: !!accessory.context.reachableLAN, + ip: accessory.context.ip || false + } }) }) return deviceList @@ -299,242 +356,188 @@ module.exports = class connectionAPI { throw new Error('Accessory not found in Homebridge') } - // Special case for the reachable WAN and LAN attributes + // Check the device is controllable + if (!accessory.control) { + throw new Error('Accessory has not been initialised yet') + } + + // If the action is 'get' then return the properties if (action === 'get') { - if (attribute === 'statuswan') { - return accessory.context.reachableWAN ? 'online' : 'offline' + if (!accessory.control.currentState()) { + throw new Error('Accessory does not yet support querying') } - if (attribute === 'statuslan') { - return accessory.context.reachableLAN ? 'online' : 'offline' + return { + status: { + wan: !!accessory.context.reachableWAN, + lan: !!accessory.context.reachableLAN, + ip: accessory.context.ip || false + }, + ...accessory.control.currentState() } } - // Check the device is controllable - if (!accessory.control) { - throw new Error('Accessory has not been initialised yet') + // From now on the action must be 'set' + + // Check a servToUpdate to update was specified + if (!servToUpdate) { + throw new Error('No service specified') } - // Check an attribute was specified - if (!attribute) { - throw new Error('No attribute specified') + let service + switch (servToUpdate) { + case 'fan': + service = this.hapServ.Fan + break + case 'light': + service = this.hapServ.Lightbulb + break + case 'outlet': + service = this.hapServ.Outlet + break + case 'switch': + service = this.hapServ.Switch + break + default: + throw new Error('Invalid service specified') } - // Check a new status was supplied if the action is set - if (action === 'set') { - if (!newStatus) { - throw new Error('No new status specified') - } + if (!accessory.getService(service)) { + throw new Error('Accessory does not have service:' + servToUpdate) } - // These variables depend on the attribute that was supplied - let service + // Check an charToUpdate for a servToUpdate was specified + if (!charToUpdate) { + throw new Error('No characteristic specified for service:' + servToUpdate) + } + + const accServ = accessory.getService(service) + + // These variables depend on the charToUpdate that was supplied let charName - switch (attribute) { + switch (charToUpdate) { case 'adaptivelighting': case 'colourtemperature': - // This can apply to lights that support colour - service = accessory.getService(this.hapServ.Lightbulb) - - // Check the accessory has one of these services - if (service) { - charName = service.testCharacteristic(this.hapChar.ColorTemperature) - ? this.hapChar.ColorTemperature - : false - } + charName = accServ.testCharacteristic(this.hapChar.ColorTemperature) + ? this.hapChar.ColorTemperature + : false break case 'brightness': - // This can apply to lights - service = accessory.getService(this.hapServ.Lightbulb) - - // Check the accessory has one of these services - if (service) { - charName = service.testCharacteristic(this.hapChar.Brightness) - ? this.hapChar.Brightness - : false - } + charName = accServ.testCharacteristic(this.hapChar.Brightness) + ? this.hapChar.Brightness + : false break case 'hue': - // This can apply to lights that support colour - service = accessory.getService(this.hapServ.Lightbulb) - - // Check the accessory has one of these services - if (service) { - charName = service.testCharacteristic(this.hapChar.Hue) - ? this.hapChar.Hue - : false - } - break - case 'humidity': - // This can apply to humidity sensors - service = accessory.getService(this.hapServ.HumiditySensor) - - // Check the accessory has one of these services - if (service) { - charName = service.testCharacteristic(this.hapChar.CurrentRelativeHumidity) - ? this.hapChar.CurrentRelativeHumidity - : false - } + charName = accServ.testCharacteristic(this.hapChar.Hue) + ? this.hapChar.Hue + : false break case 'state': - // This can apply to switches outlets and lights - service = accessory.getService(this.hapServ.Switch) || - accessory.getService(this.hapServ.Outlet) || - accessory.getService(this.hapServ.Lightbulb) - - // Check the accessory has one of these services - if (service) { - charName = service.testCharacteristic(this.hapChar.On) - ? this.hapChar.On - : false - } - break - case 'temperature': - // This can apply to temperature sensors - service = accessory.getService(this.hapServ.TemperatureSensor) - - // Check the accessory has one of these services - if (service) { - charName = service.testCharacteristic(this.hapChar.CurrentTemperature) - ? this.hapChar.CurrentTemperature - : false - } + charName = accServ.testCharacteristic(this.hapChar.On) + ? this.hapChar.On + : false break default: - throw new Error('Invalid attribute given') + throw new Error('Invalid characteristic specified for service:' + servToUpdate) } - // Check that the accessory has the corresponding characteristic for the attribute + // Check that the accessory has the corresponding characteristic for the charToUpdate if (!charName) { - throw new Error('Accessory does not support attribute:' + attribute) + throw new Error( + 'Accessory service:' + servToUpdate + ' does not support characteristic:' + charToUpdate + ) } - // Obtain the cached value of the accessory-service-characteristic - const currentHKStatus = service.getCharacteristic(charName).value - - // With a get action we return the cache value from above - if (action === 'get') { - switch (attribute) { - case 'adaptivelighting': - return accessory.alController && - accessory.alController.isAdaptiveLightingActive() - ? 'on' - : 'off' - case 'brightness': - case 'colourtemperature': - case 'hue': - case 'humidity': - case 'temperature': - return service.getCharacteristic(charName).value - case 'state': - return service.getCharacteristic(charName).value ? 'on' : 'off' - default: - throw new Error("Invalid attribute for action:get'") - } + // Check a new status was supplied if the action is set + if (!newValue) { + throw new Error('No value specified for characteristic:' + charToUpdate) } - // With a set action we need to call the set handler for the characteristic - if (action === 'set') { - let newHKStatus - switch (attribute) { - case 'brightness': { - // The new status for brightness must be an integer between 0 and 100 - newHKStatus = parseInt(newStatus) - if (isNaN(newHKStatus) || newHKStatus < 0 || newHKStatus > 100) { - throw new Error( - 'New status must be integer 0-100 for attribute:brightness' - ) - } - - // Check the accessory has a correct set handler for on/off - if (!accessory.control.internalBrightnessUpdate) { - throw new Error('Function to control accessory not found') - } - - // Call the set handler to send the request to eWeLink - await accessory.control.internalBrightnessUpdate(newHKStatus) - break + let newHKStatus + switch (charToUpdate) { + case 'brightness': { + // The new status for brightness must be an integer between 0 and 100 + newHKStatus = parseInt(newValue) + if (isNaN(newHKStatus) || newHKStatus < 0 || newHKStatus > 100) { + throw new Error('Value must be integer 0-100 for characteristic:brightness') } - case 'colourtemperature': { - // The new status for colour temperature must be an integer between 140 and 500 - newHKStatus = parseInt(newStatus) - if (isNaN(newHKStatus) || newHKStatus < 140 || newHKStatus > 500) { - throw new Error( - 'New status must be integer 140-500 for attribute:colourtemperature' - ) - } - // Check the accessory has a correct set handler for on/off - if (!accessory.control.internalCTUpdate) { - throw new Error('Function to control accessory not found') - } + // Check the accessory has a correct set handler for on/off + if (!accessory.control.internalBrightnessUpdate) { + throw new Error('Function to control accessory not found') + } - // Call the set handler to send the request to eWeLink - if ( - accessory.alController && - accessory.alController.isAdaptiveLightingActive() - ) { - accessory.alController.disableAdaptiveLighting() - } - await accessory.control.internalCTUpdate(newHKStatus) - break + // Call the set handler to send the request to eWeLink + await accessory.control.internalBrightnessUpdate(newHKStatus) + break + } + case 'colourtemperature': { + // The new status for colour temperature must be an integer between 140 and 500 + newHKStatus = parseInt(newValue) + if (isNaN(newHKStatus) || newHKStatus < 140 || newHKStatus > 500) { + throw new Error('Value must be integer 140-500 for characteristic:colourtemperature') } - case 'hue': { - // The new status for hue must be an integer between 0 and 360 - newHKStatus = parseInt(newStatus) - if (isNaN(newHKStatus) || newHKStatus < 0 || newHKStatus > 360) { - throw new Error( - 'New status must be integer 0-360 for attribute:hue' - ) - } - // Check the accessory has a correct set handler for on/off - if (!accessory.control.internalColourUpdate) { - throw new Error('Function to control accessory not found') - } + // Check the accessory has a correct set handler for on/off + if (!accessory.control.internalCTUpdate) { + throw new Error('Accessory does not support controlling characteristic:' + charToUpdate) + } - // Call the set handler to send the request to eWeLink - if ( - accessory.alController && - accessory.alController.isAdaptiveLightingActive() - ) { - accessory.alController.disableAdaptiveLighting() - } - await accessory.control.internalColourUpdate(newHKStatus) - break + // Call the set handler to send the request to eWeLink + if (accessory.alController && accessory.alController.isAdaptiveLightingActive()) { + accessory.alController.disableAdaptiveLighting() + } + await accessory.control.internalCTUpdate(newHKStatus) + break + } + case 'hue': { + // The new status for hue must be an integer between 0 and 360 + newHKStatus = parseInt(newValue) + if (isNaN(newHKStatus) || newHKStatus < 0 || newHKStatus > 360) { + throw new Error('Value must be integer 0-360 for characteristic:hue') } - case 'state': - // The new status for state must be on, off or toggle - switch (newStatus) { - case 'on': - newHKStatus = true - break - case 'off': - newHKStatus = false - break - case 'toggle': - newHKStatus = !currentHKStatus - break - default: - throw new Error( - "New status must be 'on', 'off' or 'toggle' for attribute:state" - ) - } - // Check the accessory has a correct set handler for on/off - if (!accessory.control.internalStateUpdate) { - throw new Error('Function to control accessory not found') - } + // Check the accessory has a correct set handler for on/off + if (!accessory.control.internalColourUpdate) { + throw new Error('Function to control accessory not found') + } - // Call the set handler to send the request to eWeLink - await accessory.control.internalStateUpdate(newHKStatus) - break - default: - throw new Error("Invalid attribute for action:set'") + // Call the set handler to send the request to eWeLink + if (accessory.alController && accessory.alController.isAdaptiveLightingActive()) { + accessory.alController.disableAdaptiveLighting() + } + await accessory.control.internalColourUpdate(newHKStatus) + break } + case 'state': + // The new status for state must be on, off or toggle + switch (newValue) { + case 'on': + newHKStatus = true + break + case 'off': + newHKStatus = false + break + case 'toggle': + newHKStatus = !accServ.getCharacteristic(this.hapChar.On).value + break + default: + throw new Error("Value must be 'on', 'off' or 'toggle' for characteristic:state") + } + + // Check the accessory has a correct set handler for on/off + if (!accessory.control.internalStateUpdate) { + throw new Error('Function to control accessory not found') + } - // The eWeLink request was successful so update the characteristic in HomeKit - service.updateCharacteristic(charName, newHKStatus) + // Call the set handler to send the request to eWeLink + await accessory.control.internalStateUpdate(newHKStatus) + break + default: + throw new Error('Invalid value for characteristic:' + charToUpdate) } + + // The eWeLink request was successful so update the characteristic in HomeKit + accServ.updateCharacteristic(charName, newHKStatus) } } From 32386388881db244260e910bea10e79ebb9fe387 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 6 May 2021 19:59:12 +0100 Subject: [PATCH 2046/3183] 6.5.1-beta.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index eed6d47e..72e2f578 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.5.0", + "version": "6.5.1-beta.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 304f0fda..6b3099aa 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.5.0", + "version": "6.5.1-beta.0", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From e5c88edf55c14e9abc10db504584c6da3c68605e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 6 May 2021 20:01:23 +0100 Subject: [PATCH 2047/3183] reinstate auth --- lib/connection/api.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/connection/api.js b/lib/connection/api.js index 342bb03b..3552f00d 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -282,7 +282,6 @@ module.exports = class connectionAPI { async action (req) { // Authenticate the request - /* if ( !req.headers || !req.headers.authorization || @@ -297,7 +296,6 @@ module.exports = class connectionAPI { if (user !== this.config.username || pass !== this.config.password) { throw new Error('Invalid authentication') } - */ // Obtain the parts of the request url const pathParts = req.url.split('/') From 63e910eb9d3f03e4193a30712458663fc9352b44 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 6 May 2021 20:01:54 +0100 Subject: [PATCH 2048/3183] 6.5.1-beta.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 72e2f578..4b6a4aad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.5.1-beta.0", + "version": "6.5.1-beta.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 6b3099aa..4a38e41c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.5.1-beta.0", + "version": "6.5.1-beta.1", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From 24d55cb2e1ed50b1b78ec01eff583be1496e013e Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 6 May 2021 20:51:14 +0100 Subject: [PATCH 2049/3183] add fan to api, rearrange docs --- lib/connection/api.js | 139 ++++++++++++++++++++++-------------------- lib/device/fan.js | 39 ++++++++++-- 2 files changed, 108 insertions(+), 70 deletions(-) diff --git a/lib/connection/api.js b/lib/connection/api.js index 3552f00d..1aaac912 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -71,23 +71,57 @@ module.exports = class connectionAPI { - Obtain a device list as an array.
    - Example response:
    - {"success":true,"response":[]} + Obtain a device list.
    + Returns an array, for example:
    +
    {
    +  "success": true,
    +  "response":[
    +    {
    +      "name": "Bedroom Switch",
    +      "hbdeviceid": "1000aa1a1aSW1",
    +      "status": {
    +        "wan": true,
    +        "lan": true,
    +        "ip": "192.168.1.20"
    +      }
    +    }
    +  ]
    +}
    +
    /get/devicelist - Obtain a device's current state as an object.
    - Example response:
    - {"success":true,"response":{}} + Obtain a device's current state.
    + Returns an object, for example:
    +
    {
    +  "success": true,
    +  "response": {
    +    "status": {
    +      "wan": true,
    +      "lan": true,
    +      "ip": "192.168.1.20"
    +    },
    +    "services": ["switch"],
    +    "switch": {
    +      "state": "off"
    +    }
    +  }
    +}
    +
    /get/{hbDeviceId}
    +
    Accessory Control Commands
    @@ -198,69 +232,13 @@ module.exports = class connectionAPI { - -
    /set/{hbDeviceId}/light/colourtemperature/300
    -
    -
    Example Responses
    -
    - - - - - - - - - +
    Device List ArrayDevice Query Object
    -
    {
    -  "success": true,
    -  "response":[
    -    {
    -      "name": "Bedroom Switch",
    -      "hbdeviceid": "1000aa1a1aSW1",
    -      "status": {
    -        "wan": true,
    -        "lan": true,
    -        "ip": "192.168.1.20"
    -      }
    -    },
    -    {
    -      "name": "Hall Light Bulb",
    -      "hbdeviceid": "1000aa1a1aSWX",
    -      "status": {
    -        "wan": true,
    -        "lan": false,
    -        "ip": false
    -      }
    -    }
    -  ]
    -}
    -
    -
    -
    {
    -  "success": true,
    -  "response": {
    -    "status": {
    -      "wan": true,
    -      "lan": true,
    -      "ip": "192.168.1.20"
    -    },
    -    "services": ["switch"],
    -    "switch": {
    -      "state": "off"
    -    }
    -  }
    -}
    -
    -
      -
    • services is an array of services that the device has
    • -
    • Possible services include switch, outlet and light -
    • Each service will have a corresponding object of characteristics, in this example the service is switch and a characteristic is state
    • -
    • Use the service and characteristic when using the API to control an accessory
    • -
    + Fan: set the speed to medium.
    + Command range:
    + Must be low, medium or high.
    /set/{hbDeviceId}/fan/speed/medium
    @@ -430,6 +408,11 @@ module.exports = class connectionAPI { ? this.hapChar.Hue : false break + case 'speed': + charName = accServ.testCharacteristic(this.hapChar.RotationSpeed) + ? this.hapChar.RotationSpeed + : false + break case 'state': charName = accServ.testCharacteristic(this.hapChar.On) ? this.hapChar.On @@ -507,6 +490,30 @@ module.exports = class connectionAPI { await accessory.control.internalColourUpdate(newHKStatus) break } + case 'speed': + // The new status for speed must be low, medium or high + switch (newValue) { + case 'low': + newHKStatus = 33 + break + case 'medium': + newHKStatus = 66 + break + case 'high': + newHKStatus = 99 + break + default: + throw new Error("Value must be 'low', 'medium' or 'high' for characteristic:speed") + } + + // Check the accessory has a correct set handler for speed + if (!accessory.control.internalSpeedUpdate) { + throw new Error('Function to control accessory not found') + } + + // Call the set handler to send the request to eWeLink + await accessory.control.internalSpeedUpdate(newHKStatus) + break case 'state': // The new status for state must be on, off or toggle switch (newValue) { diff --git a/lib/device/fan.js b/lib/device/fan.js index 839a3be7..dd265394 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -30,10 +30,7 @@ module.exports = class deviceFan { // Add the set handler to the fan on/off characteristic this.service.getCharacteristic(this.hapChar.On).onSet(async value => { - if (!value) { - this.service.updateCharacteristic(this.hapChar.RotationSpeed, 0) - await this.internalSpeedUpdate(0) - } + await this.internalStateUpdate(value) }) // Add the set handler to the fan rotation speed characteristic @@ -76,6 +73,13 @@ module.exports = class deviceFan { } } + async internalStateUpdate (value) { + if (!value) { + this.service.updateCharacteristic(this.hapChar.RotationSpeed, 0) + await this.internalSpeedUpdate(0) + } + } + async internalSpeedUpdate (value) { try { // This acts like a debounce function when endlessly sliding the slider @@ -214,4 +218,31 @@ module.exports = class deviceFan { this.platform.deviceUpdateError(this.accessory, err, false) } } + + currentState () { + const toReturn = {} + let speedLabel + const speed = this.service.getCharacteristic(this.hapChar.RotationSpeed).value + if (speed === 0) { + speedLabel = 'off' + } else if (speed <= 33) { + speedLabel = 'low' + } else if (speed <= 66) { + speedLabel = 'medium' + } else { + speedLabel = 'high' + } + toReturn.services = ['fan'] + toReturn.fan = { + state: this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off', + speed: speedLabel + } + if (!this.hideLight) { + toReturn.services.push('light') + toReturn.light = { + state: this.lightService.getCharacteristic(this.hapChar.On).value ? 'on' : 'off' + } + } + return toReturn + } } From 2bde3fd4614597d565507508a06c06e6feb0a6e8 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 6 May 2021 21:11:10 +0100 Subject: [PATCH 2050/3183] rearrange docs again --- lib/connection/api.js | 106 ++++++++++++------------------------------ 1 file changed, 31 insertions(+), 75 deletions(-) diff --git a/lib/connection/api.js b/lib/connection/api.js index 1aaac912..24b9bbe8 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -72,7 +72,7 @@ module.exports = class connectionAPI { Obtain a device list.
    - Returns an array, for example:
    + response property is an array, for example:
    {
       "success": true,
       "response":[
    @@ -94,7 +94,7 @@ module.exports = class connectionAPI {
                         
                           
                             Obtain a device's current state.
    - Returns an object, for example:
    + response property is an object, for example:
    {
       "success": true,
       "response": {
    @@ -118,9 +118,13 @@ module.exports = class connectionAPI {
                   
    • services is an array of services that the device has
    • -
    • Possible services include switch, outlet and light -
    • Each service will have a corresponding object of characteristics, in this example the service is switch and a characteristic is state
    • -
    • Use the service and characteristic when using the API to control an accessory
    • +
    • Possible services include switch, outlet, light and fan +
    • Each service will have a corresponding property of characteristic(s) +
        +
      • In the above example the service is switch and the only characteristic is state
      • +
      +
    • +
    • Use the service and characteristic when using the below commands to control an accessory
    Accessory Control Commands
    @@ -133,110 +137,62 @@ module.exports = class connectionAPI { - + Template /set/{hbDeviceId}/{service}/{characteristic}/{value} - Switch: set the state to on.
    - Command range:
    - Must be on. + Service: switch.
    + Characteristic: state.
    + Value: must be on, off or toggle. /set/{hbDeviceId}/switch/state/on - Switch: set the state to off.
    - Command range:
    - Must be off. - - /set/{hbDeviceId}/switch/state/off - - - - Switch: toggle the current state.
    - Command range:
    - Must be toggle. - - /set/{hbDeviceId}/switch/state/toggle - - - - Outlet: set the state to on.
    - Command range:
    - Must be on. - - /set/{hbDeviceId}/outlet/state/on - - - - Outlet: set the state to off.
    - Command range:
    - Must be off. + Service: outlet.
    + Characteristic: state.
    + Value: must be on, off or toggle. /set/{hbDeviceId}/outlet/state/off - Outlet: toggle the current state.
    - Command range:
    - Must be toggle. - - /set/{hbDeviceId}/outlet/state/toggle - - - - Light: set the state to on.
    - Command range:
    - Must be on. + Service: light.
    + Characteristic: state.
    + Value: must be on, off or toggle. /set/{hbDeviceId}/light/state/on - Light: set the state to off.
    - Command range:
    - Must be off. - - /set/{hbDeviceId}/light/state/off - - - - Light: toggle the current state.
    - Command range:
    - Must be toggle. - - /set/{hbDeviceId}/light/state/toggle - - - - Light: set the brightness to 54%.
    - Command range:
    - Must be between 0 and 100. + Service: light.
    + Characteristic: brightness.
    + Value: must be between 0 and 100. /set/{hbDeviceId}/light/brightness/54 - Light: set the hue to 157°.
    - Command range:
    - Must be between 0 and 360. + Service: light.
    + Characteristic: hue.
    + Value: must be between 0 and 360. /set/{hbDeviceId}/light/hue/157 - Light: set the colour temperature to 300 mired.
    - Command range:
    - Must be between 140 and 500. + Service: light.
    + Characteristic: colourtemperature.
    + Value: must be between 140 and 500. /set/{hbDeviceId}/light/colourtemperature/300 - Fan: set the speed to medium.
    - Command range:
    - Must be low, medium or high. + Service: fan.
    + Characteristic: speed.
    + Value: must be low, medium or high. /set/{hbDeviceId}/fan/speed/medium From c3749b948a5dde3428b014b1afeebfd6e32c3d9d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Thu, 6 May 2021 21:11:37 +0100 Subject: [PATCH 2051/3183] 6.5.1-beta.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4b6a4aad..2f6bcf08 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.5.1-beta.1", + "version": "6.5.1-beta.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 4a38e41c..a20ebbb9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.5.1-beta.1", + "version": "6.5.1-beta.2", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From 77a99df852a10e49b202d060c5081b829e4d0846 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 06:32:58 +0100 Subject: [PATCH 2052/3183] fix garage devicesInHB issues --- lib/device/simulation/garage-od-switch.js | 4 ++-- lib/device/simulation/garage-one.js | 8 ++++---- lib/index.js | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/device/simulation/garage-od-switch.js b/lib/device/simulation/garage-od-switch.js index f9c33e4b..3887e4c5 100644 --- a/lib/device/simulation/garage-od-switch.js +++ b/lib/device/simulation/garage-od-switch.js @@ -3,7 +3,7 @@ 'use strict' module.exports = class deviceGarageODSwitch { - constructor (platform, accessory) { + constructor (platform, accessory, devicesInHB) { // Set up variables from the platform this.hapChar = platform.api.hap.Characteristic this.hapServ = platform.api.hap.Service @@ -19,7 +19,7 @@ module.exports = class deviceGarageODSwitch { // Set up custom variables for this device type this.garageId = platform.obstructSwitches[accessory.context.eweDeviceId] const uuid = this.hapUUIDGen(this.garageId + 'SWX') - this.garage = platform.devicesInHB.get(uuid) + this.garage = devicesInHB.get(uuid) this.disableDeviceLogging = platform.simulations[this.garageId] && platform.simulations[this.garageId].overrideDisabledLogging ? false diff --git a/lib/device/simulation/garage-one.js b/lib/device/simulation/garage-one.js index afff559e..d88552f8 100644 --- a/lib/device/simulation/garage-one.js +++ b/lib/device/simulation/garage-one.js @@ -3,7 +3,7 @@ 'use strict' module.exports = class deviceGarageOne { - constructor (platform, accessory) { + constructor (platform, accessory, devicesInHB) { // Set up variables from the platform this.eveChar = platform.eveChar this.funcs = platform.funcs @@ -44,17 +44,17 @@ module.exports = class deviceGarageOne { if (deviceConf.sensorId) { // Check the sensor exists in Homebridge const uuid = this.hapUUIDGen(deviceConf.sensorId + 'SWX') - if (!platform.devicesInHB.has(uuid)) { + if (!devicesInHB.has(uuid)) { this.error = this.lang.simErrNoSensor } // Check the sensor is a sensor if (!platform.consts.devices.garageSensors.includes( - platform.devicesInHB.get(uuid).context.eweUIID + devicesInHB.get(uuid).context.eweUIID )) { this.error = this.lang.simErrNotSensor } - this.definedSensor = this.platform.devicesInHB.get(uuid) + this.definedSensor = devicesInHB.get(uuid) // Check the sensor has the ContactSensor service if (!this.definedSensor.getService(this.hapServ.ContactSensor)) { diff --git a/lib/index.js b/lib/index.js index b8ba7739..cc0a181b 100644 --- a/lib/index.js +++ b/lib/index.js @@ -718,7 +718,7 @@ class eWeLinkPlatform { *****************************/ const instance = './device/simulation/garage-od-switch' accessory = this.addAccessory(device, device.deviceid + 'SWX', true) - accessory.control = new (require(instance))(this, accessory) + accessory.control = new (require(instance))(this, accessory, devicesInHB) /****************************/ } else if ( this.simulations[device.deviceid] && @@ -730,7 +730,7 @@ class eWeLinkPlatform { const instance = './device/simulation/garage-one' accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new (require(instance))(this, accessory) + accessory.control = new (require(instance))(this, accessory, devicesInHB) /***************************************/ } else if ( this.simulations[device.deviceid] && From 05a23718fe80608cb92798e9d41d66ad5dc2d6da Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 06:36:02 +0100 Subject: [PATCH 2053/3183] Update CHANGELOG.md --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a9312ec..e744683b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this homebridge-ewelink will be documented in this file. +## 6.5.1 (2021-05.07) + +### Changes + +* Fixes an initialisation issue with the 'garage' and 'obstruction detection' switch simulations +* Amendments to internal API endpoints +* Device IP changes will now reflect correctly + ## 6.5.0 (2021-05-06) ### Added From c255cfb8fc43ffe68eb9aecbb19a93659f48a102 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 06:36:11 +0100 Subject: [PATCH 2054/3183] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e744683b..601da390 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this homebridge-ewelink will be documented in this file. -## 6.5.1 (2021-05.07) +## 6.5.1 (2021-05-07) ### Changes From d998c39fe526b281b23c5b17adedbc85873cabe7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 06:36:38 +0100 Subject: [PATCH 2055/3183] 6.5.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2f6bcf08..79ad1442 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.5.1-beta.2", + "version": "6.5.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a20ebbb9..0592510d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.5.1-beta.2", + "version": "6.5.1", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From f23a9698f9f492d64d4268cfce310c514a91eb1a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 07:07:02 +0100 Subject: [PATCH 2056/3183] Update sensor-ambient.js --- lib/device/zigbee/sensor-ambient.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/device/zigbee/sensor-ambient.js b/lib/device/zigbee/sensor-ambient.js index edaacc95..eb9f40b8 100644 --- a/lib/device/zigbee/sensor-ambient.js +++ b/lib/device/zigbee/sensor-ambient.js @@ -87,7 +87,7 @@ module.exports = class deviceZBSensorAmbient { this.tService.updateCharacteristic(this.hapChar.CurrentTemperature, currentTemp) eveLog.temp = currentTemp if (params.updateSource && !this.disableDeviceLogging) { - this.log('[%s] %s [%s].', this.name, this.lang.curTemp, currentTemp) + this.log('[%s] %s [%s°C].', this.name, this.lang.curTemp, currentTemp) } } if ( @@ -102,7 +102,7 @@ module.exports = class deviceZBSensorAmbient { ) eveLog.humidity = currentHumi if (params.updateSource && !this.disableDeviceLogging) { - this.log('[%s] %s [%s].', this.name, this.lang.curHumi, currentHumi) + this.log('[%s] %s [%s%].', this.name, this.lang.curHumi, currentHumi) } } if (eveLog.temp || eveLog.humidity) { From aa31e59dfb3786b5c838fd93579522ad1fe55e5f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 07:32:19 +0100 Subject: [PATCH 2057/3183] add temp+humidity query to api --- lib/device/sensor-ambient.js | 15 +++++++++++++++ lib/device/sensor-temp-humi.js | 12 ++++++++++++ lib/device/zigbee/sensor-ambient.js | 25 ++++++++++++++++++++----- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/lib/device/sensor-ambient.js b/lib/device/sensor-ambient.js index c629cf0c..0b5f4e9e 100644 --- a/lib/device/sensor-ambient.js +++ b/lib/device/sensor-ambient.js @@ -175,4 +175,19 @@ module.exports = class deviceSensorAmbient { this.platform.deviceUpdateError(this.accessory, err, false) } } + + currentState () { + const toReturn = {} + toReturn.services = ['temperature'] + toReturn.temperature = { + current: this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).value + } + if (this.humiService) { + toReturn.services.push('humidity') + toReturn.humidity = { + current: this.humiService.getCharacteristic(this.hapChar.CurrentRelativeHumidity).value + } + } + return toReturn + } } diff --git a/lib/device/sensor-temp-humi.js b/lib/device/sensor-temp-humi.js index e59d2c4b..40ba77bc 100644 --- a/lib/device/sensor-temp-humi.js +++ b/lib/device/sensor-temp-humi.js @@ -94,4 +94,16 @@ module.exports = class deviceSensorTempHumi { this.platform.deviceUpdateError(this.accessory, err, false) } } + + currentState () { + const toReturn = {} + toReturn.services = ['temperature', 'humidity'] + toReturn.temperature = { + current: this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).value + } + toReturn.humidity = { + current: this.humiService.getCharacteristic(this.hapChar.CurrentRelativeHumidity).value + } + return toReturn + } } diff --git a/lib/device/zigbee/sensor-ambient.js b/lib/device/zigbee/sensor-ambient.js index eb9f40b8..43d9dc76 100644 --- a/lib/device/zigbee/sensor-ambient.js +++ b/lib/device/zigbee/sensor-ambient.js @@ -29,16 +29,16 @@ module.exports = class deviceZBSensorAmbient { : platform.config.disableDeviceLogging // Add the temperature sensor service if it doesn't already exist - this.tService = this.accessory.getService(this.hapServ.TemperatureSensor) || + this.tempService = this.accessory.getService(this.hapServ.TemperatureSensor) || this.accessory.addService(this.hapServ.TemperatureSensor) // Add options to the current temperature characteristic - this.tService.getCharacteristic(this.hapChar.CurrentTemperature).setProps({ + this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).setProps({ minStep: 0.1 }) // Add the humidity sensor service if it doesn't already exist - this.hService = this.accessory.getService(this.hapServ.HumiditySensor) || + this.humiService = this.accessory.getService(this.hapServ.HumiditySensor) || this.accessory.addService(this.hapServ.HumiditySensor) // Add the battery service if it doesn't already exist @@ -84,7 +84,7 @@ module.exports = class deviceZBSensorAmbient { ) { this.cacheTemp = params.temperature const currentTemp = parseInt(this.cacheTemp) / 100 + this.tempOffset - this.tService.updateCharacteristic(this.hapChar.CurrentTemperature, currentTemp) + this.tempService.updateCharacteristic(this.hapChar.CurrentTemperature, currentTemp) eveLog.temp = currentTemp if (params.updateSource && !this.disableDeviceLogging) { this.log('[%s] %s [%s°C].', this.name, this.lang.curTemp, currentTemp) @@ -96,7 +96,7 @@ module.exports = class deviceZBSensorAmbient { ) { this.cacheHumi = params.humidity const currentHumi = parseInt(this.cacheHumi) / 100 - this.hService.updateCharacteristic( + this.humiService.updateCharacteristic( this.hapChar.CurrentRelativeHumidity, currentHumi ) @@ -113,4 +113,19 @@ module.exports = class deviceZBSensorAmbient { this.platform.deviceUpdateError(this.accessory, err, false) } } + + currentState () { + const toReturn = {} + toReturn.services = ['temperature', 'humidity', 'battery'] + toReturn.temperature = { + current: this.tempService.getCharacteristic(this.hapChar.CurrentTemperature).value + } + toReturn.humidity = { + current: this.humiService.getCharacteristic(this.hapChar.CurrentRelativeHumidity).value + } + toReturn.battery = { + current: this.battService.getCharacteristic(this.hapChar.BatteryLevel).value + } + return toReturn + } } From f92823ff14ee4d1847d4f19eaa4f4f518d97de8b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 07:55:18 +0100 Subject: [PATCH 2058/3183] Update CHANGELOG.md --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 601da390..57ba960e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to this homebridge-ewelink will be documented in this file. +## BETA + +### Added + +* Support querying temperature and humidity values via the internal API + +### Changes + +* Display temperature and humidity units for the zigbee temperature/humidity sensor in the logs + ## 6.5.1 (2021-05-07) ### Changes From 21345bce3cbed2f95d9bce9c989905e355245246 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 07:56:14 +0100 Subject: [PATCH 2059/3183] 6.5.2-beta.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 79ad1442..84bf8f1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.5.1", + "version": "6.5.2-beta.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 0592510d..844aa024 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.5.1", + "version": "6.5.2-beta.0", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From de8cd80714d62f4361f5d0d887d3baa47bb18266 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 08:06:26 +0100 Subject: [PATCH 2060/3183] log api requests --- lib/connection/api.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/connection/api.js b/lib/connection/api.js index 24b9bbe8..5f276bda 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -215,6 +215,11 @@ module.exports = class connectionAPI { } async action (req) { + // Log the request if appropriate + if (this.debug) { + this.log('API request [%s].', req.url) + } + // Authenticate the request if ( !req.headers || From a926b9994ac187d91cf376598bac1fab5206aa9a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 08:06:32 +0100 Subject: [PATCH 2061/3183] formatting --- lib/device/sensor-ambient.js | 2 +- lib/device/sensor-temp-humi.js | 2 +- lib/device/zigbee/sensor-ambient.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/device/sensor-ambient.js b/lib/device/sensor-ambient.js index 0b5f4e9e..50b2de5d 100644 --- a/lib/device/sensor-ambient.js +++ b/lib/device/sensor-ambient.js @@ -175,7 +175,7 @@ module.exports = class deviceSensorAmbient { this.platform.deviceUpdateError(this.accessory, err, false) } } - + currentState () { const toReturn = {} toReturn.services = ['temperature'] diff --git a/lib/device/sensor-temp-humi.js b/lib/device/sensor-temp-humi.js index 40ba77bc..5cf033b5 100644 --- a/lib/device/sensor-temp-humi.js +++ b/lib/device/sensor-temp-humi.js @@ -94,7 +94,7 @@ module.exports = class deviceSensorTempHumi { this.platform.deviceUpdateError(this.accessory, err, false) } } - + currentState () { const toReturn = {} toReturn.services = ['temperature', 'humidity'] diff --git a/lib/device/zigbee/sensor-ambient.js b/lib/device/zigbee/sensor-ambient.js index 43d9dc76..875f9560 100644 --- a/lib/device/zigbee/sensor-ambient.js +++ b/lib/device/zigbee/sensor-ambient.js @@ -113,7 +113,7 @@ module.exports = class deviceZBSensorAmbient { this.platform.deviceUpdateError(this.accessory, err, false) } } - + currentState () { const toReturn = {} toReturn.services = ['temperature', 'humidity', 'battery'] From fdc9c1a4535c5f1b1edc1c2a6787fb7599c0b61a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 08:06:34 +0100 Subject: [PATCH 2062/3183] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57ba960e..14827d5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this homebridge-ewelink will be documented in this file. ### Added +* Log internal API requests when in debug mode * Support querying temperature and humidity values via the internal API ### Changes From 158097255d38a45fd13d6be7d7894df9f9ccf700 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 08:13:16 +0100 Subject: [PATCH 2063/3183] 6.5.2-beta.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 84bf8f1a..221736e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.5.2-beta.0", + "version": "6.5.2-beta.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 844aa024..49dc4da2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.5.2-beta.0", + "version": "6.5.2-beta.1", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From 2906f6540013ffc86590c0a014e33c36d06c9c87 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 09:48:38 +0100 Subject: [PATCH 2064/3183] close ws on shutdown + lang for api shutdown --- lib/connection/ws.js | 7 ++++--- lib/index.js | 2 +- lib/utils/lang-en.js | 5 +++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/connection/ws.js b/lib/connection/ws.js index 34653f8f..cd3d1b68 100644 --- a/lib/connection/ws.js +++ b/lib/connection/ws.js @@ -381,19 +381,20 @@ module.exports = class connectionWS { async closeConnection () { // This is called when refreshing connection or if Homebridge shuts down - // Set the connection flag to false - this.wsIsConnected = false - // Clear any existing ping interval if (this.hbInterval) { clearInterval(this.hbInterval) this.hbInterval = null } + // Check the ws client is setup if (this.wsClient) { // Remove any existing existing listeners this.wsClient.removeAllListeners() + // Set the connection flag to false + this.wsIsConnected = false + // Close the web socket connection if (this.wsIsConnected) { await this.wsClient.close() diff --git a/lib/index.js b/lib/index.js index cc0a181b..c88d5b24 100644 --- a/lib/index.js +++ b/lib/index.js @@ -620,7 +620,7 @@ class eWeLinkPlatform { if (apiServer) { apiServer.close(() => { if (this.config.debug) { - this.log('%s.', 'listener closed') + this.log('%s.', this.lang.apiShutdown) } }) } diff --git a/lib/utils/lang-en.js b/lib/utils/lang-en.js index 46c1dd99..ae8031ce 100644 --- a/lib/utils/lang-en.js +++ b/lib/utils/lang-en.js @@ -3,8 +3,9 @@ 'use strict' module.exports = { - apiListenErr: 'Internal HTTP API server error', - apiListening: 'Internal HTTP API listening on port', + apiListenErr: 'Internal API server error', + apiListening: 'Internal API listening on port', + apiShutdown: 'Internal API gracefully shutdown', buttonDouble: 'double press', buttonLong: 'long press', buttonNotFound: 'rf button not found (please restart Homebridge)', From 987678da356890bead88e0a6209b30c5705abf5d Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 09:48:42 +0100 Subject: [PATCH 2065/3183] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14827d5a..e2a8dc92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ All notable changes to this homebridge-ewelink will be documented in this file. ### Changes * Display temperature and humidity units for the zigbee temperature/humidity sensor in the logs +* Fixes an issue where the web socket would not close on plugin shutdown ## 6.5.1 (2021-05-07) From a657903f1106b702370581e3f07124c32ffcce15 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 09:49:15 +0100 Subject: [PATCH 2066/3183] 6.5.2-beta.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 221736e9..99233d5a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.5.2-beta.1", + "version": "6.5.2-beta.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 49dc4da2..a0e9ebc7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.5.2-beta.1", + "version": "6.5.2-beta.2", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From 1e2ad84c040d892b8b65ce5371492220625404ba Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 09:55:17 +0100 Subject: [PATCH 2067/3183] Update index.js --- lib/index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index c88d5b24..8ac116ee 100644 --- a/lib/index.js +++ b/lib/index.js @@ -599,7 +599,11 @@ class eWeLinkPlatform { // Log that the plugin setup has been successful with a welcome message const randIndex = Math.floor(Math.random() * this.lang.zWelcome.length) - this.log('%s. %s', this.lang.complete, this.lang.zWelcome[randIndex]) + + // Set a small timeout so the message should appear after the API port log entry + setTimeout(() => { + this.log('%s. %s', this.lang.complete, this.lang.zWelcome[randIndex]) + }, 2000) } catch (err) { // Catch any errors during setup const eText = err.message === this.lang.disabled From 16636e40b55350fd6d7ec67c25a0698e2d59e95f Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 09:55:41 +0100 Subject: [PATCH 2068/3183] formatting --- lib/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 8ac116ee..7f29a84c 100644 --- a/lib/index.js +++ b/lib/index.js @@ -599,7 +599,7 @@ class eWeLinkPlatform { // Log that the plugin setup has been successful with a welcome message const randIndex = Math.floor(Math.random() * this.lang.zWelcome.length) - + // Set a small timeout so the message should appear after the API port log entry setTimeout(() => { this.log('%s. %s', this.lang.complete, this.lang.zWelcome[randIndex]) From 430bc100dda5dcbb368452c13a405b1344fd860c Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 09:56:07 +0100 Subject: [PATCH 2069/3183] 6.5.2-beta.3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 99233d5a..5afd4e12 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.5.2-beta.2", + "version": "6.5.2-beta.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a0e9ebc7..327bf6a6 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.5.2-beta.2", + "version": "6.5.2-beta.3", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From 588b61b18d24bc55fabeaadd3cecdeec226455c0 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 13:14:07 +0100 Subject: [PATCH 2070/3183] Update ws.js --- lib/connection/ws.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/connection/ws.js b/lib/connection/ws.js index cd3d1b68..f6810ba5 100644 --- a/lib/connection/ws.js +++ b/lib/connection/ws.js @@ -392,11 +392,12 @@ module.exports = class connectionWS { // Remove any existing existing listeners this.wsClient.removeAllListeners() - // Set the connection flag to false - this.wsIsConnected = false - // Close the web socket connection if (this.wsIsConnected) { + // Set the connection flag to false + this.wsIsConnected = false + + // Close the connection await this.wsClient.close() // Log if appropriate From 0a429f03a93bc7a1cb932c0b5d017240180cbcdc Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 13:14:40 +0100 Subject: [PATCH 2071/3183] Update ws.js --- lib/connection/ws.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/connection/ws.js b/lib/connection/ws.js index f6810ba5..4bd62a65 100644 --- a/lib/connection/ws.js +++ b/lib/connection/ws.js @@ -396,7 +396,7 @@ module.exports = class connectionWS { if (this.wsIsConnected) { // Set the connection flag to false this.wsIsConnected = false - + // Close the connection await this.wsClient.close() From a4c9ad7641438c77d8a9a685a17a6c81eab7b547 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Fri, 7 May 2021 13:15:01 +0100 Subject: [PATCH 2072/3183] 6.5.2-beta.4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5afd4e12..9c373d83 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.5.2-beta.3", + "version": "6.5.2-beta.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 327bf6a6..cf02b93c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.5.2-beta.3", + "version": "6.5.2-beta.4", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From 0659055c8ed3f45361c7cd6e88f7f1b7d67560e8 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 8 May 2021 09:02:17 +0100 Subject: [PATCH 2073/3183] Update package-lock.json --- package-lock.json | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9c373d83..b85634fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -121,11 +121,11 @@ "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==" }, "is-boolean-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", - "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", + "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", "requires": { - "call-bind": "^1.0.0" + "call-bind": "^1.0.2" } }, "is-callable": { @@ -134,9 +134,9 @@ "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==" }, "is-date-object": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.3.tgz", - "integrity": "sha512-tDpEUInNcy2Yw3lNSepK3Wdw1RnXLcIVienz6Ou631Acl15cJyRWK4dgA1vCmOEgIbtOV0W7MHg+AR2Gdg1NXQ==" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", + "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==" }, "is-negative-zero": { "version": "2.0.1", @@ -144,23 +144,23 @@ "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" }, "is-number-object": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", - "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", + "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==" }, "is-regex": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", - "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", + "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", "requires": { "call-bind": "^1.0.2", - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.2" } }, "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==" + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", + "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==" }, "is-symbol": { "version": "1.0.3", @@ -176,9 +176,9 @@ "integrity": "sha512-fZvDqy19zyaiSXajmRjwue1VWLrJcy8bTV/LJVtAx8DeEFVlXRBMyZknW+q6CEfiW8Y4MQDDKh9x5wF32BHAHQ==" }, "object-inspect": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.2.tgz", - "integrity": "sha512-gz58rdPpadwztRrPjZE9DZLOABUpTGdcANUgOwBFO1C+HZZhePoP83M65WGDmbpwFYJSWqavbl4SgDn4k8RYTA==" + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", + "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==" }, "object-keys": { "version": "1.1.1", From 0223a95b0c86c336706f2ae7b71af9d9d14015e0 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 8 May 2021 09:09:29 +0100 Subject: [PATCH 2074/3183] ensure hb version is 1.3 or more --- lib/index.js | 6 ++++++ lib/utils/lang-en.js | 1 + 2 files changed, 7 insertions(+) diff --git a/lib/index.js b/lib/index.js index 7f29a84c..f66d57c4 100644 --- a/lib/index.js +++ b/lib/index.js @@ -58,6 +58,11 @@ class eWeLinkPlatform { : this.consts.defaultValues.language this.lang = require('./utils/lang-' + language) + // Make sure user is running Homebridge v1.3 or above + if (!api.versionGreaterOrEqual || !api.versionGreaterOrEqual('1.3.0')) { + throw new Error(this.lang.hbVerionFail) + } + // Check the user has configured the plugin if (!config || !config.username || !config.password) { throw new Error(this.lang.missingCreds) @@ -73,6 +78,7 @@ class eWeLinkPlatform { } catch (err) { // Catch any errors during initialisation const hideErrLines = [ + this.lang.hbVerionFail, this.lang.missingCreds, this.lang.missingPW, this.lang.missingUN diff --git a/lib/utils/lang-en.js b/lib/utils/lang-en.js index ae8031ce..0ccf2724 100644 --- a/lib/utils/lang-en.js +++ b/lib/utils/lang-en.js @@ -67,6 +67,7 @@ module.exports = { errLogin: 'An error occurred during http login()', eweError: 'An eWeLink error [500] occured, retrying in 30 seconds', foundWithIP: 'found locally with IP', + hbVersionFail: 'Your version of Homebridge is too low - please update to v1.3', httpRetry: 'Unable to reach eWeLink, retrying in 30 seconds', identify: 'identify button pressed', initialised: 'initialised. Syncing with eWeLink', From 2e025e445996632531ae97c82d13320312177c51 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 8 May 2021 09:14:29 +0100 Subject: [PATCH 2075/3183] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2a8dc92..5de2fbdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ All notable changes to this homebridge-ewelink will be documented in this file. * Display temperature and humidity units for the zigbee temperature/humidity sensor in the logs * Fixes an issue where the web socket would not close on plugin shutdown +* Ensure user is using at least Homebridge v1.3.0 ## 6.5.1 (2021-05-07) From 04753d07944cc2472b9580ed7b7655fc364fb15a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 8 May 2021 09:57:03 +0100 Subject: [PATCH 2076/3183] 6.5.2-beta.5 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index b85634fe..80868b67 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.5.2-beta.4", + "version": "6.5.2-beta.5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index cf02b93c..1f0d5b57 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.5.2-beta.4", + "version": "6.5.2-beta.5", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From 3001cfb2da49b63d1ed2f15c3f91ed88faac7689 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sat, 8 May 2021 14:45:33 +0100 Subject: [PATCH 2077/3183] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1f98684d..8c299192 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ Homebridge plugin to control eWeLink devices * [RF Bridge Sensors](https://github.com/bwp91/homebridge-ewelink/wiki/RF-Bridge-Sensors) * [Accessory Simulations](https://github.com/bwp91/homebridge-ewelink/wiki/Accessory-Simulations) * [Connection Methods](https://github.com/bwp91/homebridge-ewelink/wiki/Connection-Methods) +* [Internal API](https://github.com/bwp91/homebridge-ewelink/wiki/Internal-API) ### Help/About From f9110403ef9c4cd0fbcf593fbb8cdd39abfe6391 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 8 May 2021 14:46:35 +0100 Subject: [PATCH 2078/3183] add api link --- lib/homebridge-ui/public/index.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/homebridge-ui/public/index.html b/lib/homebridge-ui/public/index.html index 287a9f73..da445271 100644 --- a/lib/homebridge-ui/public/index.html +++ b/lib/homebridge-ui/public/index.html @@ -85,11 +85,12 @@

    Setup

    Features

    Help/About

      From 495cb411703277263e5f6dcc3dde48eb64fa7c69 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 8 May 2021 14:50:58 +0100 Subject: [PATCH 2079/3183] update api docs --- lib/connection/api.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/connection/api.js b/lib/connection/api.js index 5f276bda..1a914172 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -37,7 +37,11 @@ module.exports = class connectionAPI {

      homebridge-ewelink


      -
      API Docs
      +
      Intro
      +
        +
      • The internal API allows you to query and control your homebridge-ewelink accessories using HTTP requests
      • +
      +
      Documentation
      • All requests are of type HTTP GET
      • All requests must include a HTTP authentication header in the form: @@ -118,7 +122,7 @@ module.exports = class connectionAPI {
    • services is an array of services that the device has
    • -
    • Possible services include switch, outlet, light and fan +
    • Possible services include switch, outlet, light, fan, temperature and humidity
    • Each service will have a corresponding property of characteristic(s)
      • In the above example the service is switch and the only characteristic is state
      • From c00161f7ecae38545b5abf484ee3938c45945972 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 8 May 2021 14:51:24 +0100 Subject: [PATCH 2080/3183] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5de2fbdc..c0b8c137 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to this homebridge-ewelink will be documented in this file. * Display temperature and humidity units for the zigbee temperature/humidity sensor in the logs * Fixes an issue where the web socket would not close on plugin shutdown * Ensure user is using at least Homebridge v1.3.0 +* Update homebridge-ui wiki links to match github readme file ## 6.5.1 (2021-05-07) From 1d3105dbc6676eaea75d275d5229a80852eb2eda Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sat, 8 May 2021 14:52:10 +0100 Subject: [PATCH 2081/3183] 6.5.2-beta.6 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 80868b67..76156c65 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.5.2-beta.5", + "version": "6.5.2-beta.6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1f0d5b57..56fb5929 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.5.2-beta.5", + "version": "6.5.2-beta.6", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From fdb93c27beabec87960c05be08b3ca322de93465 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 9 May 2021 07:30:18 +0100 Subject: [PATCH 2082/3183] change no response timeout to 2 seconds --- lib/device/curtain.js | 2 +- lib/device/diffuser.js | 10 +++++----- lib/device/fan.js | 4 ++-- lib/device/humidifier.js | 2 +- lib/device/light-cct.js | 6 +++--- lib/device/light-dimmer.js | 4 ++-- lib/device/light-rgb-cct.js | 8 ++++---- lib/device/light-rgb.js | 6 +++--- lib/device/motor.js | 2 +- lib/device/outlet-double.js | 2 +- lib/device/outlet-multi.js | 2 +- lib/device/outlet-scm.js | 2 +- lib/device/outlet-single.js | 2 +- lib/device/rf-bridge.js | 2 +- lib/device/sensor-ambient.js | 2 +- lib/device/simulation/switch-valve.js | 4 ++-- lib/device/simulation/tap-one.js | 2 +- lib/device/simulation/tap-two.js | 2 +- lib/device/simulation/thermostat.js | 4 ++-- lib/device/simulation/valve-four.js | 2 +- lib/device/simulation/valve-one.js | 2 +- lib/device/simulation/valve-two.js | 2 +- lib/device/switch-double.js | 2 +- lib/device/switch-multi.js | 2 +- lib/device/switch-single.js | 2 +- lib/device/thermostat.js | 4 ++-- lib/device/zigbee/light-cct.js | 6 +++--- lib/device/zigbee/light-dimmer.js | 4 ++-- lib/device/zigbee/switch-single.js | 2 +- 29 files changed, 48 insertions(+), 48 deletions(-) diff --git a/lib/device/curtain.js b/lib/device/curtain.js index fbb66826..8a660758 100644 --- a/lib/device/curtain.js +++ b/lib/device/curtain.js @@ -85,7 +85,7 @@ module.exports = class deviceCurtain { this.hapChar.TargetPosition, this.cachePos ) - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/diffuser.js b/lib/device/diffuser.js index 3308bbc4..5ae0216e 100644 --- a/lib/device/diffuser.js +++ b/lib/device/diffuser.js @@ -101,7 +101,7 @@ module.exports = class deviceDiffuser { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.fanService.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } @@ -155,7 +155,7 @@ module.exports = class deviceDiffuser { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.fanService.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } @@ -203,7 +203,7 @@ module.exports = class deviceDiffuser { this.hapChar.On, this.cacheLight === 'on' ) - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } @@ -252,7 +252,7 @@ module.exports = class deviceDiffuser { this.hapChar.On, this.cacheLight === 'on' ) - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } @@ -315,7 +315,7 @@ module.exports = class deviceDiffuser { this.hapChar.On, this.cacheLight === 'on' ) - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/fan.js b/lib/device/fan.js index dd265394..bb3c9419 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -140,7 +140,7 @@ module.exports = class deviceFan { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } @@ -167,7 +167,7 @@ module.exports = class deviceFan { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.lightService.updateCharacteristic(this.hapChar.On, this.cacheLight === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/humidifier.js b/lib/device/humidifier.js index cb02602d..4fc4325f 100644 --- a/lib/device/humidifier.js +++ b/lib/device/humidifier.js @@ -112,7 +112,7 @@ module.exports = class deviceHumidifier { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/light-cct.js b/lib/device/light-cct.js index 990e935f..c37615fa 100644 --- a/lib/device/light-cct.js +++ b/lib/device/light-cct.js @@ -115,7 +115,7 @@ module.exports = class deviceLightCCT { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } @@ -152,7 +152,7 @@ module.exports = class deviceLightCCT { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } @@ -209,7 +209,7 @@ module.exports = class deviceLightCCT { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/light-dimmer.js b/lib/device/light-dimmer.js index b2f34653..5a13cb8f 100644 --- a/lib/device/light-dimmer.js +++ b/lib/device/light-dimmer.js @@ -78,7 +78,7 @@ module.exports = class deviceLightDimmer { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } @@ -119,7 +119,7 @@ module.exports = class deviceLightDimmer { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/light-rgb-cct.js b/lib/device/light-rgb-cct.js index 80683a03..8ff50f48 100644 --- a/lib/device/light-rgb-cct.js +++ b/lib/device/light-rgb-cct.js @@ -105,7 +105,7 @@ module.exports = class deviceLightRGBCCT { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } @@ -166,7 +166,7 @@ module.exports = class deviceLightRGBCCT { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } @@ -237,7 +237,7 @@ module.exports = class deviceLightRGBCCT { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } @@ -326,7 +326,7 @@ module.exports = class deviceLightRGBCCT { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/light-rgb.js b/lib/device/light-rgb.js index 06258ac9..17c9e137 100644 --- a/lib/device/light-rgb.js +++ b/lib/device/light-rgb.js @@ -82,7 +82,7 @@ module.exports = class deviceLightRGB { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } @@ -95,7 +95,7 @@ module.exports = class deviceLightRGB { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } @@ -145,7 +145,7 @@ module.exports = class deviceLightRGB { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/motor.js b/lib/device/motor.js index f68d073b..f28f53a2 100644 --- a/lib/device/motor.js +++ b/lib/device/motor.js @@ -72,7 +72,7 @@ module.exports = class deviceMotor { this.hapChar.TargetPosition, this.cachePos ) - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/outlet-double.js b/lib/device/outlet-double.js index 4a9baf8e..8b3f2892 100644 --- a/lib/device/outlet-double.js +++ b/lib/device/outlet-double.js @@ -195,7 +195,7 @@ module.exports = class deviceOutletDouble { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, !value) - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/outlet-multi.js b/lib/device/outlet-multi.js index 16b80193..1ed65cd6 100644 --- a/lib/device/outlet-multi.js +++ b/lib/device/outlet-multi.js @@ -149,7 +149,7 @@ module.exports = class deviceOutletMulti { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, !value) - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/outlet-scm.js b/lib/device/outlet-scm.js index b1ff7fbe..eb86e64f 100644 --- a/lib/device/outlet-scm.js +++ b/lib/device/outlet-scm.js @@ -77,7 +77,7 @@ module.exports = class deviceOutletSCM { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/outlet-single.js b/lib/device/outlet-single.js index 20c61733..f72687df 100644 --- a/lib/device/outlet-single.js +++ b/lib/device/outlet-single.js @@ -174,7 +174,7 @@ module.exports = class deviceOutletSingle { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index b155fc05..4a93db08 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -130,7 +130,7 @@ module.exports = class deviceRFBridge { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.accessory.getService(service).updateCharacteristic(this.hapChar.On, false) - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/sensor-ambient.js b/lib/device/sensor-ambient.js index 50b2de5d..07ad636f 100644 --- a/lib/device/sensor-ambient.js +++ b/lib/device/sensor-ambient.js @@ -108,7 +108,7 @@ module.exports = class deviceSensorAmbient { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/simulation/switch-valve.js b/lib/device/simulation/switch-valve.js index 1286b4dc..aac1dd44 100644 --- a/lib/device/simulation/switch-valve.js +++ b/lib/device/simulation/switch-valve.js @@ -97,7 +97,7 @@ module.exports = class deviceSwitchValve { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.sService.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } @@ -136,7 +136,7 @@ module.exports = class deviceSwitchValve { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.sService.updateCharacteristic(this.hapChar.Active, 0) - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/simulation/tap-one.js b/lib/device/simulation/tap-one.js index b5e467c9..4f2f397e 100644 --- a/lib/device/simulation/tap-one.js +++ b/lib/device/simulation/tap-one.js @@ -89,7 +89,7 @@ module.exports = class deviceTapOne { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/simulation/tap-two.js b/lib/device/simulation/tap-two.js index 072ddd8f..89ab5e61 100644 --- a/lib/device/simulation/tap-two.js +++ b/lib/device/simulation/tap-two.js @@ -79,7 +79,7 @@ module.exports = class deviceTapTwo { const tapService = this.accessory.getService(tap) setTimeout(() => { tapService.updateCharacteristic(this.hapChar.Active, value === 1 ? 0 : 1) - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/simulation/thermostat.js b/lib/device/simulation/thermostat.js index dbbcea61..af9b6e70 100644 --- a/lib/device/simulation/thermostat.js +++ b/lib/device/simulation/thermostat.js @@ -154,7 +154,7 @@ module.exports = class deviceThermostat { this.hapChar.TargetHeatingCoolingState, this.cacheState === 'on' ) - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } @@ -198,7 +198,7 @@ module.exports = class deviceThermostat { this.hapChar.TargetHeatingCoolingState, this.cacheState === 'on' ) - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/simulation/valve-four.js b/lib/device/simulation/valve-four.js index db60886b..6e517bd3 100644 --- a/lib/device/simulation/valve-four.js +++ b/lib/device/simulation/valve-four.js @@ -132,7 +132,7 @@ module.exports = class deviceValveFour { const valveService = this.accessory.getService(valve) setTimeout(() => { valveService.updateCharacteristic(this.hapChar.Active, value === 1 ? 0 : 1) - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/simulation/valve-one.js b/lib/device/simulation/valve-one.js index 719f1a51..14c62d9a 100644 --- a/lib/device/simulation/valve-one.js +++ b/lib/device/simulation/valve-one.js @@ -120,7 +120,7 @@ module.exports = class deviceValveOne { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.Active, value === 1 ? 0 : 1) - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/simulation/valve-two.js b/lib/device/simulation/valve-two.js index a28abcea..2d777f4d 100644 --- a/lib/device/simulation/valve-two.js +++ b/lib/device/simulation/valve-two.js @@ -126,7 +126,7 @@ module.exports = class deviceValveTwo { const valveService = this.accessory.getService(valve) setTimeout(() => { valveService.updateCharacteristic(this.hapChar.Active, value === 1 ? 0 : 1) - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/switch-double.js b/lib/device/switch-double.js index 6c46449a..b53c2799 100644 --- a/lib/device/switch-double.js +++ b/lib/device/switch-double.js @@ -144,7 +144,7 @@ module.exports = class deviceSwitchDouble { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, !value) - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/switch-multi.js b/lib/device/switch-multi.js index 3464597e..c6a60a5a 100644 --- a/lib/device/switch-multi.js +++ b/lib/device/switch-multi.js @@ -149,7 +149,7 @@ module.exports = class deviceSwitchMulti { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, !value) - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/switch-single.js b/lib/device/switch-single.js index 498c89d2..af43e1f5 100644 --- a/lib/device/switch-single.js +++ b/lib/device/switch-single.js @@ -66,7 +66,7 @@ module.exports = class deviceSwitchSingle { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index 00c1aec3..10cd246d 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -113,7 +113,7 @@ module.exports = class deviceThermostat { this.hapChar.TargetHeatingCoolingState, this.cacheState === 'on' ) - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } @@ -137,7 +137,7 @@ module.exports = class deviceThermostat { this.hapChar.TargetHeatingCoolingState, this.cacheState === 'on' ) - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/zigbee/light-cct.js b/lib/device/zigbee/light-cct.js index 07f205e8..a7ec522d 100644 --- a/lib/device/zigbee/light-cct.js +++ b/lib/device/zigbee/light-cct.js @@ -97,7 +97,7 @@ module.exports = class deviceZBLightCCT { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } @@ -126,7 +126,7 @@ module.exports = class deviceZBLightCCT { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } @@ -172,7 +172,7 @@ module.exports = class deviceZBLightCCT { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/zigbee/light-dimmer.js b/lib/device/zigbee/light-dimmer.js index 5037894a..81f3d26b 100644 --- a/lib/device/zigbee/light-dimmer.js +++ b/lib/device/zigbee/light-dimmer.js @@ -74,7 +74,7 @@ module.exports = class deviceZBLightDimmer { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } @@ -103,7 +103,7 @@ module.exports = class deviceZBLightDimmer { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } diff --git a/lib/device/zigbee/switch-single.js b/lib/device/zigbee/switch-single.js index 4fe426ab..590f50a5 100644 --- a/lib/device/zigbee/switch-single.js +++ b/lib/device/zigbee/switch-single.js @@ -69,7 +69,7 @@ module.exports = class deviceZBSwitchSingle { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - }, 5000) + }, 2000) throw new this.hapErr(-70402) } } From 1f892122be203b1be9f6455a61107184cfe9c68a Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 9 May 2021 07:31:20 +0100 Subject: [PATCH 2083/3183] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0b8c137..7f6aac94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ All notable changes to this homebridge-ewelink will be documented in this file. * Display temperature and humidity units for the zigbee temperature/humidity sensor in the logs * Fixes an issue where the web socket would not close on plugin shutdown +* Reduce the 'No Response' timeout to 2 seconds * Ensure user is using at least Homebridge v1.3.0 * Update homebridge-ui wiki links to match github readme file From 70d2fef1b75f2cdb7fa4950d40d65753c3fba845 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 9 May 2021 07:32:15 +0100 Subject: [PATCH 2084/3183] Update package-lock.json --- package-lock.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 76156c65..1d124247 100644 --- a/package-lock.json +++ b/package-lock.json @@ -163,11 +163,11 @@ "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==" }, "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "requires": { - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.2" } }, "node-dns-sd": { From 88c99453a68b3380925c0c583206e42c2d56b377 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 9 May 2021 09:06:57 +0100 Subject: [PATCH 2085/3183] update correct characteristic on no response timeout --- lib/device/diffuser.js | 10 +++++----- lib/device/fan.js | 2 +- lib/device/humidifier.js | 2 +- lib/device/light-cct.js | 4 ++-- lib/device/light-dimmer.js | 2 +- lib/device/light-rgb-cct.js | 6 +++--- lib/device/light-rgb.js | 4 ++-- lib/device/simulation/blind.js | 2 +- lib/device/simulation/door.js | 2 +- lib/device/simulation/garage-eachen.js | 2 +- lib/device/simulation/garage-four.js | 2 +- lib/device/simulation/garage-one.js | 2 +- lib/device/simulation/garage-two.js | 2 +- lib/device/simulation/lock-one.js | 2 +- lib/device/simulation/thermostat.js | 12 +++++------- lib/device/simulation/window.js | 2 +- lib/device/thermostat.js | 6 +++--- lib/device/zigbee/light-cct.js | 4 ++-- lib/device/zigbee/light-dimmer.js | 2 +- 19 files changed, 34 insertions(+), 36 deletions(-) diff --git a/lib/device/diffuser.js b/lib/device/diffuser.js index 5ae0216e..1ae55218 100644 --- a/lib/device/diffuser.js +++ b/lib/device/diffuser.js @@ -154,7 +154,7 @@ module.exports = class deviceDiffuser { // Catch any errors and let the platform display them this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.fanService.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') + this.fanService.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed) }, 2000) throw new this.hapErr(-70402) } @@ -249,8 +249,8 @@ module.exports = class deviceDiffuser { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.lightService.updateCharacteristic( - this.hapChar.On, - this.cacheLight === 'on' + this.hapChar.Brightness, + this.cacheBright ) }, 2000) throw new this.hapErr(-70402) @@ -312,8 +312,8 @@ module.exports = class deviceDiffuser { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.lightService.updateCharacteristic( - this.hapChar.On, - this.cacheLight === 'on' + this.hapChar.Hue, + this.cacheHue ) }, 2000) throw new this.hapErr(-70402) diff --git a/lib/device/fan.js b/lib/device/fan.js index bb3c9419..8a2e261e 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -139,7 +139,7 @@ module.exports = class deviceFan { } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') + this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed) }, 2000) throw new this.hapErr(-70402) } diff --git a/lib/device/humidifier.js b/lib/device/humidifier.js index 4fc4325f..c0a5e09a 100644 --- a/lib/device/humidifier.js +++ b/lib/device/humidifier.js @@ -111,7 +111,7 @@ module.exports = class deviceHumidifier { } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') + this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheMode * 33) }, 2000) throw new this.hapErr(-70402) } diff --git a/lib/device/light-cct.js b/lib/device/light-cct.js index c37615fa..8357a5e2 100644 --- a/lib/device/light-cct.js +++ b/lib/device/light-cct.js @@ -151,7 +151,7 @@ module.exports = class deviceLightCCT { } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') + this.service.updateCharacteristic(this.hapChar.Brightness, this.cacheBright) }, 2000) throw new this.hapErr(-70402) } @@ -208,7 +208,7 @@ module.exports = class deviceLightCCT { } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') + this.service.updateCharacteristic(this.hapChar.ColorTemperature, this.cacheMired) }, 2000) throw new this.hapErr(-70402) } diff --git a/lib/device/light-dimmer.js b/lib/device/light-dimmer.js index 5a13cb8f..e0ede673 100644 --- a/lib/device/light-dimmer.js +++ b/lib/device/light-dimmer.js @@ -118,7 +118,7 @@ module.exports = class deviceLightDimmer { } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') + this.service.updateCharacteristic(this.hapChar.Brightness, this.cacheBright) }, 2000) throw new this.hapErr(-70402) } diff --git a/lib/device/light-rgb-cct.js b/lib/device/light-rgb-cct.js index 8ff50f48..0e925252 100644 --- a/lib/device/light-rgb-cct.js +++ b/lib/device/light-rgb-cct.js @@ -165,7 +165,7 @@ module.exports = class deviceLightRGBCCT { } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') + this.service.updateCharacteristic(this.hapChar.Brightness, this.cacheBright) }, 2000) throw new this.hapErr(-70402) } @@ -236,7 +236,7 @@ module.exports = class deviceLightRGBCCT { } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') + this.service.updateCharacteristic(this.hapChar.Hue, this.cacheHue) }, 2000) throw new this.hapErr(-70402) } @@ -325,7 +325,7 @@ module.exports = class deviceLightRGBCCT { } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') + this.service.updateCharacteristic(this.hapChar.ColorTemperature, this.cacheMired) }, 2000) throw new this.hapErr(-70402) } diff --git a/lib/device/light-rgb.js b/lib/device/light-rgb.js index 17c9e137..d185a032 100644 --- a/lib/device/light-rgb.js +++ b/lib/device/light-rgb.js @@ -94,7 +94,7 @@ module.exports = class deviceLightRGB { } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') + this.service.updateCharacteristic(this.hapChar.Brightness, this.cacheBright) }, 2000) throw new this.hapErr(-70402) } @@ -144,7 +144,7 @@ module.exports = class deviceLightRGB { } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') + this.service.updateCharacteristic(this.hapChar.Hue, this.cacheHue) }, 2000) throw new this.hapErr(-70402) } diff --git a/lib/device/simulation/blind.js b/lib/device/simulation/blind.js index 6561b62e..10981bf7 100644 --- a/lib/device/simulation/blind.js +++ b/lib/device/simulation/blind.js @@ -131,7 +131,7 @@ module.exports = class deviceBlind { this.hapChar.TargetPosition, this.accessory.context.cacheTargetPosition ) - }, 5000) + }, 2000) this.service.updateCharacteristic( this.hapChar.TargetPosition, new this.hapErr(-70402) diff --git a/lib/device/simulation/door.js b/lib/device/simulation/door.js index ba168627..9a36f093 100644 --- a/lib/device/simulation/door.js +++ b/lib/device/simulation/door.js @@ -131,7 +131,7 @@ module.exports = class deviceDoor { this.hapChar.TargetPosition, this.accessory.context.cacheTargetPosition ) - }, 5000) + }, 2000) this.service.updateCharacteristic( this.hapChar.TargetPosition, new this.hapErr(-70402) diff --git a/lib/device/simulation/garage-eachen.js b/lib/device/simulation/garage-eachen.js index 888c3246..281e780e 100644 --- a/lib/device/simulation/garage-eachen.js +++ b/lib/device/simulation/garage-eachen.js @@ -123,7 +123,7 @@ module.exports = class deviceGarageEachen { this.hapChar.TargetPosition, this.accessory.context.cacheTargetPosition ) - }, 5000) + }, 2000) this.service.updateCharacteristic( this.hapChar.TargetPosition, new this.hapErr(-70402) diff --git a/lib/device/simulation/garage-four.js b/lib/device/simulation/garage-four.js index 87a77fbd..4e3adca6 100644 --- a/lib/device/simulation/garage-four.js +++ b/lib/device/simulation/garage-four.js @@ -134,7 +134,7 @@ module.exports = class deviceGarageFour { this.hapChar.TargetPosition, this.accessory.context.cacheTargetPosition ) - }, 5000) + }, 2000) gdService.updateCharacteristic( this.hapChar.TargetPosition, new this.hapErr(-70402) diff --git a/lib/device/simulation/garage-one.js b/lib/device/simulation/garage-one.js index d88552f8..bc84044b 100644 --- a/lib/device/simulation/garage-one.js +++ b/lib/device/simulation/garage-one.js @@ -198,7 +198,7 @@ module.exports = class deviceGarageOne { this.hapChar.TargetPosition, this.accessory.context.cacheTargetPosition ) - }, 5000) + }, 2000) this.service.updateCharacteristic( this.hapChar.TargetPosition, new this.hapErr(-70402) diff --git a/lib/device/simulation/garage-two.js b/lib/device/simulation/garage-two.js index d0cc187a..9f911a21 100644 --- a/lib/device/simulation/garage-two.js +++ b/lib/device/simulation/garage-two.js @@ -143,7 +143,7 @@ module.exports = class deviceGarageTwo { this.hapChar.TargetPosition, this.accessory.context.cacheTargetPosition ) - }, 5000) + }, 2000) gdService.updateCharacteristic( this.hapChar.TargetPosition, new this.hapErr(-70402) diff --git a/lib/device/simulation/lock-one.js b/lib/device/simulation/lock-one.js index 0153c99a..50ce701c 100644 --- a/lib/device/simulation/lock-one.js +++ b/lib/device/simulation/lock-one.js @@ -97,7 +97,7 @@ module.exports = class deviceLockOne { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic(this.hapChar.LockTargetState, 1) - }, 5000) + }, 2000) this.service.updateCharacteristic( this.hapChar.LockTargetState, new this.hapErr(-70402) diff --git a/lib/device/simulation/thermostat.js b/lib/device/simulation/thermostat.js index af9b6e70..5105a631 100644 --- a/lib/device/simulation/thermostat.js +++ b/lib/device/simulation/thermostat.js @@ -88,6 +88,7 @@ module.exports = class deviceThermostat { .onSet(async value => { await this.internalTargetTempUpdate(value) }) + this.cacheTarg = this.service.getCharacteristic(this.hapChar.TargetTemperature).value // The DS18B20 sensor does not provide humidity readings if ( @@ -152,7 +153,7 @@ module.exports = class deviceThermostat { setTimeout(() => { this.service.updateCharacteristic( this.hapChar.TargetHeatingCoolingState, - this.cacheState === 'on' + this.cacheState === 'on' ? 1 : 0 ) }, 2000) throw new this.hapErr(-70402) @@ -188,16 +189,14 @@ module.exports = class deviceThermostat { this.accessory.context.cacheTarget = value this.cacheState = 'on' this.cacheHeat = newValue + this.cacheTarg = value if (!this.disableDeviceLogging) { this.log('[%s] %s [%s°C].', this.name, this.lang.curTarg, value) } } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.service.updateCharacteristic( - this.hapChar.TargetHeatingCoolingState, - this.cacheState === 'on' - ) + this.service.updateCharacteristic(this.hapChar.TargetTemperature, this.cacheTarg) }, 2000) throw new this.hapErr(-70402) } @@ -239,8 +238,7 @@ module.exports = class deviceThermostat { const currentTemp = Number(params.currentTemperature) + this.tempOffset if (this.cacheTemp !== currentTemp) { this.cacheTemp = currentTemp - this.service - .updateCharacteristic(this.hapChar.CurrentTemperature, this.cacheTemp) + this.service.updateCharacteristic(this.hapChar.CurrentTemperature, this.cacheTemp) this.accessory.eveService.addEntry({ temp: currentTemp }) if (params.updateSource && !this.disableDeviceLogging) { this.log('[%s] %s [%s°C].', this.name, this.lang.curTemp, this.cacheTemp) diff --git a/lib/device/simulation/window.js b/lib/device/simulation/window.js index 09972186..58d38d92 100644 --- a/lib/device/simulation/window.js +++ b/lib/device/simulation/window.js @@ -131,7 +131,7 @@ module.exports = class deviceWindow { this.hapChar.TargetPosition, this.accessory.context.cacheTargetPosition ) - }, 5000) + }, 2000) this.service.updateCharacteristic( this.hapChar.TargetPosition, new this.hapErr(-70402) diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index 10cd246d..bb12ad61 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -111,7 +111,7 @@ module.exports = class deviceThermostat { setTimeout(() => { this.service.updateCharacteristic( this.hapChar.TargetHeatingCoolingState, - this.cacheState === 'on' + this.cacheState === 'on' ? 1 : 0 ) }, 2000) throw new this.hapErr(-70402) @@ -134,8 +134,8 @@ module.exports = class deviceThermostat { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { this.service.updateCharacteristic( - this.hapChar.TargetHeatingCoolingState, - this.cacheState === 'on' + this.hapChar.TargetTemperature, + this.cacheTarg ) }, 2000) throw new this.hapErr(-70402) diff --git a/lib/device/zigbee/light-cct.js b/lib/device/zigbee/light-cct.js index a7ec522d..50d30225 100644 --- a/lib/device/zigbee/light-cct.js +++ b/lib/device/zigbee/light-cct.js @@ -125,7 +125,7 @@ module.exports = class deviceZBLightCCT { } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') + this.service.updateCharacteristic(this.hapChar.Brightness, this.cacheBright) }, 2000) throw new this.hapErr(-70402) } @@ -171,7 +171,7 @@ module.exports = class deviceZBLightCCT { } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') + this.service.updateCharacteristic(this.hapChar.ColorTemperature, this.cacheMired) }, 2000) throw new this.hapErr(-70402) } diff --git a/lib/device/zigbee/light-dimmer.js b/lib/device/zigbee/light-dimmer.js index 81f3d26b..273d4d3c 100644 --- a/lib/device/zigbee/light-dimmer.js +++ b/lib/device/zigbee/light-dimmer.js @@ -102,7 +102,7 @@ module.exports = class deviceZBLightDimmer { } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') + this.service.updateCharacteristic(this.hapChar.Brightness, this.cacheBright) }, 2000) throw new this.hapErr(-70402) } From da0ad8cddf383b7aeceb055ecbfd3ed7e26874bc Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 9 May 2021 09:08:37 +0100 Subject: [PATCH 2086/3183] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f6aac94..fddb8f4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to this homebridge-ewelink will be documented in this file. * Display temperature and humidity units for the zigbee temperature/humidity sensor in the logs * Fixes an issue where the web socket would not close on plugin shutdown * Reduce the 'No Response' timeout to 2 seconds +* Update the correct corresponding characteristic after the 'No Response' timeout * Ensure user is using at least Homebridge v1.3.0 * Update homebridge-ui wiki links to match github readme file From 38d2a460e2713457c1af985c2da856e16a81fd59 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 9 May 2021 09:09:17 +0100 Subject: [PATCH 2087/3183] 6.5.2-beta.7 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1d124247..fa8a0bac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.5.2-beta.6", + "version": "6.5.2-beta.7", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 56fb5929..02285ac9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.5.2-beta.6", + "version": "6.5.2-beta.7", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From 49a944aced3ea725fce893cf2e94e9f697b40b33 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 9 May 2021 17:44:31 +0100 Subject: [PATCH 2088/3183] remove encodedPassword and language options --- config.schema.json | 64 +++++++++++++++--------------------------- lib/connection/http.js | 24 +++++++++------- lib/index.js | 25 ++--------------- lib/utils/constants.js | 8 ++---- 4 files changed, 41 insertions(+), 80 deletions(-) diff --git a/config.schema.json b/config.schema.json index 63b892f7..b12f8484 100644 --- a/config.schema.json +++ b/config.schema.json @@ -24,26 +24,35 @@ "title": "Password", "required": true }, - "language": { + "mode": { "type": "string", - "title": "Language", - "description": "If you wish to see the plugin logging in your language and can help translate then let me know!", - "default": "en", + "title": "Connection Mode", + "description": "This setting defines how the plugin communicates with your devices. For further guidance, please refer to this wiki article.", + "default": "auto", "oneOf": [{ - "title": "English", - "enum": ["en"] + "title": "Auto (Recommended)", + "enum": ["auto"] + }, + { + "title": "Cloud Only", + "enum": ["wan"] + }, + { + "title": "LAN Only", + "enum": ["lan"] } ] }, - "encodedPassword": { - "title": "Encoded Password", - "type": "boolean", - "description": "If true, the plugin will decode your entered password from a base64 encoded string to plain text and use this to log into eWeLink." + "countryCode": { + "title": "Country Code", + "type": "string", + "description": "Override the default country code sent, may help with login issues for users in other regions.", + "placeholder": "+44" }, "httpHost": { "title": "HTTP Host", "type": "string", - "description": "Override the default eWeLink HTTP API host, useful if you need to force a specific region/host.", + "description": "Override the default API host, may help with login issues for users in other regions.", "placeholder": "eu-apia.coolkit.cc", "oneOf": [{ "title": "Auto (Recommended)", @@ -67,34 +76,9 @@ } ] }, - "countryCode": { - "title": "Country Code", - "type": "string", - "description": "Override the default country code sent for login, may help with auth issues for users in other regions.", - "placeholder": "+44" - }, - "mode": { - "type": "string", - "title": "Connection Mode", - "description": "This setting defines how the plugin communicates with your devices. For further guidance, please refer to this wiki article.", - "default": "auto", - "oneOf": [{ - "title": "Auto (Recommended)", - "enum": ["auto"] - }, - { - "title": "Cloud Only", - "enum": ["wan"] - }, - { - "title": "LAN Only", - "enum": ["lan"] - } - ] - }, "apiPort": { "type": "number", - "title": "Server API Port", + "title": "Internal API Port", "description": "Port to use for the internal HTTP API. Set to 0 to disable. Set to 1 to choose a randomly available port." }, "disableDeviceLogging": { @@ -728,11 +712,9 @@ "title": "Optional Settings", "expandable": true, "items": [ - "language", - "encodedPassword", - "httpHost", - "countryCode", "mode", + "countryCode", + "httpHost", "apiPort", "disableDeviceLogging", "debug", diff --git a/lib/connection/http.js b/lib/connection/http.js index 86acdb17..05b51ead 100644 --- a/lib/connection/http.js +++ b/lib/connection/http.js @@ -18,6 +18,7 @@ module.exports = class connectionHTTP { this.log = platform.log this.obstructSwitches = platform.obstructSwitches this.password = platform.config.password + this.triedBase64 = false this.username = platform.config.username } @@ -46,17 +47,14 @@ module.exports = class connectionHTTP { .update(JSON.stringify(data)).digest('base64') // Send the request - const res = await axios.post( - 'https://' + this.httpHost + '/v2/user/login', data, - { - headers: { - Authorization: 'Sign ' + dataToSign, - 'Content-Type': 'application/json', - 'X-CK-Appid': this.consts.appId, - 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) - } + const res = await axios.post('https://' + this.httpHost + '/v2/user/login', data, { + headers: { + Authorization: 'Sign ' + dataToSign, + 'Content-Type': 'application/json', + 'X-CK-Appid': this.consts.appId, + 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) } - ) + }) // Parse the response const body = res.data @@ -85,6 +83,12 @@ module.exports = class connectionHTTP { // Retry the login with the new http host return await this.login() + } else if (body.error === 10001 && !this.triedBase64) { + // In this case the password is incorrect so try base64 decoding just once + this.triedBase64 = true + const buff = Buffer.from(this.password, 'base64') + this.password = buff.toString('utf8').replace(/(\r\n|\n|\r)/gm, '').trim() + return await this.login() } else { if (body.data.at) { // User api key and token received successfully diff --git a/lib/index.js b/lib/index.js index f66d57c4..9f129e7d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -52,11 +52,7 @@ class eWeLinkPlatform { this.obstructSwitches = {} // Retrieve the user's chosen language file - const language = config && config.language && - this.consts.allowed.languages.includes(config.language) - ? config.language - : this.consts.defaultValues.language - this.lang = require('./utils/lang-' + language) + this.lang = require('./utils/lang-en') // Make sure user is running Homebridge v1.3 or above if (!api.versionGreaterOrEqual || !api.versionGreaterOrEqual('1.3.0')) { @@ -203,7 +199,6 @@ class eWeLinkPlatform { case 'debugFakegato': case 'disableDeviceLogging': case 'disablePlugin': - case 'encodedPassword': if (typeof val === 'string') { logQuotes(key) } @@ -448,14 +443,6 @@ class eWeLinkPlatform { } break } - case 'language': { - const inSet = this.consts.allowed.languages.includes(val) - if (typeof val !== 'string' || !inSet) { - logIgnore(key) - } - this.config.language = inSet ? val : this.consts.defaultValues[key] - break - } case 'mode': { const inSet = this.consts.allowed.modes.includes(val) if (typeof val !== 'string' || !inSet) { @@ -492,9 +479,7 @@ class eWeLinkPlatform { try { // If the user has disabled the plugin then remove all accessories if (this.config.disablePlugin) { - devicesInHB.forEach(accessory => { - this.removeAccessory(accessory) - }) + devicesInHB.forEach(accessory => this.removeAccessory(accessory)) throw new Error(this.lang.disabled) } @@ -506,12 +491,6 @@ class eWeLinkPlatform { this.eveService = require('./fakegato/fakegato-history')(this.api) this.eveChar = new (require('./utils/eve-chars'))(this.api) - // Check to see if the user has encoded their password - if (this.config.encodedPassword) { - const buff = Buffer.from(this.config.password, 'base64') - this.config.password = buff.toString('utf8').replace(/(\r\n|\n|\r)/gm, '').trim() - } - // Set up the HTTP client, get the user HTTP host, and login httpClient = new (require('./connection/http'))(this) const authData = await httpClient.login() diff --git a/lib/utils/constants.js b/lib/utils/constants.js index 3034ff9b..3320fb99 100644 --- a/lib/utils/constants.js +++ b/lib/utils/constants.js @@ -7,11 +7,9 @@ module.exports = { name: 'eWeLink', username: '', password: '', - language: 'en', - encodedPassword: false, - httpHost: 'eu-apia.coolkit.cc', - countryCode: '+44', mode: 'auto', + countryCode: '+44', + httpHost: 'eu-apia.coolkit.cc', apiPort: 0, disableDeviceLogging: false, debug: false, @@ -31,7 +29,6 @@ module.exports = { }, defaultValues: { - language: 'en', httpHost: 'eu-apia.coolkit.cc', apiPort: 0, inUsePowerThreshold: 0, @@ -70,7 +67,6 @@ module.exports = { httpRetryCodes: ['ENOTFOUND', 'ETIMEDOUT', 'EAI_AGAIN'], allowed: { - languages: ['en'], httpHosts: [ 'auto', 'eu-apia.coolkit.cc', 'us-apia.coolkit.cc', 'as-apia.coolkit.cc', 'cn-apia.coolkit.cn' From 1174474730a07b99700b0c7aaaef966ffdefb2ff Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 9 May 2021 17:44:34 +0100 Subject: [PATCH 2089/3183] Update package-lock.json --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index fa8a0bac..cb462b70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -78,9 +78,9 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, "follow-redirects": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.0.tgz", - "integrity": "sha512-0vRwd7RKQBTt+mgu87mtYeofLFZpTas2S9zY+jIeuLJMNvudIgF52nr19q40HOwH5RrhWIPuj9puybzSJiRrVg==" + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", + "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" }, "function-bind": { "version": "1.1.1", From 5e30a13f948824ab332a5e1b00cff99ed8365ef1 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 9 May 2021 17:44:39 +0100 Subject: [PATCH 2090/3183] line lengths --- lib/connection/lan.js | 20 ++++++-------------- lib/connection/ws.js | 13 +++++-------- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/lib/connection/lan.js b/lib/connection/lan.js index ced38be3..a34420e0 100644 --- a/lib/connection/lan.js +++ b/lib/connection/lan.js @@ -41,9 +41,7 @@ module.exports = class connectionLAN { if (this.debug) { this.log('%s.', this.lang.lanStarting) } - const res = await dnsSd.discover({ - name: '_ewelink._tcp.local' - }) + const res = await dnsSd.discover({ name: '_ewelink._tcp.local' }) if (this.debug) { this.log('%s.', this.lang.lanStarted) } @@ -51,8 +49,7 @@ module.exports = class connectionLAN { // Update the device map for each device found on the local network res.forEach(device => { // Obtain the ewelink deviceId and check to see it is in our map - const deviceId = device.fqdn.replace('._ewelink._tcp.local', '') - .replace('eWeLink_', '') + const deviceId = device.fqdn.replace('._ewelink._tcp.local', '').replace('eWeLink_', '') let d if ((d = this.deviceMap.get(deviceId)) && !d.ip) { // Update the map with the found IP address @@ -98,8 +95,7 @@ module.exports = class connectionLAN { const dText = crypto .createDecipheriv('aes-128-cbc', key, Buffer.from(rdata.iv, 'base64')) const pText = Buffer - .concat([dText.update(Buffer.from(data, 'base64')), dText.final()]) - .toString('utf8') + .concat([dText.update(Buffer.from(data, 'base64')), dText.final()]).toString('utf8') // Check to see if the IP address of the device has changed if (packet.address !== deviceInfo.ip && !this.ipOverride[rdata.id]) { @@ -193,13 +189,11 @@ module.exports = class connectionLAN { } // Generate the HTTP request - const key = crypto.createHash('md5') - .update(Buffer.from(apiKey, 'utf8')).digest() + const key = crypto.createHash('md5').update(Buffer.from(apiKey, 'utf8')).digest() const iv = crypto.randomBytes(16) const enc = crypto.createCipheriv('aes-128-cbc', key, iv) const data = { - data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]) - .toString('base64'), + data: Buffer.concat([enc.update(JSON.stringify(params)), enc.final()]).toString('base64'), deviceid: json.deviceid, encrypt: true, iv: iv.toString('base64'), @@ -222,9 +216,7 @@ module.exports = class connectionLAN { // Check for any errors in the response if (!res.data || res.data.error !== 0) { - const error = res.data && res.data.error - ? res.data.error - : this.lang.lanErr + const error = res.data && res.data.error ? res.data.error : this.lang.lanErr throw new Error(error) } diff --git a/lib/connection/ws.js b/lib/connection/ws.js index 4bd62a65..a4588d9e 100644 --- a/lib/connection/ws.js +++ b/lib/connection/ws.js @@ -195,10 +195,7 @@ module.exports = class connectionWS { switch (msg.action) { case 'update': case 'sysmsg': { - if ( - msg.action === 'sysmsg' && - this.funcs.hasProperty(msg.params, 'online') - ) { + if (msg.action === 'sysmsg' && this.funcs.hasProperty(msg.params, 'online')) { // Update the online/offline status provided in the message onlineStatus = msg.params.online } @@ -337,8 +334,8 @@ module.exports = class connectionWS { // The web socket isn't currently open so log this this.log.warn('%s.', this.lang.wsResend) - // Try sending the update again in 30 seconds when it's hopefully open again - await this.funcs.sleep(30000) + // Try sending the update again in 10 seconds when it's hopefully open again + await this.funcs.sleep(10000) await this.sendUpdate(json) } } @@ -372,8 +369,8 @@ module.exports = class connectionWS { // The web socket isn't currently open so log this this.log.warn('[%s] %s.', accessory.displayName, this.lang.wsResend) - // Try sending the update again in 30 seconds when it's hopefully open again - await this.funcs.sleep(30000) + // Try sending the update again in 10 seconds when it's hopefully open again + await this.funcs.sleep(10000) await this.requestUpdate(accessory) } } From 4fe3ed44fb6d91dc8f0b2255d8361750a5ff0261 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 9 May 2021 17:44:41 +0100 Subject: [PATCH 2091/3183] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fddb8f4e..940d2b8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ All notable changes to this homebridge-ewelink will be documented in this file. ### Changes +* Removed `encodedPassword` and `language` config options + * The plugin will now initially try the supplied password and if incorrect will attempt another login with a base64 decoded version + * Language option unnecessary until other languages are available * Display temperature and humidity units for the zigbee temperature/humidity sensor in the logs * Fixes an issue where the web socket would not close on plugin shutdown * Reduce the 'No Response' timeout to 2 seconds From d8891b6d0a51af83f98d59a4af0caac8c3993009 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 9 May 2021 17:54:09 +0100 Subject: [PATCH 2092/3183] line lengths --- lib/fakegato/fakegato-history.js | 105 +++++++++++-------------------- lib/fakegato/fakegato-storage.js | 10 +-- lib/fakegato/fakegato-timer.js | 5 +- 3 files changed, 40 insertions(+), 80 deletions(-) diff --git a/lib/fakegato/fakegato-history.js b/lib/fakegato/fakegato-history.js index 2d6f6a64..592fb856 100644 --- a/lib/fakegato/fakegato-history.js +++ b/lib/fakegato/fakegato-history.js @@ -59,11 +59,7 @@ module.exports = function (homebridge) { super('S2R1', S2R1Characteristic.UUID) this.setProps({ format: Characteristic.Formats.DATA, - perms: [ - Characteristic.Perms.READ, - Characteristic.Perms.NOTIFY, - Characteristic.Perms.HIDDEN - ] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.HIDDEN] }) } } @@ -75,11 +71,7 @@ module.exports = function (homebridge) { super('S2R2', S2R2Characteristic.UUID) this.setProps({ format: Characteristic.Formats.DATA, - perms: [ - Characteristic.Perms.READ, - Characteristic.Perms.NOTIFY, - Characteristic.Perms.HIDDEN - ] + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.HIDDEN] }) } } @@ -365,7 +357,7 @@ module.exports = function (homebridge) { this.setTime = true this.restarted = true this.refTime = 0 - this.memoryAddress = 0 + this.memAddress = 0 this.dataStream = '' this.saving = false this.registerEvents() @@ -626,62 +618,54 @@ module.exports = function (homebridge) { getCurrentS2R2 () { const entry2address = val => val % this.memorySize if (this.currentEntry <= this.lastEntry && this.transfer) { - this.memoryAddress = entry2address(this.currentEntry) + this.memAddress = entry2address(this.currentEntry) for (let i = 0; i < 11; i++) { if ( - this.history[this.memoryAddress].setRefTime === 1 || + this.history[this.memAddress].setRefTime === 1 || this.setTime || (this.currentEntry === this.firstEntry + 1) ) { this.dataStream += Format( ',15%s 0100 0000 81%s0000 0000 00 0000', numToHex(swap32(this.currentEntry), 8), - numToHex(swap32(this.refTime), 8)) + numToHex(swap32(this.refTime), 8) + ) this.setTime = false } else { this.log( '[%s] FG history: entry [%s] address [%s].', this.accessoryName, this.currentEntry, - this.memoryAddress + this.memAddress ) switch (this.accessoryType) { case 'weather': this.dataStream += Format( ',10 %s%s-%s:%s %s %s', numToHex(swap32(this.currentEntry), 8), - numToHex(swap32( - this.history[this.memoryAddress].time - this.refTime - _EPOCH), - 8 - ), + numToHex(swap32(this.history[this.memAddress].time - this.refTime - _EPOCH), 8), this.accessoryType117, - numToHex(swap16(this.history[this.memoryAddress].temp * 100), 4), - numToHex(swap16(this.history[this.memoryAddress].humidity * 100), 4), - numToHex(swap16(this.history[this.memoryAddress].pressure * 10), 4)) + numToHex(swap16(this.history[this.memAddress].temp * 100), 4), + numToHex(swap16(this.history[this.memAddress].humidity * 100), 4), + numToHex(swap16(this.history[this.memAddress].pressure * 10), 4)) break case 'energy': this.dataStream += Format( ',14 %s%s-%s:0000 0000 %s 0000 0000', numToHex(swap32(this.currentEntry), 8), - numToHex(swap32( - this.history[this.memoryAddress].time - this.refTime - _EPOCH), - 8 - ), + numToHex(swap32(this.history[this.memAddress].time - this.refTime - _EPOCH), 8), this.accessoryType117, - numToHex(swap16(this.history[this.memoryAddress].power * 10), 4)) + numToHex(swap16(this.history[this.memAddress].power * 10), 4)) break case 'room': this.dataStream += Format( ',13 %s%s%s%s%s%s0000 00', numToHex(swap32(this.currentEntry), 8), - numToHex(swap32( - this.history[this.memoryAddress].time - this.refTime - _EPOCH), - 8 - ), + numToHex(swap32(this.history[this.memAddress].time - this.refTime - _EPOCH), 8), this.accessoryType117, - numToHex(swap16(this.history[this.memoryAddress].temp * 100), 4), - numToHex(swap16(this.history[this.memoryAddress].humidity * 100), 4), - numToHex(swap16(this.history[this.memoryAddress].ppm), 4)) + numToHex(swap16(this.history[this.memAddress].temp * 100), 4), + numToHex(swap16(this.history[this.memAddress].humidity * 100), 4), + numToHex(swap16(this.history[this.memAddress].ppm), 4)) break case 'door': case 'motion': @@ -689,60 +673,47 @@ module.exports = function (homebridge) { this.dataStream += Format( ',0b %s%s%s%s', numToHex(swap32(this.currentEntry), 8), - numToHex(swap32( - this.history[this.memoryAddress].time - this.refTime - _EPOCH), - 8 - ), + numToHex(swap32(this.history[this.memAddress].time - this.refTime - _EPOCH), 8), this.accessoryType117, - numToHex(this.history[this.memoryAddress].status, 2)) + numToHex(this.history[this.memAddress].status, 2)) break case 'aqua': - if (this.history[this.memoryAddress].status) { + if (this.history[this.memAddress].status) { this.dataStream += Format( ',0d %s%s%s%s 300c', numToHex(swap32(this.currentEntry), 8), - numToHex(swap32( - this.history[this.memoryAddress].time - this.refTime - _EPOCH), - 8 - ), + numToHex(swap32(this.history[this.memAddress].time - this.refTime - _EPOCH), 8), this.accessoryType117, - numToHex(this.history[this.memoryAddress].status, 2)) + numToHex(this.history[this.memAddress].status, 2)) } else { this.dataStream += Format( ',15 %s%s%s%s%s 00000000 300c', numToHex(swap32(this.currentEntry), 8), - numToHex(swap32( - this.history[this.memoryAddress].time - this.refTime - _EPOCH), - 8 - ), + numToHex(swap32(this.history[this.memAddress].time - this.refTime - _EPOCH), 8), this.accessoryType117bis, - numToHex(this.history[this.memoryAddress].status, 2), - numToHex(swap32(this.history[this.memoryAddress].waterAmount), 8)) + numToHex(this.history[this.memAddress].status, 2), + numToHex(swap32(this.history[this.memAddress].waterAmount), 8)) } break case 'thermo': this.dataStream += Format( ',11 %s%s%s%s%s%s 0000', numToHex(swap32(this.currentEntry), 8), - numToHex(swap32( - this.history[this.memoryAddress].time - this.refTime - _EPOCH), - 8 - ), + numToHex(swap32(this.history[this.memAddress].time - this.refTime - _EPOCH), 8), this.accessoryType117, - numToHex(swap16(this.history[this.memoryAddress].currentTemp * 100), 4), - numToHex(swap16(this.history[this.memoryAddress].setTemp * 100), 4), - numToHex(this.history[this.memoryAddress].valvePosition, 2)) + numToHex(swap16(this.history[this.memAddress].currentTemp * 100), 4), + numToHex(swap16(this.history[this.memAddress].setTemp * 100), 4), + numToHex(this.history[this.memAddress].valvePosition, 2)) break case 'custom': { const result = [] let bitmask = 0 - const dataStream = Format('%s%s', + const dataStream = Format( + '%s%s', numToHex(swap32(this.currentEntry), 8), - numToHex(swap32( - this.history[this.memoryAddress].time - this.refTime - _EPOCH), - 8 - )) - for (const [k, v] of Object.entries(this.history[this.memoryAddress])) { + numToHex(swap32(this.history[this.memAddress].time - this.refTime - _EPOCH), 8) + ) + for (const [k, v] of Object.entries(this.history[this.memAddress])) { switch (k) { case 'time': break @@ -771,9 +742,7 @@ module.exports = function (homebridge) { case 2: result[x] = Format( '%s', - numToHex( - v * this.signatures[x].factor, - this.signatures[x].length) + numToHex(v * this.signatures[x].factor, this.signatures[x].length) ) break } @@ -797,7 +766,7 @@ module.exports = function (homebridge) { } } this.currentEntry++ - this.memoryAddress = entry2address(this.currentEntry) + this.memAddress = entry2address(this.currentEntry) if (this.currentEntry > this.lastEntry) { break } diff --git a/lib/fakegato/fakegato-storage.js b/lib/fakegato/fakegato-storage.js index bcc23eee..a97be704 100644 --- a/lib/fakegato/fakegato-storage.js +++ b/lib/fakegato/fakegato-storage.js @@ -32,9 +32,7 @@ class FakeGatoStorage { callback: params.callback, fileName: hostname + '_' + service.accessoryName + '_persist.json' } - const onReady = typeof (params.onReady) === 'function' - ? params.onReady - : () => {} + const onReady = typeof (params.onReady) === 'function' ? params.onReady : () => {} newWriter.storageHandler = fs newWriter.path = params.path || path.join(os.homedir(), '.homebridge') this.writers.push(newWriter) @@ -93,11 +91,7 @@ class FakeGatoStorage { ? params.callback : (typeof (writer.callback) === 'function' ? writer.callback : () => {}) this.log('FG storage: read file [%s].', path.join(writer.path, writer.fileName)) - writer.storageHandler.readFile( - path.join(writer.path, writer.fileName), - 'utf8', - callBack - ) + writer.storageHandler.readFile(path.join(writer.path, writer.fileName), 'utf8', callBack) } remove (params) { diff --git a/lib/fakegato/fakegato-timer.js b/lib/fakegato/fakegato-timer.js index 0c8661f0..d64a3441 100644 --- a/lib/fakegato/fakegato-timer.js +++ b/lib/fakegato/fakegato-timer.js @@ -55,10 +55,7 @@ class FakeGatoTimer { this.stop() } this.running = true - this.intervalID = setInterval( - this.executeCallbacks.bind(this), - this.minutes * 60 * 1000 - ) + this.intervalID = setInterval(this.executeCallbacks.bind(this), this.minutes * 60 * 1000) } stop () { From 0917336e9cfd0854095fa55582c8306b1797feeb Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 9 May 2021 17:57:14 +0100 Subject: [PATCH 2093/3183] 6.5.2-beta.8 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index cb462b70..1584c920 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.5.2-beta.7", + "version": "6.5.2-beta.8", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 02285ac9..2437482b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.5.2-beta.7", + "version": "6.5.2-beta.8", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From 33428d1af8038ba1f183717b690f1dfa235e33e4 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 9 May 2021 19:06:36 +0100 Subject: [PATCH 2094/3183] dont use unnecessary devicesInEwe map --- lib/index.js | 207 ++++++++++++++++----------------------------------- 1 file changed, 65 insertions(+), 142 deletions(-) diff --git a/lib/index.js b/lib/index.js index 9f129e7d..b5392246 100644 --- a/lib/index.js +++ b/lib/index.js @@ -495,12 +495,8 @@ class eWeLinkPlatform { httpClient = new (require('./connection/http'))(this) const authData = await httpClient.login() - // Get a device list and add to the devicesInEW map + // Get a device list via HTTP request const deviceList = await httpClient.getDevices() - const devicesInEW = new Map() - deviceList.forEach(device => { - devicesInEW.set(device.deviceid, device) - }) // Set up the WS client, get the user WS host, and login if (this.config.mode !== 'lan') { @@ -517,13 +513,13 @@ class eWeLinkPlatform { // Remove HB accessories that are no longer in eWeLink account devicesInHB.forEach(accessory => { - if (!devicesInEW.has(accessory.context.eweDeviceId)) { + if (!deviceList.some(el => el.deviceid === accessory.context.eweDeviceId)) { this.removeAccessory(accessory) } }) // Initialise each device into HB - devicesInEW.forEach(device => this.initialiseDevice(device)) + deviceList.forEach(device => this.initialiseDevice(device)) // Set up the WS and LAN listener for device updates if (wsClient) { @@ -653,8 +649,7 @@ class eWeLinkPlatform { /*********************** BLINDS [EWELINK UIID 11] ***********************/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/curtain'))(this, accessory) /**********************/ } else if ( @@ -664,8 +659,7 @@ class eWeLinkPlatform { /************************* BLINDS [DUALR3 MOTOR MODE] *************************/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/motor'))(this, accessory) /************************/ } else if ( @@ -675,8 +669,7 @@ class eWeLinkPlatform { /**************************** BLINDS [ACCESSORY SIMULATION] ****************************/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/simulation/blind'))(this, accessory) /***************************/ } else if ( @@ -686,8 +679,7 @@ class eWeLinkPlatform { /*************************** DOORS [ACCESSORY SIMULATION] ***************************/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/simulation/door'))(this, accessory) /**************************/ } else if ( @@ -697,8 +689,7 @@ class eWeLinkPlatform { /***************************** WINDOWS [ACCESSORY SIMULATION] *****************************/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/simulation/window'))(this, accessory) /****************************/ } else if (this.obstructSwitches[device.deviceid]) { @@ -717,8 +708,7 @@ class eWeLinkPlatform { GARAGE DOORS [ONE] [ACCESSORY SIMULATION] ****************************************/ const instance = './device/simulation/garage-one' - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require(instance))(this, accessory, devicesInHB) /***************************************/ } else if ( @@ -728,10 +718,8 @@ class eWeLinkPlatform { /**************************************** GARAGE DOORS [TWO] [ACCESSORY SIMULATION] ****************************************/ - const instance = './device/simulation/garage-two' - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new (require(instance))(this, accessory) + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new (require('./device/simulation/garage-two'))(this, accessory) /***************************************/ } else if ( this.simulations[device.deviceid] && @@ -740,10 +728,8 @@ class eWeLinkPlatform { /***************************************** GARAGE DOORS [FOUR] [ACCESSORY SIMULATION] *****************************************/ - const instance = './device/simulation/garage-four' - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new (require(instance))(this, accessory) + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new (require('./device/simulation/garage-four'))(this, accessory) /****************************************/ } else if ( this.simulations[device.deviceid] && @@ -752,10 +738,8 @@ class eWeLinkPlatform { /*************************** GARAGE DOORS [EACHEN GD-DC5] ***************************/ - const instance = './device/simulation/garage-eachen' - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new (require(instance))(this, accessory) + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new (require('./device/simulation/garage-eachen'))(this, accessory) /**************************/ } else if ( this.simulations[device.deviceid] && @@ -764,8 +748,7 @@ class eWeLinkPlatform { /*************************** LOCKS [ACCESSORY SIMULATION] ***************************/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/simulation/lock-one'))(this, accessory) /**************************/ } else if ( @@ -775,10 +758,8 @@ class eWeLinkPlatform { /********************************** SWITCH-VALVE [ACCESSORY SIMULATION] **********************************/ - const instance = './device/simulation/switch-valve' - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new (require(instance))(this, accessory) + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new (require('./device/simulation/switch-valve'))(this, accessory) /*********************************/ } else if ( this.simulations[device.deviceid] && @@ -787,8 +768,7 @@ class eWeLinkPlatform { /******************************** TAPS [ONE] [ACCESSORY SIMULATION] ********************************/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/simulation/tap-one'))(this, accessory) /*******************************/ } else if ( @@ -798,8 +778,7 @@ class eWeLinkPlatform { /******************************** TAPS [TWO] [ACCESSORY SIMULATION] ********************************/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/simulation/tap-two'))(this, accessory) /*******************************/ } else if ( @@ -809,10 +788,8 @@ class eWeLinkPlatform { /********************************** VALVES [ONE] [ACCESSORY SIMULATION] **********************************/ - const instance = './device/simulation/valve-one' - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new (require(instance))(this, accessory) + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new (require('./device/simulation/valve-one'))(this, accessory) /*********************************/ } else if ( this.simulations[device.deviceid] && @@ -821,10 +798,8 @@ class eWeLinkPlatform { /********************************** VALVES [TWO] [ACCESSORY SIMULATION] **********************************/ - const instance = './device/simulation/valve-two' - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new (require(instance))(this, accessory) + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new (require('./device/simulation/valve-two'))(this, accessory) /*********************************/ } else if ( this.simulations[device.deviceid] && @@ -833,10 +808,8 @@ class eWeLinkPlatform { /*********************************** VALVES [FOUR] [ACCESSORY SIMULATION] ***********************************/ - const instance = './device/simulation/valve-four' - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new (require(instance))(this, accessory) + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new (require('./device/simulation/valve-four'))(this, accessory) /**********************************/ } else if ( this.simulations[device.deviceid] && @@ -846,50 +819,42 @@ class eWeLinkPlatform { /************************************** SENSORS [LEAK DW2 ACCESSORY SIMULATION] **************************************/ - const instance = './device/simulation/sensor-leak' - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new (require(instance))(this, accessory) + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new (require('./device/simulation/sensor-leak'))(this, accessory) /*************************************/ } else if (this.consts.devices.sensorContact.includes(uiid)) { /******************* SENSORS [SONOFF DW2] *******************/ - const instance = './device/sensor-contact' - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new (require(instance))(this, accessory, devicesInHB) + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new (require('./device/sensor-contact'))(this, accessory, devicesInHB) /******************/ } else if (this.consts.devices.fan.includes(uiid)) { /*** FANS ***/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/fan'))(this, accessory) /**/ } else if (this.consts.devices.diffuser.includes(uiid)) { /******** DIFFUSERS ********/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/diffuser'))(this, accessory) /*******/ } else if (this.consts.devices.humidifier.includes(uiid)) { /********** HUMIDIFIERS **********/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/humidifier'))(this, accessory) /*********/ } else if (this.consts.devices.thermostat.includes(uiid)) { /********** THERMOSTATS **********/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/thermostat'))(this, accessory) /*******/ } else if ( @@ -900,17 +865,14 @@ class eWeLinkPlatform { /********************************* THERMOSTATS [ACCESSORY SIMULATION] *********************************/ - const instance = './device/simulation/thermostat' - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new (require(instance))(this, accessory) + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new (require('./device/simulation/thermostat'))(this, accessory) /********************************/ } else if (this.consts.devices.sensorAmbient.includes(uiid)) { /*********************** SENSOR [AMBIENT-TH10/16] ***********************/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.context.sensorType = device.params.sensorType accessory.control = new (require('./device/sensor-ambient'))(this, accessory) /**********************/ @@ -918,8 +880,7 @@ class eWeLinkPlatform { /************************* SENSOR [AMBIENT-SONOFF SC] *************************/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/sensor-temp-humi'))(this, accessory) /************************/ } else if ( @@ -932,8 +893,7 @@ class eWeLinkPlatform { /****** OUTLETS ******/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = this.outletDevices[device.deviceid] && this.outletDevices[device.deviceid].showAsSwitch ? new (require('./device/switch-single'))(this, accessory) @@ -943,48 +903,42 @@ class eWeLinkPlatform { /************************************* OUTLETS [SINGLE BUT MULTIPLE HARDWARE] *************************************/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/outlet-scm'))(this, accessory) /************************************/ } else if (this.consts.devices.lightRGB.includes(uiid)) { /*********** LIGHTS [RGB] ***********/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/light-rgb'))(this, accessory) /**********/ } else if (this.consts.devices.lightCCT.includes(uiid)) { /*********** LIGHTS [CCT] ***********/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/light-cct'))(this, accessory) /**********/ } else if (this.consts.devices.lightRGBCCT.includes(uiid)) { /***************** LIGHTS [RGB & CCT] *****************/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/light-rgb-cct'))(this, accessory) /****************/ } else if (this.consts.devices.lightDimmer.includes(uiid)) { /************** LIGHTS [DIMMER] **************/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/light-dimmer'))(this, accessory) /*************/ } else if (this.consts.devices.singleSwitch.includes(uiid)) { /************************ SWITCHES [SINGLE CHANNEL] ************************/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = this.singleDevices[device.deviceid] && this.singleDevices[device.deviceid].showAsOutlet ? new (require('./device/outlet-single'))(this, accessory) @@ -1192,62 +1146,50 @@ class eWeLinkPlatform { /********************** ZIGBEE STATELESS SWITCH **********************/ - const instance = './device/zigbee/switch-stateless' - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new (require(instance))(this, accessory) + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new (require('./device/zigbee/switch-stateless'))(this, accessory) /*********************/ } else if (this.consts.devices.zbSwitchSingle.includes(uiid)) { /*************** ZB SINGLE SWITCH ***************/ - const instance = './device/zigbee/switch-single' - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new (require(instance))(this, accessory) + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new (require('./device/zigbee/switch-single'))(this, accessory) /**************/ } else if (this.consts.devices.zbLightDimmer.includes(uiid)) { /***************** ZB LIGHTS [DIMMER] *****************/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/zigbee/light-dimmer'))(this, accessory) /****************/ } else if (this.consts.devices.zbLightCCT.includes(uiid)) { /************** ZB LIGHTS [CCT] **************/ - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/zigbee/light-cct'))(this, accessory) /*************/ } else if (this.consts.devices.zbSensorAmbient.includes(uiid)) { /****************** ZB SENSOR [AMBIENT] ******************/ - const instance = './device/zigbee/sensor-ambient' - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new (require(instance))(this, accessory) + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new (require('./device/zigbee/sensor-ambient'))(this, accessory) /*****************/ } else if (this.consts.devices.zbSensorMotion.includes(uiid)) { /***************** ZB SENSOR [MOTION] *****************/ - const instance = './device/zigbee/sensor-motion' - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new (require(instance))(this, accessory) + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new (require('./device/zigbee/sensor-motion'))(this, accessory) /****************/ } else if (this.consts.devices.zbSensorContact.includes(uiid)) { /****************** ZB SENSOR [CONTACT] ******************/ - const instance = './device/zigbee/sensor-contact' - accessory = devicesInHB.get(uuid) || - this.addAccessory(device, device.deviceid + 'SWX') - accessory.control = new (require(instance))(this, accessory, devicesInHB) + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = new (require('./device/zigbee/sensor-contact'))(this, accessory, devicesInHB) /*****************/ } else if (this.consts.devices.camera.includes(uiid)) { /************* @@ -1308,10 +1250,7 @@ class eWeLinkPlatform { this.api.updatePlatformAccessories(plugin.name, plugin.alias, [accessory]) devicesInHB.set(accessory.UUID, accessory) this.log('[%s] %s %s.', device.name, this.lang.devInit, str) - if ( - this.config.mode === 'lan' && - !this.consts.devices.lanOut.includes(uiid) - ) { + if (this.config.mode === 'lan' && !this.consts.devices.lanOut.includes(uiid)) { this.log.warn('[%s] %s.', device.name, this.lang.devNoControl) } } catch (err) { @@ -1425,11 +1364,10 @@ class eWeLinkPlatform { // Set the correct firmware version if we can if (this.api && accessory.context.firmware) { - accessory.getService(this.api.hap.Service.AccessoryInformation) - .updateCharacteristic( - this.api.hap.Characteristic.FirmwareRevision, - accessory.context.firmware - ) + accessory.getService(this.api.hap.Service.AccessoryInformation).updateCharacteristic( + this.api.hap.Characteristic.FirmwareRevision, + accessory.context.firmware + ) } // Add the configured accessory to our global map @@ -1459,12 +1397,7 @@ class eWeLinkPlatform { return await queue.add(async () => { // Log the update being sent if (this.config.debug) { - this.log( - '[%s] %s %s.', - accessory.displayName, - this.lang.updSend, - JSON.stringify(params) - ) + this.log('[%s] %s %s.', accessory.displayName, this.lang.updSend, JSON.stringify(params)) } // Set up the payload to send via LAN/WS @@ -1584,12 +1517,7 @@ class eWeLinkPlatform { reachableChange = true // Log the new reachability of the device - this.log( - '[%s] %s %s.', - accessory.displayName, - this.lang.repOnline, - this.lang.viaLAN - ) + this.log('[%s] %s %s.', accessory.displayName, this.lang.repOnline, this.lang.viaLAN) // Try and request an update through WS if the device has come back online if (accessory.context.reachableWAN && wsClient) { @@ -1645,12 +1573,7 @@ class eWeLinkPlatform { // Log the update if debug is set to true if (this.config.debug) { - this.log( - '[%s] %s %s.', - deviceId, - this.lang.recNew, - JSON.stringify(device.params) - ) + this.log('[%s] %s %s.', deviceId, this.lang.recNew, JSON.stringify(device.params)) } // Obtain full device information from the HTTP API From 053971e732a597fcf5d5e3a20dd4bb38bad065a3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 9 May 2021 19:07:35 +0100 Subject: [PATCH 2095/3183] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 940d2b8e..ffa6232f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ All notable changes to this homebridge-ewelink will be documented in this file. * Removed `encodedPassword` and `language` config options * The plugin will now initially try the supplied password and if incorrect will attempt another login with a base64 decoded version - * Language option unnecessary until other languages are available + * Language option unnecessary until if and when other languages are available * Display temperature and humidity units for the zigbee temperature/humidity sensor in the logs * Fixes an issue where the web socket would not close on plugin shutdown * Reduce the 'No Response' timeout to 2 seconds From b91b83c067d6cabc47f13e574049da745fc005a3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Sun, 9 May 2021 19:08:04 +0100 Subject: [PATCH 2096/3183] 6.5.2-beta.9 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1584c920..168687e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.5.2-beta.8", + "version": "6.5.2-beta.9", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 2437482b..5da94925 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.5.2-beta.8", + "version": "6.5.2-beta.9", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From 5eed16be19b8d83823e4fdce8841fd911f146fb7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 10 May 2021 09:32:18 +0100 Subject: [PATCH 2097/3183] add descriptions for username & password --- config.schema.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config.schema.json b/config.schema.json index b12f8484..5e28212a 100644 --- a/config.schema.json +++ b/config.schema.json @@ -17,12 +17,14 @@ "type": "string", "title": "Username", "required": true, - "placeholder": "Email or full phone (e.g. +8613185260282)" + "placeholder": "Email or full phone (e.g. +8613185260282)", + "description": "Your eWeLink username, please use your main eWeLink credentials (not a secondary/shared account)." }, "password": { "type": "string", "title": "Password", - "required": true + "required": true, + "description": "Your eWeLink password, can also be a base64 encoded version of your password." }, "mode": { "type": "string", From 0865775b236e4920ade823137906afac5d44b7d1 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 10 May 2021 09:57:28 +0100 Subject: [PATCH 2098/3183] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffa6232f..40fd2434 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this homebridge-ewelink will be documented in this file. -## BETA +## 6.6.0 (2021-05-10) ### Added From 3a08e58408b1b4b1a7035902c426ee457381e326 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Mon, 10 May 2021 09:57:55 +0100 Subject: [PATCH 2099/3183] 6.6.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 168687e8..a89142a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "homebridge-ewelink", - "version": "6.5.2-beta.9", + "version": "6.6.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 5da94925..92ba05df 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge-ewelink", "alias": "eWeLink", - "version": "6.5.2-beta.9", + "version": "6.6.0", "author": "bwp91", "description": "Homebridge plugin to control eWeLink devices.", "license": "MIT", From e4931f19306cc4037e970d4bfd24b9d6772032e3 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 11 May 2021 13:15:21 +0100 Subject: [PATCH 2100/3183] Update config.schema.json --- config.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.schema.json b/config.schema.json index 5e28212a..3dbbf602 100644 --- a/config.schema.json +++ b/config.schema.json @@ -48,7 +48,7 @@ "countryCode": { "title": "Country Code", "type": "string", - "description": "Override the default country code sent, may help with login issues for users in other regions.", + "description": "Override the default country code, may help with login issues for users in other regions.", "placeholder": "+44" }, "httpHost": { From 4c9f038b465268c1c3ad8ac64bb2da2e9ff0bdef Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 11 May 2021 14:17:26 +0100 Subject: [PATCH 2101/3183] split outlet and power outlet files --- lib/device/outlet-power.js | 225 ++++++++++++++++++++++++++++++++++++ lib/device/outlet-single.js | 184 +++-------------------------- lib/index.js | 28 +++-- 3 files changed, 258 insertions(+), 179 deletions(-) create mode 100644 lib/device/outlet-power.js diff --git a/lib/device/outlet-power.js b/lib/device/outlet-power.js new file mode 100644 index 00000000..39e59fc8 --- /dev/null +++ b/lib/device/outlet-power.js @@ -0,0 +1,225 @@ +/* jshint -W014, -W033, esversion: 9 */ +/* eslint-disable new-cap */ +'use strict' + +module.exports = class deviceOutletPower { + constructor (platform, accessory) { + // Set up variables from the platform + this.eveChar = platform.eveChar + this.funcs = platform.funcs + this.hapChar = platform.api.hap.Characteristic + this.hapErr = platform.api.hap.HapStatusError + this.hapServ = platform.api.hap.Service + this.lang = platform.lang + this.log = platform.log + this.platform = platform + + // Set up variables from the accessory + this.name = accessory.displayName + this.accessory = accessory + + // Set up custom variables for this device type + const deviceConf = platform.outletDevices[accessory.context.eweDeviceId] + this.inUsePowerThreshold = deviceConf && deviceConf.inUsePowerThreshold + ? deviceConf.inUsePowerThreshold + : platform.consts.defaultValues.inUsePowerThreshold + this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging + + // If the accessory has a switch service then remove it + if (this.accessory.getService(this.hapServ.Switch)) { + this.accessory.removeService(this.accessory.getService(this.hapServ.Switch)) + } + + // Add the outlet service if it doesn't already exist + if (!(this.service = this.accessory.getService(this.hapServ.Outlet))) { + this.service = this.accessory.addService(this.hapServ.Outlet) + this.service.addCharacteristic(this.eveChar.Voltage) + this.service.addCharacteristic(this.eveChar.CurrentConsumption) + this.service.addCharacteristic(this.eveChar.ElectricCurrent) + this.service.addCharacteristic(this.eveChar.TotalConsumption) + this.service.addCharacteristic(this.eveChar.ResetTotal) + } + + // Add the set handler to the outlet on/off characteristic + this.service.getCharacteristic(this.hapChar.On).onSet(async value => { + await this.internalStateUpdate(value) + }) + + // Pass the accessory to Fakegato to set up with Eve + this.accessory.eveService = new platform.eveService('energy', this.accessory, { + log: platform.config.debugFakegato ? this.log : () => {} + }) + + // TotalConsumption is calculated by the plugin with these context readings + if (!this.funcs.hasProperty(this.accessory.context, 'energyReadings')) { + this.accessory.context.energyReadings = [] + } + if (!this.funcs.hasProperty(this.accessory.context, 'energyReadingTotal')) { + this.accessory.context.energyReadingTotal = 0 + } + + // Add the set handler to the outlet eve reset total energy characteristic + this.service.getCharacteristic(this.eveChar.ResetTotal).onSet(value => { + this.accessory.context.energyReadings = [] + this.accessory.context.energyReadingTotal = 0 + this.service.updateCharacteristic(this.eveChar.TotalConsumption, 0) + }) + + // Set up an interval for the plugin to calculate an approx total consumption + this.intervalPower = setInterval(() => { + // Every 30 seconds start with a zero reading + let total = 0 + + // Check we have had readings within the previous 30 seconds + if (this.accessory.context.energyReadings.length > 0) { + // Accumulate the total from the energy readings + this.accessory.context.energyReadings.forEach(x => { + total += x + }) + + // Divide this by the number of entries to get an average W5m + total /= this.accessory.context.energyReadings.length + + // Convert this to Wh then kWh + total /= 12 + total /= 1000 + + // Accumulate the grand total that Eve reads as the total consumption + this.accessory.context.energyReadingTotal += total + } + + // Reset the array for each 30 second readings + this.accessory.context.energyReadings = [] + + // Update Eve with the new grand total + this.service.updateCharacteristic( + this.eveChar.TotalConsumption, + this.accessory.context.energyReadingTotal + ) + }, 30000) + + // Set up an interval to get eWeLink to send power updates + setTimeout(() => { + this.internalUIUpdate() + this.intervalPoll = setInterval(() => this.internalUIUpdate(), 60000) + }, 5000) + + // Stop the intervals on Homebridge shutdown + platform.api.on('shutdown', () => { + clearInterval(this.intervalPoll) + clearInterval(this.intervalPower) + }) + + // Output the customised options to the log if in debug mode + if (platform.config.debug) { + const opts = JSON.stringify({ + disableDeviceLogging: this.disableDeviceLogging, + inUsePowerThreshold: this.inUsePowerThreshold + }) + this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts) + } + } + + async internalStateUpdate (value) { + try { + const newValue = value ? 'on' : 'off' + if (newValue === this.cacheState) { + return + } + await this.platform.sendDeviceUpdate(this.accessory, { + switch: newValue + }) + this.cacheState = newValue + if (!value) { + this.service.updateCharacteristic(this.hapChar.OutletInUse, false) + this.service.updateCharacteristic(this.eveChar.CurrentConsumption, 0) + this.accessory.eveService.addEntry({ power: 0 }) + this.accessory.context.energyReadings.push(0) + } + if (!this.disableDeviceLogging) { + this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState) + } + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + setTimeout(() => { + this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') + }, 2000) + throw new this.hapErr(-70402) + } + } + + async internalUIUpdate () { + try { + const params = { uiActive: 60 } + await this.platform.sendDeviceUpdate(this.accessory, params, true) + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, true) + } + } + + async externalUpdate (params) { + try { + if (params.switch && params.switch !== this.cacheState) { + this.service.updateCharacteristic(this.hapChar.On, params.switch === 'on') + this.cacheState = params.switch + if (this.cacheState === 'off') { + this.service.updateCharacteristic(this.hapChar.OutletInUse, false) + this.service.updateCharacteristic(this.eveChar.CurrentConsumption, 0) + this.accessory.eveService.addEntry({ power: 0 }) + this.accessory.context.energyReadings.push(0) + } + if (params.updateSource && !this.disableDeviceLogging) { + this.log('[%s] %s [%s].', this.name, this.lang.curState, params.switch) + } + } + let logger = false + if (this.funcs.hasProperty(params, 'power')) { + const power = parseFloat(params.power) + this.service.updateCharacteristic( + this.hapChar.OutletInUse, + this.cacheState === 'on' && power > this.inUsePowerThreshold + ) + this.service.updateCharacteristic(this.eveChar.CurrentConsumption, power) + this.accessory.eveService.addEntry({ power: this.cacheState === 'on' ? power : 0 }) + this.accessory.context.energyReadings.push(power) + logger = true + } + if (this.funcs.hasProperty(params, 'voltage')) { + this.service.updateCharacteristic(this.eveChar.Voltage, parseFloat(params.voltage)) + logger = true + } + if (this.funcs.hasProperty(params, 'current')) { + this.service.updateCharacteristic(this.eveChar.ElectricCurrent, parseFloat(params.current)) + logger = true + } + if (params.updateSource && logger && !this.disableDeviceLogging) { + this.log( + '[%s] %s%s%s.', + this.name, + this.funcs.hasProperty(params, 'power') + ? ' ' + this.lang.curPower + ' [' + params.power + 'W]' + : '', + this.funcs.hasProperty(params, 'voltage') + ? ' ' + this.lang.curVolt + ' [' + params.voltage + 'V]' + : '', + this.funcs.hasProperty(params, 'current') + ? ' ' + this.lang.curCurr + ' [' + params.current + 'A]' + : '' + ) + } + } catch (err) { + this.platform.deviceUpdateError(this.accessory, err, false) + } + } + + currentState () { + const toReturn = {} + toReturn.services = ['outlet'] + toReturn.outlet = { + state: this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off' + } + return toReturn + } +} diff --git a/lib/device/outlet-single.js b/lib/device/outlet-single.js index f72687df..3506992b 100644 --- a/lib/device/outlet-single.js +++ b/lib/device/outlet-single.js @@ -17,13 +17,9 @@ module.exports = class deviceOutletSingle { // Set up variables from the accessory this.name = accessory.displayName this.accessory = accessory - this.hasReadings = platform.consts.devices.outlet.includes(accessory.context.eweUIID) // Set up custom variables for this device type const deviceConf = platform.outletDevices[accessory.context.eweDeviceId] - this.inUsePowerThreshold = deviceConf && deviceConf.inUsePowerThreshold - ? deviceConf.inUsePowerThreshold - : platform.consts.defaultValues.inUsePowerThreshold this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging ? false : platform.config.disableDeviceLogging @@ -34,16 +30,8 @@ module.exports = class deviceOutletSingle { } // Add the outlet service if it doesn't already exist - if (!(this.service = this.accessory.getService(this.hapServ.Outlet))) { - this.service = this.accessory.addService(this.hapServ.Outlet) - if (this.hasReadings) { - this.service.addCharacteristic(this.eveChar.Voltage) - this.service.addCharacteristic(this.eveChar.CurrentConsumption) - this.service.addCharacteristic(this.eveChar.ElectricCurrent) - this.service.addCharacteristic(this.eveChar.TotalConsumption) - this.service.addCharacteristic(this.eveChar.ResetTotal) - } - } + this.service = this.accessory.getService(this.hapServ.Outlet) || + this.accessory.addService(this.hapServ.Outlet) // Add the set handler to the outlet on/off characteristic this.service.getCharacteristic(this.hapChar.On).onSet(async value => { @@ -55,97 +43,26 @@ module.exports = class deviceOutletSingle { log: platform.config.debugFakegato ? this.log : () => {} }) - if (this.hasReadings) { - // TotalConsumption is calculated by the plugin with these context readings - if (!this.funcs.hasProperty(this.accessory.context, 'energyReadings')) { - this.accessory.context.energyReadings = [] - } - if (!this.funcs.hasProperty(this.accessory.context, 'energyReadingTotal')) { - this.accessory.context.energyReadingTotal = 0 - } - - // Add the set handler to the outlet eve reset total energy characteristic - this.service.getCharacteristic(this.eveChar.ResetTotal).onSet(value => { - this.accessory.context.energyReadings = [] - this.accessory.context.energyReadingTotal = 0 - this.service.updateCharacteristic(this.eveChar.TotalConsumption, 0) - }) - - // Set up an interval for the plugin to calculate an approx total consumption - this.intervalPower = setInterval(() => { - // Every 30 seconds start with a zero reading - let total = 0 - - // Check we have had readings within the previous 30 seconds - if (this.accessory.context.energyReadings.length > 0) { - // Accumulate the total from the energy readings - this.accessory.context.energyReadings.forEach(x => { - total += x - }) - - // Divide this by the number of entries to get an average W5m - total /= this.accessory.context.energyReadings.length - - // Convert this to Wh - total /= 12 - - // Convert this to kWh - total /= 1000 - - // Accumulate the grand total that Eve reads as the total consumption - this.accessory.context.energyReadingTotal += total - } - - // Reset the array for each 30 second readings - this.accessory.context.energyReadings = [] - - // Update Eve with the new grand total - this.service.updateCharacteristic( - this.eveChar.TotalConsumption, - this.accessory.context.energyReadingTotal - ) - }, 30000) - - // Set up an interval to get eWeLink to send power updates - setTimeout(() => { - this.internalUIUpdate() - this.intervalPoll = setInterval(() => this.internalUIUpdate(), 60000) - }, 5000) - - // Stop the intervals on Homebridge shutdown - platform.api.on('shutdown', () => { - clearInterval(this.intervalPoll) - clearInterval(this.intervalPower) - }) - } else { - // Just a simple outlet model so remove any existing power characteristics - if (this.service.testCharacteristic(this.eveChar.Voltage)) { - this.service.removeCharacteristic( - this.service.getCharacteristic(this.eveChar.Voltage) - ) - this.service.removeCharacteristic( - this.service.getCharacteristic(this.eveChar.CurrentConsumption) - ) - this.service.removeCharacteristic( - this.service.getCharacteristic(this.eveChar.ElectricCurrent) - ) - this.service.removeCharacteristic( - this.service.getCharacteristic(this.eveChar.TotalConsumption) - ) - this.service.removeCharacteristic( - this.service.getCharacteristic(this.eveChar.ResetTotal) - ) - this.service.removeCharacteristic( - this.service.getCharacteristic(this.hapChar.OutletInUse) - ) - } + // Just a simple outlet model so remove any existing power characteristics + if (this.service.testCharacteristic(this.eveChar.Voltage)) { + this.service.removeCharacteristic(this.service.getCharacteristic(this.eveChar.Voltage)) + this.service.removeCharacteristic( + this.service.getCharacteristic(this.eveChar.CurrentConsumption) + ) + this.service.removeCharacteristic( + this.service.getCharacteristic(this.eveChar.ElectricCurrent) + ) + this.service.removeCharacteristic( + this.service.getCharacteristic(this.eveChar.TotalConsumption) + ) + this.service.removeCharacteristic(this.service.getCharacteristic(this.eveChar.ResetTotal)) + this.service.removeCharacteristic(this.service.getCharacteristic(this.hapChar.OutletInUse)) } // Output the customised options to the log if in debug mode if (platform.config.debug) { const opts = JSON.stringify({ - disableDeviceLogging: this.disableDeviceLogging, - inUsePowerThreshold: this.inUsePowerThreshold + disableDeviceLogging: this.disableDeviceLogging }) this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts) } @@ -161,12 +78,6 @@ module.exports = class deviceOutletSingle { switch: newValue }) this.cacheState = newValue - if (this.hasReadings && !value) { - this.service.updateCharacteristic(this.hapChar.OutletInUse, false) - this.service.updateCharacteristic(this.eveChar.CurrentConsumption, 0) - this.accessory.eveService.addEntry({ power: 0 }) - this.accessory.context.energyReadings.push(0) - } if (!this.disableDeviceLogging) { this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState) } @@ -179,76 +90,15 @@ module.exports = class deviceOutletSingle { } } - async internalUIUpdate () { - try { - const params = { uiActive: 60 } - await this.platform.sendDeviceUpdate(this.accessory, params, true) - } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, true) - } - } - async externalUpdate (params) { try { if (params.switch && params.switch !== this.cacheState) { this.service.updateCharacteristic(this.hapChar.On, params.switch === 'on') this.cacheState = params.switch - if (this.hasReadings && this.cacheState === 'off') { - this.service.updateCharacteristic(this.hapChar.OutletInUse, false) - this.service.updateCharacteristic(this.eveChar.CurrentConsumption, 0) - this.accessory.eveService.addEntry({ power: 0 }) - this.accessory.context.energyReadings.push(0) - } if (params.updateSource && !this.disableDeviceLogging) { this.log('[%s] %s [%s].', this.name, this.lang.curState, params.switch) } } - if (!this.hasReadings) { - return - } - let logger = false - if (this.funcs.hasProperty(params, 'power')) { - const power = parseFloat(params.power) - this.service.updateCharacteristic( - this.hapChar.OutletInUse, - this.cacheState === 'on' && power > this.inUsePowerThreshold - ) - this.service.updateCharacteristic(this.eveChar.CurrentConsumption, power) - this.accessory.eveService.addEntry({ - power: this.cacheState === 'on' ? power : 0 - }) - this.accessory.context.energyReadings.push(power) - logger = true - } - if (this.funcs.hasProperty(params, 'voltage')) { - this.service.updateCharacteristic( - this.eveChar.Voltage, - parseFloat(params.voltage) - ) - logger = true - } - if (this.funcs.hasProperty(params, 'current')) { - this.service.updateCharacteristic( - this.eveChar.ElectricCurrent, - parseFloat(params.current) - ) - logger = true - } - if (params.updateSource && logger && !this.disableDeviceLogging) { - this.log( - '[%s] %s%s%s.', - this.name, - this.funcs.hasProperty(params, 'power') - ? ' ' + this.lang.curPower + ' [' + params.power + 'W]' - : '', - this.funcs.hasProperty(params, 'voltage') - ? ' ' + this.lang.curVolt + ' [' + params.voltage + 'V]' - : '', - this.funcs.hasProperty(params, 'current') - ? ' ' + this.lang.curCurr + ' [' + params.current + 'A]' - : '' - ) - } } catch (err) { this.platform.deviceUpdateError(this.accessory, err, false) } diff --git a/lib/index.js b/lib/index.js index b5392246..26d82b52 100644 --- a/lib/index.js +++ b/lib/index.js @@ -883,22 +883,16 @@ class eWeLinkPlatform { accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/sensor-temp-humi'))(this, accessory) /************************/ - } else if ( - this.consts.devices.outlet.includes(uiid) || - ( - this.consts.devices.singleSwitch.includes(uiid) && - this.consts.devices.singleSwitchOutlet.includes(device.productModel) - ) - ) { - /****** - OUTLETS - ******/ + } else if (this.consts.devices.outlet.includes(uiid)) { + /**************************** + OUTLETS [WITH POWER READINGS] + ****************************/ accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = this.outletDevices[device.deviceid] && this.outletDevices[device.deviceid].showAsSwitch ? new (require('./device/switch-single'))(this, accessory) - : new (require('./device/outlet-single'))(this, accessory) - /*****/ + : new (require('./device/outlet-power'))(this, accessory) + /***************************/ } else if (this.consts.devices.outletSCM.includes(uiid)) { /************************************* OUTLETS [SINGLE BUT MULTIPLE HARDWARE] @@ -906,6 +900,16 @@ class eWeLinkPlatform { accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') accessory.control = new (require('./device/outlet-scm'))(this, accessory) /************************************/ + } else if (this.consts.devices.singleSwitchOutlet.includes(device.productModel)) { + /****** + OUTLETS + ******/ + accessory = devicesInHB.get(uuid) || this.addAccessory(device, device.deviceid + 'SWX') + accessory.control = this.outletDevices[device.deviceid] && + this.outletDevices[device.deviceid].showAsSwitch + ? new (require('./device/switch-single'))(this, accessory) + : new (require('./device/outlet-single'))(this, accessory) + /*****/ } else if (this.consts.devices.lightRGB.includes(uiid)) { /*********** LIGHTS [RGB] From fea888e417a8b046c6fef2383ba3680336167e6b Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 11 May 2021 14:21:47 +0100 Subject: [PATCH 2102/3183] line lengths --- lib/utils/eve-chars.js | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/lib/utils/eve-chars.js b/lib/utils/eve-chars.js index 0e882655..526e8d67 100644 --- a/lib/utils/eve-chars.js +++ b/lib/utils/eve-chars.js @@ -71,11 +71,7 @@ module.exports = class eveCharacteristics { this.setProps({ format: self.hapChar.Formats.UINT32, unit: self.hapChar.Units.seconds, - perms: [ - self.hapChar.Perms.READ, - self.hapChar.Perms.NOTIFY, - self.hapChar.Perms.WRITE - ] + perms: [self.hapChar.Perms.READ, self.hapChar.Perms.NOTIFY, self.hapChar.Perms.WRITE] }) this.value = this.getDefaultValue() } @@ -93,11 +89,7 @@ module.exports = class eveCharacteristics { this.setProps({ format: self.hapChar.Formats.UINT32, unit: self.hapChar.Units.SECONDS, - perms: [ - self.hapChar.Perms.READ, - self.hapChar.Perms.NOTIFY, - self.hapChar.Perms.WRITE - ] + perms: [self.hapChar.Perms.READ, self.hapChar.Perms.NOTIFY, self.hapChar.Perms.WRITE] }) this.value = this.getDefaultValue() } @@ -106,11 +98,7 @@ module.exports = class eveCharacteristics { this.setProps({ format: self.hapChar.Formats.UINT32, unit: self.hapChar.Units.SECONDS, - perms: [ - self.hapChar.Perms.READ, - self.hapChar.Perms.NOTIFY, - self.hapChar.Perms.WRITE - ] + perms: [self.hapChar.Perms.READ, self.hapChar.Perms.NOTIFY, self.hapChar.Perms.WRITE] }) this.value = this.getDefaultValue() } From adcd2a12462534de035f3887ce7f27cae9780737 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Tue, 11 May 2021 14:27:38 +0100 Subject: [PATCH 2103/3183] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8c299192..808394e3 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Homebridge plugin to control eWeLink devices ### Prerequisites * To use this plugin, you will need to already have [Homebridge](https://homebridge.io) (at least v1.3.3) or [HOOBS](https://hoobs.org) (at least v3.3.4) installed. Please refer to the links for more information and installation instructions. -* It is recommended to use the current LTS version of Node, currently v14, however Node v10 and v12 are also supported. +* It is recommended to use the current LTS version of Node, currently v14, however Node v12 is also supported. ### Setup * [Installation](https://github.com/bwp91/homebridge-ewelink/wiki/Installation) From 5b676e16322795e86c51e2c31c0974ed32cf5a58 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Tue, 11 May 2021 15:01:04 +0100 Subject: [PATCH 2104/3183] correct lang property typo --- lib/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/index.js b/lib/index.js index 26d82b52..682680ee 100644 --- a/lib/index.js +++ b/lib/index.js @@ -56,7 +56,7 @@ class eWeLinkPlatform { // Make sure user is running Homebridge v1.3 or above if (!api.versionGreaterOrEqual || !api.versionGreaterOrEqual('1.3.0')) { - throw new Error(this.lang.hbVerionFail) + throw new Error(this.lang.hbVersionFail) } // Check the user has configured the plugin @@ -74,7 +74,7 @@ class eWeLinkPlatform { } catch (err) { // Catch any errors during initialisation const hideErrLines = [ - this.lang.hbVerionFail, + this.lang.hbVersionFail, this.lang.missingCreds, this.lang.missingPW, this.lang.missingUN From b2891ebdf1f0bdd10f7a97eadb9e04023496abf7 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 12 May 2021 09:13:10 +0100 Subject: [PATCH 2105/3183] use prettier code style --- .prettierignore | 2 ++ package.json | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 .prettierignore diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..8b42361c --- /dev/null +++ b/.prettierignore @@ -0,0 +1,2 @@ +.github/ +.nova \ No newline at end of file diff --git a/package.json b/package.json index 92ba05df..fde639ee 100644 --- a/package.json +++ b/package.json @@ -54,5 +54,8 @@ "p-queue": "^6.6.2", "websocket-as-promised": "^2.0.1", "ws": "^7.4.5" + }, + "prettier": { + "printWidth": 100 } } From e5b5168e77d1e1f97ed9ffece2ec9b5c8d45ca11 Mon Sep 17 00:00:00 2001 From: bwp91 <43026681+bwp91@users.noreply.github.com> Date: Wed, 12 May 2021 09:14:36 +0100 Subject: [PATCH 2106/3183] prettier formatted code --- CHANGELOG.md | 484 +++++++++++----------- README.md | 73 ++-- config.schema.json | 320 +++++++------- lib/connection/api.js | 13 +- lib/connection/http.js | 33 +- lib/connection/lan.js | 41 +- lib/connection/ws.js | 44 +- lib/device/curtain.js | 23 +- lib/device/diffuser.js | 88 ++-- lib/device/fan.js | 22 +- lib/device/humidifier.js | 41 +- lib/device/light-cct.js | 83 ++-- lib/device/light-dimmer.js | 24 +- lib/device/light-rgb-cct.js | 119 ++---- lib/device/light-rgb.js | 39 +- lib/device/motor.js | 33 +- lib/device/outlet-double.js | 59 +-- lib/device/outlet-multi.js | 50 +-- lib/device/outlet-power.js | 18 +- lib/device/outlet-scm.js | 13 +- lib/device/outlet-single.js | 10 +- lib/device/rf-bridge.js | 45 +- lib/device/sensor-ambient.js | 44 +- lib/device/sensor-contact.js | 41 +- lib/device/sensor-temp-humi.js | 28 +- lib/device/simulation/blind.js | 27 +- lib/device/simulation/door.js | 27 +- lib/device/simulation/garage-eachen.js | 17 +- lib/device/simulation/garage-four.js | 33 +- lib/device/simulation/garage-od-switch.js | 14 +- lib/device/simulation/garage-one.js | 26 +- lib/device/simulation/garage-two.js | 46 +- lib/device/simulation/lock-one.js | 27 +- lib/device/simulation/sensor-leak.js | 23 +- lib/device/simulation/switch-valve.js | 23 +- lib/device/simulation/tap-one.js | 20 +- lib/device/simulation/thermostat.js | 59 ++- lib/device/simulation/valve-four.js | 16 +- lib/device/simulation/valve-one.js | 16 +- lib/device/simulation/valve-two.js | 16 +- lib/device/simulation/window.js | 27 +- lib/device/switch-double.js | 46 +- lib/device/switch-multi.js | 46 +- lib/device/switch-single.js | 14 +- lib/device/thermostat.js | 56 ++- lib/device/zigbee/light-cct.js | 60 +-- lib/device/zigbee/light-dimmer.js | 27 +- lib/device/zigbee/sensor-ambient.js | 48 +-- lib/device/zigbee/sensor-contact.js | 41 +- lib/device/zigbee/sensor-motion.js | 41 +- lib/device/zigbee/switch-single.js | 21 +- lib/device/zigbee/switch-stateless.js | 39 +- lib/fakegato/fakegato-history.js | 112 +++-- lib/fakegato/fakegato-storage.js | 32 +- lib/fakegato/fakegato-timer.js | 4 +- lib/fakegato/uuid.js | 2 +- lib/homebridge-ui/public/index.html | 201 +++++++-- lib/homebridge-ui/server.js | 2 +- lib/index.js | 191 ++++----- lib/utils/colour-utils.js | 6 +- lib/utils/constants.js | 122 +++++- lib/utils/functions.js | 5 +- 62 files changed, 1734 insertions(+), 1587 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40fd2434..2c7aec8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,530 +6,530 @@ All notable changes to this homebridge-ewelink will be documented in this file. ### Added -* Log internal API requests when in debug mode -* Support querying temperature and humidity values via the internal API +- Log internal API requests when in debug mode +- Support querying temperature and humidity values via the internal API ### Changes -* Removed `encodedPassword` and `language` config options - * The plugin will now initially try the supplied password and if incorrect will attempt another login with a base64 decoded version - * Language option unnecessary until if and when other languages are available -* Display temperature and humidity units for the zigbee temperature/humidity sensor in the logs -* Fixes an issue where the web socket would not close on plugin shutdown -* Reduce the 'No Response' timeout to 2 seconds -* Update the correct corresponding characteristic after the 'No Response' timeout -* Ensure user is using at least Homebridge v1.3.0 -* Update homebridge-ui wiki links to match github readme file +- Removed `encodedPassword` and `language` config options + - The plugin will now initially try the supplied password and if incorrect will attempt another login with a base64 decoded version + - Language option unnecessary until if and when other languages are available +- Display temperature and humidity units for the zigbee temperature/humidity sensor in the logs +- Fixes an issue where the web socket would not close on plugin shutdown +- Reduce the 'No Response' timeout to 2 seconds +- Update the correct corresponding characteristic after the 'No Response' timeout +- Ensure user is using at least Homebridge v1.3.0 +- Update homebridge-ui wiki links to match github readme file ## 6.5.1 (2021-05-07) ### Changes -* Fixes an initialisation issue with the 'garage' and 'obstruction detection' switch simulations -* Amendments to internal API endpoints -* Device IP changes will now reflect correctly +- Fixes an initialisation issue with the 'garage' and 'obstruction detection' switch simulations +- Amendments to internal API endpoints +- Device IP changes will now reflect correctly ## 6.5.0 (2021-05-06) ### Added -* Internal HTTP API to query/control the state of certain homebridge-ewelink accessories - * Options for new configuration setting `apiPort` are: - * `0` to disable the API (default setting) - * `1` to enable the API with a random available port (port will be shown in the log) - * Any higher integer to enable the API on this fixed port - * Documentation for the API can be seen at the base url (Homebridge IP + API port) +- Internal HTTP API to query/control the state of certain homebridge-ewelink accessories + - Options for new configuration setting `apiPort` are: + - `0` to disable the API (default setting) + - `1` to enable the API with a random available port (port will be shown in the log) + - Any higher integer to enable the API on this fixed port + - Documentation for the API can be seen at the base url (Homebridge IP + API port) ## 6.4.0 (2021-05-04) ### Added -* Power, voltage and current readings for DUALR3 when exposed as outlets -* RF Bridge remote buttons will turn on for 3 seconds in HomeKit when pressed -* Link a Zigbee contact sensor to a single garage door to report the garage door state -* Set a temperature offset for the Zigbee temperature/humidity sensor -* Configuration options to manually set account http host and country code [#249](https://github.com/bwp91/homebridge-ewelink/pull/249) +- Power, voltage and current readings for DUALR3 when exposed as outlets +- RF Bridge remote buttons will turn on for 3 seconds in HomeKit when pressed +- Link a Zigbee contact sensor to a single garage door to report the garage door state +- Set a temperature offset for the Zigbee temperature/humidity sensor +- Configuration options to manually set account http host and country code [#249](https://github.com/bwp91/homebridge-ewelink/pull/249) ### Changes -* Change Sonoff POWR2/S31 polling interval to a fixed 60 seconds -* iFan speed will now log as {low, medium, high} -* Remove 'Outlet In Use' characteristics for outlets that don't support power readings -* Remove Eve power characteristics for outlets that don't support power readings -* More language strings added to separate language file -* Accessory 'identify' function will now add an entry to the log -* Backend refactoring, function and variable name changes +- Change Sonoff POWR2/S31 polling interval to a fixed 60 seconds +- iFan speed will now log as {low, medium, high} +- Remove 'Outlet In Use' characteristics for outlets that don't support power readings +- Remove Eve power characteristics for outlets that don't support power readings +- More language strings added to separate language file +- Accessory 'identify' function will now add an entry to the log +- Backend refactoring, function and variable name changes ## 6.3.0 (2021-04-28) ### Added -* Support DUALR3 motor mode (as a *WindowCovering* service) +- Support DUALR3 motor mode (as a _WindowCovering_ service) ### Changes -* Remove old *Switch* services from DUALR3 when in motor mode -* iFan devices now use caching to avoid unnecessary duplicate updates -* Increase ws timeout from 5 to 6 seconds -* Decrease lan-only timeout from 10 to 9 seconds +- Remove old _Switch_ services from DUALR3 when in motor mode +- iFan devices now use caching to avoid unnecessary duplicate updates +- Increase ws timeout from 5 to 6 seconds +- Decrease lan-only timeout from 10 to 9 seconds ## 6.2.2 (2021-04-27) ### Changes -* Adjust iFan speed thresholds (now 0% is off, 1-33% is low, 34-66% is medium and 67-100% is high) -* Changed commands for multi-channel devices to only update desired channel (not all channels) -* Pause Adaptive Lighting if device is offline -* Automatically retry eWeLink login on startup in case of certain error codes -* Update package description (remove 'with original firmware' as this is redundant for eWeLink devices) +- Adjust iFan speed thresholds (now 0% is off, 1-33% is low, 34-66% is medium and 67-100% is high) +- Changed commands for multi-channel devices to only update desired channel (not all channels) +- Pause Adaptive Lighting if device is offline +- Automatically retry eWeLink login on startup in case of certain error codes +- Update package description (remove 'with original firmware' as this is redundant for eWeLink devices) ## 6.2.1 (2021-04-18) ### Changes -* Trim new lines and spaces from password when decoded from base64 -* Updated dependencies (`ws`) +- Trim new lines and spaces from password when decoded from base64 +- Updated dependencies (`ws`) ## 6.2.0 (2021-04-16) ### Added -* LAN mode for Sonoff RF Bridge +- LAN mode for Sonoff RF Bridge ### Changes -* Fix characteristic NaN warning for `LastActivation` -* More compact logging for eWeLink 504 error -* Remove online/offline status for Zigbee sensor devices -* Recover accessories from the cache using the UUID -* Reduce WS timeout to 5 seconds to reduce cases of `was slow to respond` HB warning -* Update wiki links in the Homebridge plugin-ui +- Fix characteristic NaN warning for `LastActivation` +- More compact logging for eWeLink 504 error +- Remove online/offline status for Zigbee sensor devices +- Recover accessories from the cache using the UUID +- Reduce WS timeout to 5 seconds to reduce cases of `was slow to respond` HB warning +- Update wiki links in the Homebridge plugin-ui ## 6.1.2 (2021-04-14) ### Changes -* Remove any existing humidity sensor for TH10/16 if DS18B20 sensor is used +- Remove any existing humidity sensor for TH10/16 if DS18B20 sensor is used ## 6.1.1 (2021-04-13) ### Changes -* Fixed an unhandled rejection error when controlling certain CCT bulbs +- Fixed an unhandled rejection error when controlling certain CCT bulbs ## 6.1.0 (2021-04-12) ### Added -* Support for doorbell model SA-026 (can be exposed as any sensor type as per other RF sensors) -* Updated plugin-ui 'Support' page links to match GitHub readme file +- Support for doorbell model SA-026 (can be exposed as any sensor type as per other RF sensors) +- Updated plugin-ui 'Support' page links to match GitHub readme file ### Changes -* Improvements to RF Bridge: - * No more characteristic warnings for `LastActivation` for motion and contact sensors - * Removed logs for 'not triggered' if device has since been triggered again -* Fixed the interval time length for calculating total energy consumption for relevant devices +- Improvements to RF Bridge: + - No more characteristic warnings for `LastActivation` for motion and contact sensors + - Removed logs for 'not triggered' if device has since been triggered again +- Fixed the interval time length for calculating total energy consumption for relevant devices ## 6.0.3 (2021-04-08) ### Changes -* [fix] Revert 'No Response' messages for **DW2** devices as they go on and offline +- [fix] Revert 'No Response' messages for **DW2** devices as they go on and offline ## 6.0.2 (2021-04-07) ### Changes -* Revert 'No Response' messages for **DW2** devices as they go on and offline +- Revert 'No Response' messages for **DW2** devices as they go on and offline ## 6.0.1 (2021-04-07) ### Requirements -* **Homebridge Users** - * This plugin has a minimum requirement of Homebridge v1.3.3 +- **Homebridge Users** -* **HOOBS Users** - * This plugin has a minimum requirement of HOOBS v3.3.4 + - This plugin has a minimum requirement of Homebridge v1.3.3 + +- **HOOBS Users** + - This plugin has a minimum requirement of HOOBS v3.3.4 ### Changes -* 'No Response' messages for **Zigbee and DW2** devices as they go on and offline -* 'No Response' messages for **all devices** if controlled and unsuccessful (and this status will be reverted after 5 seconds) -* Use the new `.onGet`/`.onSet` methods available in Homebridge v1.3 -* Fixes a caching issue with the iFan accessory -* Updated README to reflect minimum supported Homebridge/HOOBS and Node versions -* Updated recommended Node to v14.16.1 - +- 'No Response' messages for **Zigbee and DW2** devices as they go on and offline +- 'No Response' messages for **all devices** if controlled and unsuccessful (and this status will be reverted after 5 seconds) +- Use the new `.onGet`/`.onSet` methods available in Homebridge v1.3 +- Fixes a caching issue with the iFan accessory +- Updated README to reflect minimum supported Homebridge/HOOBS and Node versions +- Updated recommended Node to v14.16.1 + ## 5.6.0 (2021-03-25) ### Added -* Enter your eWeLink password as a base64 encoded string and use the option `encodedPassword` to let the plugin know ([#223](https://github.com/bwp91/homebridge-ewelink/issues/223)) -* Support for zigbee colour temperature lights (ewelink uiid 1258) ([#222](https://github.com/bwp91/homebridge-ewelink/issues/222)), including: - * Ikea Tradfri E14 600 lumen +- Enter your eWeLink password as a base64 encoded string and use the option `encodedPassword` to let the plugin know ([#223](https://github.com/bwp91/homebridge-ewelink/issues/223)) +- Support for zigbee colour temperature lights (ewelink uiid 1258) ([#222](https://github.com/bwp91/homebridge-ewelink/issues/222)), including: + - Ikea Tradfri E14 600 lumen ### Changes -* Improvements to web socket connection: ([#224](https://github.com/bwp91/homebridge-ewelink/issues/224)) - * On startup, the plugin will wait to connect to the web socket before initialising devices - * A new web socket address will be requested if the provided address causes errors - * In particular this should fix the `ENOTFOUND as-pconnect4.coolkit.cc` error that some users in the Asia continent were receiving +- Improvements to web socket connection: ([#224](https://github.com/bwp91/homebridge-ewelink/issues/224)) + - On startup, the plugin will wait to connect to the web socket before initialising devices + - A new web socket address will be requested if the provided address causes errors + - In particular this should fix the `ENOTFOUND as-pconnect4.coolkit.cc` error that some users in the Asia continent were receiving ## 5.5.1 (2021-03-21) ### Changes -* Remove the custom `minValue` for `CurrentTemperature` characteristic -* More welcome messages -* Updated `plugin-ui-utils` dependency +- Remove the custom `minValue` for `CurrentTemperature` characteristic +- More welcome messages +- Updated `plugin-ui-utils` dependency ## 5.5.0 (2021-03-17) ### Added -* Enable LAN control for the Sonoff SV -* Log entries will show for 'uncontrollable' devices if `mode:lan` on plugin startup -* Log entries to highlight unnecessary top-level configuration options you may have set -* Added a note in the plugin settings about changing RF bridge sensors and its consequences +- Enable LAN control for the Sonoff SV +- Log entries will show for 'uncontrollable' devices if `mode:lan` on plugin startup +- Log entries to highlight unnecessary top-level configuration options you may have set +- Added a note in the plugin settings about changing RF bridge sensors and its consequences ### Changes -* Remove country code configuration option as the plugin can determine your region automatically -* Modified config schema to show titles/descriptions for non Homebridge UI users -* Automatically show useful info in logs for 'yet to implement' devices -* Updated links on plugin-ui to match GitHub wiki -* [backend] Eve characteristics abstracted into separate file for better efficiency +- Remove country code configuration option as the plugin can determine your region automatically +- Modified config schema to show titles/descriptions for non Homebridge UI users +- Automatically show useful info in logs for 'yet to implement' devices +- Updated links on plugin-ui to match GitHub wiki +- [backend] Eve characteristics abstracted into separate file for better efficiency ## 5.4.0 (2021-03-14) ### Added -* The plugin now differentiates between LAN support for **incoming** and **outgoing** updates, allowing incoming updates for: - * TH10/16 - * B02 and B05 bulbs +- The plugin now differentiates between LAN support for **incoming** and **outgoing** updates, allowing incoming updates for: + - TH10/16 + - B02 and B05 bulbs ### Changes -* Attempt to fix outlet polling updates so the device reports updated info rather than the previous info. +- Attempt to fix outlet polling updates so the device reports updated info rather than the previous info. ## 5.3.0 (2021-03-10) ### Added -* Set up a polling interval for outlet devices to obtain power information on a regular basis (useful when the device doesn't automatically send frequent updates) +- Set up a polling interval for outlet devices to obtain power information on a regular basis (useful when the device doesn't automatically send frequent updates) ### Changes -* Adaptive Lighting now requires Homebridge 1.3 release -* Garages no longer need 'dummy' contact sensor to view Eve history - * For this reason, the `exposeContactSensor` setting is now redundant and so has been removed -* Outlet intervals for energy calculation and updates will stop on Homebridge shutdown +- Adaptive Lighting now requires Homebridge 1.3 release +- Garages no longer need 'dummy' contact sensor to view Eve history + - For this reason, the `exposeContactSensor` setting is now redundant and so has been removed +- Outlet intervals for energy calculation and updates will stop on Homebridge shutdown ## 5.2.0 (2021-03-08) ### Added -* **Accessory Simulations** - * Expose an optional contact sensor for Eachen garage devices for historical data in the Eve app - * Set custom minimum/maximum target temperatures for the TH10/16 thermostat simulation +- **Accessory Simulations** + - Expose an optional contact sensor for Eachen garage devices for historical data in the Eve app + - Set custom minimum/maximum target temperatures for the TH10/16 thermostat simulation ### Changes -* Specify a custom IP for the Sonoff D1 -* Show full error stack on plugin disable in debug mode -* Fixes a `multiple callback` error with CCT bulb accessories -* Updated dependencies +- Specify a custom IP for the Sonoff D1 +- Show full error stack on plugin disable in debug mode +- Fixes a `multiple callback` error with CCT bulb accessories +- Updated dependencies ## 5.1.1 (2021-03-02) ### Changes -* Fixes an issue sending LAN updates to multi-channel devices +- Fixes an issue sending LAN updates to multi-channel devices ## 5.1.0 (2021-03-02) ### Added -* **Accessory Simulations** - * Added `Door` service type simulation - * Added `Window` service type simulation - * [experimental] Specify different operation time for UP and DOWN for garages, blinds, doors and windows -* **Accessories** - * Support for Sonoff DUALR3 - * Support for Konesky Mosquito Killer - * Support for Sonoff SC (Sensor Centre) - * [experimental] Support for Sonoff D1 LAN control +- **Accessory Simulations** + - Added `Door` service type simulation + - Added `Window` service type simulation + - [experimental] Specify different operation time for UP and DOWN for garages, blinds, doors and windows +- **Accessories** + - Support for Sonoff DUALR3 + - Support for Konesky Mosquito Killer + - Support for Sonoff SC (Sensor Centre) + - [experimental] Support for Sonoff D1 LAN control ### Changes -* Less strict threshold for determining a 'significant' colour change for disabling Adaptive Lighting +- Less strict threshold for determining a 'significant' colour change for disabling Adaptive Lighting ## 5.0.6 (2021-02-26) ### Changes -* Removes the extra *Switch* service that was accidentally added to certain bulbs +- Removes the extra _Switch_ service that was accidentally added to certain bulbs ## 5.0.5 (2021-02-25) ### Changes -* Reverse the polarity of the leak sensor simulation - * You can expose a DW2 sensor as a leak sensor using [this guide](https://www.youtube.com/watch?v=YFu2LZfrrqs) as an Accessory Simulation +- Reverse the polarity of the leak sensor simulation + - You can expose a DW2 sensor as a leak sensor using [this guide](https://www.youtube.com/watch?v=YFu2LZfrrqs) as an Accessory Simulation ## 5.0.4 (2021-02-24) ### Changes -* Plugin will check that certain Accessory Simulations have been setup with the device type -* Hide IP address field in plugin settings if plugin `mode` is set to `wan` +- Plugin will check that certain Accessory Simulations have been setup with the device type +- Hide IP address field in plugin settings if plugin `mode` is set to `wan` ## 5.0.3 (2021-02-24) ### Changes -* Remove old *Switch* services when setting up Accessory Simulations -* Add the type of Accessory Simulation to the logged options on restart +- Remove old _Switch_ services when setting up Accessory Simulations +- Add the type of Accessory Simulation to the logged options on restart ## 5.0.2 (2021-02-24) ### Changes -* Fixes an issue initialising Accessory Simulation Lock devices +- Fixes an issue initialising Accessory Simulation Lock devices ## 5.0.1 (2021-02-24) ### Changes -* Fixes an issue initialising Contact Sensor devices +- Fixes an issue initialising Contact Sensor devices ## 5.0.0 (2021-02-24) -* ⚠ī¸ This release includes an overhaul of the settings in particular to specific device configuration -* The following options have been replaced: - * `hideChanFromHB`, `switchAsOutlet`, `outletAsSwitch`, `inUsePowerThreshold`, `hideLightFromFan`, `hideSwitchFromTH`, `thAsThermostat`, `resetRFBridge`, `lowBattThreshold`, `sensorTimeDifference`, `bulbB02BA60`, `bulbB02FST64`, `thTempOffset`, `hideZBLDPress`, `ZBDWBatt`, `ipOverride` -* If you use any of the above options then please take some time to review the changes after updating the plugin -* Detailed information about the changes can be seen [here](https://gist.github.com/bwp91/e87d9d3eb0e5dbc08e9ae7b31e33366e) - +- ⚠ī¸ This release includes an overhaul of the settings in particular to specific device configuration +- The following options have been replaced: + - `hideChanFromHB`, `switchAsOutlet`, `outletAsSwitch`, `inUsePowerThreshold`, `hideLightFromFan`, `hideSwitchFromTH`, `thAsThermostat`, `resetRFBridge`, `lowBattThreshold`, `sensorTimeDifference`, `bulbB02BA60`, `bulbB02FST64`, `thTempOffset`, `hideZBLDPress`, `ZBDWBatt`, `ipOverride` +- If you use any of the above options then please take some time to review the changes after updating the plugin +- Detailed information about the changes can be seen [here](https://gist.github.com/bwp91/e87d9d3eb0e5dbc08e9ae7b31e33366e) ### Added -* **Configuration** - * The ability to explicitly enable device logging per device if you have `disableDeviceLogging` set to true - * A `label` setting per device group which has no effect except to help identify the device when editing the configuration - * New `brightnessStep` option to specify a minimum brightness step in the Home app per dimmer/bulb/LED strip - * New `adaptiveLightingShift` option to offset the Adaptive Lighting values per bulb - * `showAsOutlet` option extended multi-channel switch and light switch devices to expose them as outlets -* **Accessories** - * Enhanced Eve information available for contact sensors: - * DW2 - * Zigbee Contact Sensor -* **Accessory Simulations** - * Expose a DW2 contact sensor as a leak sensor - * Sub-accessories will be removed automatically when setting up a new Accessory Simulation -* **Homebridge Plugin UI** - * 'My Devices' shows a red/green icon on the to show device WAN/LAN reachability - * 'My Devices' shows the firmware version for your device -* **New Devices** - * Support for eWeLink switch uiid 81, 82, 83, 84 and 107 device types - * Support for the 'Sonoff Hum' humidifier device (on/off and mode) - -### Changes - -* New plugin configuration format - [more info](https://gist.github.com/bwp91/e87d9d3eb0e5dbc08e9ae7b31e33366e) -* Device firmware version will now show correctly in HomeKit apps -* Fixes a characteristic warning for *MotionDetected* for Zigbee Motion Sensors -* Information about error 406 added to the logs in the form of a link (shown when error is received) -* Updated minimum Node to v14.16.0 +- **Configuration** + - The ability to explicitly enable device logging per device if you have `disableDeviceLogging` set to true + - A `label` setting per device group which has no effect except to help identify the device when editing the configuration + - New `brightnessStep` option to specify a minimum brightness step in the Home app per dimmer/bulb/LED strip + - New `adaptiveLightingShift` option to offset the Adaptive Lighting values per bulb + - `showAsOutlet` option extended multi-channel switch and light switch devices to expose them as outlets +- **Accessories** + - Enhanced Eve information available for contact sensors: + - DW2 + - Zigbee Contact Sensor +- **Accessory Simulations** + - Expose a DW2 contact sensor as a leak sensor + - Sub-accessories will be removed automatically when setting up a new Accessory Simulation +- **Homebridge Plugin UI** + - 'My Devices' shows a red/green icon on the to show device WAN/LAN reachability + - 'My Devices' shows the firmware version for your device +- **New Devices** + - Support for eWeLink switch uiid 81, 82, 83, 84 and 107 device types + - Support for the 'Sonoff Hum' humidifier device (on/off and mode) + +### Changes + +- New plugin configuration format - [more info](https://gist.github.com/bwp91/e87d9d3eb0e5dbc08e9ae7b31e33366e) +- Device firmware version will now show correctly in HomeKit apps +- Fixes a characteristic warning for _MotionDetected_ for Zigbee Motion Sensors +- Information about error 406 added to the logs in the form of a link (shown when error is received) +- Updated minimum Node to v14.16.0 ## 4.7.6 (2021-02-17) ### Changes -* Fixes an issue with the DW2 detecting garage door states +- Fixes an issue with the DW2 detecting garage door states ## 4.7.5 (2021-02-15) ### Changes -* Fixes an issue with the DW2 detecting garage door states +- Fixes an issue with the DW2 detecting garage door states ## 4.7.4 (2021-02-15) ### Changes -* Fixes an issue when using custom RF sensors +- Fixes an issue when using custom RF sensors ## 4.7.3 (2021-02-13) ### Changes -* Hide WS messages that have no useful information about a device -* Thermostat accessory simulation will now setup after a small delay to let the accessory initialise first -* Thermostat device will now suggest changing temperature scale from F to C in the eWeLink app -* Changes to colour conversion: - * Lighter colours appear brighter - * Solid red is now easier to obtain via the Home app +- Hide WS messages that have no useful information about a device +- Thermostat accessory simulation will now setup after a small delay to let the accessory initialise first +- Thermostat device will now suggest changing temperature scale from F to C in the eWeLink app +- Changes to colour conversion: + - Lighter colours appear brighter + - Solid red is now easier to obtain via the Home app ## 4.7.2 (2021-02-12) ### Changes -* Fixes a bug where config items separated by a comma weren't adhered to properly -* Stop subsequent warning messages if a device fails to initialise +- Fixes a bug where config items separated by a comma weren't adhered to properly +- Stop subsequent warning messages if a device fails to initialise ## 4.7.1 (2021-02-11) ### Changes -* The 'auto' and 'cool' modes will now be hidden for thermostat devices in the Eve app -* Fixed a bug when initialising lock accessory simulations -* Added a 10 second timeout when sending web socket messages -* Updated dependencies: - * `websocket-as-promised` to v2.0.1 -* Fakegato library formatting and simplification +- The 'auto' and 'cool' modes will now be hidden for thermostat devices in the Eve app +- Fixed a bug when initialising lock accessory simulations +- Added a 10 second timeout when sending web socket messages +- Updated dependencies: + - `websocket-as-promised` to v2.0.1 +- Fakegato library formatting and simplification ## 4.7.0 (2021-02-10) ### Added -* Support for the [eWeLink thermostat](https://ewelinkcommunity.net/device-lists/heating/kkmoon-hc-t010-ewf/) device type -* A queue for device updates to improve reliability, this also results in: - * Faster device updates for colour bulbs and diffusers -* Configuration checks to highlight in the logs any unnecessary or incorrectly formatted settings you have -* Added a note in the plugin UI when adding an Accessory Simulation that the accessory will need to be removed from the cache -* Links to 'Configuration' and 'Uninstall' wiki pages in the plugin-ui - -### Changes - -* ⚠ī¸ `ignoredDevices` configuration option is now an array not a string - [see details](https://gist.github.com/bwp91/90db67d578a8206c5a98a3447839f9e5) -* ⚠ī¸ Removed `nameOverride` configuration option - the plugin can now obtain channel names from eWeLink -* ⚠ī¸ Removed `resetRFBridge` option - the same usage can be achieved with `ignoredDevices` -* Reinstated `ipOverride` into the Homebridge plugin UI screen -* Improved colour temperature conversion for L1 and L1 Lite devices -* Fixed a bug where Adaptive Lighting would not be disabled if the colour was changed from the eWeLink app -* Fixed an issue with the 'Lock' Accessory Simulation where the status would never update as 'Unlocked' -* HTTP error codes will be displayed in the logs if and when the plugin re-attempts the connection -* Error messages refactored to show the most useful information -* [Backend] Major code refactoring -* [Backend] Code comments -* Updated minimum Node to v14.15.5 -* Updated minimum Homebridge to v1.1.7 -* Updated dependencies +- Support for the [eWeLink thermostat](https://ewelinkcommunity.net/device-lists/heating/kkmoon-hc-t010-ewf/) device type +- A queue for device updates to improve reliability, this also results in: + - Faster device updates for colour bulbs and diffusers +- Configuration checks to highlight in the logs any unnecessary or incorrectly formatted settings you have +- Added a note in the plugin UI when adding an Accessory Simulation that the accessory will need to be removed from the cache +- Links to 'Configuration' and 'Uninstall' wiki pages in the plugin-ui + +### Changes + +- ⚠ī¸ `ignoredDevices` configuration option is now an array not a string - [see details](https://gist.github.com/bwp91/90db67d578a8206c5a98a3447839f9e5) +- ⚠ī¸ Removed `nameOverride` configuration option - the plugin can now obtain channel names from eWeLink +- ⚠ī¸ Removed `resetRFBridge` option - the same usage can be achieved with `ignoredDevices` +- Reinstated `ipOverride` into the Homebridge plugin UI screen +- Improved colour temperature conversion for L1 and L1 Lite devices +- Fixed a bug where Adaptive Lighting would not be disabled if the colour was changed from the eWeLink app +- Fixed an issue with the 'Lock' Accessory Simulation where the status would never update as 'Unlocked' +- HTTP error codes will be displayed in the logs if and when the plugin re-attempts the connection +- Error messages refactored to show the most useful information +- [Backend] Major code refactoring +- [Backend] Code comments +- Updated minimum Node to v14.15.5 +- Updated minimum Homebridge to v1.1.7 +- Updated dependencies ## 4.6.1 (2021-02-02) ### Changes -* Extra debug logging for WS reconnection status -* Updated `ws` dependency to v7.4.3 +- Extra debug logging for WS reconnection status +- Updated `ws` dependency to v7.4.3 ## 4.6.0 (2021-01-30) ### New -* **[Experimental]** Use a TH10/16 device as a thermostat using an Accessory Simulation [more info](https://github.com/bwp91/homebridge-ewelink/issues/161#issuecomment-770230157) -* Support for the Zigbee type white bulb +- **[Experimental]** Use a TH10/16 device as a thermostat using an Accessory Simulation [more info](https://github.com/bwp91/homebridge-ewelink/issues/161#issuecomment-770230157) +- Support for the Zigbee type white bulb ### Changes -* Updated plugin-ui-utils dep and use new method to get cached accessories -* Increase the timeout for LAN control to 10 seconds for LAN only settings -* Show LAN update errors in the log +- Updated plugin-ui-utils dep and use new method to get cached accessories +- Increase the timeout for LAN control to 10 seconds for LAN only settings +- Show LAN update errors in the log ## 4.5.1 (2021-01-28) ### Changes -* Set the switch as the primary service of a TH10/16 device -* Only show the line in error logs if it exists (no more `[line undefined]`) -* Fixes an issue where RF sensors would not use a custom defined type (again!) +- Set the switch as the primary service of a TH10/16 device +- Only show the line in error logs if it exists (no more `[line undefined]`) +- Fixes an issue where RF sensors would not use a custom defined type (again!) ## 4.5.0 (2021-01-28) ### New -* Use a switch to control the `Obstruction Detected` feature of a garage door +- Use a switch to control the `Obstruction Detected` feature of a garage door ### Changes -* Fix for TH10/16 devices when the HomeKit switch would show the state of 'auto' mode -* Fix for TH10/16 devices (shown as thermostat) where the plugin would not show the current state of the device -* Fix for the display of watts/amps/volts for outlets that support this -* More consistent and clearer error logging +- Fix for TH10/16 devices when the HomeKit switch would show the state of 'auto' mode +- Fix for TH10/16 devices (shown as thermostat) where the plugin would not show the current state of the device +- Fix for the display of watts/amps/volts for outlets that support this +- More consistent and clearer error logging ## 4.4.5 (2021-01-24) ### Changes -* Fix where the battery for DW2 device would not update +- Fix where the battery for DW2 device would not update ## 4.4.4 (2021-01-24) ### Changes -* Backend - better handling of errors +- Backend - better handling of errors ## 4.4.3 (2021-01-20) ### Changes -* Fixes an issue where RF sensors would not use a custom defined type +- Fixes an issue where RF sensors would not use a custom defined type ## 4.4.2 (2021-01-20) ### Changes -* Fixes an issue when adding new RF bridge devices -* Minimum Homebridge beta needed for Adaptive Lighting bumped to beta-46 +- Fixes an issue when adding new RF bridge devices +- Minimum Homebridge beta needed for Adaptive Lighting bumped to beta-46 ## 4.4.1 (2021-01-20) ### Changes -* Fakegato logging disabled in Homebridge `debug` mode, can be explicitly enabled with `debugFakegato` +- Fakegato logging disabled in Homebridge `debug` mode, can be explicitly enabled with `debugFakegato` ## 4.4.0 (2021-01-14) ### ⚠ī¸ Breaking Changes -* **Accessory Simulations** - if use the following: - * 1 Lock - * 1 Tap/Faucet - * 1 Valve -* you will need to update your configuration with the Device Setup field (via Homebridge UI) or adding the line `"setup": "oneSwitch"` directly to your configuration file in the groups section +- **Accessory Simulations** - if use the following: + - 1 Lock + - 1 Tap/Faucet + - 1 Valve +- you will need to update your configuration with the Device Setup field (via Homebridge UI) or adding the line `"setup": "oneSwitch"` directly to your configuration file in the groups section ### New -* Single Accessory Simulations for multi-channel devices (e.g. 1 valve using a Sonoff 4CH) -* `operationTime` for Accessory Simulations will now be validated and increased to 20 if less than 20 or an invalid number +- Single Accessory Simulations for multi-channel devices (e.g. 1 valve using a Sonoff 4CH) +- `operationTime` for Accessory Simulations will now be validated and increased to 20 if less than 20 or an invalid number ### Changes -* Changes to plugin now in CHANGELOG.md -* Removed `Obstruction Detected` tests +- Changes to plugin now in CHANGELOG.md +- Removed `Obstruction Detected` tests ## 4.3.0 (2021-01-12) ### ⚠ī¸ Breaking Changes -* `hideDevFromHB` config option renamed to `ignoredDevices` - * After installing this update any hidden devices may reappear in Homebridge. Please edit your configuration directly, changing `hideDevFromHB` to `ignoredDevices`. The devices will be removed upon Homebridge restart. +- `hideDevFromHB` config option renamed to `ignoredDevices` + - After installing this update any hidden devices may reappear in Homebridge. Please edit your configuration directly, changing `hideDevFromHB` to `ignoredDevices`. The devices will be removed upon Homebridge restart. ### New -* New Accessory Simulations: - * 2 Taps/Faucets using a multi-channel device - * 4 Irrigation Valves using a multi-channel device #182 -* New `disableDeviceLogging` config option to hide device state logging #183 +- New Accessory Simulations: + - 2 Taps/Faucets using a multi-channel device + - 4 Irrigation Valves using a multi-channel device #182 +- New `disableDeviceLogging` config option to hide device state logging #183 ### Changes -* Minimum `operationTime` for associated Accessory Simulations increased to 20 (2 seconds) -* Removal of maximum values on plugin settings screen for all `number` types -* Changes to startup log messages -* Adaptive lighting minimum Homebridge beta version is now beta-42 -* Backend code changes -* Updated dependencies +- Minimum `operationTime` for associated Accessory Simulations increased to 20 (2 seconds) +- Removal of maximum values on plugin settings screen for all `number` types +- Changes to startup log messages +- Adaptive lighting minimum Homebridge beta version is now beta-42 +- Backend code changes +- Updated dependencies diff --git a/README.md b/README.md index 808394e3..71178f1e 100644 --- a/README.md +++ b/README.md @@ -3,62 +3,67 @@

        -# homebridge-ewelink +# homebridge-ewelink Homebridge plugin to control eWeLink devices [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) -[![hoobs-certified](https://badgen.net/badge/HOOBS/certified/yellow)](https://plugins.hoobs.org/plugin/homebridge-ewelink) +[![hoobs-certified](https://badgen.net/badge/HOOBS/certified/yellow)](https://plugins.hoobs.org/plugin/homebridge-ewelink) [![npm](https://img.shields.io/npm/v/homebridge-ewelink/latest?label=latest)](https://www.npmjs.com/package/homebridge-ewelink) -[![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://github.com/bwp91/homebridge-ewelink/wiki/Beta-Version) +[![npm](https://img.shields.io/npm/v/homebridge-ewelink/beta?label=beta)](https://github.com/bwp91/homebridge-ewelink/wiki/Beta-Version) [![npm](https://img.shields.io/npm/dt/homebridge-ewelink)](https://www.npmjs.com/package/homebridge-ewelink) -[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) +[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Discord](https://img.shields.io/discord/784827113378676736?color=728ED5&logo=discord&label=bwp91-discord)](https://discord.com/channels/784827113378676736/784827113378676739) [![Discord](https://img.shields.io/discord/432663330281226270?color=728ED5&logo=discord&label=hb-discord)](https://discord.com/channels/432663330281226270/742733745743855627) - ### Plugin Information -* This plugin allows you to view and control your eWeLink devices within HomeKit. The plugin: - * requires your eWeLink credentials to function - * supports LAN control for certain devices - * uses a web socket for real-time device control and updates + +- This plugin allows you to view and control your eWeLink devices within HomeKit. The plugin: + - requires your eWeLink credentials to function + - supports LAN control for certain devices + - uses a web socket for real-time device control and updates ### Prerequisites -* To use this plugin, you will need to already have [Homebridge](https://homebridge.io) (at least v1.3.3) or [HOOBS](https://hoobs.org) (at least v3.3.4) installed. Please refer to the links for more information and installation instructions. -* It is recommended to use the current LTS version of Node, currently v14, however Node v12 is also supported. + +- To use this plugin, you will need to already have [Homebridge](https://homebridge.io) (at least v1.3.3) or [HOOBS](https://hoobs.org) (at least v3.3.4) installed. Please refer to the links for more information and installation instructions. +- It is recommended to use the current LTS version of Node, currently v14, however Node v12 is also supported. ### Setup -* [Installation](https://github.com/bwp91/homebridge-ewelink/wiki/Installation) -* [Configuration](https://github.com/bwp91/homebridge-ewelink/wiki/Configuration) -* [Beta Version](https://github.com/bwp91/homebridge-ewelink/wiki/Beta-Version) -* [Node Version](https://github.com/bwp91/homebridge-ewelink/wiki/Node-Version) -* [Uninstallation](https://github.com/bwp91/homebridge-ewelink/wiki/Uninstallation) + +- [Installation](https://github.com/bwp91/homebridge-ewelink/wiki/Installation) +- [Configuration](https://github.com/bwp91/homebridge-ewelink/wiki/Configuration) +- [Beta Version](https://github.com/bwp91/homebridge-ewelink/wiki/Beta-Version) +- [Node Version](https://github.com/bwp91/homebridge-ewelink/wiki/Node-Version) +- [Uninstallation](https://github.com/bwp91/homebridge-ewelink/wiki/Uninstallation) ### Features -* [Supported Devices](https://github.com/bwp91/homebridge-ewelink/wiki/Supported-Devices) -* [Multi Channel Devices](https://github.com/bwp91/homebridge-ewelink/wiki/Multi-Channel-Devices) -* [RF Bridge Sensors](https://github.com/bwp91/homebridge-ewelink/wiki/RF-Bridge-Sensors) -* [Accessory Simulations](https://github.com/bwp91/homebridge-ewelink/wiki/Accessory-Simulations) -* [Connection Methods](https://github.com/bwp91/homebridge-ewelink/wiki/Connection-Methods) -* [Internal API](https://github.com/bwp91/homebridge-ewelink/wiki/Internal-API) + +- [Supported Devices](https://github.com/bwp91/homebridge-ewelink/wiki/Supported-Devices) +- [Multi Channel Devices](https://github.com/bwp91/homebridge-ewelink/wiki/Multi-Channel-Devices) +- [RF Bridge Sensors](https://github.com/bwp91/homebridge-ewelink/wiki/RF-Bridge-Sensors) +- [Accessory Simulations](https://github.com/bwp91/homebridge-ewelink/wiki/Accessory-Simulations) +- [Connection Methods](https://github.com/bwp91/homebridge-ewelink/wiki/Connection-Methods) +- [Internal API](https://github.com/bwp91/homebridge-ewelink/wiki/Internal-API) ### Help/About -* [Common Errors](https://github.com/bwp91/homebridge-ewelink/wiki/Common-Errors) -* [Support Request](https://github.com/bwp91/homebridge-ewelink/issues/new/choose) -* [Changelog](https://github.com/bwp91/homebridge-ewelink/blob/latest/CHANGELOG.md) -* [About Me](https://github.com/sponsors/bwp91) +- [Common Errors](https://github.com/bwp91/homebridge-ewelink/wiki/Common-Errors) +- [Support Request](https://github.com/bwp91/homebridge-ewelink/issues/new/choose) +- [Changelog](https://github.com/bwp91/homebridge-ewelink/blob/latest/CHANGELOG.md) +- [About Me](https://github.com/sponsors/bwp91) ### Credits -* To the original plugin maintainer: [@gbro115](https://github.com/gbro115). -* To successive contributors: [@MrTomAsh](https://github.com/MrTomAsh) and [@howanghk](https://github.com/howanghk) for [homebridge-ewelink-max](https://github.com/howanghk/homebridge-ewelink). -* To the creators/contributors of [Homebridge](https://homebridge.io) who make this plugin possible. -* To the creators/contributors of [Fakegato](https://github.com/simont77/fakegato-history): [@simont77](https://github.com/simont77) and [@NorthernMan54](https://github.com/NorthernMan54). -* To the creator of the awesome plugin header logo: [Keryan Belahcene](https://www.instagram.com/keryan.me). -* To all users who have shared their devices to enable functionality. + +- To the original plugin maintainer: [@gbro115](https://github.com/gbro115). +- To successive contributors: [@MrTomAsh](https://github.com/MrTomAsh) and [@howanghk](https://github.com/howanghk) for [homebridge-ewelink-max](https://github.com/howanghk/homebridge-ewelink). +- To the creators/contributors of [Homebridge](https://homebridge.io) who make this plugin possible. +- To the creators/contributors of [Fakegato](https://github.com/simont77/fakegato-history): [@simont77](https://github.com/simont77) and [@NorthernMan54](https://github.com/NorthernMan54). +- To the creator of the awesome plugin header logo: [Keryan Belahcene](https://www.instagram.com/keryan.me). +- To all users who have shared their devices to enable functionality. ### Disclaimer -* I am in no way affiliated with eWeLink nor any of the device brands (like Sonoff) and this plugin is a personal project that I maintain in my free time. -* Use this plugin entirely at your own risk - please see licence for more information. + +- I am in no way affiliated with eWeLink nor any of the device brands (like Sonoff) and this plugin is a personal project that I maintain in my free time. +- Use this plugin entirely at your own risk - please see licence for more information. diff --git a/config.schema.json b/config.schema.json index 3dbbf602..3000fab9 100644 --- a/config.schema.json +++ b/config.schema.json @@ -31,7 +31,8 @@ "title": "Connection Mode", "description": "This setting defines how the plugin communicates with your devices. For further guidance, please refer to this wiki article.", "default": "auto", - "oneOf": [{ + "oneOf": [ + { "title": "Auto (Recommended)", "enum": ["auto"] }, @@ -56,27 +57,28 @@ "type": "string", "description": "Override the default API host, may help with login issues for users in other regions.", "placeholder": "eu-apia.coolkit.cc", - "oneOf": [{ - "title": "Auto (Recommended)", - "enum": ["auto"] - }, - { - "title": "eu-apia.coolkit.cc", - "enum": ["eu-apia.coolkit.cc"] - }, - { - "title": "us-apia.coolkit.cc", - "enum": ["us-apia.coolkit.cc"] - }, - { - "title": "as-apia.coolkit.cc", - "enum": ["as-apia.coolkit.cc"] - }, - { - "title": "cn-apia.coolkit.cn", - "enum": ["cn-apia.coolkit.cn"] - } - ] + "oneOf": [ + { + "title": "Auto (Recommended)", + "enum": ["auto"] + }, + { + "title": "eu-apia.coolkit.cc", + "enum": ["eu-apia.coolkit.cc"] + }, + { + "title": "us-apia.coolkit.cc", + "enum": ["us-apia.coolkit.cc"] + }, + { + "title": "as-apia.coolkit.cc", + "enum": ["as-apia.coolkit.cc"] + }, + { + "title": "cn-apia.coolkit.cn", + "enum": ["cn-apia.coolkit.cn"] + } + ] }, "apiPort": { "type": "number", @@ -268,7 +270,8 @@ "type": "string", "title": "Device Model", "description": "If your model is not listed then you do not need to set this.", - "oneOf": [{ + "oneOf": [ + { "title": "B02-B-A60", "enum": ["bulbB02BA60"] }, @@ -477,7 +480,8 @@ "type": "string", "title": "Sensor Type", "description": "Select the type of sensor you would like to expose this as.", - "oneOf": [{ + "oneOf": [ + { "title": "Motion", "enum": ["motion"] }, @@ -552,7 +556,8 @@ "type": "string", "title": "Type", "description": "The new type for this device.", - "oneOf": [{ + "oneOf": [ + { "title": "1 Thermostat (with Sonoff TH10 or TH16)", "enum": ["thermostat"] }, @@ -625,7 +630,8 @@ "condition": { "functionBody": "return (model.groups[arrayIndices] && ['garage', 'lock', 'tap', 'valve'].includes(model.groups[arrayIndices].type));" }, - "oneOf": [{ + "oneOf": [ + { "title": "Single-Channel", "enum": ["oneSwitch"] }, @@ -701,13 +707,11 @@ } } }, - "layout": [{ + "layout": [ + { "type": "fieldset", "title": "Required Settings", - "items": [ - "username", - "password" - ] + "items": ["username", "password"] }, { "type": "fieldset", @@ -730,16 +734,18 @@ "expandable": true, "add": "Add Another Device", "type": "array", - "items": [{ - "type": "fieldset", - "items": [ - "singleDevices[].deviceId", - "singleDevices[].label", - "singleDevices[].showAsOutlet", - "singleDevices[].ipAddress", - "singleDevices[].overrideDisabledLogging" - ] - }] + "items": [ + { + "type": "fieldset", + "items": [ + "singleDevices[].deviceId", + "singleDevices[].label", + "singleDevices[].showAsOutlet", + "singleDevices[].ipAddress", + "singleDevices[].overrideDisabledLogging" + ] + } + ] }, { "key": "multiDevices", @@ -748,18 +754,20 @@ "expandable": true, "add": "Add Another Device", "type": "array", - "items": [{ - "type": "fieldset", - "items": [ - "multiDevices[].deviceId", - "multiDevices[].label", - "multiDevices[].showAsOutlet", - "multiDevices[].inUsePowerThreshold", - "multiDevices[].hideChannels", - "multiDevices[].ipAddress", - "multiDevices[].overrideDisabledLogging" - ] - }] + "items": [ + { + "type": "fieldset", + "items": [ + "multiDevices[].deviceId", + "multiDevices[].label", + "multiDevices[].showAsOutlet", + "multiDevices[].inUsePowerThreshold", + "multiDevices[].hideChannels", + "multiDevices[].ipAddress", + "multiDevices[].overrideDisabledLogging" + ] + } + ] }, { "key": "outletDevices", @@ -768,17 +776,19 @@ "expandable": true, "add": "Add Another Device", "type": "array", - "items": [{ - "type": "fieldset", - "items": [ - "outletDevices[].deviceId", - "outletDevices[].label", - "outletDevices[].showAsSwitch", - "outletDevices[].inUsePowerThreshold", - "outletDevices[].ipAddress", - "outletDevices[].overrideDisabledLogging" - ] - }] + "items": [ + { + "type": "fieldset", + "items": [ + "outletDevices[].deviceId", + "outletDevices[].label", + "outletDevices[].showAsSwitch", + "outletDevices[].inUsePowerThreshold", + "outletDevices[].ipAddress", + "outletDevices[].overrideDisabledLogging" + ] + } + ] }, { "key": "lightDevices", @@ -787,18 +797,20 @@ "expandable": true, "add": "Add Another Device", "type": "array", - "items": [{ - "type": "fieldset", - "items": [ - "lightDevices[].deviceId", - "lightDevices[].label", - "lightDevices[].bulbModel", - "lightDevices[].brightnessStep", - "lightDevices[].adaptiveLightingShift", - "lightDevices[].ipAddress", - "lightDevices[].overrideDisabledLogging" - ] - }] + "items": [ + { + "type": "fieldset", + "items": [ + "lightDevices[].deviceId", + "lightDevices[].label", + "lightDevices[].bulbModel", + "lightDevices[].brightnessStep", + "lightDevices[].adaptiveLightingShift", + "lightDevices[].ipAddress", + "lightDevices[].overrideDisabledLogging" + ] + } + ] }, { "key": "thDevices", @@ -807,18 +819,20 @@ "expandable": true, "add": "Add Another Device", "type": "array", - "items": [{ - "type": "fieldset", - "items": [ - "thDevices[].deviceId", - "thDevices[].label", - "thDevices[].hideSwitch", - "thDevices[].offset", - "thDevices[].minTarget", - "thDevices[].maxTarget", - "thDevices[].overrideDisabledLogging" - ] - }] + "items": [ + { + "type": "fieldset", + "items": [ + "thDevices[].deviceId", + "thDevices[].label", + "thDevices[].hideSwitch", + "thDevices[].offset", + "thDevices[].minTarget", + "thDevices[].maxTarget", + "thDevices[].overrideDisabledLogging" + ] + } + ] }, { "key": "fanDevices", @@ -827,15 +841,17 @@ "expandable": true, "add": "Add Another Device", "type": "array", - "items": [{ - "type": "fieldset", - "items": [ - "fanDevices[].deviceId", - "fanDevices[].label", - "fanDevices[].hideLight", - "fanDevices[].overrideDisabledLogging" - ] - }] + "items": [ + { + "type": "fieldset", + "items": [ + "fanDevices[].deviceId", + "fanDevices[].label", + "fanDevices[].hideLight", + "fanDevices[].overrideDisabledLogging" + ] + } + ] }, { "key": "sensorDevices", @@ -844,18 +860,20 @@ "expandable": true, "add": "Add Another Device", "type": "array", - "items": [{ - "type": "fieldset", - "items": [ - "sensorDevices[].deviceId", - "sensorDevices[].label", - "sensorDevices[].lowBattThreshold", - "sensorDevices[].offset", - "sensorDevices[].hideLongDouble", - "sensorDevices[].scaleBattery", - "sensorDevices[].overrideDisabledLogging" - ] - }] + "items": [ + { + "type": "fieldset", + "items": [ + "sensorDevices[].deviceId", + "sensorDevices[].label", + "sensorDevices[].lowBattThreshold", + "sensorDevices[].offset", + "sensorDevices[].hideLongDouble", + "sensorDevices[].scaleBattery", + "sensorDevices[].overrideDisabledLogging" + ] + } + ] }, { "key": "bridgeSensors", @@ -864,21 +882,23 @@ "expandable": true, "add": "Add Another Sensor", "type": "array", - "items": [{ - "type": "fieldset", - "items": [ - "bridgeSensors[].fullDeviceId", - "bridgeSensors[].label", - "bridgeSensors[].type", - "bridgeSensors[].sensorTimeLength", - "bridgeSensors[].sensorTimeDifference", - "bridgeSensors[].overrideDisabledLogging", - { - "type": "help", - "helpvalue": "" - } - ] - }] + "items": [ + { + "type": "fieldset", + "items": [ + "bridgeSensors[].fullDeviceId", + "bridgeSensors[].label", + "bridgeSensors[].type", + "bridgeSensors[].sensorTimeLength", + "bridgeSensors[].sensorTimeDifference", + "bridgeSensors[].overrideDisabledLogging", + { + "type": "help", + "helpvalue": "" + } + ] + } + ] }, { "key": "groups", @@ -887,25 +907,27 @@ "description": "Set up simulated accessories from generic switch devices (more info).", "add": "Add Another Type", "type": "array", - "items": [{ - "type": "fieldset", - "items": [ - "groups[].deviceId", - "groups[].label", - "groups[].type", - "groups[].setup", - "groups[].operationTime", - "groups[].operationTimeDown", - "groups[].sensorId", - "groups[].obstructId", - "groups[].ipAddress", - "groups[].overrideDisabledLogging", - { - "type": "help", - "helpvalue": "" - } - ] - }] + "items": [ + { + "type": "fieldset", + "items": [ + "groups[].deviceId", + "groups[].label", + "groups[].type", + "groups[].setup", + "groups[].operationTime", + "groups[].operationTimeDown", + "groups[].sensorId", + "groups[].obstructId", + "groups[].ipAddress", + "groups[].overrideDisabledLogging", + { + "type": "help", + "helpvalue": "" + } + ] + } + ] }, { "key": "ignoredDevices", @@ -913,12 +935,12 @@ "title": "Ignored Devices", "add": "Add Another Device", "type": "array", - "items": [{ - "type": "fieldset", - "items": [ - "ignoredDevices[]" - ] - }] + "items": [ + { + "type": "fieldset", + "items": ["ignoredDevices[]"] + } + ] } ] } diff --git a/lib/connection/api.js b/lib/connection/api.js index 1a914172..016d37b4 100644 --- a/lib/connection/api.js +++ b/lib/connection/api.js @@ -234,7 +234,10 @@ module.exports = class connectionAPI { } const encodedCreds = req.headers.authorization.split(' ')[1] const buff = Buffer.from(encodedCreds, 'base64') - const decodedCreds = buff.toString('utf8').replace(/(\r\n|\n|\r)/gm, '').trim() + const decodedCreds = buff + .toString('utf8') + .replace(/(\r\n|\n|\r)/gm, '') + .trim() const [user, pass] = decodedCreds.split(':') if (user !== this.config.username || pass !== this.config.password) { throw new Error('Invalid authentication') @@ -369,9 +372,7 @@ module.exports = class connectionAPI { : false break case 'hue': - charName = accServ.testCharacteristic(this.hapChar.Hue) - ? this.hapChar.Hue - : false + charName = accServ.testCharacteristic(this.hapChar.Hue) ? this.hapChar.Hue : false break case 'speed': charName = accServ.testCharacteristic(this.hapChar.RotationSpeed) @@ -379,9 +380,7 @@ module.exports = class connectionAPI { : false break case 'state': - charName = accServ.testCharacteristic(this.hapChar.On) - ? this.hapChar.On - : false + charName = accServ.testCharacteristic(this.hapChar.On) ? this.hapChar.On : false break default: throw new Error('Invalid characteristic specified for service:' + servToUpdate) diff --git a/lib/connection/http.js b/lib/connection/http.js index 05b51ead..2582a136 100644 --- a/lib/connection/http.js +++ b/lib/connection/http.js @@ -43,8 +43,10 @@ module.exports = class connectionHTTP { } // Set up the request signature - const dataToSign = crypto.createHmac('sha256', this.consts.appSecret) - .update(JSON.stringify(data)).digest('base64') + const dataToSign = crypto + .createHmac('sha256', this.consts.appSecret) + .update(JSON.stringify(data)) + .digest('base64') // Send the request const res = await axios.post('https://' + this.httpHost + '/v2/user/login', data, { @@ -52,7 +54,9 @@ module.exports = class connectionHTTP { Authorization: 'Sign ' + dataToSign, 'Content-Type': 'application/json', 'X-CK-Appid': this.consts.appId, - 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) + 'X-CK-Nonce': Math.random() + .toString(36) + .substr(2, 8) } }) @@ -87,7 +91,10 @@ module.exports = class connectionHTTP { // In this case the password is incorrect so try base64 decoding just once this.triedBase64 = true const buff = Buffer.from(this.password, 'base64') - this.password = buff.toString('utf8').replace(/(\r\n|\n|\r)/gm, '').trim() + this.password = buff + .toString('utf8') + .replace(/(\r\n|\n|\r)/gm, '') + .trim() return await this.login() } else { if (body.data.at) { @@ -135,7 +142,9 @@ module.exports = class connectionHTTP { Authorization: 'Bearer ' + this.aToken, 'Content-Type': 'application/json', 'X-CK-Appid': this.consts.appId, - 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) + 'X-CK-Nonce': Math.random() + .toString(36) + .substr(2, 8) }, params: { num: 0 @@ -198,17 +207,21 @@ module.exports = class connectionHTTP { const res = await axios.post( 'https://' + this.httpHost + '/v2/device/thing', { - thingList: [{ - itemType: 1, - id: deviceId - }] + thingList: [ + { + itemType: 1, + id: deviceId + } + ] }, { headers: { Authorization: 'Bearer ' + this.aToken, 'Content-Type': 'application/json', 'X-CK-Appid': this.consts.appId, - 'X-CK-Nonce': Math.random().toString(36).substr(2, 8) + 'X-CK-Nonce': Math.random() + .toString(36) + .substr(2, 8) } } ) diff --git a/lib/connection/lan.js b/lib/connection/lan.js index a34420e0..8046b785 100644 --- a/lib/connection/lan.js +++ b/lib/connection/lan.js @@ -70,7 +70,8 @@ module.exports = class connectionLAN { if (!packet.answers) { return } - packet.answers.filter(value => value.name.includes('_ewelink._tcp.local')) + packet.answers + .filter(value => value.name.includes('_ewelink._tcp.local')) .filter(value => value.type === 'TXT') .filter(value => this.deviceMap.has(value.rdata.id)) .forEach(value => { @@ -86,16 +87,21 @@ module.exports = class connectionLAN { deviceInfo.lastIV = rdata.iv // Obtain the packet information - const data = rdata.data1 + - (rdata.data2 || '') + - (rdata.data3 || '') + - (rdata.data4 || '') - const key = crypto.createHash('md5') - .update(Buffer.from(deviceInfo.apiKey, 'utf8')).digest() - const dText = crypto - .createDecipheriv('aes-128-cbc', key, Buffer.from(rdata.iv, 'base64')) - const pText = Buffer - .concat([dText.update(Buffer.from(data, 'base64')), dText.final()]).toString('utf8') + const data = + rdata.data1 + (rdata.data2 || '') + (rdata.data3 || '') + (rdata.data4 || '') + const key = crypto + .createHash('md5') + .update(Buffer.from(deviceInfo.apiKey, 'utf8')) + .digest() + const dText = crypto.createDecipheriv( + 'aes-128-cbc', + key, + Buffer.from(rdata.iv, 'base64') + ) + const pText = Buffer.concat([ + dText.update(Buffer.from(data, 'base64')), + dText.final() + ]).toString('utf8') // Check to see if the IP address of the device has changed if (packet.address !== deviceInfo.ip && !this.ipOverride[rdata.id]) { @@ -111,13 +117,7 @@ module.exports = class connectionLAN { try { params = JSON.parse(pText) } catch (e) { - this.log.warn( - '[%s] %s %s:\n%s', - rdata.id, - this.lang.cantReadPacket, - e.message, - pText - ) + this.log.warn('[%s] %s %s:\n%s', rdata.id, this.lang.cantReadPacket, e.message, pText) return } @@ -189,7 +189,10 @@ module.exports = class connectionLAN { } // Generate the HTTP request - const key = crypto.createHash('md5').update(Buffer.from(apiKey, 'utf8')).digest() + const key = crypto + .createHash('md5') + .update(Buffer.from(apiKey, 'utf8')) + .digest() const iv = crypto.randomBytes(16) const enc = crypto.createCipheriv('aes-128-cbc', key, iv) const data = { diff --git a/lib/connection/ws.js b/lib/connection/ws.js index a4588d9e..1c9f449a 100644 --- a/lib/connection/ws.js +++ b/lib/connection/ws.js @@ -38,7 +38,9 @@ module.exports = class connectionWS { }, data: { appid: this.consts.appId, - nonce: Math.random().toString(36).substr(2, 8), + nonce: Math.random() + .toString(36) + .substr(2, 8), ts: Math.floor(new Date().getTime() / 1000), version: 8 } @@ -97,7 +99,7 @@ module.exports = class connectionWS { attachRequestId: (data, requestId) => Object.assign({ sequence: requestId }, data), extractRequestId: data => data && data.sequence, packMessage: data => JSON.stringify(data), - unpackMessage: data => data === 'pong' ? data : JSON.parse(data), + unpackMessage: data => (data === 'pong' ? data : JSON.parse(data)), timeout: 6000 }) @@ -111,7 +113,9 @@ module.exports = class connectionWS { apikey: this.apiKey, appid: this.consts.appId, at: this.aToken, - nonce: Math.random().toString(36).substr(2, 8), + nonce: Math.random() + .toString(36) + .substr(2, 8), sequence, ts: Math.floor(new Date() / 1000), userAgent: 'app', @@ -125,8 +129,10 @@ module.exports = class connectionWS { // Attempt to authenticate the web socket connection try { - // Send the request - const res = await this.wsClient.sendRequest(payload, { requestId: sequence }) + // Send the request + const res = await this.wsClient.sendRequest(payload, { + requestId: sequence + }) // Parse the response if (res.config && res.config.hb && res.config.hbInterval) { @@ -136,10 +142,10 @@ module.exports = class connectionWS { // Create a new ping interval this.hbInterval = setInterval(() => { try { - // Send the ping + // Send the ping this.wsClient.send('ping') } catch (err) { - // Catch errors sending ping and show in debug mode + // Catch errors sending ping and show in debug mode if (this.debug) { const eText = this.funcs.parseError(err) this.log.warn('%s %s.', this.lang.wsPingError, eText) @@ -152,7 +158,7 @@ module.exports = class connectionWS { this.log('%s.', this.lang.wsLoginSuccess) } } else { - // There was a problem with the authentication response + // There was a problem with the authentication response if (res.error === 406) { this.log.warn(this.lang.wsLogin406) } else { @@ -161,7 +167,7 @@ module.exports = class connectionWS { } } } catch (err) { - // Catch any errors authenticating the WS connection + // Catch any errors authenticating the WS connection const eText = this.funcs.parseError(err) this.log.warn('%s %s.', this.lang.wsLoginError, eText) } @@ -169,7 +175,7 @@ module.exports = class connectionWS { // Add a listener for when we receive a WS message this.wsClient.onUnpackedMessage.addListener(msg => { - // Don't continue if it's a simple pong + // Don't continue if it's a simple pong if (msg === 'pong') { return } @@ -191,19 +197,19 @@ module.exports = class connectionWS { // Normally the WS messages comes with an action if (msg.action) { - // Check which action the WS message includes + // Check which action the WS message includes switch (msg.action) { case 'update': case 'sysmsg': { if (msg.action === 'sysmsg' && this.funcs.hasProperty(msg.params, 'online')) { - // Update the online/offline status provided in the message + // Update the online/offline status provided in the message onlineStatus = msg.params.online } // Loop through the device parameters received for (const param in msg.params) { if (this.funcs.hasProperty(msg.params, param)) { - // Remove any params that the plugin doesn't need + // Remove any params that the plugin doesn't need if (!this.consts.paramsToKeep.includes(param.replace(/[0-9]/g, ''))) { delete msg.params[param] } @@ -211,7 +217,7 @@ module.exports = class connectionWS { } if (Object.keys(msg.params).length > 0) { - // Add more params to report back to the plugin + // Add more params to report back to the plugin msg.params.online = onlineStatus msg.params.updateSource = 'WS' @@ -227,7 +233,7 @@ module.exports = class connectionWS { break } case 'reportSubDevice': - // We don't need to do anything with this action + // We don't need to do anything with this action return default: { this.log.warn( @@ -239,9 +245,9 @@ module.exports = class connectionWS { } } } else if (this.funcs.hasProperty(msg, 'error') && msg.error === 0) { - // Safe to ignore these messages + // Safe to ignore these messages } else { - // WS message received has an unknown action + // WS message received has an unknown action this.log.warn('%s.\n%s', this.lang.wsUnkCmd, JSON.stringify(msg, null, 2)) } }) @@ -309,7 +315,9 @@ module.exports = class connectionWS { const sequence = Math.floor(new Date()).toString() // Send the request to eWeLink - const res = await this.wsClient.sendRequest(toSend, { requestId: sequence }) + const res = await this.wsClient.sendRequest(toSend, { + requestId: sequence + }) // Parse the response and see if any error has been reported back res.error = this.funcs.hasProperty(res, 'error') ? res.error : -1 diff --git a/lib/device/curtain.js b/lib/device/curtain.js index 8a660758..864495bd 100644 --- a/lib/device/curtain.js +++ b/lib/device/curtain.js @@ -25,12 +25,14 @@ module.exports = class deviceCurtain { // Set up custom variables for this device type const deviceConf = platform.singleDevices[accessory.context.eweDeviceId] - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // Add the window covering service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.WindowCovering) || + this.service = + this.accessory.getService(this.hapServ.WindowCovering) || this.accessory.addService(this.hapServ.WindowCovering) // Add the set handler to the target position characteristic @@ -40,7 +42,9 @@ module.exports = class deviceCurtain { // Output the customised options to the log if in debug mode if (platform.config.debug) { - const opts = JSON.stringify({ disableDeviceLogging: this.disableDeviceLogging }) + const opts = JSON.stringify({ + disableDeviceLogging: this.disableDeviceLogging + }) this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts) } } @@ -48,7 +52,9 @@ module.exports = class deviceCurtain { async internalPositionUpdate (value) { try { // This acts like a debounce function when endlessly sliding the slider - const updateKey = Math.random().toString(36).substr(2, 8) + const updateKey = Math.random() + .toString(36) + .substr(2, 8) this.updateKey = updateKey await this.funcs.sleep(500) if (updateKey !== this.updateKey) { @@ -81,10 +87,7 @@ module.exports = class deviceCurtain { // Catch any errors and let the platform display them this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.service.updateCharacteristic( - this.hapChar.TargetPosition, - this.cachePos - ) + this.service.updateCharacteristic(this.hapChar.TargetPosition, this.cachePos) }, 2000) throw new this.hapErr(-70402) } diff --git a/lib/device/diffuser.js b/lib/device/diffuser.js index 1ae55218..001e3158 100644 --- a/lib/device/diffuser.js +++ b/lib/device/diffuser.js @@ -20,16 +20,19 @@ module.exports = class deviceDiffuser { // Set up custom variables for this device type const deviceConf = platform.singleDevices[accessory.context.eweDeviceId] - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // Add the fan service if it doesn't already exist - this.fanService = this.accessory.getService('Diffuser') || + this.fanService = + this.accessory.getService('Diffuser') || this.accessory.addService(this.hapServ.Fan, 'Diffuser', 'diffuser') // Add the lightbulb service if it doesn't already exist - this.lightService = this.accessory.getService('Light') || + this.lightService = + this.accessory.getService('Light') || this.accessory.addService(this.hapServ.Lightbulb, 'Light', 'light') // Add the set handler to the fan on/off characteristic @@ -38,7 +41,8 @@ module.exports = class deviceDiffuser { }) // Add the set handler to the fan rotation characteristic - this.fanService.getCharacteristic(this.hapChar.RotationSpeed) + this.fanService + .getCharacteristic(this.hapChar.RotationSpeed) .setProps({ minStep: 50 }) .onSet(async value => { await this.internalDiffuserSpeedUpdate(value) @@ -61,7 +65,9 @@ module.exports = class deviceDiffuser { // Output the customised options to the log if in debug mode if (platform.config.debug) { - const opts = JSON.stringify({ disableDeviceLogging: this.disableDeviceLogging }) + const opts = JSON.stringify({ + disableDeviceLogging: this.disableDeviceLogging + }) this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts) } } @@ -78,7 +84,9 @@ module.exports = class deviceDiffuser { const params = { switch: newValue } // Set up a five second timeout for the plugin to ignore incoming updates - const timerKey = Math.random().toString(36).substr(2, 8) + const timerKey = Math.random() + .toString(36) + .substr(2, 8) this.updateTimeout = timerKey setTimeout(() => { if (this.updateTimeout === timerKey) { @@ -125,7 +133,9 @@ module.exports = class deviceDiffuser { const params = { state: newValue / 50 } // This acts like a debounce function when endlessly sliding the brightness scale - const updateKeySpeed = Math.random().toString(36).substr(2, 8) + const updateKeySpeed = Math.random() + .toString(36) + .substr(2, 8) this.updateKeySpeed = updateKeySpeed await this.funcs.sleep(450) if (updateKeySpeed !== this.updateKeySpeed) { @@ -172,7 +182,9 @@ module.exports = class deviceDiffuser { const params = { lightswitch: this.cacheLight } // Set up a five second timeout for the plugin to ignore incoming updates - const updateKeyLight = Math.random().toString(36).substr(2, 8) + const updateKeyLight = Math.random() + .toString(36) + .substr(2, 8) this.updateTimeout = updateKeyLight setTimeout(() => { if (this.updateTimeout === updateKeyLight) { @@ -188,21 +200,13 @@ module.exports = class deviceDiffuser { // Log the update if appropriate if (!this.disableDeviceLogging) { - this.log( - '[%s] %s [%s%].', - this.name, - this.lang.curLight, - value === 1 ? 'on' : 'off' - ) + this.log('[%s] %s [%s%].', this.name, this.lang.curLight, value === 1 ? 'on' : 'off') } } catch (err) { // Catch any errors and let the platform display them this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.lightService.updateCharacteristic( - this.hapChar.On, - this.cacheLight === 'on' - ) + this.lightService.updateCharacteristic(this.hapChar.On, this.cacheLight === 'on') }, 2000) throw new this.hapErr(-70402) } @@ -219,7 +223,9 @@ module.exports = class deviceDiffuser { const params = { lightbright: value } // This acts like a debounce function when endlessly sliding the brightness scale - const updateKeyBright = Math.random().toString(36).substr(2, 8) + const updateKeyBright = Math.random() + .toString(36) + .substr(2, 8) this.updateKeyBright = updateKeyBright await this.funcs.sleep(500) if (updateKeyBright !== this.updateKeyBright) { @@ -248,10 +254,7 @@ module.exports = class deviceDiffuser { // Catch any errors and let the platform display them this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.lightService.updateCharacteristic( - this.hapChar.Brightness, - this.cacheBright - ) + this.lightService.updateCharacteristic(this.hapChar.Brightness, this.cacheBright) }, 2000) throw new this.hapErr(-70402) } @@ -274,7 +277,9 @@ module.exports = class deviceDiffuser { } // This acts like a debounce function when endlessly sliding the colour wheel - const updateKeyColour = Math.random().toString(36).substr(2, 8) + const updateKeyColour = Math.random() + .toString(36) + .substr(2, 8) this.updateKeyColour = updateKeyColour await this.funcs.sleep(400) if (updateKeyColour !== this.updateKeyColour) { @@ -311,10 +316,7 @@ module.exports = class deviceDiffuser { // Catch any errors and let the platform display them this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.lightService.updateCharacteristic( - this.hapChar.Hue, - this.cacheHue - ) + this.lightService.updateCharacteristic(this.hapChar.Hue, this.cacheHue) }, 2000) throw new this.hapErr(-70402) } @@ -337,10 +339,7 @@ module.exports = class deviceDiffuser { // If the diffuser is on but no speed provided, then update speed with the cache if (this.cacheState === 'on' && !this.funcs.hasProperty(params, 'state')) { - this.fanService.updateCharacteristic( - this.hapChar.RotationSpeed, - this.cacheSpeed - ) + this.fanService.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed) } // Log if appropriate @@ -350,10 +349,7 @@ module.exports = class deviceDiffuser { } // Check to see if we are provided new and different speed information - if ( - this.funcs.hasProperty(params, 'state') && - params.state * 50 !== this.cacheSpeed - ) { + if (this.funcs.hasProperty(params, 'state') && params.state * 50 !== this.cacheSpeed) { // State is {0, 1, 2} corresponding to {0, 50, 100} rotation speed this.cacheSpeed = params.state * 50 @@ -367,10 +363,7 @@ module.exports = class deviceDiffuser { } // Check to see if we are provided new and different light on/off information - if ( - this.funcs.hasProperty(params, 'lightswitch') && - this.cacheLight !== params.lightswitch - ) { + if (this.funcs.hasProperty(params, 'lightswitch') && this.cacheLight !== params.lightswitch) { // Lightswitch is {0, 1} corresponding to {false, true} off/on state this.cacheLight = params.lightswitch @@ -397,10 +390,7 @@ module.exports = class deviceDiffuser { this.cacheBright = params.lightbright // Update the HomeKit value - this.lightService.updateCharacteristic( - this.hapChar.Brightness, - params.lightbright - ) + this.lightService.updateCharacteristic(this.hapChar.Brightness, params.lightbright) // Log if appropriate if (params.updateSource && !this.disableDeviceLogging) { @@ -411,11 +401,9 @@ module.exports = class deviceDiffuser { // Check to see if we are provided new and different light colour information if ( this.funcs.hasProperty(params, 'lightRcolor') && - ( - this.cacheR !== params.lightRcolor || + (this.cacheR !== params.lightRcolor || this.cacheG !== params.lightGcolor || - this.cacheB !== params.lightBcolor - ) + this.cacheB !== params.lightBcolor) ) { // Lightcolor is provided as [0, 255] corresponding to RGB values this.cacheR = params.lightRcolor diff --git a/lib/device/fan.js b/lib/device/fan.js index 8a2e261e..8749d859 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -20,13 +20,14 @@ module.exports = class deviceFan { // Set up custom variables for this device type const deviceConf = platform.fanDevices[accessory.context.eweDeviceId] this.hideLight = deviceConf && deviceConf.hideLight - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // Add the fan service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.Fan) || - this.accessory.addService(this.hapServ.Fan) + this.service = + this.accessory.getService(this.hapServ.Fan) || this.accessory.addService(this.hapServ.Fan) // Add the set handler to the fan on/off characteristic this.service.getCharacteristic(this.hapChar.On).onSet(async value => { @@ -34,7 +35,9 @@ module.exports = class deviceFan { }) // Add the set handler to the fan rotation speed characteristic - this.service.getCharacteristic(this.hapChar.RotationSpeed).setProps({ minStep: 33 }) + this.service + .getCharacteristic(this.hapChar.RotationSpeed) + .setProps({ minStep: 33 }) .onSet(async value => { await this.internalSpeedUpdate(value) }) @@ -47,7 +50,8 @@ module.exports = class deviceFan { } } else { // The user has not hidden the light channel, so add it if it doesn't exist - this.lightService = this.accessory.getService(this.hapServ.Lightbulb) || + this.lightService = + this.accessory.getService(this.hapServ.Lightbulb) || this.accessory.addService(this.hapServ.Lightbulb) // Add the set handler to the lightbulb on/off characteristic @@ -83,7 +87,9 @@ module.exports = class deviceFan { async internalSpeedUpdate (value) { try { // This acts like a debounce function when endlessly sliding the slider - const updateKey = Math.random().toString(36).substr(2, 8) + const updateKey = Math.random() + .toString(36) + .substr(2, 8) this.updateKey = updateKey await this.funcs.sleep(500) if (updateKey !== this.updateKey) { diff --git a/lib/device/humidifier.js b/lib/device/humidifier.js index c0a5e09a..3695e382 100644 --- a/lib/device/humidifier.js +++ b/lib/device/humidifier.js @@ -19,9 +19,10 @@ module.exports = class deviceHumidifier { // Set up custom variables for this device type const deviceConf = platform.singleDevices[accessory.context.eweDeviceId] - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging /* The device does not provide a current humidity reading so @@ -30,8 +31,8 @@ module.exports = class deviceHumidifier { */ // Add the fan service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.Fan) || - this.accessory.addService(this.hapServ.Fan) + this.service = + this.accessory.getService(this.hapServ.Fan) || this.accessory.addService(this.hapServ.Fan) // Add the set handler to the fan on/off characteristic this.service.getCharacteristic(this.hapChar.On).onSet(async value => { @@ -41,7 +42,8 @@ module.exports = class deviceHumidifier { }) // Add the set handler to the fan rotation speed characteristic - this.service.getCharacteristic(this.hapChar.RotationSpeed) + this.service + .getCharacteristic(this.hapChar.RotationSpeed) .setProps({ minStep: 33 }) .onSet(async value => { await this.internalModeUpdate(value) @@ -56,14 +58,18 @@ module.exports = class deviceHumidifier { // Output the customised options to the log if in debug mode if (platform.config.debug) { - const opts = JSON.stringify({ disableDeviceLogging: this.disableDeviceLogging }) + const opts = JSON.stringify({ + disableDeviceLogging: this.disableDeviceLogging + }) this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts) } } async internalModeUpdate (value) { try { - const updateKey = Math.random().toString(36).substr(2, 8) + const updateKey = Math.random() + .toString(36) + .substr(2, 8) this.updateKey = updateKey await this.funcs.sleep(500) if (updateKey !== this.updateKey) { @@ -100,12 +106,7 @@ module.exports = class deviceHumidifier { this.cacheState = 'on' this.cacheMode = newMode if (!this.disableDeviceLogging) { - this.log( - '[%s] %s [%s].', - this.name, - this.lang.curMode, - this.mode2label[this.cacheMode] - ) + this.log('[%s] %s [%s].', this.name, this.lang.curMode, this.mode2label[this.cacheMode]) } } } catch (err) { @@ -133,17 +134,9 @@ module.exports = class deviceHumidifier { this.cacheMode = params.state if (this.cacheState === 'on') { if (params.updateSource && !this.disableDeviceLogging) { - this.log( - '[%s] %s [%s].', - this.name, - this.lang.curMode, - this.mode2label[this.cacheMode] - ) + this.log('[%s] %s [%s].', this.name, this.lang.curMode, this.mode2label[this.cacheMode]) } - this.service.updateCharacteristic( - this.hapChar.RotationSpeed, - this.cacheMode * 33 - ) + this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheMode * 33) } } } catch (err) { diff --git a/lib/device/light-cct.js b/lib/device/light-cct.js index 8357a5e2..bc25f773 100644 --- a/lib/device/light-cct.js +++ b/lib/device/light-cct.js @@ -19,18 +19,22 @@ module.exports = class deviceLightCCT { // Set up custom variables for this device type const deviceConf = platform.lightDevices[accessory.context.eweDeviceId] - this.bulbModel = deviceConf && deviceConf.bulbModel - ? deviceConf.bulbModel - : platform.consts.defaultValues.bulbModel - this.alShift = deviceConf && deviceConf.adaptiveLightingShift - ? deviceConf.adaptiveLightingShift - : platform.consts.defaultValues.adaptiveLightingShift - this.brightStep = deviceConf && deviceConf.brightnessStep - ? Math.min(deviceConf.brightnessStep, 100) - : platform.consts.defaultValues.brightnessStep - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.bulbModel = + deviceConf && deviceConf.bulbModel + ? deviceConf.bulbModel + : platform.consts.defaultValues.bulbModel + this.alShift = + deviceConf && deviceConf.adaptiveLightingShift + ? deviceConf.adaptiveLightingShift + : platform.consts.defaultValues.adaptiveLightingShift + this.brightStep = + deviceConf && deviceConf.brightnessStep + ? Math.min(deviceConf.brightnessStep, 100) + : platform.consts.defaultValues.brightnessStep + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // Different bulbs have different colour temperature ranges switch (this.bulbModel) { @@ -49,7 +53,8 @@ module.exports = class deviceLightCCT { } // Add the lightbulb service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.Lightbulb) || + this.service = + this.accessory.getService(this.hapServ.Lightbulb) || this.accessory.addService(this.hapServ.Lightbulb) // Add the set handler to the lightbulb on/off characteristic @@ -58,7 +63,8 @@ module.exports = class deviceLightCCT { }) // Add the set handler to the lightbulb brightness characteristic - this.service.getCharacteristic(this.hapChar.Brightness) + this.service + .getCharacteristic(this.hapChar.Brightness) .setProps({ minStep: this.brightStep }) .onSet(async value => { await this.internalBrightnessUpdate(value) @@ -73,10 +79,9 @@ module.exports = class deviceLightCCT { this.cacheBright = this.service.getCharacteristic(this.hapChar.Brightness).value // Set up the adaptive lighting controller - this.accessory.alController = new platform.api.hap.AdaptiveLightingController( - this.service, - { customTemperatureAdjustment: this.alShift } - ) + this.accessory.alController = new platform.api.hap.AdaptiveLightingController(this.service, { + customTemperatureAdjustment: this.alShift + }) this.accessory.configureController(this.accessory.alController) // Output the customised options to the log if in debug mode @@ -97,7 +102,9 @@ module.exports = class deviceLightCCT { if (this.cacheState === newValue) { return } - const timerKey = Math.random().toString(36).substr(2, 8) + const timerKey = Math.random() + .toString(36) + .substr(2, 8) this.updateTimeout = timerKey setTimeout(() => { if (this.updateTimeout === timerKey) { @@ -125,7 +132,9 @@ module.exports = class deviceLightCCT { if (this.cacheBright === value) { return } - const updateKey = Math.random().toString(36).substr(2, 8) + const updateKey = Math.random() + .toString(36) + .substr(2, 8) this.updateKeyBright = updateKey await this.funcs.sleep(500) if (updateKey !== this.updateKeyBright) { @@ -165,7 +174,9 @@ module.exports = class deviceLightCCT { if (!this.isOnline && this.accessory.alController.isAdaptiveLightingActive()) { return } - const updateKey = Math.random().toString(36).substr(2, 8) + const updateKey = Math.random() + .toString(36) + .substr(2, 8) this.updateKeyCT = updateKey await this.funcs.sleep(400) if (updateKey !== this.updateKeyCT) { @@ -190,17 +201,8 @@ module.exports = class deviceLightCCT { this.cacheMired = value this.cacheCT = scaledCT if (!this.disableDeviceLogging) { - if ( - this.accessory.alController && - this.accessory.alController.isAdaptiveLightingActive() - ) { - this.log( - '[%s] %s [%sK] %s.', - this.name, - this.lang.curColour, - scaledK, - this.lang.viaAL - ) + if (this.accessory.alController && this.accessory.alController.isAdaptiveLightingActive()) { + this.log('[%s] %s [%sK] %s.', this.name, this.lang.curColour, scaledK, this.lang.viaAL) } else { this.log('[%s] %s [%sK].', this.name, this.lang.curColour, scaledK) } @@ -227,29 +229,20 @@ module.exports = class deviceLightCCT { } } if (params.white) { - if ( - this.funcs.hasProperty(params.white, 'br') && - this.cacheBright !== params.white.br - ) { + if (this.funcs.hasProperty(params.white, 'br') && this.cacheBright !== params.white.br) { this.cacheBright = params.white.br this.service.updateCharacteristic(this.hapChar.Brightness, this.cacheBright) if (params.updateSource && !this.disableDeviceLogging) { this.log('[%s] %s [%s%].', this.name, this.lang.curBright, this.cacheBright) } } - if ( - this.funcs.hasProperty(params.white, 'ct') && - this.cacheCT !== params.white.ct - ) { + if (this.funcs.hasProperty(params.white, 'ct') && this.cacheCT !== params.white.ct) { const ctDiff = Math.abs(params.white.ct - this.cacheCT) this.cacheCT = params.white.ct - const kelvin = this.cacheCT / 255 * (this.maxK - this.minK) + this.minK + const kelvin = (this.cacheCT / 255) * (this.maxK - this.minK) + this.minK const scaledK = Math.round(kelvin) this.cacheMired = Math.min(Math.max(Math.round(1000000 / scaledK), 140), 500) - this.service.updateCharacteristic( - this.hapChar.ColorTemperature, - this.cacheMired - ) + this.service.updateCharacteristic(this.hapChar.ColorTemperature, this.cacheMired) if (params.updateSource) { if (!this.disableDeviceLogging) { this.log('[%s] %s [%sK].', this.name, this.lang.curColour, scaledK) diff --git a/lib/device/light-dimmer.js b/lib/device/light-dimmer.js index e0ede673..ddb52ea2 100644 --- a/lib/device/light-dimmer.js +++ b/lib/device/light-dimmer.js @@ -19,15 +19,18 @@ module.exports = class deviceLightDimmer { // Set up custom variables for this device type const deviceConf = platform.lightDevices[accessory.context.eweDeviceId] - this.brightStep = deviceConf && deviceConf.brightnessStep - ? Math.min(deviceConf.brightnessStep, 100) - : platform.consts.defaultValues.brightnessStep - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.brightStep = + deviceConf && deviceConf.brightnessStep + ? Math.min(deviceConf.brightnessStep, 100) + : platform.consts.defaultValues.brightnessStep + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // Add the lightbulb service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.Lightbulb) || + this.service = + this.accessory.getService(this.hapServ.Lightbulb) || this.accessory.addService(this.hapServ.Lightbulb) // Add the set handler to the lightbulb on/off characteristic @@ -36,7 +39,8 @@ module.exports = class deviceLightDimmer { }) // Add the set handler to the lightbulb brightness characteristic - this.service.getCharacteristic(this.hapChar.Brightness) + this.service + .getCharacteristic(this.hapChar.Brightness) .setProps({ minStep: this.brightStep }) .onSet(async value => { await this.internalBrightnessUpdate(value) @@ -88,7 +92,9 @@ module.exports = class deviceLightDimmer { if (this.cacheBright === value) { return } - const updateKey = Math.random().toString(36).substr(2, 8) + const updateKey = Math.random() + .toString(36) + .substr(2, 8) this.updateKeyBright = updateKey await this.funcs.sleep(500) if (updateKey !== this.updateKeyBright) { diff --git a/lib/device/light-rgb-cct.js b/lib/device/light-rgb-cct.js index 0e925252..22eb7e82 100644 --- a/lib/device/light-rgb-cct.js +++ b/lib/device/light-rgb-cct.js @@ -20,15 +20,18 @@ module.exports = class deviceLightRGBCCT { // Set up custom variables for this device type const deviceConf = platform.lightDevices[accessory.context.eweDeviceId] - this.alShift = deviceConf && deviceConf.adaptiveLightingShift - ? deviceConf.adaptiveLightingShift - : platform.consts.defaultValues.adaptiveLightingShift - this.brightStep = deviceConf && deviceConf.brightnessStep - ? Math.min(deviceConf.brightnessStep, 100) - : platform.consts.defaultValues.brightnessStep - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.alShift = + deviceConf && deviceConf.adaptiveLightingShift + ? deviceConf.adaptiveLightingShift + : platform.consts.defaultValues.adaptiveLightingShift + this.brightStep = + deviceConf && deviceConf.brightnessStep + ? Math.min(deviceConf.brightnessStep, 100) + : platform.consts.defaultValues.brightnessStep + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // If the accessory has a outlet service then remove it (remedies bug int in v5) if (this.accessory.getService(this.hapServ.Switch)) { @@ -36,7 +39,8 @@ module.exports = class deviceLightRGBCCT { } // Add the lightbulb service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.Lightbulb) || + this.service = + this.accessory.getService(this.hapServ.Lightbulb) || this.accessory.addService(this.hapServ.Lightbulb) // Add the set handler to the lightbulb on/off characteristic @@ -45,7 +49,8 @@ module.exports = class deviceLightRGBCCT { }) // Add the set handler to the lightbulb brightness characteristic - this.service.getCharacteristic(this.hapChar.Brightness) + this.service + .getCharacteristic(this.hapChar.Brightness) .setProps({ minStep: this.brightStep }) .onSet(async value => { await this.internalBrightnessUpdate(value) @@ -65,10 +70,9 @@ module.exports = class deviceLightRGBCCT { this.cacheBright = this.service.getCharacteristic(this.hapChar.Brightness).value // Set up the adaptive lighting controller - this.accessory.alController = new platform.api.hap.AdaptiveLightingController( - this.service, - { customTemperatureAdjustment: this.alShift } - ) + this.accessory.alController = new platform.api.hap.AdaptiveLightingController(this.service, { + customTemperatureAdjustment: this.alShift + }) this.accessory.configureController(this.accessory.alController) // Output the customised options to the log if in debug mode @@ -88,7 +92,9 @@ module.exports = class deviceLightRGBCCT { if (this.cacheState === newValue) { return } - const timerKey = Math.random().toString(36).substr(2, 8) + const timerKey = Math.random() + .toString(36) + .substr(2, 8) this.updateTimeout = timerKey setTimeout(() => { if (this.updateTimeout === timerKey) { @@ -115,7 +121,9 @@ module.exports = class deviceLightRGBCCT { if (this.cacheBright === value) { return } - const updateKey = Math.random().toString(36).substr(2, 8) + const updateKey = Math.random() + .toString(36) + .substr(2, 8) this.updateKeyBright = updateKey await this.funcs.sleep(500) if (updateKey !== this.updateKeyBright) { @@ -176,7 +184,9 @@ module.exports = class deviceLightRGBCCT { if (this.cacheHue === value || this.cacheState !== 'on') { return } - const updateKey = Math.random().toString(36).substr(2, 8) + const updateKey = Math.random() + .toString(36) + .substr(2, 8) this.updateKey = updateKey await this.funcs.sleep(400) if (updateKey !== this.updateKey) { @@ -250,7 +260,9 @@ module.exports = class deviceLightRGBCCT { if (!this.isOnline && this.accessory.alController.isAdaptiveLightingActive()) { return } - const updateKey = Math.random().toString(36).substr(2, 8) + const updateKey = Math.random() + .toString(36) + .substr(2, 8) this.updateKey = updateKey await this.funcs.sleep(400) if (updateKey !== this.updateKey) { @@ -311,13 +323,7 @@ module.exports = class deviceLightRGBCCT { } if (!this.disableDeviceLogging) { if (this.accessory.alController.isAdaptiveLightingActive()) { - this.log( - '[%s] %s [%sK] %s.', - this.name, - this.lang.curColour, - mToK, - this.lang.viaAL - ) + this.log('[%s] %s [%sK] %s.', this.name, this.lang.curColour, mToK, this.lang.viaAL) } else { this.log('[%s] %s [%sK].', this.name, this.lang.curColour, mToK) } @@ -352,12 +358,7 @@ module.exports = class deviceLightRGBCCT { this.cacheBright = params.bright this.service.updateCharacteristic(this.hapChar.Brightness, this.cacheBright) if (params.updateSource && !this.disableDeviceLogging) { - this.log( - '[%s] %s [%s%].', - this.name, - this.lang.curBright, - this.cacheBright - ) + this.log('[%s] %s [%s%].', this.name, this.lang.curBright, this.cacheBright) } } } @@ -367,7 +368,8 @@ module.exports = class deviceLightRGBCCT { params.colorG !== this.cacheB || params.colorB !== this.cacheB ) { - const rgbDiff = Math.abs(params.colorR - this.cacheR) + + const rgbDiff = + Math.abs(params.colorR - this.cacheR) + Math.abs(params.colorG - this.cacheG) + Math.abs(params.colorG - this.cacheB) this.cacheR = params.colorR @@ -387,10 +389,7 @@ module.exports = class deviceLightRGBCCT { this.cacheR + ' ' + this.cacheG + ' ' + this.cacheB ) } - if ( - this.accessory.alController.isAdaptiveLightingActive() && - rgbDiff > 50 - ) { + if (this.accessory.alController.isAdaptiveLightingActive() && rgbDiff > 50) { this.accessory.alController.disableAdaptiveLighting() if (!this.disableDeviceLogging) { this.log('[%s] %s.', this.name, this.lang.disabledAL) @@ -406,17 +405,9 @@ module.exports = class deviceLightRGBCCT { if (this.funcs.hasProperty(params.color, 'br')) { if (params.color.br !== this.cacheBright) { this.cacheBright = params.color.br - this.service.updateCharacteristic( - this.hapChar.Brightness, - this.cacheBright - ) + this.service.updateCharacteristic(this.hapChar.Brightness, this.cacheBright) if (params.updateSource && !this.disableDeviceLogging) { - this.log( - '[%s] %s [%s%].', - this.name, - this.lang.curBright, - this.cacheBright - ) + this.log('[%s] %s [%s%].', this.name, this.lang.curBright, this.cacheBright) } } } @@ -447,10 +438,7 @@ module.exports = class deviceLightRGBCCT { } } } - if ( - params.updateSource && - this.accessory.alController.isAdaptiveLightingActive() - ) { + if (params.updateSource && this.accessory.alController.isAdaptiveLightingActive()) { this.accessory.alController.disableAdaptiveLighting() if (!this.disableDeviceLogging) { this.log('[%s] %s.', this.name, this.lang.disabledAL) @@ -461,45 +449,28 @@ module.exports = class deviceLightRGBCCT { if (this.funcs.hasProperty(params.white, 'br')) { if (params.white.br !== this.cacheBright || this.cacheMode !== 'white') { this.cacheBright = params.white.br - this.service.updateCharacteristic( - this.hapChar.Brightness, - this.cacheBright - ) + this.service.updateCharacteristic(this.hapChar.Brightness, this.cacheBright) if (params.updateSource && !this.disableDeviceLogging) { - this.log( - '[%s] %s [%s%].', - this.name, - this.lang.curBright, - this.cacheBright - ) + this.log('[%s] %s [%s%].', this.name, this.lang.curBright, this.cacheBright) } } } - if ( - this.funcs.hasProperty(params.white, 'ct') && - params.white.ct !== this.cacheCT - ) { + if (this.funcs.hasProperty(params.white, 'ct') && params.white.ct !== this.cacheCT) { this.cacheMode = 'white' const ctDiff = Math.abs(params.white.ct - this.cacheCT) this.cacheCT = params.white.ct - const ctToK = Math.round(this.cacheCT / 255 * 3800 + 2700) + const ctToK = Math.round((this.cacheCT / 255) * 3800 + 2700) this.cacheMired = Math.max(Math.min(Math.round(1000000 / ctToK), 500), 140) hs = this.colourUtils.m2hs(this.cacheMired) this.cacheHue = hs[0] this.service.updateCharacteristic(this.hapChar.Hue, this.cacheHue) this.service.updateCharacteristic(this.hapChar.Saturation, hs[1]) - this.service.updateCharacteristic( - this.hapChar.ColorTemperature, - this.cacheMired - ) + this.service.updateCharacteristic(this.hapChar.ColorTemperature, this.cacheMired) if (params.updateSource) { if (!this.disableDeviceLogging) { this.log('[%s] %s [%sK].', this.name, this.lang.curColour, ctToK) } - if ( - this.accessory.alController.isAdaptiveLightingActive() && - ctDiff > 20 - ) { + if (this.accessory.alController.isAdaptiveLightingActive() && ctDiff > 20) { // Look for a variation greater than twenty this.accessory.alController.disableAdaptiveLighting() if (!this.disableDeviceLogging) { diff --git a/lib/device/light-rgb.js b/lib/device/light-rgb.js index d185a032..cd0d73b0 100644 --- a/lib/device/light-rgb.js +++ b/lib/device/light-rgb.js @@ -20,18 +20,22 @@ module.exports = class deviceLightRGB { // Set up custom variables for this device type const deviceConf = platform.lightDevices[accessory.context.eweDeviceId] - this.alShift = deviceConf && deviceConf.adaptiveLightingShift - ? deviceConf.adaptiveLightingShift - : platform.consts.defaultValues.adaptiveLightingShift - this.brightStep = deviceConf && deviceConf.brightnessStep - ? Math.min(deviceConf.brightnessStep, 100) - : platform.consts.defaultValues.brightnessStep - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.alShift = + deviceConf && deviceConf.adaptiveLightingShift + ? deviceConf.adaptiveLightingShift + : platform.consts.defaultValues.adaptiveLightingShift + this.brightStep = + deviceConf && deviceConf.brightnessStep + ? Math.min(deviceConf.brightnessStep, 100) + : platform.consts.defaultValues.brightnessStep + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // Add the lightbulb service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.Lightbulb) || + this.service = + this.accessory.getService(this.hapServ.Lightbulb) || this.accessory.addService(this.hapServ.Lightbulb) // Add the set handler to the lightbulb on/off characteristic @@ -40,7 +44,8 @@ module.exports = class deviceLightRGB { }) // Add the set handler to the lightbulb brightness characteristic - this.service.getCharacteristic(this.hapChar.Brightness) + this.service + .getCharacteristic(this.hapChar.Brightness) .setProps({ minStep: 100 }) .onSet(async value => { await this.internalBrightnessUpdate(value) @@ -53,7 +58,9 @@ module.exports = class deviceLightRGB { // Output the customised options to the log if in debug mode if (platform.config.debug) { - const opts = JSON.stringify({ disableDeviceLogging: this.disableDeviceLogging }) + const opts = JSON.stringify({ + disableDeviceLogging: this.disableDeviceLogging + }) this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts) } } @@ -66,7 +73,9 @@ module.exports = class deviceLightRGB { return } params.state = newValue - const timerKey = Math.random().toString(36).substr(2, 8) + const timerKey = Math.random() + .toString(36) + .substr(2, 8) this.updateTimeout = timerKey setTimeout(() => { if (this.updateTimeout === timerKey) { @@ -105,7 +114,9 @@ module.exports = class deviceLightRGB { if (this.cacheHue === value) { return } - const updateKeyColour = Math.random().toString(36).substr(2, 8) + const updateKeyColour = Math.random() + .toString(36) + .substr(2, 8) this.updateKeyColour = updateKeyColour await this.funcs.sleep(400) if (updateKeyColour !== this.updateKeyColour) { diff --git a/lib/device/motor.js b/lib/device/motor.js index f28f53a2..36940590 100644 --- a/lib/device/motor.js +++ b/lib/device/motor.js @@ -27,12 +27,14 @@ module.exports = class deviceMotor { // Set up custom variables for this device type const deviceConf = platform.multiDevices[accessory.context.eweDeviceId] - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // Add the window covering service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.WindowCovering) || + this.service = + this.accessory.getService(this.hapServ.WindowCovering) || this.accessory.addService(this.hapServ.WindowCovering) // Add the set handler to the target position characteristic @@ -42,7 +44,9 @@ module.exports = class deviceMotor { // Output the customised options to the log if in debug mode if (platform.config.debug) { - const opts = JSON.stringify({ disableDeviceLogging: this.disableDeviceLogging }) + const opts = JSON.stringify({ + disableDeviceLogging: this.disableDeviceLogging + }) this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts) } } @@ -52,7 +56,9 @@ module.exports = class deviceMotor { if (this.cachePos === value) { return } - const updateKey = Math.random().toString(36).substr(2, 8) + const updateKey = Math.random() + .toString(36) + .substr(2, 8) this.updateKey = updateKey await this.funcs.sleep(500) if (updateKey !== this.updateKey) { @@ -68,10 +74,7 @@ module.exports = class deviceMotor { // Catch any errors and let the platform display them this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.service.updateCharacteristic( - this.hapChar.TargetPosition, - this.cachePos - ) + this.service.updateCharacteristic(this.hapChar.TargetPosition, this.cachePos) }, 2000) throw new this.hapErr(-70402) } @@ -86,14 +89,8 @@ module.exports = class deviceMotor { ) { if (this.cachePos !== params.location) { this.cachePos = params.location - this.service.updateCharacteristic( - this.hapChar.TargetPosition, - this.cachePos - ) - this.service.updateCharacteristic( - this.hapChar.CurrentPosition, - this.cachePos - ) + this.service.updateCharacteristic(this.hapChar.TargetPosition, this.cachePos) + this.service.updateCharacteristic(this.hapChar.CurrentPosition, this.cachePos) this.service.updateCharacteristic(this.hapChar.PositionState, 2) if (!this.disableDeviceLogging) { this.log('[%s] %s [%s%].', this.name, this.lang.curPos, this.cachePos) diff --git a/lib/device/outlet-double.js b/lib/device/outlet-double.js index 8b3f2892..2d335c0e 100644 --- a/lib/device/outlet-double.js +++ b/lib/device/outlet-double.js @@ -22,15 +22,15 @@ module.exports = class deviceOutletDouble { // Set up custom variables for this device type const deviceConf = platform.multiDevices[accessory.context.eweDeviceId] - this.hideChannels = deviceConf && deviceConf.hideChannels - ? deviceConf.hideChannels - : undefined - this.inUsePowerThreshold = deviceConf && deviceConf.inUsePowerThreshold - ? deviceConf.inUsePowerThreshold - : platform.consts.defaultValues.inUsePowerThreshold - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.hideChannels = deviceConf && deviceConf.hideChannels ? deviceConf.hideChannels : undefined + this.inUsePowerThreshold = + deviceConf && deviceConf.inUsePowerThreshold + ? deviceConf.inUsePowerThreshold + : platform.consts.defaultValues.inUsePowerThreshold + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // If the accessory has a switch service then remove it if (this.accessory.getService(this.hapServ.Switch)) { @@ -70,14 +70,10 @@ module.exports = class deviceOutletDouble { if (accessory.context.switchNumber === '0') { if (this.service.testCharacteristic(this.hapChar.OutletInUse)) { - this.service.removeCharacteristic( - this.service.getCharacteristic(this.hapChar.OutletInUse) - ) + this.service.removeCharacteristic(this.service.getCharacteristic(this.hapChar.OutletInUse)) } if (this.service.testCharacteristic(this.eveChar.Voltage)) { - this.service.removeCharacteristic( - this.service.getCharacteristic(this.eveChar.Voltage) - ) + this.service.removeCharacteristic(this.service.getCharacteristic(this.eveChar.Voltage)) this.service.removeCharacteristic( this.service.getCharacteristic(this.eveChar.CurrentConsumption) ) @@ -115,7 +111,10 @@ module.exports = class deviceOutletDouble { break case '1': case '2': - params.switches.push({ switch: value ? 'on' : 'off', outlet: switchNumber - 1 }) + params.switches.push({ + switch: value ? 'on' : 'off', + outlet: switchNumber - 1 + }) break } await this.platform.sendDeviceUpdate(this.accessory, params) @@ -184,10 +183,9 @@ module.exports = class deviceOutletDouble { const idToCheck = this.accessory.context.eweDeviceId + 'SW0' const uuid = this.hapUUIDGen(idToCheck) const priAccessory = this.devicesInHB.get(uuid) - priAccessory.getService(this.hapServ.Outlet).updateCharacteristic( - this.hapChar.On, - primaryState - ) + priAccessory + .getService(this.hapServ.Outlet) + .updateCharacteristic(this.hapChar.On, primaryState) } break } @@ -222,14 +220,9 @@ module.exports = class deviceOutletDouble { if (params.switches[i - 1].switch === 'on') { primaryState = true } - const currentState = service.getCharacteristic(this.hapChar.On).value - ? 'on' - : 'off' + const currentState = service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off' if (!params.updateSource || params.switches[i - 1].switch !== currentState) { - service.updateCharacteristic( - this.hapChar.On, - params.switches[i - 1].switch === 'on' - ) + service.updateCharacteristic(this.hapChar.On, params.switches[i - 1].switch === 'on') if (params.switches[i - 1].switch === 'off') { service.updateCharacteristic(this.hapChar.OutletInUse, false) service.updateCharacteristic(this.eveChar.CurrentConsumption, 0) @@ -277,15 +270,9 @@ module.exports = class deviceOutletDouble { this.log( '[%s] %s%s%s.', this.name, - power !== undefined - ? ' ' + this.lang.curPower + ' [' + power + 'W]' - : '', - voltage !== undefined - ? ' ' + this.lang.curVolt + ' [' + voltage + 'V]' - : '', - current !== undefined - ? ' ' + this.lang.curCurr + ' [' + current + 'A]' - : '' + power !== undefined ? ' ' + this.lang.curPower + ' [' + power + 'W]' : '', + voltage !== undefined ? ' ' + this.lang.curVolt + ' [' + voltage + 'V]' : '', + current !== undefined ? ' ' + this.lang.curCurr + ' [' + current + 'A]' : '' ) } } diff --git a/lib/device/outlet-multi.js b/lib/device/outlet-multi.js index 1ed65cd6..6a286bcb 100644 --- a/lib/device/outlet-multi.js +++ b/lib/device/outlet-multi.js @@ -21,12 +21,11 @@ module.exports = class deviceOutletMulti { // Set up custom variables for this device type const deviceConf = platform.multiDevices[accessory.context.eweDeviceId] - this.hideChannels = deviceConf && deviceConf.hideChannels - ? deviceConf.hideChannels - : undefined - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.hideChannels = deviceConf && deviceConf.hideChannels ? deviceConf.hideChannels : undefined + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // If the accessory has a switch service then remove it if (this.accessory.getService(this.hapServ.Switch)) { @@ -34,7 +33,8 @@ module.exports = class deviceOutletMulti { } // Add the outlet service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.Outlet) || + this.service = + this.accessory.getService(this.hapServ.Outlet) || this.accessory.addService(this.hapServ.Outlet) // Add the set handler to the switch/outlet on/off characteristic @@ -44,9 +44,7 @@ module.exports = class deviceOutletMulti { // Remove any OutletInUse characteristics from previous plugin versions if (this.service.testCharacteristic(this.hapChar.OutletInUse)) { - this.service.removeCharacteristic( - this.service.getCharacteristic(this.hapChar.OutletInUse) - ) + this.service.removeCharacteristic(this.service.getCharacteristic(this.hapChar.OutletInUse)) } // Output the customised options to the log if in debug mode @@ -77,7 +75,10 @@ module.exports = class deviceOutletMulti { case '2': case '3': case '4': - params.switches.push({ switch: value ? 'on' : 'off', outlet: switchNumber - 1 }) + params.switches.push({ + switch: value ? 'on' : 'off', + outlet: switchNumber - 1 + }) break } await this.platform.sendDeviceUpdate(this.accessory, params) @@ -88,10 +89,9 @@ module.exports = class deviceOutletMulti { const uuid = this.hapUUIDGen(idToCheck) if (this.devicesInHB.has(uuid)) { const subAccessory = this.devicesInHB.get(uuid) - subAccessory.getService(this.hapServ.Outlet).updateCharacteristic( - this.hapChar.On, - value - ) + subAccessory + .getService(this.hapServ.Outlet) + .updateCharacteristic(this.hapChar.On, value) if (i > 0 && !this.disableDeviceLogging) { this.log( '[%s] %s [%s].', @@ -126,8 +126,8 @@ module.exports = class deviceOutletMulti { } } else { if ( - subAccessory.getService(this.hapServ.Outlet) - .getCharacteristic(this.hapChar.On).value + subAccessory.getService(this.hapServ.Outlet).getCharacteristic(this.hapChar.On) + .value ) { primaryState = true } @@ -138,10 +138,9 @@ module.exports = class deviceOutletMulti { const idToCheck = this.accessory.context.eweDeviceId + 'SW0' const uuid = this.hapUUIDGen(idToCheck) const priAccessory = this.devicesInHB.get(uuid) - priAccessory.getService(this.hapServ.Outlet).updateCharacteristic( - this.hapChar.On, - primaryState - ) + priAccessory + .getService(this.hapServ.Outlet) + .updateCharacteristic(this.hapChar.On, primaryState) } break } @@ -169,16 +168,11 @@ module.exports = class deviceOutletMulti { } const subAccessory = this.devicesInHB.get(uuid) const service = subAccessory.getService(this.hapServ.Outlet) - const currentState = service.getCharacteristic(this.hapChar.On).value - ? 'on' - : 'off' + const currentState = service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off' if (params.updateSource && params.switches[i - 1].switch === currentState) { continue } - service.updateCharacteristic( - this.hapChar.On, - params.switches[i - 1].switch === 'on' - ) + service.updateCharacteristic(this.hapChar.On, params.switches[i - 1].switch === 'on') if (params.updateSource && !this.disableDeviceLogging) { this.log( '[%s] %s [%s].', diff --git a/lib/device/outlet-power.js b/lib/device/outlet-power.js index 39e59fc8..29862e6f 100644 --- a/lib/device/outlet-power.js +++ b/lib/device/outlet-power.js @@ -20,12 +20,14 @@ module.exports = class deviceOutletPower { // Set up custom variables for this device type const deviceConf = platform.outletDevices[accessory.context.eweDeviceId] - this.inUsePowerThreshold = deviceConf && deviceConf.inUsePowerThreshold - ? deviceConf.inUsePowerThreshold - : platform.consts.defaultValues.inUsePowerThreshold - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.inUsePowerThreshold = + deviceConf && deviceConf.inUsePowerThreshold + ? deviceConf.inUsePowerThreshold + : platform.consts.defaultValues.inUsePowerThreshold + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // If the accessory has a switch service then remove it if (this.accessory.getService(this.hapServ.Switch)) { @@ -182,7 +184,9 @@ module.exports = class deviceOutletPower { this.cacheState === 'on' && power > this.inUsePowerThreshold ) this.service.updateCharacteristic(this.eveChar.CurrentConsumption, power) - this.accessory.eveService.addEntry({ power: this.cacheState === 'on' ? power : 0 }) + this.accessory.eveService.addEntry({ + power: this.cacheState === 'on' ? power : 0 + }) this.accessory.context.energyReadings.push(power) logger = true } diff --git a/lib/device/outlet-scm.js b/lib/device/outlet-scm.js index eb86e64f..30c54e0c 100644 --- a/lib/device/outlet-scm.js +++ b/lib/device/outlet-scm.js @@ -19,9 +19,10 @@ module.exports = class deviceOutletSCM { // Set up custom variables for this device type const deviceConf = platform.outletDevices[accessory.context.eweDeviceId] this.showAsSwitch = deviceConf && deviceConf.showAsSwitch - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // Check if the user has overridden how this accessory should appear if (this.showAsSwitch) { @@ -31,7 +32,8 @@ module.exports = class deviceOutletSCM { } // Add the switch service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.Switch) || + this.service = + this.accessory.getService(this.hapServ.Switch) || this.accessory.addService(this.hapServ.Switch) } else { // The default is an outlet so if the accessory has an switch service then remove it @@ -40,7 +42,8 @@ module.exports = class deviceOutletSCM { } // Add the outlet service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.Outlet) || + this.service = + this.accessory.getService(this.hapServ.Outlet) || this.accessory.addService(this.hapServ.Outlet) } diff --git a/lib/device/outlet-single.js b/lib/device/outlet-single.js index 3506992b..40955a43 100644 --- a/lib/device/outlet-single.js +++ b/lib/device/outlet-single.js @@ -20,9 +20,10 @@ module.exports = class deviceOutletSingle { // Set up custom variables for this device type const deviceConf = platform.outletDevices[accessory.context.eweDeviceId] - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // If the accessory has a switch service then remove it if (this.accessory.getService(this.hapServ.Switch)) { @@ -30,7 +31,8 @@ module.exports = class deviceOutletSingle { } // Add the outlet service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.Outlet) || + this.service = + this.accessory.getService(this.hapServ.Outlet) || this.accessory.addService(this.hapServ.Outlet) // Add the set handler to the outlet on/off characteristic diff --git a/lib/device/rf-bridge.js b/lib/device/rf-bridge.js index 4a93db08..f4e1d95e 100644 --- a/lib/device/rf-bridge.js +++ b/lib/device/rf-bridge.js @@ -34,7 +34,9 @@ module.exports = class deviceRFBridge { this.accessory.getService(name).updateCharacteristic(this.hapChar.On, false) // Add the set handler to the switch on/off characteristic - this.accessory.getService(name).getCharacteristic(this.hapChar.On) + this.accessory + .getService(name) + .getCharacteristic(this.hapChar.On) .onSet(async value => { await this.internalPressUpdate(chan, name, value) }) @@ -117,12 +119,7 @@ module.exports = class deviceRFBridge { rfChl: parseInt(rfChl) } await this.platform.sendDeviceUpdate(this.accessory, params) - this.log( - '[%s] %s [%s].', - this.name, - this.lang.curState, - this.lang.buttonTrig - ) + this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.buttonTrig) setTimeout(() => { this.accessory.getService(service).updateCharacteristic(this.hapChar.On, false) }, 1000) @@ -210,10 +207,7 @@ module.exports = class deviceRFBridge { case 'button': case 'curtain': { const service = subAccessory.context.buttons[channel] - subAccessory.getService(service).updateCharacteristic( - this.hapChar.On, - true - ) + subAccessory.getService(service).updateCharacteristic(this.hapChar.On, true) this.log( '[%s] %s [%s].', subAccessory.displayName, @@ -221,10 +215,7 @@ module.exports = class deviceRFBridge { this.lang.buttonTrig ) await this.funcs.sleep(3000) - subAccessory.getService(service).updateCharacteristic( - this.hapChar.On, - false - ) + subAccessory.getService(service).updateCharacteristic(this.hapChar.On, false) return } case 'water': @@ -248,10 +239,12 @@ module.exports = class deviceRFBridge { serv = this.hapServ.ContactSensor char = this.hapChar.ContactSensorState const initialTime = subAccessory.eveService.getInitialTime() - subAccessory.getService(serv).updateCharacteristic( - this.eveChar.LastActivation, - Math.round(new Date().valueOf() / 1000) - initialTime - ) + subAccessory + .getService(serv) + .updateCharacteristic( + this.eveChar.LastActivation, + Math.round(new Date().valueOf() / 1000) - initialTime + ) break } case 'occupancy': @@ -262,10 +255,12 @@ module.exports = class deviceRFBridge { serv = this.hapServ.MotionSensor char = this.hapChar.MotionDetected const initialTime = subAccessory.eveService.getInitialTime() - subAccessory.getService(serv).updateCharacteristic( - this.eveChar.LastActivation, - Math.round(new Date().valueOf() / 1000) - initialTime - ) + subAccessory + .getService(serv) + .updateCharacteristic( + this.eveChar.LastActivation, + Math.round(new Date().valueOf() / 1000) - initialTime + ) break } } @@ -279,7 +274,9 @@ module.exports = class deviceRFBridge { this.lang.rfTrigYes ) } - const updateKey = Math.random().toString(36).substr(2, 8) + const updateKey = Math.random() + .toString(36) + .substr(2, 8) subAccessory.context.updateKey = updateKey await this.funcs.sleep(subAccessory.context.sensorTimeLength * 1000) if (updateKey !== subAccessory.context.updateKey) { diff --git a/lib/device/sensor-ambient.js b/lib/device/sensor-ambient.js index 07ad636f..b0a54b9c 100644 --- a/lib/device/sensor-ambient.js +++ b/lib/device/sensor-ambient.js @@ -20,12 +20,12 @@ module.exports = class deviceSensorAmbient { // Set up custom variables for this device type const deviceConf = platform.thDevices[accessory.context.eweDeviceId] this.hideSwitch = deviceConf && deviceConf.hideSwitch - this.tempOffset = deviceConf && deviceConf.offset - ? deviceConf.offset - : platform.consts.defaultValues.offset - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.tempOffset = + deviceConf && deviceConf.offset ? deviceConf.offset : platform.consts.defaultValues.offset + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // If the accessory has a thermostat service then remove it if (this.accessory.getService(this.hapServ.Thermostat)) { @@ -40,7 +40,8 @@ module.exports = class deviceSensorAmbient { } } else { // User has not hidden the switch service so add it if it doesn't already exist - this.switchService = this.accessory.getService(this.hapServ.Switch) || + this.switchService = + this.accessory.getService(this.hapServ.Switch) || this.accessory.addService(this.hapServ.Switch) // Add the set handler to the switch on/off characteristic @@ -50,7 +51,8 @@ module.exports = class deviceSensorAmbient { } // Add the temperature sensor service if it doesn't already exist - this.tempService = this.accessory.getService(this.hapServ.TemperatureSensor) || + this.tempService = + this.accessory.getService(this.hapServ.TemperatureSensor) || this.accessory.addService(this.hapServ.TemperatureSensor) // Set custom properties of the current temperature characteristic @@ -61,13 +63,12 @@ module.exports = class deviceSensorAmbient { // The DS18B20 sensor does not provide humidity readings if (this.accessory.context.sensorType === 'DS18B20') { if (this.accessory.getService(this.hapServ.HumiditySensor)) { - this.accessory.removeService( - this.accessory.getService(this.hapServ.HumiditySensor) - ) + this.accessory.removeService(this.accessory.getService(this.hapServ.HumiditySensor)) } } else { // Add the humidity sensor service if it doesn't already exist - this.humiService = this.accessory.getService(this.hapServ.HumiditySensor) || + this.humiService = + this.accessory.getService(this.hapServ.HumiditySensor) || this.accessory.addService(this.hapServ.HumiditySensor) } @@ -119,11 +120,10 @@ module.exports = class deviceSensorAmbient { const newState = params.switch if (this.cacheState !== newState) { this.cacheState = newState - this.switchService.updateCharacteristic( - this.hapChar.On, - this.cacheState === 'on' - ) - this.accessory.eveService.addEntry({ status: this.cacheState === 'on' ? 1 : 0 }) + this.switchService.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') + this.accessory.eveService.addEntry({ + status: this.cacheState === 'on' ? 1 : 0 + }) if (params.updateSource && !this.disableDeviceLogging) { this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState) } @@ -138,10 +138,7 @@ module.exports = class deviceSensorAmbient { eveLog.temp = currentTemp if (this.cacheTemp !== currentTemp) { this.cacheTemp = currentTemp - this.tempService.updateCharacteristic( - this.hapChar.CurrentTemperature, - this.cacheTemp - ) + this.tempService.updateCharacteristic(this.hapChar.CurrentTemperature, this.cacheTemp) if (params.updateSource && !this.disableDeviceLogging) { this.log('[%s] %s [%s°C].', this.name, this.lang.curTemp, this.cacheTemp) } @@ -165,10 +162,7 @@ module.exports = class deviceSensorAmbient { } } } - if ( - this.funcs.hasProperty(eveLog, 'temp') || - this.funcs.hasProperty(eveLog, 'humidity') - ) { + if (this.funcs.hasProperty(eveLog, 'temp') || this.funcs.hasProperty(eveLog, 'humidity')) { this.accessory.eveService.addEntry(eveLog) } } catch (err) { diff --git a/lib/device/sensor-contact.js b/lib/device/sensor-contact.js index 72b7eb74..be636de3 100644 --- a/lib/device/sensor-contact.js +++ b/lib/device/sensor-contact.js @@ -21,12 +21,14 @@ module.exports = class deviceSensorContact { // Set up custom variables for this device type const deviceConf = platform.sensorDevices[accessory.context.eweDeviceId] - this.lowBattThreshold = deviceConf && deviceConf.lowBattThreshold - ? Math.min(deviceConf.lowBattThreshold, 100) - : platform.consts.defaultValues.lowBattThreshold - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.lowBattThreshold = + deviceConf && deviceConf.lowBattThreshold + ? Math.min(deviceConf.lowBattThreshold, 100) + : platform.consts.defaultValues.lowBattThreshold + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // If the accessory has a leak sensor service then remove it if (this.accessory.getService(this.hapServ.LeakSensor)) { @@ -53,7 +55,8 @@ module.exports = class deviceSensorContact { }) // Add the battery service if it doesn't already exist - this.batteryService = this.accessory.getService(this.hapServ.BatteryService) || + this.batteryService = + this.accessory.getService(this.hapServ.BatteryService) || this.accessory.addService(this.hapServ.BatteryService) // Pass the accessory to Fakegato to set up with Eve @@ -77,10 +80,7 @@ module.exports = class deviceSensorContact { const scaledBattery = Math.round(params.battery * 33.3) if (this.cacheBatt !== scaledBattery) { this.cacheBatt = scaledBattery - this.batteryService.updateCharacteristic( - this.hapChar.BatteryLevel, - this.cacheBatt - ) + this.batteryService.updateCharacteristic(this.hapChar.BatteryLevel, this.cacheBatt) this.batteryService.updateCharacteristic( this.hapChar.StatusLowBattery, this.cacheBatt < this.lowBattThreshold @@ -118,10 +118,7 @@ module.exports = class deviceSensorContact { ) } for (const [deviceId, group] of Object.entries(this.platform.simulations)) { - if ( - group.sensorId === this.accessory.context.eweDeviceId && - group.type === 'garage' - ) { + if (group.sensorId === this.accessory.context.eweDeviceId && group.type === 'garage') { const uuid = this.hapUUIDGen(deviceId + 'SWX') if (this.devicesInHB.has(uuid)) { const subAccessory = this.devicesInHB.get(uuid) @@ -132,12 +129,7 @@ module.exports = class deviceSensorContact { gdService.updateCharacteristic(this.hapChar.TargetDoorState, 1) gdService.updateCharacteristic(this.hapChar.CurrentDoorState, 1) if (params.updateSource && !this.disableDeviceLogging) { - this.log( - '[%s] %s [%s].', - name, - this.lang.curState, - this.lang.doorClosed - ) + this.log('[%s] %s [%s].', name, this.lang.curState, this.lang.doorClosed) } break case 1: @@ -145,12 +137,7 @@ module.exports = class deviceSensorContact { gdService.updateCharacteristic(this.hapChar.TargetDoorState, 0) gdService.updateCharacteristic(this.hapChar.CurrentDoorState, 0) if (params.updateSource && !this.disableDeviceLogging) { - this.log( - '[%s] %s [%s].', - name, - this.lang.curState, - this.lang.doorOpen - ) + this.log('[%s] %s [%s].', name, this.lang.curState, this.lang.doorOpen) } break } diff --git a/lib/device/sensor-temp-humi.js b/lib/device/sensor-temp-humi.js index 5cf033b5..89a6cca1 100644 --- a/lib/device/sensor-temp-humi.js +++ b/lib/device/sensor-temp-humi.js @@ -18,15 +18,16 @@ module.exports = class deviceSensorTempHumi { // Set up custom variables for this device type const deviceConf = platform.thDevices[accessory.context.eweDeviceId] - this.tempOffset = deviceConf && deviceConf.offset - ? deviceConf.offset - : platform.consts.defaultValues.offset - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.tempOffset = + deviceConf && deviceConf.offset ? deviceConf.offset : platform.consts.defaultValues.offset + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // Add the temperature sensor service if it doesn't already exist - this.tempService = this.accessory.getService(this.hapServ.TemperatureSensor) || + this.tempService = + this.accessory.getService(this.hapServ.TemperatureSensor) || this.accessory.addService(this.hapServ.TemperatureSensor) // Set custom properties of the current temperature characteristic @@ -35,7 +36,8 @@ module.exports = class deviceSensorTempHumi { }) // Add the humidity sensor service if it doesn't already exist - this.humiService = this.accessory.getService(this.hapServ.HumiditySensor) || + this.humiService = + this.accessory.getService(this.hapServ.HumiditySensor) || this.accessory.addService(this.hapServ.HumiditySensor) // Pass the accessory to Fakegato to set up with Eve @@ -61,10 +63,7 @@ module.exports = class deviceSensorTempHumi { eveLog.temp = currentTemp if (this.cacheTemp !== currentTemp) { this.cacheTemp = currentTemp - this.tempService.updateCharacteristic( - this.hapChar.CurrentTemperature, - this.cacheTemp - ) + this.tempService.updateCharacteristic(this.hapChar.CurrentTemperature, this.cacheTemp) if (params.updateSource && !this.disableDeviceLogging) { this.log('[%s] %s [%s°C].', this.name, this.lang.curTemp, this.cacheTemp) } @@ -84,10 +83,7 @@ module.exports = class deviceSensorTempHumi { } } } - if ( - this.funcs.hasProperty(eveLog, 'temp') || - this.funcs.hasProperty(eveLog, 'humidity') - ) { + if (this.funcs.hasProperty(eveLog, 'temp') || this.funcs.hasProperty(eveLog, 'humidity')) { this.accessory.eveService.addEntry(eveLog) } } catch (err) { diff --git a/lib/device/simulation/blind.js b/lib/device/simulation/blind.js index 10981bf7..5101b2ba 100644 --- a/lib/device/simulation/blind.js +++ b/lib/device/simulation/blind.js @@ -19,12 +19,12 @@ module.exports = class deviceBlind { // Set up custom variables for this device type const deviceConf = platform.simulations[accessory.context.eweDeviceId] - this.operationTimeUp = deviceConf.operationTime || - platform.consts.defaultValues.operationTime + this.operationTimeUp = deviceConf.operationTime || platform.consts.defaultValues.operationTime this.operationTimeDown = deviceConf.operationTimeDown || this.operationTimeUp - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // Set up the accessory with default positions when added the first time if (!this.funcs.hasProperty(this.accessory.context, 'cacheCurrentPosition')) { @@ -71,15 +71,17 @@ module.exports = class deviceBlind { const prevState = this.accessory.context.cachePositionState const percentStepUpPerDS = this.operationTimeUp / 100 const percentStepDownPerDS = this.operationTimeDown / 100 - const updateKey = Math.random().toString(36).substr(2, 8) + const updateKey = Math.random() + .toString(36) + .substr(2, 8) this.updateKey = updateKey if (prevState !== 2) { params.switches.push({ switch: 'off', outlet: 0 }) params.switches.push({ switch: 'off', outlet: 1 }) await this.platform.sendDeviceUpdate(this.accessory, params) params.switches = [] - const posPercentChange = Math.floor(Date.now() / 100) - - this.accessory.context.cacheLastStartTime + const posPercentChange = + Math.floor(Date.now() / 100) - this.accessory.context.cacheLastStartTime const posPercentChangeUp = Math.floor(percentStepUpPerDS * posPercentChange) const posPercentChangeDown = Math.floor(percentStepDownPerDS * posPercentChange) if (prevState === 0) { @@ -132,14 +134,9 @@ module.exports = class deviceBlind { this.accessory.context.cacheTargetPosition ) }, 2000) - this.service.updateCharacteristic( - this.hapChar.TargetPosition, - new this.hapErr(-70402) - ) + this.service.updateCharacteristic(this.hapChar.TargetPosition, new this.hapErr(-70402)) } } - async externalUpdate (params) { - - } + async externalUpdate (params) {} } diff --git a/lib/device/simulation/door.js b/lib/device/simulation/door.js index 9a36f093..634dbb0e 100644 --- a/lib/device/simulation/door.js +++ b/lib/device/simulation/door.js @@ -19,12 +19,12 @@ module.exports = class deviceDoor { // Set up custom variables for this device type const deviceConf = platform.simulations[accessory.context.eweDeviceId] - this.operationTimeUp = deviceConf.operationTime || - platform.consts.defaultValues.operationTime + this.operationTimeUp = deviceConf.operationTime || platform.consts.defaultValues.operationTime this.operationTimeDown = deviceConf.operationTimeDown || this.operationTimeUp - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // Set up the accessory with default positions when added the first time if (!this.funcs.hasProperty(this.accessory.context, 'cacheCurrentPosition')) { @@ -71,15 +71,17 @@ module.exports = class deviceDoor { const prevState = this.accessory.context.cachePositionState const percentStepUpPerDS = this.operationTimeUp / 100 const percentStepDownPerDS = this.operationTimeDown / 100 - const updateKey = Math.random().toString(36).substr(2, 8) + const updateKey = Math.random() + .toString(36) + .substr(2, 8) this.updateKey = updateKey if (prevState !== 2) { params.switches.push({ switch: 'off', outlet: 0 }) params.switches.push({ switch: 'off', outlet: 1 }) await this.platform.sendDeviceUpdate(this.accessory, params) params.switches = [] - const posPercentChange = Math.floor(Date.now() / 100) - - this.accessory.context.cacheLastStartTime + const posPercentChange = + Math.floor(Date.now() / 100) - this.accessory.context.cacheLastStartTime const posPercentChangeUp = Math.floor(percentStepUpPerDS * posPercentChange) const posPercentChangeDown = Math.floor(percentStepDownPerDS * posPercentChange) if (prevState === 0) { @@ -132,14 +134,9 @@ module.exports = class deviceDoor { this.accessory.context.cacheTargetPosition ) }, 2000) - this.service.updateCharacteristic( - this.hapChar.TargetPosition, - new this.hapErr(-70402) - ) + this.service.updateCharacteristic(this.hapChar.TargetPosition, new this.hapErr(-70402)) } } - async externalUpdate (params) { - - } + async externalUpdate (params) {} } diff --git a/lib/device/simulation/garage-eachen.js b/lib/device/simulation/garage-eachen.js index 281e780e..719889ae 100644 --- a/lib/device/simulation/garage-eachen.js +++ b/lib/device/simulation/garage-eachen.js @@ -20,8 +20,7 @@ module.exports = class deviceGarageEachen { // Set up custom variables for this device type const deviceConf = platform.simulations[accessory.context.eweDeviceId] - this.operationTime = deviceConf.operationTime || - platform.consts.defaultValues.operationTime + this.operationTime = deviceConf.operationTime || platform.consts.defaultValues.operationTime this.disableDeviceLogging = deviceConf.overrideDisabledLogging ? false : platform.config.disableDeviceLogging @@ -33,9 +32,7 @@ module.exports = class deviceGarageEachen { // If the accessory has a contact sensor service then remove it if (this.accessory.getService(this.hapServ.ContactSensor)) { - this.accessory.removeService( - this.accessory.getService(this.hapServ.ContactSensor) - ) + this.accessory.removeService(this.accessory.getService(this.hapServ.ContactSensor)) } // Add the garage door service if it doesn't already exist @@ -124,10 +121,7 @@ module.exports = class deviceGarageEachen { this.accessory.context.cacheTargetPosition ) }, 2000) - this.service.updateCharacteristic( - this.hapChar.TargetPosition, - new this.hapErr(-70402) - ) + this.service.updateCharacteristic(this.hapChar.TargetPosition, new this.hapErr(-70402)) } } @@ -153,10 +147,7 @@ module.exports = class deviceGarageEachen { Math.round(new Date().valueOf() / 1000) - initialTime ) this.timesOpened++ - this.service.updateCharacteristic( - this.eveChar.TimesOpened, - this.timesOpened - ) + this.service.updateCharacteristic(this.eveChar.TimesOpened, this.timesOpened) } else { this.service.updateCharacteristic(this.hapChar.ContactSensorState, 0) this.accessory.eveService.addEntry({ status: 1 }) // swapped diff --git a/lib/device/simulation/garage-four.js b/lib/device/simulation/garage-four.js index 4e3adca6..8be00288 100644 --- a/lib/device/simulation/garage-four.js +++ b/lib/device/simulation/garage-four.js @@ -19,8 +19,7 @@ module.exports = class deviceGarageFour { // Set up custom variables for this device type const deviceConf = platform.simulations[accessory.context.eweDeviceId] - this.operationTimeUp = deviceConf.operationTime || - platform.consts.defaultValues.operationTime + this.operationTimeUp = deviceConf.operationTime || platform.consts.defaultValues.operationTime this.operationTimeDown = deviceConf.operationTimeDown || this.operationTimeUp this.disableDeviceLogging = deviceConf.overrideDisabledLogging ? false @@ -87,24 +86,27 @@ module.exports = class deviceGarageFour { garageChannel = 3 break } - const prevState = this.accessory.context.cacheStates[garageChannel] - .cacheCurrentDoorState + const prevState = this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState if (value === prevState % 2) { return } const gdService = this.accessory.getService('Garage ' + garage) this.inUse = true - const updateKey = Math.random().toString(36).substr(2, 8) + const updateKey = Math.random() + .toString(36) + .substr(2, 8) this.updateKey = updateKey gdService.updateCharacteristic(this.hapChar.TargetDoorState, value) gdService.updateCharacteristic(this.hapChar.CurrentDoorState, value + 2) this.accessory.context.cacheStates[garageChannel].cacheTargetDoorState = value this.accessory.context.cacheStates[garageChannel].cacheCurrentDoorState = value + 2 const params = { - switches: [{ - switch: 'on', - outlet: garageChannel - }] + switches: [ + { + switch: 'on', + outlet: garageChannel + } + ] } await this.platform.sendDeviceUpdate(this.accessory, params) await this.funcs.sleep(2000) @@ -135,18 +137,9 @@ module.exports = class deviceGarageFour { this.accessory.context.cacheTargetPosition ) }, 2000) - gdService.updateCharacteristic( - this.hapChar.TargetPosition, - new this.hapErr(-70402) - ) + gdService.updateCharacteristic(this.hapChar.TargetPosition, new this.hapErr(-70402)) } } - async externalUpdate (params) { - try { - - } catch (err) { - this.platform.deviceUpdateError(this.accessory, err, false) - } - } + async externalUpdate (params) {} } diff --git a/lib/device/simulation/garage-od-switch.js b/lib/device/simulation/garage-od-switch.js index 3887e4c5..51c77399 100644 --- a/lib/device/simulation/garage-od-switch.js +++ b/lib/device/simulation/garage-od-switch.js @@ -20,13 +20,15 @@ module.exports = class deviceGarageODSwitch { this.garageId = platform.obstructSwitches[accessory.context.eweDeviceId] const uuid = this.hapUUIDGen(this.garageId + 'SWX') this.garage = devicesInHB.get(uuid) - this.disableDeviceLogging = platform.simulations[this.garageId] && + this.disableDeviceLogging = + platform.simulations[this.garageId] && platform.simulations[this.garageId].overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + ? false + : platform.config.disableDeviceLogging // Add the switch service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.Switch) || + this.service = + this.accessory.getService(this.hapServ.Switch) || this.accessory.addService(this.hapServ.Switch) // Get the garage door accessory to which this switch relates @@ -40,7 +42,9 @@ module.exports = class deviceGarageODSwitch { // Output the customised options to the log if in debug mode if (platform.config.debug) { - const opts = JSON.stringify({ disableDeviceLogging: this.disableDeviceLogging }) + const opts = JSON.stringify({ + disableDeviceLogging: this.disableDeviceLogging + }) this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts) } } diff --git a/lib/device/simulation/garage-one.js b/lib/device/simulation/garage-one.js index bc84044b..1885c636 100644 --- a/lib/device/simulation/garage-one.js +++ b/lib/device/simulation/garage-one.js @@ -22,8 +22,7 @@ module.exports = class deviceGarageOne { // Set up custom variables for this device type const deviceConf = platform.simulations[accessory.context.eweDeviceId] this.setup = deviceConf.setup - this.operationTimeUp = deviceConf.operationTime || - platform.consts.defaultValues.operationTime + this.operationTimeUp = deviceConf.operationTime || platform.consts.defaultValues.operationTime this.operationTimeDown = deviceConf.operationTimeDown || this.operationTimeUp this.disableDeviceLogging = deviceConf.overrideDisabledLogging ? false @@ -49,9 +48,7 @@ module.exports = class deviceGarageOne { } // Check the sensor is a sensor - if (!platform.consts.devices.garageSensors.includes( - devicesInHB.get(uuid).context.eweUIID - )) { + if (!platform.consts.devices.garageSensors.includes(devicesInHB.get(uuid).context.eweUIID)) { this.error = this.lang.simErrNotSensor } this.definedSensor = devicesInHB.get(uuid) @@ -69,9 +66,7 @@ module.exports = class deviceGarageOne { // If the accessory has a contact sensor service then remove it if (this.accessory.getService(this.hapServ.ContactSensor)) { - this.accessory.removeService( - this.accessory.getService(this.hapServ.ContactSensor) - ) + this.accessory.removeService(this.accessory.getService(this.hapServ.ContactSensor)) } // Add the garage door service if it doesn't already exist @@ -130,8 +125,9 @@ module.exports = class deviceGarageOne { const params = {} let delay = 0 const prevState = this.definedSensor - ? this.definedSensor.getService(this.hapServ.ContactSensor) - .getCharacteristic(this.hapChar.ContactSensorState).value === 0 + ? this.definedSensor + .getService(this.hapServ.ContactSensor) + .getCharacteristic(this.hapChar.ContactSensorState).value === 0 ? 1 : 0 : this.accessory.context.cacheCurrentDoorState @@ -141,10 +137,7 @@ module.exports = class deviceGarageOne { this.inUse = true this.cacheState = value if (this.setup === 'oneSwitch' && [2, 3].includes(prevState)) { - this.service.updateCharacteristic( - this.hapChar.CurrentDoorState, - ((prevState * 2) % 3) + 2 - ) + this.service.updateCharacteristic(this.hapChar.CurrentDoorState, ((prevState * 2) % 3) + 2) this.accessory.context.cacheCurrentDoorState = ((prevState * 2) % 3) + 2 delay = 1500 } @@ -199,10 +192,7 @@ module.exports = class deviceGarageOne { this.accessory.context.cacheTargetPosition ) }, 2000) - this.service.updateCharacteristic( - this.hapChar.TargetPosition, - new this.hapErr(-70402) - ) + this.service.updateCharacteristic(this.hapChar.TargetPosition, new this.hapErr(-70402)) } } diff --git a/lib/device/simulation/garage-two.js b/lib/device/simulation/garage-two.js index 9f911a21..4b4eafb0 100644 --- a/lib/device/simulation/garage-two.js +++ b/lib/device/simulation/garage-two.js @@ -19,8 +19,7 @@ module.exports = class deviceGarageTwo { // Set up custom variables for this device type const deviceConf = platform.simulations[accessory.context.eweDeviceId] - this.operationTimeUp = deviceConf.operationTime || - platform.consts.defaultValues.operationTime + this.operationTimeUp = deviceConf.operationTime || platform.consts.defaultValues.operationTime this.operationTimeDown = deviceConf.operationTimeDown || this.operationTimeUp this.disableDeviceLogging = deviceConf.overrideDisabledLogging ? false @@ -75,9 +74,10 @@ module.exports = class deviceGarageTwo { switches: [] } const gdService = this.accessory.getService(garage) - const prevState = garage === 'Garage 1' - ? this.accessory.context.cacheOneCurrentDoorState - : this.accessory.context.cacheTwoCurrentDoorState + const prevState = + garage === 'Garage 1' + ? this.accessory.context.cacheOneCurrentDoorState + : this.accessory.context.cacheTwoCurrentDoorState if (newPos === prevState % 2) { return } @@ -88,24 +88,34 @@ module.exports = class deviceGarageTwo { case 'Garage 1': { this.accessory.context.cacheOneTargetDoorState = newPos this.accessory.context.cacheOneCurrentDoorState = newPos + 2 - params.switches.push({ switch: newPos === 0 ? 'on' : 'off', outlet: 0 }) - params.switches.push({ switch: newPos === 1 ? 'on' : 'off', outlet: 1 }) + params.switches.push({ + switch: newPos === 0 ? 'on' : 'off', + outlet: 0 + }) + params.switches.push({ + switch: newPos === 1 ? 'on' : 'off', + outlet: 1 + }) break } case 'Garage 2': { this.accessory.context.cacheTwoTargetDoorState = newPos this.accessory.context.cacheTwoCurrentDoorState = newPos + 2 - params.switches.push({ switch: newPos === 0 ? 'on' : 'off', outlet: 2 }) - params.switches.push({ switch: newPos === 1 ? 'on' : 'off', outlet: 3 }) + params.switches.push({ + switch: newPos === 0 ? 'on' : 'off', + outlet: 2 + }) + params.switches.push({ + switch: newPos === 1 ? 'on' : 'off', + outlet: 3 + }) break } } await this.platform.sendDeviceUpdate(this.accessory, params) await this.funcs.sleep(2000) this.inUse = false - const operationTime = newPos === 0 - ? this.operationTimeUp - : this.operationTimeDown + const operationTime = newPos === 0 ? this.operationTimeUp : this.operationTimeDown await this.funcs.sleep(Math.max((operationTime - 20) * 100, 0)) gdService.updateCharacteristic(this.hapChar.CurrentDoorState, newPos) switch (garage) { @@ -144,10 +154,7 @@ module.exports = class deviceGarageTwo { this.accessory.context.cacheTargetPosition ) }, 2000) - gdService.updateCharacteristic( - this.hapChar.TargetPosition, - new this.hapErr(-70402) - ) + gdService.updateCharacteristic(this.hapChar.TargetPosition, new this.hapErr(-70402)) } } @@ -158,9 +165,10 @@ module.exports = class deviceGarageTwo { } ;['1', '2'].forEach(async v => { const gcService = this.accessory.getService('Garage ' + v) - const prevState = v === '1' - ? this.accessory.context.cacheOneCurrentDoorState - : this.accessory.context.cacheTwoCurrentDoorState + const prevState = + v === '1' + ? this.accessory.context.cacheOneCurrentDoorState + : this.accessory.context.cacheTwoCurrentDoorState const newPos = [0, 2].includes(prevState) ? 3 : 2 switch (v) { case '1': diff --git a/lib/device/simulation/lock-one.js b/lib/device/simulation/lock-one.js index 50ce701c..eddbcbdd 100644 --- a/lib/device/simulation/lock-one.js +++ b/lib/device/simulation/lock-one.js @@ -19,8 +19,7 @@ module.exports = class deviceLockOne { // Set up custom variables for this device type const deviceConf = platform.simulations[accessory.context.eweDeviceId] - this.operationTime = deviceConf.operationTime || - platform.consts.defaultValues.operationTime + this.operationTime = deviceConf.operationTime || platform.consts.defaultValues.operationTime this.setup = deviceConf.setup this.disableDeviceLogging = deviceConf.overrideDisabledLogging ? false @@ -37,7 +36,8 @@ module.exports = class deviceLockOne { } // Add the lock service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.LockMechanism) || + this.service = + this.accessory.getService(this.hapServ.LockMechanism) || this.accessory.addService(this.hapServ.LockMechanism) // Add the set handler to the lock target state characteristic @@ -47,7 +47,8 @@ module.exports = class deviceLockOne { }) // Always show the accessory as locked on Homebridge restart - this.service.updateCharacteristic(this.hapChar.LockCurrentState, 1) + this.service + .updateCharacteristic(this.hapChar.LockCurrentState, 1) .updateCharacteristic(this.hapChar.LockTargetState, 1) // Output the customised options to the log if in debug mode @@ -73,10 +74,12 @@ module.exports = class deviceLockOne { params.switch = 'on' break case 'twoSwitch': - params.switches = [{ - switch: 'on', - outlet: 0 - }] + params.switches = [ + { + switch: 'on', + outlet: 0 + } + ] break } this.inUse = true @@ -98,10 +101,7 @@ module.exports = class deviceLockOne { setTimeout(() => { this.service.updateCharacteristic(this.hapChar.LockTargetState, 1) }, 2000) - this.service.updateCharacteristic( - this.hapChar.LockTargetState, - new this.hapErr(-70402) - ) + this.service.updateCharacteristic(this.hapChar.LockTargetState, new this.hapErr(-70402)) } } @@ -132,7 +132,8 @@ module.exports = class deviceLockOne { this.log('[%s] %s [%s].', this.name, this.lang.curState, this.lang.lockUnlocked) } await this.funcs.sleep(Math.max(this.operationTime * 100, 1000)) - this.service.updateCharacteristic(this.hapChar.LockCurrentState, 1) + this.service + .updateCharacteristic(this.hapChar.LockCurrentState, 1) .updateCharacteristic(this.hapChar.LockTargetState, 1) this.inUse = false if (params.updateSource && !this.disableDeviceLogging) { diff --git a/lib/device/simulation/sensor-leak.js b/lib/device/simulation/sensor-leak.js index 7e38b22d..0569ae6e 100644 --- a/lib/device/simulation/sensor-leak.js +++ b/lib/device/simulation/sensor-leak.js @@ -20,13 +20,14 @@ module.exports = class deviceSensorLeak { // Set up custom variables for this device type const deviceConf = platform.sensorDevices[accessory.context.eweDeviceId] const deviceConf2 = platform.simulations[accessory.context.eweDeviceId] - this.lowBattThreshold = deviceConf && deviceConf.lowBattThreshold - ? Math.min(deviceConf.lowBattThreshold, 100) - : platform.consts.defaultValues.lowBattThreshold - this.disableDeviceLogging = (deviceConf && deviceConf.overrideDisabledLogging) || - deviceConf2.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.lowBattThreshold = + deviceConf && deviceConf.lowBattThreshold + ? Math.min(deviceConf.lowBattThreshold, 100) + : platform.consts.defaultValues.lowBattThreshold + this.disableDeviceLogging = + (deviceConf && deviceConf.overrideDisabledLogging) || deviceConf2.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // If the accessory has a contact sensor service then remove it if (this.accessory.getService(this.hapServ.ContactSensor)) { @@ -40,7 +41,8 @@ module.exports = class deviceSensorLeak { } // Add the battery service if it doesn't already exist - this.batteryService = this.accessory.getService(this.hapServ.BatteryService) || + this.batteryService = + this.accessory.getService(this.hapServ.BatteryService) || this.accessory.addService(this.hapServ.BatteryService) // Pass the accessory to Fakegato to set up with Eve @@ -65,10 +67,7 @@ module.exports = class deviceSensorLeak { const scaledBattery = Math.round(params.battery * 33.3) if (this.cacheBatt !== scaledBattery) { this.cacheBatt = scaledBattery - this.batteryService.updateCharacteristic( - this.hapChar.BatteryLevel, - this.cacheBatt - ) + this.batteryService.updateCharacteristic(this.hapChar.BatteryLevel, this.cacheBatt) this.batteryService.updateCharacteristic( this.hapChar.StatusLowBattery, this.cacheBatt < this.lowBattThreshold diff --git a/lib/device/simulation/switch-valve.js b/lib/device/simulation/switch-valve.js index aac1dd44..8547dd8e 100644 --- a/lib/device/simulation/switch-valve.js +++ b/lib/device/simulation/switch-valve.js @@ -23,7 +23,8 @@ module.exports = class deviceSwitchValve { : platform.config.disableDeviceLogging // Add the switch service if it doesn't already exist - this.sService = this.accessory.getService(this.hapServ.Switch) || + this.sService = + this.accessory.getService(this.hapServ.Switch) || this.accessory.addService(this.hapServ.Switch) // Add the valve service if it doesn't already exist @@ -82,10 +83,12 @@ module.exports = class deviceSwitchValve { async internalSwitchUpdate (value) { try { const params = { - switches: [{ - switch: value ? 'on' : 'off', - outlet: 0 - }] + switches: [ + { + switch: value ? 'on' : 'off', + outlet: 0 + } + ] } await this.platform.sendDeviceUpdate(this.accessory, params) this.cacheState = value ? 'on' : 'off' @@ -105,10 +108,12 @@ module.exports = class deviceSwitchValve { async internalValveUpdate (value) { try { const params = { - switches: [{ - switch: value ? 'on' : 'off', - outlet: 1 - }] + switches: [ + { + switch: value ? 'on' : 'off', + outlet: 1 + } + ] } this.vService.updateCharacteristic(this.hapChar.InUse, value) switch (value) { diff --git a/lib/device/simulation/tap-one.js b/lib/device/simulation/tap-one.js index 4f2f397e..82512afb 100644 --- a/lib/device/simulation/tap-one.js +++ b/lib/device/simulation/tap-one.js @@ -68,10 +68,12 @@ module.exports = class deviceTapOne { params.switch = value ? 'on' : 'off' break case 'twoSwitch': - params.switches = [{ - switch: value ? 'on' : 'off', - outlet: 0 - }] + params.switches = [ + { + switch: value ? 'on' : 'off', + outlet: 0 + } + ] break } await this.platform.sendDeviceUpdate(this.accessory, params) @@ -113,14 +115,8 @@ module.exports = class deviceTapOne { this.cacheState = params.switches[0].switch break } - this.service.updateCharacteristic( - this.hapChar.Active, - this.cacheState === 'on' ? 1 : 0 - ) - this.service.updateCharacteristic( - this.hapChar.InUse, - this.cacheState === 'on' ? 1 : 0 - ) + this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0) + this.service.updateCharacteristic(this.hapChar.InUse, this.cacheState === 'on' ? 1 : 0) if (params.updateSource && !this.disableDeviceLogging) { this.log( '[%s] %s [%s].', diff --git a/lib/device/simulation/thermostat.js b/lib/device/simulation/thermostat.js index 5105a631..2f5e8030 100644 --- a/lib/device/simulation/thermostat.js +++ b/lib/device/simulation/thermostat.js @@ -20,19 +20,20 @@ module.exports = class deviceThermostat { // Set up custom variables for this device type const deviceConf = platform.thDevices[accessory.context.eweDeviceId] const deviceConf2 = platform.simulations[accessory.context.eweDeviceId] - this.tempOffset = deviceConf && deviceConf.offset - ? deviceConf.offset - : platform.consts.defaultValues.offset - this.minTarget = deviceConf && deviceConf.minTarget - ? deviceConf.minTarget - : platform.consts.defaultValues.minTarget - this.maxTarget = deviceConf && deviceConf.maxTarget - ? Math.max(deviceConf.maxTarget, this.minTarget + 1) - : platform.consts.defaultValues.maxTarget - this.disableDeviceLogging = (deviceConf && deviceConf.overrideDisabledLogging) || - deviceConf2.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.tempOffset = + deviceConf && deviceConf.offset ? deviceConf.offset : platform.consts.defaultValues.offset + this.minTarget = + deviceConf && deviceConf.minTarget + ? deviceConf.minTarget + : platform.consts.defaultValues.minTarget + this.maxTarget = + deviceConf && deviceConf.maxTarget + ? Math.max(deviceConf.maxTarget, this.minTarget + 1) + : platform.consts.defaultValues.maxTarget + this.disableDeviceLogging = + (deviceConf && deviceConf.overrideDisabledLogging) || deviceConf2.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // If the accessory has a switch service then remove it if (this.accessory.getService(this.hapServ.Switch)) { @@ -41,16 +42,12 @@ module.exports = class deviceThermostat { // If the accessory has a temperature sensor service then remove it if (this.accessory.getService(this.hapServ.TemperatureSensor)) { - this.accessory.removeService( - this.accessory.getService(this.hapServ.TemperatureSensor) - ) + this.accessory.removeService(this.accessory.getService(this.hapServ.TemperatureSensor)) } // If the accessory has a humidity sensor service then remove it if (this.accessory.getService(this.hapServ.HumiditySensor)) { - this.accessory.removeService( - this.accessory.getService(this.hapServ.HumiditySensor) - ) + this.accessory.removeService(this.accessory.getService(this.hapServ.HumiditySensor)) } // Set up the accessory with default target temp when added the first time @@ -59,7 +56,8 @@ module.exports = class deviceThermostat { } // Add the thermostat service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.Thermostat) || + this.service = + this.accessory.getService(this.hapServ.Thermostat) || this.accessory.addService(this.hapServ.Thermostat) // Set custom properties of the current temperature characteristic @@ -68,7 +66,8 @@ module.exports = class deviceThermostat { }) // Add the set handler to the target state characteristic - this.service.getCharacteristic(this.hapChar.TargetHeatingCoolingState) + this.service + .getCharacteristic(this.hapChar.TargetHeatingCoolingState) .setProps({ minValue: 0, maxValue: 1, @@ -79,7 +78,8 @@ module.exports = class deviceThermostat { }) // Add the set handler to the target temperature characteristic - this.service.getCharacteristic(this.hapChar.TargetTemperature) + this.service + .getCharacteristic(this.hapChar.TargetTemperature) .setProps({ minValue: this.minTarget, maxValue: this.maxTarget, @@ -135,10 +135,8 @@ module.exports = class deviceThermostat { } const newValue = value !== 0 ? 'on' : 'off' const currentTemp = this.service.getCharacteristic(this.hapChar.CurrentTemperature) - this.cacheHeat = newValue === 'on' && - currentTemp.value < this.accessory.context.cacheTarget - ? 'on' - : 'off' + this.cacheHeat = + newValue === 'on' && currentTemp.value < this.accessory.context.cacheTarget ? 'on' : 'off' this.service.updateCharacteristic( this.hapChar.CurrentHeatingCoolingState, newValue === 'on' ? 1 : 0 @@ -212,7 +210,9 @@ module.exports = class deviceThermostat { this.hapChar.TargetHeatingCoolingState, this.cacheState === 'on' ? 1 : 0 ) - this.accessory.eveService.addEntry({ status: this.cacheState === 'on' ? 1 : 0 }) + this.accessory.eveService.addEntry({ + status: this.cacheState === 'on' ? 1 : 0 + }) if (this.cacheState === 'off') { this.cacheHeat = 'off' } @@ -253,10 +253,7 @@ module.exports = class deviceThermostat { const currentHumi = parseInt(params.currentHumidity) if (this.cacheHumi !== currentHumi) { this.cacheHumi = currentHumi - this.service.updateCharacteristic( - this.hapChar.CurrentRelativeHumidity, - this.cacheHumi - ) + this.service.updateCharacteristic(this.hapChar.CurrentRelativeHumidity, this.cacheHumi) this.accessory.eveService.addEntry({ humidity: currentHumi }) if (params.updateSource && !this.disableDeviceLogging) { this.log('[%s] %s [%s%].', this.name, this.lang.curHumi, this.cacheHumi) diff --git a/lib/device/simulation/valve-four.js b/lib/device/simulation/valve-four.js index 6e517bd3..319df775 100644 --- a/lib/device/simulation/valve-four.js +++ b/lib/device/simulation/valve-four.js @@ -99,26 +99,14 @@ module.exports = class deviceValveFour { valveService.updateCharacteristic(this.hapChar.RemainingDuration, 0) clearTimeout(this.accessory.getService(valve).timer) if (!this.disableDeviceLogging) { - this.log( - '[%s] %s [%s %s].', - this.name, - this.lang.curState, - valve, - this.lang.valveNo - ) + this.log('[%s] %s [%s %s].', this.name, this.lang.curState, valve, this.lang.valveNo) } break case 1: { const timer = valveService.getCharacteristic(this.hapChar.SetDuration).value valveService.updateCharacteristic(this.hapChar.RemainingDuration, timer) if (!this.disableDeviceLogging) { - this.log( - '[%s] %s [%s %s].', - this.name, - this.lang.curState, - valve, - this.lang.valveYes - ) + this.log('[%s] %s [%s %s].', this.name, this.lang.curState, valve, this.lang.valveYes) } valveService.timer = setTimeout(() => { valveService.setCharacteristic(this.hapChar.Active, 0) diff --git a/lib/device/simulation/valve-one.js b/lib/device/simulation/valve-one.js index 14c62d9a..21fea9fc 100644 --- a/lib/device/simulation/valve-one.js +++ b/lib/device/simulation/valve-one.js @@ -88,10 +88,12 @@ module.exports = class deviceValveOne { params.switch = value ? 'on' : 'off' break case 'twoSwitch': - params.switches = [{ - switch: value ? 'on' : 'off', - outlet: 0 - }] + params.switches = [ + { + switch: value ? 'on' : 'off', + outlet: 0 + } + ] break } this.service.updateCharacteristic(this.hapChar.InUse, value) @@ -148,7 +150,8 @@ module.exports = class deviceValveOne { if (isOn) { if (this.service.getCharacteristic(this.hapChar.Active).value === 0) { const timer = this.service.getCharacteristic(this.hapChar.SetDuration).value - this.service.updateCharacteristic(this.hapChar.Active, 1) + this.service + .updateCharacteristic(this.hapChar.Active, 1) .updateCharacteristic(this.hapChar.InUse, 1) .updateCharacteristic(this.hapChar.RemainingDuration, timer) if (params.updateSource && !this.disableDeviceLogging) { @@ -160,7 +163,8 @@ module.exports = class deviceValveOne { } return } - this.service.updateCharacteristic(this.hapChar.Active, 0) + this.service + .updateCharacteristic(this.hapChar.Active, 0) .updateCharacteristic(this.hapChar.InUse, 0) .updateCharacteristic(this.hapChar.RemainingDuration, 0) clearTimeout(this.timer) diff --git a/lib/device/simulation/valve-two.js b/lib/device/simulation/valve-two.js index 2d777f4d..ff4188e9 100644 --- a/lib/device/simulation/valve-two.js +++ b/lib/device/simulation/valve-two.js @@ -93,26 +93,14 @@ module.exports = class deviceValveTwo { valveService.updateCharacteristic(this.hapChar.RemainingDuration, 0) clearTimeout(this.accessory.getService(valve).timer) if (!this.disableDeviceLogging) { - this.log( - '[%s] %s [%s %s].', - this.name, - this.lang.curState, - valve, - this.lang.valveNo - ) + this.log('[%s] %s [%s %s].', this.name, this.lang.curState, valve, this.lang.valveNo) } break case 1: { const timer = valveService.getCharacteristic(this.hapChar.SetDuration).value valveService.updateCharacteristic(this.hapChar.RemainingDuration, timer) if (!this.disableDeviceLogging) { - this.log( - '[%s] %s [%s %s].', - this.name, - this.lang.curState, - valve, - this.lang.valveYes - ) + this.log('[%s] %s [%s %s].', this.name, this.lang.curState, valve, this.lang.valveYes) } valveService.timer = setTimeout(() => { valveService.setCharacteristic(this.hapChar.Active, 0) diff --git a/lib/device/simulation/window.js b/lib/device/simulation/window.js index 58d38d92..938f90b5 100644 --- a/lib/device/simulation/window.js +++ b/lib/device/simulation/window.js @@ -19,12 +19,12 @@ module.exports = class deviceWindow { // Set up custom variables for this device type const deviceConf = platform.simulations[accessory.context.eweDeviceId] - this.operationTimeUp = deviceConf.operationTime || - platform.consts.defaultValues.operationTime + this.operationTimeUp = deviceConf.operationTime || platform.consts.defaultValues.operationTime this.operationTimeDown = deviceConf.operationTimeDown || this.operationTimeUp - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // Set up the accessory with default positions when added the first time if (!this.funcs.hasProperty(this.accessory.context, 'cacheCurrentPosition')) { @@ -71,15 +71,17 @@ module.exports = class deviceWindow { const prevState = this.accessory.context.cachePositionState const percentStepUpPerDS = this.operationTimeUp / 100 const percentStepDownPerDS = this.operationTimeDown / 100 - const updateKey = Math.random().toString(36).substr(2, 8) + const updateKey = Math.random() + .toString(36) + .substr(2, 8) this.updateKey = updateKey if (prevState !== 2) { params.switches.push({ switch: 'off', outlet: 0 }) params.switches.push({ switch: 'off', outlet: 1 }) await this.platform.sendDeviceUpdate(this.accessory, params) params.switches = [] - const posPercentChange = Math.floor(Date.now() / 100) - - this.accessory.context.cacheLastStartTime + const posPercentChange = + Math.floor(Date.now() / 100) - this.accessory.context.cacheLastStartTime const posPercentChangeUp = Math.floor(percentStepUpPerDS * posPercentChange) const posPercentChangeDown = Math.floor(percentStepDownPerDS * posPercentChange) if (prevState === 0) { @@ -132,14 +134,9 @@ module.exports = class deviceWindow { this.accessory.context.cacheTargetPosition ) }, 2000) - this.service.updateCharacteristic( - this.hapChar.TargetPosition, - new this.hapErr(-70402) - ) + this.service.updateCharacteristic(this.hapChar.TargetPosition, new this.hapErr(-70402)) } } - async externalUpdate (params) { - - } + async externalUpdate (params) {} } diff --git a/lib/device/switch-double.js b/lib/device/switch-double.js index b53c2799..382cd581 100644 --- a/lib/device/switch-double.js +++ b/lib/device/switch-double.js @@ -21,12 +21,11 @@ module.exports = class deviceSwitchDouble { // Set up custom variables for this device type const deviceConf = platform.multiDevices[accessory.context.eweDeviceId] - this.hideChannels = deviceConf && deviceConf.hideChannels - ? deviceConf.hideChannels - : undefined - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.hideChannels = deviceConf && deviceConf.hideChannels ? deviceConf.hideChannels : undefined + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // If the accessory has an outlet service then remove it if (this.accessory.getService(this.hapServ.Outlet)) { @@ -34,7 +33,8 @@ module.exports = class deviceSwitchDouble { } // Add the switch service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.Switch) || + this.service = + this.accessory.getService(this.hapServ.Switch) || this.accessory.addService(this.hapServ.Switch) // Add the set handler to the switch/outlet on/off characteristic @@ -71,7 +71,10 @@ module.exports = class deviceSwitchDouble { break case '1': case '2': - params.switches.push({ switch: value ? 'on' : 'off', outlet: switchNumber - 1 }) + params.switches.push({ + switch: value ? 'on' : 'off', + outlet: switchNumber - 1 + }) break } await this.platform.sendDeviceUpdate(this.accessory, params) @@ -82,10 +85,9 @@ module.exports = class deviceSwitchDouble { const uuid = this.hapUUIDGen(idToCheck) if (this.devicesInHB.has(uuid)) { const subAccessory = this.devicesInHB.get(uuid) - subAccessory.getService(this.hapServ.Switch).updateCharacteristic( - this.hapChar.On, - value - ) + subAccessory + .getService(this.hapServ.Switch) + .updateCharacteristic(this.hapChar.On, value) subAccessory.eveService.addEntry({ status: value ? 1 : 0 }) if (i > 0 && !this.disableDeviceLogging) { this.log( @@ -120,8 +122,8 @@ module.exports = class deviceSwitchDouble { } } else { if ( - subAccessory.getService(this.hapServ.Switch) - .getCharacteristic(this.hapChar.On).value + subAccessory.getService(this.hapServ.Switch).getCharacteristic(this.hapChar.On) + .value ) { primaryState = true } @@ -132,10 +134,9 @@ module.exports = class deviceSwitchDouble { const idToCheck = this.accessory.context.eweDeviceId + 'SW0' const uuid = this.hapUUIDGen(idToCheck) const priAccessory = this.devicesInHB.get(uuid) - priAccessory.getService(this.hapServ.Switch).updateCharacteristic( - this.hapChar.On, - primaryState - ) + priAccessory + .getService(this.hapServ.Switch) + .updateCharacteristic(this.hapChar.On, primaryState) priAccessory.eveService.addEntry({ status: primaryState ? 1 : 0 }) } break @@ -164,16 +165,11 @@ module.exports = class deviceSwitchDouble { } const subAccessory = this.devicesInHB.get(uuid) const service = subAccessory.getService(this.hapServ.Switch) - const currentState = service.getCharacteristic(this.hapChar.On).value - ? 'on' - : 'off' + const currentState = service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off' if (params.updateSource && params.switches[i - 1].switch === currentState) { continue } - service.updateCharacteristic( - this.hapChar.On, - params.switches[i - 1].switch === 'on' - ) + service.updateCharacteristic(this.hapChar.On, params.switches[i - 1].switch === 'on') subAccessory.eveService.addEntry({ status: params.switches[i - 1].switch === 'on' ? 1 : 0 }) diff --git a/lib/device/switch-multi.js b/lib/device/switch-multi.js index c6a60a5a..35f9a468 100644 --- a/lib/device/switch-multi.js +++ b/lib/device/switch-multi.js @@ -20,12 +20,11 @@ module.exports = class deviceSwitchMulti { // Set up custom variables for this device type const deviceConf = platform.multiDevices[accessory.context.eweDeviceId] - this.hideChannels = deviceConf && deviceConf.hideChannels - ? deviceConf.hideChannels - : undefined - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.hideChannels = deviceConf && deviceConf.hideChannels ? deviceConf.hideChannels : undefined + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // If the accessory has an outlet service then remove it if (this.accessory.getService(this.hapServ.Outlet)) { @@ -33,7 +32,8 @@ module.exports = class deviceSwitchMulti { } // Add the switch service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.Switch) || + this.service = + this.accessory.getService(this.hapServ.Switch) || this.accessory.addService(this.hapServ.Switch) // Add the set handler to the switch/outlet on/off characteristic @@ -74,7 +74,10 @@ module.exports = class deviceSwitchMulti { case '2': case '3': case '4': - params.switches.push({ switch: value ? 'on' : 'off', outlet: switchNumber - 1 }) + params.switches.push({ + switch: value ? 'on' : 'off', + outlet: switchNumber - 1 + }) break } await this.platform.sendDeviceUpdate(this.accessory, params) @@ -85,10 +88,9 @@ module.exports = class deviceSwitchMulti { const uuid = this.hapUUIDGen(idToCheck) if (this.devicesInHB.has(uuid)) { const subAccessory = this.devicesInHB.get(uuid) - subAccessory.getService(this.hapServ.Switch).updateCharacteristic( - this.hapChar.On, - value - ) + subAccessory + .getService(this.hapServ.Switch) + .updateCharacteristic(this.hapChar.On, value) subAccessory.eveService.addEntry({ status: value ? 1 : 0 }) if (i > 0 && !this.disableDeviceLogging) { this.log( @@ -125,8 +127,8 @@ module.exports = class deviceSwitchMulti { } } else { if ( - subAccessory.getService(this.hapServ.Switch) - .getCharacteristic(this.hapChar.On).value + subAccessory.getService(this.hapServ.Switch).getCharacteristic(this.hapChar.On) + .value ) { primaryState = true } @@ -137,10 +139,9 @@ module.exports = class deviceSwitchMulti { const idToCheck = this.accessory.context.eweDeviceId + 'SW0' const uuid = this.hapUUIDGen(idToCheck) const priAccessory = this.devicesInHB.get(uuid) - priAccessory.getService(this.hapServ.Switch).updateCharacteristic( - this.hapChar.On, - primaryState - ) + priAccessory + .getService(this.hapServ.Switch) + .updateCharacteristic(this.hapChar.On, primaryState) priAccessory.eveService.addEntry({ status: primaryState ? 1 : 0 }) } break @@ -169,16 +170,11 @@ module.exports = class deviceSwitchMulti { } const subAccessory = this.devicesInHB.get(uuid) const service = subAccessory.getService(this.hapServ.Switch) - const currentState = service.getCharacteristic(this.hapChar.On).value - ? 'on' - : 'off' + const currentState = service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off' if (params.updateSource && params.switches[i - 1].switch === currentState) { continue } - service.updateCharacteristic( - this.hapChar.On, - params.switches[i - 1].switch === 'on' - ) + service.updateCharacteristic(this.hapChar.On, params.switches[i - 1].switch === 'on') subAccessory.eveService.addEntry({ status: params.switches[i - 1].switch === 'on' ? 1 : 0 }) diff --git a/lib/device/switch-single.js b/lib/device/switch-single.js index af43e1f5..88015215 100644 --- a/lib/device/switch-single.js +++ b/lib/device/switch-single.js @@ -18,9 +18,10 @@ module.exports = class deviceSwitchSingle { // Set up custom variables for this device type const deviceConf = platform.singleDevices[accessory.context.eweDeviceId] - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // If the accessory has a outlet service then remove it if (this.accessory.getService(this.hapServ.Outlet)) { @@ -28,7 +29,8 @@ module.exports = class deviceSwitchSingle { } // Add the switch service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.Switch) || + this.service = + this.accessory.getService(this.hapServ.Switch) || this.accessory.addService(this.hapServ.Switch) // Add the set handler to the switch on/off characteristic @@ -43,7 +45,9 @@ module.exports = class deviceSwitchSingle { // Output the customised options to the log if in debug mode if (platform.config.debug) { - const opts = JSON.stringify({ disableDeviceLogging: this.disableDeviceLogging }) + const opts = JSON.stringify({ + disableDeviceLogging: this.disableDeviceLogging + }) this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts) } } diff --git a/lib/device/thermostat.js b/lib/device/thermostat.js index bb12ad61..c5b6a305 100644 --- a/lib/device/thermostat.js +++ b/lib/device/thermostat.js @@ -19,12 +19,12 @@ module.exports = class deviceThermostat { // Set up custom variables for this device type const deviceConf = platform.thDevices[accessory.context.eweDeviceId] - this.tempOffset = deviceConf && deviceConf.offset - ? deviceConf.offset - : platform.consts.defaultValues.offset - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.tempOffset = + deviceConf && deviceConf.offset ? deviceConf.offset : platform.consts.defaultValues.offset + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging /* ************** @@ -49,7 +49,8 @@ module.exports = class deviceThermostat { */ // Add the thermostat service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.Thermostat) || + this.service = + this.accessory.getService(this.hapServ.Thermostat) || this.accessory.addService(this.hapServ.Thermostat) // Set custom properties of the current temperature characteristic @@ -58,21 +59,25 @@ module.exports = class deviceThermostat { }) // Add the set handler to the target state characteristic - this.service.getCharacteristic(this.hapChar.TargetHeatingCoolingState).setProps({ - minValue: 0, - maxValue: 1, - validValues: [0, 1] - }) + this.service + .getCharacteristic(this.hapChar.TargetHeatingCoolingState) + .setProps({ + minValue: 0, + maxValue: 1, + validValues: [0, 1] + }) .onSet(async value => { await this.internalStateUpdate(value) }) // Add the set handler to the target temperature characteristic - this.service.getCharacteristic(this.hapChar.TargetTemperature).setProps({ - minValue: 5, - maxValue: 45, - minStep: 0.5 - }) + this.service + .getCharacteristic(this.hapChar.TargetTemperature) + .setProps({ + minValue: 5, + maxValue: 45, + minStep: 0.5 + }) .onSet(async value => { await this.internalTargetUpdate(value) }) @@ -133,10 +138,7 @@ module.exports = class deviceThermostat { } catch (err) { this.platform.deviceUpdateError(this.accessory, err, true) setTimeout(() => { - this.service.updateCharacteristic( - this.hapChar.TargetTemperature, - this.cacheTarg - ) + this.service.updateCharacteristic(this.hapChar.TargetTemperature, this.cacheTarg) }, 2000) throw new this.hapErr(-70402) } @@ -176,10 +178,7 @@ module.exports = class deviceThermostat { const targetTemp = Number(params.targetTemp) if (this.cacheTarg !== targetTemp) { this.cacheTarg = targetTemp - this.service.updateCharacteristic( - this.hapChar.TargetTemperature, - this.cacheTarg - ) + this.service.updateCharacteristic(this.hapChar.TargetTemperature, this.cacheTarg) if (params.updateSource && !this.disableDeviceLogging) { this.log('[%s] %s [%s°C].', this.name, this.lang.curTarg, this.cacheTarg) } @@ -190,7 +189,7 @@ module.exports = class deviceThermostat { let currentTemp if (params.tempScale && params.tempScale === 'f') { // Convert to celcius - currentTemp = (Number(params.temperature) - 32) * 5 / 9 + currentTemp = ((Number(params.temperature) - 32) * 5) / 9 // Round to nearest 0.5 currentTemp = Math.round(currentTemp * 2) / 2 @@ -200,10 +199,7 @@ module.exports = class deviceThermostat { currentTemp += this.tempOffset if (this.cacheTemp !== currentTemp) { this.cacheTemp = currentTemp - this.service.updateCharacteristic( - this.hapChar.CurrentTemperature, - this.cacheTemp - ) + this.service.updateCharacteristic(this.hapChar.CurrentTemperature, this.cacheTemp) if (params.updateSource && !this.disableDeviceLogging) { this.log('[%s] %s [%s°C].', this.name, this.lang.curTemp, this.cacheTemp) } diff --git a/lib/device/zigbee/light-cct.js b/lib/device/zigbee/light-cct.js index 50d30225..e4d7c23b 100644 --- a/lib/device/zigbee/light-cct.js +++ b/lib/device/zigbee/light-cct.js @@ -19,26 +19,31 @@ module.exports = class deviceZBLightCCT { // Set up custom variables for this device type const deviceConf = platform.lightDevices[accessory.context.eweDeviceId] - this.brightStep = deviceConf && deviceConf.brightnessStep - ? Math.min(deviceConf.brightnessStep, 100) - : platform.consts.defaultValues.brightnessStep - this.alShift = deviceConf && deviceConf.adaptiveLightingShift - ? deviceConf.adaptiveLightingShift - : platform.consts.defaultValues.adaptiveLightingShift - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.brightStep = + deviceConf && deviceConf.brightnessStep + ? Math.min(deviceConf.brightnessStep, 100) + : platform.consts.defaultValues.brightnessStep + this.alShift = + deviceConf && deviceConf.adaptiveLightingShift + ? deviceConf.adaptiveLightingShift + : platform.consts.defaultValues.adaptiveLightingShift + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // Different bulbs have different colour temperature ranges this.minK = 2200 this.maxK = 4000 // Add the lightbulb service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.Lightbulb) || + this.service = + this.accessory.getService(this.hapServ.Lightbulb) || this.accessory.addService(this.hapServ.Lightbulb) // Add the get/set handler to the lightbulb on/off characteristic - this.service.getCharacteristic(this.hapChar.On) + this.service + .getCharacteristic(this.hapChar.On) .onGet(() => { if (this.isOnline) { return this.service.getCharacteristic(this.hapChar.On).value @@ -51,7 +56,8 @@ module.exports = class deviceZBLightCCT { }) // Add the set handler to the lightbulb brightness characteristic - this.service.getCharacteristic(this.hapChar.Brightness) + this.service + .getCharacteristic(this.hapChar.Brightness) .setProps({ minStep: this.brightStep }) .onSet(async value => { await this.internalBrightnessUpdate(value) @@ -66,10 +72,9 @@ module.exports = class deviceZBLightCCT { this.cacheBright = this.service.getCharacteristic(this.hapChar.Brightness).value // Set up the adaptive lighting controller - this.accessory.alController = new platform.api.hap.AdaptiveLightingController( - this.service, - { customTemperatureAdjustment: this.alShift } - ) + this.accessory.alController = new platform.api.hap.AdaptiveLightingController(this.service, { + customTemperatureAdjustment: this.alShift + }) this.accessory.configureController(this.accessory.alController) // Output the customised options to the log if in debug mode @@ -107,7 +112,9 @@ module.exports = class deviceZBLightCCT { if (this.cacheBright === value || value === 0) { return } - const updateKey = Math.random().toString(36).substr(2, 8) + const updateKey = Math.random() + .toString(36) + .substr(2, 8) this.updateKeyBright = updateKey await this.funcs.sleep(500) if (updateKey !== this.updateKeyBright) { @@ -139,7 +146,9 @@ module.exports = class deviceZBLightCCT { if (!this.isOnline && this.accessory.alController.isAdaptiveLightingActive()) { return } - const updateKey = Math.random().toString(36).substr(2, 8) + const updateKey = Math.random() + .toString(36) + .substr(2, 8) this.updateKeyCT = updateKey await this.funcs.sleep(400) if (updateKey !== this.updateKeyCT) { @@ -157,13 +166,7 @@ module.exports = class deviceZBLightCCT { this.cacheCT = scaledCT if (!this.disableDeviceLogging) { if (this.accessory.alController.isAdaptiveLightingActive()) { - this.log( - '[%s] %s [%sK] %s.', - this.name, - this.lang.curColour, - scaledK, - this.lang.viaAL - ) + this.log('[%s] %s [%sK] %s.', this.name, this.lang.curColour, scaledK, this.lang.viaAL) } else { this.log('[%s] %s [%sK].', this.name, this.lang.curColour, scaledK) } @@ -199,13 +202,10 @@ module.exports = class deviceZBLightCCT { if (params.colorTemp !== this.cacheCT) { const ctDiff = Math.abs(params.colorTemp - this.cacheCT) this.cacheCT = params.colorTemp - const kelvin = this.cacheCT / 100 * (this.maxK - this.minK) + this.minK + const kelvin = (this.cacheCT / 100) * (this.maxK - this.minK) + this.minK const scaledK = Math.round(kelvin) this.cacheMired = Math.min(Math.max(Math.round(1000000 / scaledK), 140), 500) - this.service.updateCharacteristic( - this.hapChar.ColorTemperature, - this.cacheMired - ) + this.service.updateCharacteristic(this.hapChar.ColorTemperature, this.cacheMired) if (params.updateSource) { if (!this.disableDeviceLogging) { this.log('[%s] %s [%sK].', this.name, this.lang.curColour, scaledK) diff --git a/lib/device/zigbee/light-dimmer.js b/lib/device/zigbee/light-dimmer.js index 273d4d3c..9d431110 100644 --- a/lib/device/zigbee/light-dimmer.js +++ b/lib/device/zigbee/light-dimmer.js @@ -19,19 +19,23 @@ module.exports = class deviceZBLightDimmer { // Set up custom variables for this device type const deviceConf = platform.lightDevices[accessory.context.eweDeviceId] - this.brightStep = deviceConf && deviceConf.brightnessStep - ? Math.min(deviceConf.brightnessStep, 100) - : platform.consts.defaultValues.brightnessStep - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.brightStep = + deviceConf && deviceConf.brightnessStep + ? Math.min(deviceConf.brightnessStep, 100) + : platform.consts.defaultValues.brightnessStep + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // Add the lightbulb service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.Lightbulb) || + this.service = + this.accessory.getService(this.hapServ.Lightbulb) || this.accessory.addService(this.hapServ.Lightbulb) // Add the get/set handler to the lightbulb on/off characteristic - this.service.getCharacteristic(this.hapChar.On) + this.service + .getCharacteristic(this.hapChar.On) .onGet(() => { if (this.isOnline) { return this.service.getCharacteristic(this.hapChar.On).value @@ -44,7 +48,8 @@ module.exports = class deviceZBLightDimmer { }) // Add the set handler to the lightbulb brightness characteristic - this.service.getCharacteristic(this.hapChar.Brightness) + this.service + .getCharacteristic(this.hapChar.Brightness) .setProps({ minStep: this.brightStep }) .onSet(async value => { await this.internalBrightnessUpdate(value) @@ -84,7 +89,9 @@ module.exports = class deviceZBLightDimmer { if (this.cacheBright === value || value === 0) { return } - const updateKey = Math.random().toString(36).substr(2, 8) + const updateKey = Math.random() + .toString(36) + .substr(2, 8) this.updateKey = updateKey await this.funcs.sleep(500) if (updateKey !== this.updateKey) { diff --git a/lib/device/zigbee/sensor-ambient.js b/lib/device/zigbee/sensor-ambient.js index 875f9560..06caae4f 100644 --- a/lib/device/zigbee/sensor-ambient.js +++ b/lib/device/zigbee/sensor-ambient.js @@ -18,18 +18,20 @@ module.exports = class deviceZBSensorAmbient { // Set up custom variables for this device type const deviceConf = platform.sensorDevices[accessory.context.eweDeviceId] - this.lowBattThreshold = deviceConf && deviceConf.lowBattThreshold - ? Math.min(deviceConf.lowBattThreshold, 100) - : platform.consts.defaultValues.lowBattThreshold - this.tempOffset = deviceConf && deviceConf.offset - ? deviceConf.offset - : platform.consts.defaultValues.offset - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.lowBattThreshold = + deviceConf && deviceConf.lowBattThreshold + ? Math.min(deviceConf.lowBattThreshold, 100) + : platform.consts.defaultValues.lowBattThreshold + this.tempOffset = + deviceConf && deviceConf.offset ? deviceConf.offset : platform.consts.defaultValues.offset + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // Add the temperature sensor service if it doesn't already exist - this.tempService = this.accessory.getService(this.hapServ.TemperatureSensor) || + this.tempService = + this.accessory.getService(this.hapServ.TemperatureSensor) || this.accessory.addService(this.hapServ.TemperatureSensor) // Add options to the current temperature characteristic @@ -38,11 +40,13 @@ module.exports = class deviceZBSensorAmbient { }) // Add the humidity sensor service if it doesn't already exist - this.humiService = this.accessory.getService(this.hapServ.HumiditySensor) || + this.humiService = + this.accessory.getService(this.hapServ.HumiditySensor) || this.accessory.addService(this.hapServ.HumiditySensor) // Add the battery service if it doesn't already exist - this.battService = this.accessory.getService(this.hapServ.BatteryService) || + this.battService = + this.accessory.getService(this.hapServ.BatteryService) || this.accessory.addService(this.hapServ.BatteryService) // Pass the accessory to Fakegato to set up with Eve @@ -63,10 +67,7 @@ module.exports = class deviceZBSensorAmbient { async externalUpdate (params) { try { - if ( - this.funcs.hasProperty(params, 'battery') && - params.battery !== this.cacheBatt - ) { + if (this.funcs.hasProperty(params, 'battery') && params.battery !== this.cacheBatt) { this.cacheBatt = params.battery this.battService.updateCharacteristic(this.hapChar.BatteryLevel, this.cacheBatt) this.battService.updateCharacteristic( @@ -78,10 +79,7 @@ module.exports = class deviceZBSensorAmbient { } } const eveLog = {} - if ( - this.funcs.hasProperty(params, 'temperature') && - params.temperature !== this.cacheTemp - ) { + if (this.funcs.hasProperty(params, 'temperature') && params.temperature !== this.cacheTemp) { this.cacheTemp = params.temperature const currentTemp = parseInt(this.cacheTemp) / 100 + this.tempOffset this.tempService.updateCharacteristic(this.hapChar.CurrentTemperature, currentTemp) @@ -90,16 +88,10 @@ module.exports = class deviceZBSensorAmbient { this.log('[%s] %s [%s°C].', this.name, this.lang.curTemp, currentTemp) } } - if ( - this.funcs.hasProperty(params, 'humidity') && - params.humidity !== this.cacheHumi - ) { + if (this.funcs.hasProperty(params, 'humidity') && params.humidity !== this.cacheHumi) { this.cacheHumi = params.humidity const currentHumi = parseInt(this.cacheHumi) / 100 - this.humiService.updateCharacteristic( - this.hapChar.CurrentRelativeHumidity, - currentHumi - ) + this.humiService.updateCharacteristic(this.hapChar.CurrentRelativeHumidity, currentHumi) eveLog.humidity = currentHumi if (params.updateSource && !this.disableDeviceLogging) { this.log('[%s] %s [%s%].', this.name, this.lang.curHumi, currentHumi) diff --git a/lib/device/zigbee/sensor-contact.js b/lib/device/zigbee/sensor-contact.js index b382cfcc..2aafebc9 100644 --- a/lib/device/zigbee/sensor-contact.js +++ b/lib/device/zigbee/sensor-contact.js @@ -22,12 +22,14 @@ module.exports = class deviceZBSensorContact { // Set up custom variables for this device type const deviceConf = platform.sensorDevices[accessory.context.eweDeviceId] this.scaleBattery = deviceConf && deviceConf.scaleBattery - this.lowBattThreshold = deviceConf && deviceConf.lowBattThreshold - ? Math.min(deviceConf.lowBattThreshold, 100) - : platform.consts.defaultValues.lowBattThreshold - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.lowBattThreshold = + deviceConf && deviceConf.lowBattThreshold + ? Math.min(deviceConf.lowBattThreshold, 100) + : platform.consts.defaultValues.lowBattThreshold + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // Add the contact sensor service if it doesn't already exist if (!(this.service = this.accessory.getService(this.hapServ.ContactSensor))) { @@ -49,7 +51,8 @@ module.exports = class deviceZBSensorContact { }) // Add the battery service if it doesn't already exist - this.battService = this.accessory.getService(this.hapServ.BatteryService) || + this.battService = + this.accessory.getService(this.hapServ.BatteryService) || this.accessory.addService(this.hapServ.BatteryService) // Pass the accessory to Fakegato to set up with Eve @@ -70,10 +73,7 @@ module.exports = class deviceZBSensorContact { async externalUpdate (params) { try { - if ( - this.funcs.hasProperty(params, 'battery') && - params.battery !== this.cacheBattery - ) { + if (this.funcs.hasProperty(params, 'battery') && params.battery !== this.cacheBattery) { this.cacheBattery = params.battery const scaledBatt = this.scaleBattery ? this.cacheBattery * 10 : this.cacheBattery this.battService.updateCharacteristic(this.hapChar.BatteryLevel, scaledBatt) @@ -111,10 +111,7 @@ module.exports = class deviceZBSensorContact { } } for (const [deviceId, group] of Object.entries(this.platform.simulations)) { - if ( - group.sensorId === this.accessory.context.eweDeviceId && - group.type === 'garage' - ) { + if (group.sensorId === this.accessory.context.eweDeviceId && group.type === 'garage') { const uuid = this.hapUUIDGen(deviceId + 'SWX') if (this.devicesInHB.has(uuid)) { const subAccessory = this.devicesInHB.get(uuid) @@ -125,12 +122,7 @@ module.exports = class deviceZBSensorContact { gdService.updateCharacteristic(this.hapChar.TargetDoorState, 1) gdService.updateCharacteristic(this.hapChar.CurrentDoorState, 1) if (params.updateSource && !this.disableDeviceLogging) { - this.log( - '[%s] %s [%s].', - name, - this.lang.curState, - this.lang.doorClosed - ) + this.log('[%s] %s [%s].', name, this.lang.curState, this.lang.doorClosed) } break case 1: @@ -138,12 +130,7 @@ module.exports = class deviceZBSensorContact { gdService.updateCharacteristic(this.hapChar.TargetDoorState, 0) gdService.updateCharacteristic(this.hapChar.CurrentDoorState, 0) if (params.updateSource && !this.disableDeviceLogging) { - this.log( - '[%s] %s [%s].', - name, - this.lang.curState, - this.lang.doorOpen - ) + this.log('[%s] %s [%s].', name, this.lang.curState, this.lang.doorOpen) } break } diff --git a/lib/device/zigbee/sensor-motion.js b/lib/device/zigbee/sensor-motion.js index c43eb056..9f3bb085 100644 --- a/lib/device/zigbee/sensor-motion.js +++ b/lib/device/zigbee/sensor-motion.js @@ -19,15 +19,18 @@ module.exports = class deviceZBSensorMotion { // Set up custom variables for this device type const deviceConf = platform.sensorDevices[accessory.context.eweDeviceId] - this.lowBattThreshold = deviceConf && deviceConf.lowBattThreshold - ? Math.min(deviceConf.lowBattThreshold, 100) - : platform.consts.defaultValues.lowBattThreshold - this.sensorTimeDifference = deviceConf && deviceConf.sensorTimeDifference - ? deviceConf.sensorTimeDifference - : platform.consts.defaultValues.sensorTimeDifference - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.lowBattThreshold = + deviceConf && deviceConf.lowBattThreshold + ? Math.min(deviceConf.lowBattThreshold, 100) + : platform.consts.defaultValues.lowBattThreshold + this.sensorTimeDifference = + deviceConf && deviceConf.sensorTimeDifference + ? deviceConf.sensorTimeDifference + : platform.consts.defaultValues.sensorTimeDifference + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // Add the motion sensor service if it doesn't already exist if (!(this.service = this.accessory.getService(this.hapServ.MotionSensor))) { @@ -36,7 +39,9 @@ module.exports = class deviceZBSensorMotion { } // Add the battery service if it doesn't already exist - this.battService = this.accessory.getService(this.hapServ.BatteryService) || this.accessory.addService(this.hapServ.BatteryService) + this.battService = + this.accessory.getService(this.hapServ.BatteryService) || + this.accessory.addService(this.hapServ.BatteryService) // Pass the accessory to Fakegato to set up with Eve this.accessory.eveService = new platform.eveService('motion', this.accessory, { @@ -56,10 +61,7 @@ module.exports = class deviceZBSensorMotion { async externalUpdate (params) { try { - if ( - this.funcs.hasProperty(params, 'battery') && - params.battery !== this.cacheBatt - ) { + if (this.funcs.hasProperty(params, 'battery') && params.battery !== this.cacheBatt) { this.cacheBatt = params.battery this.battService.updateCharacteristic(this.hapChar.BatteryLevel, this.cacheBatt) this.battService.updateCharacteristic( @@ -70,15 +72,14 @@ module.exports = class deviceZBSensorMotion { this.log('[%s] %s [%s%].', this.name, this.lang.curBatt, this.cacheBatt) } } - if ( - this.funcs.hasProperty(params, 'motion') && - this.funcs.hasProperty(params, 'trigTime') - ) { + if (this.funcs.hasProperty(params, 'motion') && this.funcs.hasProperty(params, 'trigTime')) { const timeNow = new Date() const diff = (timeNow.getTime() - params.trigTime) / 1000 - const motionDetected = !!(params.updateSource && + const motionDetected = !!( + params.updateSource && params.motion === 1 && - diff < this.sensorTimeDifference) + diff < this.sensorTimeDifference + ) this.service.updateCharacteristic(this.hapChar.MotionDetected, motionDetected) if (motionDetected) { const initialTime = this.accessory.eveService.getInitialTime() diff --git a/lib/device/zigbee/switch-single.js b/lib/device/zigbee/switch-single.js index 590f50a5..dcf57f8f 100644 --- a/lib/device/zigbee/switch-single.js +++ b/lib/device/zigbee/switch-single.js @@ -18,16 +18,19 @@ module.exports = class deviceZBSwitchSingle { // Set up custom variables for this device type const deviceConf = platform.singleDevices[accessory.context.eweDeviceId] - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // Add the switch service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.Switch) || + this.service = + this.accessory.getService(this.hapServ.Switch) || this.accessory.addService(this.hapServ.Switch) // Add the get/set handler to the switch on/off characteristic - this.service.getCharacteristic(this.hapChar.On) + this.service + .getCharacteristic(this.hapChar.On) .onGet(() => { if (this.isOnline) { return this.service.getCharacteristic(this.hapChar.On).value @@ -46,7 +49,9 @@ module.exports = class deviceZBSwitchSingle { // Output the customised options to the log if in debug mode if (platform.config.debug) { - const opts = JSON.stringify({ disableDeviceLogging: this.disableDeviceLogging }) + const opts = JSON.stringify({ + disableDeviceLogging: this.disableDeviceLogging + }) this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts) } } @@ -81,7 +86,9 @@ module.exports = class deviceZBSwitchSingle { } this.cacheState = params.switch this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on') - this.accessory.eveService.addEntry({ status: this.cacheState === 'on' ? 1 : 0 }) + this.accessory.eveService.addEntry({ + status: this.cacheState === 'on' ? 1 : 0 + }) if (params.updateSource && !this.disableDeviceLogging) { this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState) } diff --git a/lib/device/zigbee/switch-stateless.js b/lib/device/zigbee/switch-stateless.js index 4dc7addc..a5a39991 100644 --- a/lib/device/zigbee/switch-stateless.js +++ b/lib/device/zigbee/switch-stateless.js @@ -19,15 +19,18 @@ module.exports = class deviceZBSwitchStateless { // Set up custom variables for this device type const deviceConf = platform.sensorDevices[accessory.context.eweDeviceId] this.hideLongDouble = deviceConf && deviceConf.hideLongDouble - this.lowBattThreshold = deviceConf && deviceConf.lowBattThreshold - ? Math.min(deviceConf.lowBattThreshold, 100) - : platform.consts.defaultValues.lowBattThreshold - this.disableDeviceLogging = deviceConf && deviceConf.overrideDisabledLogging - ? false - : platform.config.disableDeviceLogging + this.lowBattThreshold = + deviceConf && deviceConf.lowBattThreshold + ? Math.min(deviceConf.lowBattThreshold, 100) + : platform.consts.defaultValues.lowBattThreshold + this.disableDeviceLogging = + deviceConf && deviceConf.overrideDisabledLogging + ? false + : platform.config.disableDeviceLogging // Add the stateless switch service if it doesn't already exist - this.service = this.accessory.getService(this.hapServ.StatelessProgrammableSwitch) || + this.service = + this.accessory.getService(this.hapServ.StatelessProgrammableSwitch) || this.accessory.addService(this.hapServ.StatelessProgrammableSwitch) // Hide the double and long press options if the user wants @@ -38,7 +41,8 @@ module.exports = class deviceZBSwitchStateless { } // Add the battery service if it doesn't already exist - this.battService = this.accessory.getService(this.hapServ.BatteryService) || + this.battService = + this.accessory.getService(this.hapServ.BatteryService) || this.accessory.addService(this.hapServ.BatteryService) // Output the customised options to the log if in debug mode @@ -54,10 +58,7 @@ module.exports = class deviceZBSwitchStateless { async externalUpdate (params) { try { - if ( - this.funcs.hasProperty(params, 'battery') && - params.battery !== this.cacheBatt - ) { + if (this.funcs.hasProperty(params, 'battery') && params.battery !== this.cacheBatt) { this.cacheBatt = params.battery this.battService.updateCharacteristic(this.hapChar.BatteryLevel, this.cacheBatt) this.battService.updateCharacteristic( @@ -69,14 +70,14 @@ module.exports = class deviceZBSwitchStateless { } } if (this.funcs.hasProperty(params, 'key') && [0, 1, 2].includes(params.key)) { - this.service.updateCharacteristic( - this.hapChar.ProgrammableSwitchEvent, - params.key - ) + this.service.updateCharacteristic(this.hapChar.ProgrammableSwitchEvent, params.key) if (params.updateSource && !this.disableDeviceLogging) { - const textLabel = params.key === 0 - ? this.lang.buttonSingle - : (params.key === 1 ? this.lang.buttonDouble : this.lang.buttonLong) + const textLabel = + params.key === 0 + ? this.lang.buttonSingle + : params.key === 1 + ? this.lang.buttonDouble + : this.lang.buttonLong this.log('[%s] %s [%s].', this.name, this.lang.curState, textLabel) } } diff --git a/lib/fakegato/fakegato-history.js b/lib/fakegato/fakegato-history.js index 592fb856..820db050 100644 --- a/lib/fakegato/fakegato-history.js +++ b/lib/fakegato/fakegato-history.js @@ -13,7 +13,7 @@ module.exports = function (homebridge) { Service = homebridge.hap.Service const hexToBase64 = val => { - return Buffer.from(('' + val).replace(/[^0-9A-F]/ig, ''), 'hex').toString('base64') + return Buffer.from(('' + val).replace(/[^0-9A-F]/gi, ''), 'hex').toString('base64') } const base64ToHex = val => { @@ -24,14 +24,13 @@ module.exports = function (homebridge) { } const swap16 = val => { - return ((val & 0xFF) << 8) | ((val >>> 8) & 0xFF) + return ((val & 0xff) << 8) | ((val >>> 8) & 0xff) } const swap32 = val => { - return ((val & 0xFF) << 24) | - ((val & 0xFF00) << 8) | - ((val >>> 8) & 0xFF00) | - ((val >>> 24) & 0xFF) + return ( + ((val & 0xff) << 24) | ((val & 0xff00) << 8) | ((val >>> 8) & 0xff00) | ((val >>> 24) & 0xff) + ) } const numToHex = (val, len) => { @@ -137,21 +136,25 @@ module.exports = function (homebridge) { } this.loaded = false if (homebridge.globalFakeGatoStorage === undefined) { - homebridge.globalFakeGatoStorage = new FakeGatoStorage({ log: this.log }) + homebridge.globalFakeGatoStorage = new FakeGatoStorage({ + log: this.log + }) } homebridge.globalFakeGatoStorage.addWriter(this, { path: this.path, onReady: function () { - this.load(function (err, loaded) { - if (err) { - this.log('FG history: load error: %s.', err) - } else { - if (loaded) { - this.log('FG history: loaded from storage.') + this.load( + function (err, loaded) { + if (err) { + this.log('FG history: load error: %s.', err) + } else { + if (loaded) { + this.log('FG history: loaded from storage.') + } + this.loaded = true } - this.loaded = true - } - }.bind(this)) + }.bind(this) + ) }.bind(this) }) switch (accessoryType) { @@ -327,12 +330,16 @@ module.exports = function (homebridge) { } }) }) - this.accessoryType116 = ' 0' + + this.accessoryType116 = + ' 0' + this.signatures.length.toString() + ' ' + - this.signatures.sort((a, b) => { - return a.signature > b.signature ? 1 : -1 - }).map(a => a.signature).join(' ') + + this.signatures + .sort((a, b) => { + return a.signature > b.signature ? 1 : -1 + }) + .map(a => a.signature) + .join(' ') + ' ' homebridge.globalFakeGatoTimer.subscribe(this, this.calculateAverage) break @@ -457,17 +464,29 @@ module.exports = function (homebridge) { }) break case 'weather': - homebridge.globalFakeGatoTimer.addData({ entry: entry, service: this }) + homebridge.globalFakeGatoTimer.addData({ + entry: entry, + service: this + }) break case 'room': - homebridge.globalFakeGatoTimer.addData({ entry: entry, service: this }) + homebridge.globalFakeGatoTimer.addData({ + entry: entry, + service: this + }) break case 'energy': - homebridge.globalFakeGatoTimer.addData({ entry: entry, service: this }) + homebridge.globalFakeGatoTimer.addData({ + entry: entry, + service: this + }) break case 'custom': if ('power' in entry || 'temp' in entry || 'humidity' in entry) { - homebridge.globalFakeGatoTimer.addData({ entry: entry, service: this }) + homebridge.globalFakeGatoTimer.addData({ + entry: entry, + service: this + }) } else { this._addEntry(entry) } @@ -509,7 +528,7 @@ module.exports = function (homebridge) { this.lastEntry++ this.usedMemory++ } - this.history[entry2address(this.lastEntry)] = (entry) + this.history[entry2address(this.lastEntry)] = entry if (this.usedMemory < this.memorySize) { val = Format( '%s00000000%s%s%s%s%s000000000101', @@ -518,7 +537,8 @@ module.exports = function (homebridge) { this.accessoryType116, numToHex(swap16(this.usedMemory + 1), 4), numToHex(swap16(this.memorySize), 4), - numToHex(swap32(this.firstEntry), 8)) + numToHex(swap32(this.firstEntry), 8) + ) } else { val = Format( '%s00000000%s%s%s%s%s000000000101', @@ -527,7 +547,8 @@ module.exports = function (homebridge) { this.accessoryType116, numToHex(swap16(this.usedMemory), 4), numToHex(swap16(this.memorySize), 4), - numToHex(swap32(this.firstEntry + 1), 8)) + numToHex(swap32(this.firstEntry + 1), 8) + ) } this.service.getCharacteristic(S2R1Characteristic).setValue(hexToBase64(val)) this.log( @@ -573,7 +594,7 @@ module.exports = function (homebridge) { } homebridge.globalFakeGatoStorage.write({ service: this, - data: typeof (data) === 'object' ? JSON.stringify(data) : data + data: typeof data === 'object' ? JSON.stringify(data) : data }) } else { setTimeout(() => this.save(), 100) @@ -589,7 +610,7 @@ module.exports = function (homebridge) { if (data) { try { // this.log('[%s] read data [%s].', this.accessoryName, data) - const jsonFile = typeof (data) === 'object' ? data : JSON.parse(data) + const jsonFile = typeof data === 'object' ? data : JSON.parse(data) this.firstEntry = jsonFile.firstEntry this.lastEntry = jsonFile.lastEntry this.usedMemory = jsonFile.usedMemory @@ -623,7 +644,7 @@ module.exports = function (homebridge) { if ( this.history[this.memAddress].setRefTime === 1 || this.setTime || - (this.currentEntry === this.firstEntry + 1) + this.currentEntry === this.firstEntry + 1 ) { this.dataStream += Format( ',15%s 0100 0000 81%s0000 0000 00 0000', @@ -647,7 +668,8 @@ module.exports = function (homebridge) { this.accessoryType117, numToHex(swap16(this.history[this.memAddress].temp * 100), 4), numToHex(swap16(this.history[this.memAddress].humidity * 100), 4), - numToHex(swap16(this.history[this.memAddress].pressure * 10), 4)) + numToHex(swap16(this.history[this.memAddress].pressure * 10), 4) + ) break case 'energy': this.dataStream += Format( @@ -655,7 +677,8 @@ module.exports = function (homebridge) { numToHex(swap32(this.currentEntry), 8), numToHex(swap32(this.history[this.memAddress].time - this.refTime - _EPOCH), 8), this.accessoryType117, - numToHex(swap16(this.history[this.memAddress].power * 10), 4)) + numToHex(swap16(this.history[this.memAddress].power * 10), 4) + ) break case 'room': this.dataStream += Format( @@ -665,7 +688,8 @@ module.exports = function (homebridge) { this.accessoryType117, numToHex(swap16(this.history[this.memAddress].temp * 100), 4), numToHex(swap16(this.history[this.memAddress].humidity * 100), 4), - numToHex(swap16(this.history[this.memAddress].ppm), 4)) + numToHex(swap16(this.history[this.memAddress].ppm), 4) + ) break case 'door': case 'motion': @@ -675,7 +699,8 @@ module.exports = function (homebridge) { numToHex(swap32(this.currentEntry), 8), numToHex(swap32(this.history[this.memAddress].time - this.refTime - _EPOCH), 8), this.accessoryType117, - numToHex(this.history[this.memAddress].status, 2)) + numToHex(this.history[this.memAddress].status, 2) + ) break case 'aqua': if (this.history[this.memAddress].status) { @@ -684,7 +709,8 @@ module.exports = function (homebridge) { numToHex(swap32(this.currentEntry), 8), numToHex(swap32(this.history[this.memAddress].time - this.refTime - _EPOCH), 8), this.accessoryType117, - numToHex(this.history[this.memAddress].status, 2)) + numToHex(this.history[this.memAddress].status, 2) + ) } else { this.dataStream += Format( ',15 %s%s%s%s%s 00000000 300c', @@ -692,7 +718,8 @@ module.exports = function (homebridge) { numToHex(swap32(this.history[this.memAddress].time - this.refTime - _EPOCH), 8), this.accessoryType117bis, numToHex(this.history[this.memAddress].status, 2), - numToHex(swap32(this.history[this.memAddress].waterAmount), 8)) + numToHex(swap32(this.history[this.memAddress].waterAmount), 8) + ) } break case 'thermo': @@ -703,7 +730,8 @@ module.exports = function (homebridge) { this.accessoryType117, numToHex(swap16(this.history[this.memAddress].currentTemp * 100), 4), numToHex(swap16(this.history[this.memAddress].setTemp * 100), 4), - numToHex(this.history[this.memAddress].valvePosition, 2)) + numToHex(this.history[this.memAddress].valvePosition, 2) + ) break case 'custom': { const result = [] @@ -751,13 +779,11 @@ module.exports = function (homebridge) { } } } - const results = dataStream + - ' ' + - numToHex(bitmask, 2) + + const results = + dataStream + ' ' + numToHex(bitmask, 2) + ' ' + result.map(a => a).join(' ') + this.dataStream += ' ' + - result.map(a => a).join(' ') - this.dataStream += ' ' + - numToHex((results.replace(/[^0-9A-F]/ig, '').length) / 2 + 1) + + numToHex(results.replace(/[^0-9A-F]/gi, '').length / 2 + 1) + ' ' + results + ',' diff --git a/lib/fakegato/fakegato-storage.js b/lib/fakegato/fakegato-storage.js index a97be704..290184b3 100644 --- a/lib/fakegato/fakegato-storage.js +++ b/lib/fakegato/fakegato-storage.js @@ -32,7 +32,7 @@ class FakeGatoStorage { callback: params.callback, fileName: hostname + '_' + service.accessoryName + '_persist.json' } - const onReady = typeof (params.onReady) === 'function' ? params.onReady : () => {} + const onReady = typeof params.onReady === 'function' ? params.onReady : () => {} newWriter.storageHandler = fs newWriter.path = params.path || path.join(os.homedir(), '.homebridge') this.writers.push(newWriter) @@ -64,12 +64,16 @@ class FakeGatoStorage { if (!this.writing) { this.writing = true const writer = this.getWriter(params.service) - const callBack = typeof (params.callback) === 'function' - ? params.callback - : (typeof (writer.callback) === 'function' ? writer.callback : () => {}) + const callBack = + typeof params.callback === 'function' + ? params.callback + : typeof writer.callback === 'function' + ? writer.callback + : () => {} this.log( 'FG storage: write file [%s].', - path.join(writer.path, writer.fileName), params.data.substr(1, 80) + path.join(writer.path, writer.fileName), + params.data.substr(1, 80) ) writer.storageHandler.writeFile( path.join(writer.path, writer.fileName), @@ -87,18 +91,24 @@ class FakeGatoStorage { read (params) { const writer = this.getWriter(params.service) - const callBack = typeof (params.callback) === 'function' - ? params.callback - : (typeof (writer.callback) === 'function' ? writer.callback : () => {}) + const callBack = + typeof params.callback === 'function' + ? params.callback + : typeof writer.callback === 'function' + ? writer.callback + : () => {} this.log('FG storage: read file [%s].', path.join(writer.path, writer.fileName)) writer.storageHandler.readFile(path.join(writer.path, writer.fileName), 'utf8', callBack) } remove (params) { const writer = this.getWriter(params.service) - const callBack = typeof (params.callback) === 'function' - ? params.callback - : (typeof (writer.callback) === 'function' ? writer.callback : () => {}) + const callBack = + typeof params.callback === 'function' + ? params.callback + : typeof writer.callback === 'function' + ? writer.callback + : () => {} this.log('FG storage: delete file [%s].', path.join(writer.path, writer.fileName)) writer.storageHandler.unlink(path.join(writer.path, writer.fileName), callBack) } diff --git a/lib/fakegato/fakegato-timer.js b/lib/fakegato/fakegato-timer.js index d64a3441..2d0e1119 100644 --- a/lib/fakegato/fakegato-timer.js +++ b/lib/fakegato/fakegato-timer.js @@ -71,7 +71,7 @@ class FakeGatoTimer { for (const s in this.subscribedServices) { if (Object.prototype.hasOwnProperty.call(this.subscribedServices, s)) { const service = this.subscribedServices[s] - if (typeof (service.callback) === 'function') { + if (typeof service.callback === 'function') { service.previousAvrg = service.callback({ backLog: service.backLog, previousAvrg: service.previousAvrg, @@ -86,7 +86,7 @@ class FakeGatoTimer { executeImmediateCallback (service) { this.log('FG timer: executeImmediateCallback().') - if (typeof (service.callback) === 'function' && service.backLog.length) { + if (typeof service.callback === 'function' && service.backLog.length) { service.callback({ backLog: service.backLog, timer: this, diff --git a/lib/fakegato/uuid.js b/lib/fakegato/uuid.js index 56a47fd2..f7b8f19c 100644 --- a/lib/fakegato/uuid.js +++ b/lib/fakegato/uuid.js @@ -25,7 +25,7 @@ function toLongFormUUID (uuid, base = '-0000-1000-8000-0026BB765291') { function toShortFormUUID (uuid, base = '-0000-1000-8000-0026BB765291') { uuid = toLongFormUUID(uuid, base) - return (uuid.substr(0, 8)) + return uuid.substr(0, 8) } exports.isValid = isValid diff --git a/lib/homebridge-ui/public/index.html b/lib/homebridge-ui/public/index.html index da445271..a9385ca0 100644 --- a/lib/homebridge-ui/public/index.html +++ b/lib/homebridge-ui/public/index.html @@ -1,18 +1,46 @@

        - homebridge-ewelink logo + homebridge-ewelink logo

        -