From 08f5866536ad3b21ac76b5d4acbb0e901f9ea499 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Mon, 15 Jul 2024 07:32:17 +0100 Subject: [PATCH] Split appliances into different files for more specific features per model --- CHANGELOG.md | 6 + ...{dehumidifier.js => dehumidifier-H7150.js} | 4 +- lib/device/dehumidifier-H7151.js | 157 ++++++++ lib/device/{diffuser.js => diffuser-H7161.js} | 0 lib/device/diffuser-H7162.js | 117 ++++++ lib/device/fan.js | 1 + lib/device/humidifier-H7140.js | 224 ++++++++++++ ...umidifier-h7141.js => humidifier-H7141.js} | 0 ...umidifier-h7142.js => humidifier-H7142.js} | 0 .../{humidifier.js => humidifier-H7143.js} | 43 +-- ...umidifier-h7160.js => humidifier-H7160.js} | 0 .../{ice-maker.js => ice-maker-H7162.js} | 0 lib/device/index.js | 40 ++- lib/device/{purifier.js => purifier-H7120.js} | 28 +- lib/device/purifier-H7121.js | 336 ++++++++++++++++++ .../{purifier-h7122.js => purifier-H7122.js} | 1 + .../{purifier-h7123.js => purifier-H7123.js} | 1 + lib/device/purifier-H7126.js | 310 ++++++++++++++++ lib/device/sensor-monitor.js | 1 + lib/platform.js | 32 +- lib/utils/constants.js | 2 +- 21 files changed, 1194 insertions(+), 109 deletions(-) rename lib/device/{dehumidifier.js => dehumidifier-H7150.js} (97%) create mode 100644 lib/device/dehumidifier-H7151.js rename lib/device/{diffuser.js => diffuser-H7161.js} (100%) create mode 100644 lib/device/diffuser-H7162.js create mode 100644 lib/device/humidifier-H7140.js rename lib/device/{humidifier-h7141.js => humidifier-H7141.js} (100%) rename lib/device/{humidifier-h7142.js => humidifier-H7142.js} (100%) rename lib/device/{humidifier.js => humidifier-H7143.js} (90%) rename lib/device/{humidifier-h7160.js => humidifier-H7160.js} (100%) rename lib/device/{ice-maker.js => ice-maker-H7162.js} (100%) rename lib/device/{purifier.js => purifier-H7120.js} (96%) create mode 100644 lib/device/purifier-H7121.js rename lib/device/{purifier-h7122.js => purifier-H7122.js} (99%) rename lib/device/{purifier-h7123.js => purifier-H7123.js} (99%) create mode 100644 lib/device/purifier-H7126.js diff --git a/CHANGELOG.md b/CHANGELOG.md index f6f993fc..093d6cf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ This project tries to adhere to [Semantic Versioning](http://semver.org/). In pr - `MINOR` version when a new device type is added, or when a new feature is added that is backwards-compatible - `PATCH` version when backwards-compatible bug fixes are implemented +## 10.9.2 (2024-07-15) + +### Changed + +- Split appliances into different files for more specific features per model + ## 10.9.1 (2024-07-13) ### Changed diff --git a/lib/device/dehumidifier.js b/lib/device/dehumidifier-H7150.js similarity index 97% rename from lib/device/dehumidifier.js rename to lib/device/dehumidifier-H7150.js index 46ff4b58..9ccbb0bf 100644 --- a/lib/device/dehumidifier.js +++ b/lib/device/dehumidifier-H7150.js @@ -170,7 +170,9 @@ export default class { return; } - switch (command) { + const deviceFunction = `${getTwoItemPosition(hexParts, 2)}${getTwoItemPosition(hexParts, 3)}`; + + switch (deviceFunction) { default: this.accessory.logWarn(`${platformLang.newScene}: [${command}] [${hexString}]`); break; diff --git a/lib/device/dehumidifier-H7151.js b/lib/device/dehumidifier-H7151.js new file mode 100644 index 00000000..c1cd6ecf --- /dev/null +++ b/lib/device/dehumidifier-H7151.js @@ -0,0 +1,157 @@ +import { + base64ToHex, + getTwoItemPosition, + hexToTwoItems, + parseError, +} from '../utils/functions.js'; +import platformLang from '../utils/lang-en.js'; + +export default class { + constructor(platform, accessory) { + // Set up variables from the platform + this.hapChar = platform.api.hap.Characteristic; + this.hapErr = platform.api.hap.HapStatusError; + this.hapServ = platform.api.hap.Service; + this.platform = platform; + + // Set up variables from the accessory + this.accessory = accessory; + + // Rotation speed to value in {1, 2, ..., 8} + this.speed2Value = (speed) => Math.min(Math.max(parseInt(Math.round(speed / 10), 10), 1), 8); + + // Speed codes + this.value2Code = { + 1: 'MwUBAQAAAAAAAAAAAAAAAAAAADY=', + 2: 'MwUBAgAAAAAAAAAAAAAAAAAAADU=', + 3: 'MwUBAwAAAAAAAAAAAAAAAAAAADQ=', + 4: 'MwUBBAAAAAAAAAAAAAAAAAAAADM=', + 5: 'MwUBBQAAAAAAAAAAAAAAAAAAADI=', + 6: 'MwUBBgAAAAAAAAAAAAAAAAAAADE=', + 7: 'MwUBBwAAAAAAAAAAAAAAAAAAADA=', + 8: 'MwUBCAAAAAAAAAAAAAAAAAAAAD8=', + }; + + // Add the fan service if it doesn't already exist + 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) => this.internalStateUpdate(value)); + this.cacheState = this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off'; + + // Add the set handler to the fan rotation speed characteristic + this.service + .getCharacteristic(this.hapChar.RotationSpeed) + .setProps({ + minStep: 10, + validValues: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100], + }) + .onSet(async (value) => this.internalSpeedUpdate(value)); + this.cacheSpeed = this.service.getCharacteristic(this.hapChar.RotationSpeed).value; + + // Output the customised options to the log + const opts = JSON.stringify({}); + platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts); + } + + async internalStateUpdate(value) { + try { + const newValue = value ? 'on' : 'off'; + + // Don't continue if the new value is the same as before + if (this.cacheState === newValue) { + return; + } + + // Send the request to the platform sender function + await this.platform.sendDeviceUpdate(this.accessory, { + cmd: 'stateHumi', + value: value ? 1 : 0, + }); + + // Cache the new state and log if appropriate + this.cacheState = newValue; + this.accessory.log(`${platformLang.curState} [${newValue}]`); + } catch (err) { + // Catch any errors during the process + this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`); + + // Throw a 'no response' error and set a timeout to revert this after 2 seconds + setTimeout(() => { + this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on'); + }, 2000); + throw new this.hapErr(-70402); + } + } + + async internalSpeedUpdate(value) { + try { + // Don't continue if the speed is 0 + if (value === 0) { + return; + } + + // Get the single Govee value {1, 2, ..., 8} + const newValue = this.speed2Value(value); + + // Don't continue if the speed value won't have effect + if (newValue * 10 === this.cacheSpeed) { + return; + } + + // Get the scene code for this value + const newCode = this.value2Code[newValue]; + + // Send the request to the platform sender function + await this.platform.sendDeviceUpdate(this.accessory, { + cmd: 'ptReal', + value: newCode, + }); + + // Cache the new state and log if appropriate + this.cacheSpeed = newValue * 10; + this.accessory.log(`${platformLang.curSpeed} [${newValue}]`); + } catch (err) { + // Catch any errors during the process + this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`); + + // Throw a 'no response' error and set a timeout to revert this after 2 seconds + setTimeout(() => { + this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed); + }, 2000); + throw new this.hapErr(-70402); + } + } + + externalUpdate(params) { + // Check for an ON/OFF change + if (params.state && params.state !== this.cacheState) { + this.cacheState = params.state; + this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on'); + + // Log the change + this.accessory.log(`${platformLang.curState} [${this.cacheState}]`); + } + + // Check for some other scene/mode change + (params.commands || []).forEach((command) => { + const hexString = base64ToHex(command); + const hexParts = hexToTwoItems(hexString); + + // Return now if not a device query update code + if (getTwoItemPosition(hexParts, 1) !== 'aa') { + return; + } + + const deviceFunction = `${getTwoItemPosition(hexParts, 2)}${getTwoItemPosition(hexParts, 3)}`; + + switch (deviceFunction) { + default: + this.accessory.logWarn(`${platformLang.newScene}: [${command}] [${hexString}]`); + break; + } + }); + } +} diff --git a/lib/device/diffuser.js b/lib/device/diffuser-H7161.js similarity index 100% rename from lib/device/diffuser.js rename to lib/device/diffuser-H7161.js diff --git a/lib/device/diffuser-H7162.js b/lib/device/diffuser-H7162.js new file mode 100644 index 00000000..651a4b14 --- /dev/null +++ b/lib/device/diffuser-H7162.js @@ -0,0 +1,117 @@ +import { + base64ToHex, + getTwoItemPosition, + hexToTwoItems, + parseError, +} from '../utils/functions.js'; +import platformLang from '../utils/lang-en.js'; + +export default class { + constructor(platform, accessory) { + // Set up variables from the platform + this.hapChar = platform.api.hap.Characteristic; + this.hapErr = platform.api.hap.HapStatusError; + this.hapServ = platform.api.hap.Service; + this.platform = platform; + + // Set up variables from the accessory + this.accessory = accessory; + + // Remove fan service if exists + if (this.accessory.getService(this.hapServ.Fan)) { + this.accessory.removeService(this.accessory.getService(this.hapServ.Fan)); + } + + // Add the purifier service if it doesn't already exist + this.service = this.accessory.getService(this.hapServ.AirPurifier) + || this.accessory.addService(this.hapServ.AirPurifier); + + // Add the set handler to the switch on/off characteristic + this.service.getCharacteristic(this.hapChar.Active).onSet(async (value) => { + await this.internalStateUpdate(value); + }); + this.cacheState = this.service.getCharacteristic(this.hapChar.Active).value === 1 ? 'on' : 'off'; + + // Add options to the purifier target state characteristic + this.service + .getCharacteristic(this.hapChar.TargetAirPurifierState) + .updateValue(1) + .setProps({ + minValue: 1, + maxValue: 1, + validValues: [1], + }); + + // Output the customised options to the log + const opts = JSON.stringify({}); + platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts); + } + + async internalStateUpdate(value) { + try { + const newValue = value === 1 ? 'on' : 'off'; + + // Don't continue if the new value is the same as before + if (this.cacheState === newValue) { + return; + } + + // Send the request to the platform sender function + await this.platform.sendDeviceUpdate(this.accessory, { + cmd: 'stateHumi', + value, + }); + + // Cache the new state and log if appropriate + if (this.cacheState !== newValue) { + this.cacheState = newValue; + this.accessory.log(`${platformLang.curState} [${this.cacheState}]`); + } + + this.service.updateCharacteristic(this.hapChar.CurrentAirPurifierState, value === 1 ? 2 : 0); + } catch (err) { + // Catch any errors during the process + this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`); + + // Throw a 'no response' error and set a timeout to revert this after 2 seconds + setTimeout(() => { + this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0); + }, 2000); + throw new this.hapErr(-70402); + } + } + + externalUpdate(params) { + // Check for an ON/OFF change + if (params.state && params.state !== this.cacheState) { + this.cacheState = params.state; + this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0); + this.service.updateCharacteristic( + this.hapChar.CurrentAirPurifierState, + this.cacheState === 'on' ? 2 : 0, + ); + + // Log the change + this.accessory.log(`${platformLang.curState} [${this.cacheState}]`); + } + + // Check for some other scene/mode change + (params.commands || []).forEach((command) => { + const hexString = base64ToHex(command); + const hexParts = hexToTwoItems(hexString); + + // Return now if not a device query update code + if (getTwoItemPosition(hexParts, 1) !== 'aa') { + return; + } + + const deviceFunction = `${getTwoItemPosition(hexParts, 2)}${getTwoItemPosition(hexParts, 3)}`; + + switch (deviceFunction) { + default: + this.accessory.logWarn(`${platformLang.newScene}: [${command}] [${hexString}]`); + break; + } + }); + } +} diff --git a/lib/device/fan.js b/lib/device/fan.js index a6759676..4c5e921b 100644 --- a/lib/device/fan.js +++ b/lib/device/fan.js @@ -311,6 +311,7 @@ export default class { } const deviceFunction = `${getTwoItemPosition(hexParts, 2)}${getTwoItemPosition(hexParts, 3)}`; + switch (deviceFunction) { case '0501': { // Fan speed diff --git a/lib/device/humidifier-H7140.js b/lib/device/humidifier-H7140.js new file mode 100644 index 00000000..d862b202 --- /dev/null +++ b/lib/device/humidifier-H7140.js @@ -0,0 +1,224 @@ +import { hs2rgb } from '../utils/colour.js'; +import { + base64ToHex, + generateCodeFromHexValues, + getTwoItemPosition, + hexToTwoItems, + parseError, +} from '../utils/functions.js'; +import platformLang from '../utils/lang-en.js'; + +export default class { + constructor(platform, accessory) { + // Set up variables from the platform + this.hapChar = platform.api.hap.Characteristic; + this.hapErr = platform.api.hap.HapStatusError; + this.hapServ = platform.api.hap.Service; + this.platform = platform; + + // Set up variables from the accessory + this.accessory = accessory; + + // Rotation speed to value in {1, 2, ..., 8} + this.speed2Value = (speed) => Math.min(Math.max(parseInt(Math.round(speed / 10), 10), 1), 8); + + // Speed codes + this.value2Code = { + 1: 'MwUBAQAAAAAAAAAAAAAAAAAAADY=', + 2: 'MwUBAgAAAAAAAAAAAAAAAAAAADU=', + 3: 'MwUBAwAAAAAAAAAAAAAAAAAAADQ=', + 4: 'MwUBBAAAAAAAAAAAAAAAAAAAADM=', + 5: 'MwUBBQAAAAAAAAAAAAAAAAAAADI=', + 6: 'MwUBBgAAAAAAAAAAAAAAAAAAADE=', + 7: 'MwUBBwAAAAAAAAAAAAAAAAAAADA=', + 8: 'MwUBCAAAAAAAAAAAAAAAAAAAAD8=', + }; + + // Add the fan service if it doesn't already exist + this.service = this.accessory.getService(this.hapServ.Fan) || this.accessory.addService(this.hapServ.Fan); + + // Add the night light service if it doesn't already exist + this.lightService = this.accessory.getService(this.hapServ.Lightbulb) + || this.accessory.addService(this.hapServ.Lightbulb); + + // Add the set handler to the fan on/off characteristic + this.service + .getCharacteristic(this.hapChar.On) + .onSet(async (value) => this.internalStateUpdate(value)); + this.cacheState = this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off'; + + // Add the set handler to the fan rotation speed characteristic + this.service + .getCharacteristic(this.hapChar.RotationSpeed) + .setProps({ + minStep: 10, + validValues: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100], + }) + .onSet(async (value) => this.internalSpeedUpdate(value)); + this.cacheSpeed = this.service.getCharacteristic(this.hapChar.RotationSpeed).value; + + // Add the set handler to the lightbulb on/off characteristic + this.lightService.getCharacteristic(this.hapChar.On).onSet(async (value) => { + await this.internalLightStateUpdate(value); + }); + this.cacheLightState = this.lightService.getCharacteristic(this.hapChar.On).value ? 'on' : 'off'; + + // Output the customised options to the log + const opts = JSON.stringify({}); + platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts); + } + + async internalStateUpdate(value) { + try { + const newValue = value ? 'on' : 'off'; + + // Don't continue if the new value is the same as before + if (this.cacheState === newValue) { + return; + } + + // Send the request to the platform sender function + await this.platform.sendDeviceUpdate(this.accessory, { + cmd: 'stateHumi', + value: value ? 1 : 0, + }); + + // Cache the new state and log if appropriate + this.cacheState = newValue; + this.accessory.log(`${platformLang.curState} [${this.cacheState}]`); + } catch (err) { + // Catch any errors during the process + this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`); + + // Throw a 'no response' error and set a timeout to revert this after 2 seconds + setTimeout(() => { + this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on'); + }, 2000); + throw new this.hapErr(-70402); + } + } + + async internalSpeedUpdate(value) { + try { + // Don't continue if the speed is 0 + if (value === 0) { + return; + } + + // Get the single Govee value {1, 2, ..., 8} + const newValue = this.speed2Value(value); + + // Don't continue if the speed value won't have effect + if (newValue * 10 === this.cacheSpeed) { + return; + } + + // Get the scene code for this value + const newCode = this.value2Code[newValue]; + + // Send the request to the platform sender function + await this.platform.sendDeviceUpdate(this.accessory, { + cmd: 'ptReal', + value: newCode, + }); + + // Cache the new state and log if appropriate + this.cacheSpeed = newValue * 10; + this.accessory.log(`${platformLang.curSpeed} [${newValue}]`); + } catch (err) { + // Catch any errors during the process + this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`); + + // Throw a 'no response' error and set a timeout to revert this after 2 seconds + setTimeout(() => { + this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed); + }, 2000); + throw new this.hapErr(-70402); + } + } + + async internalLightStateUpdate(value) { + try { + const newValue = value ? 'on' : 'off'; + + // Don't continue if the new value is the same as before + if (this.cacheLightState === newValue) { + return; + } + + // Generate the hex values for the code + let hexValues; + if (value) { + // Calculate current RGB values + const newRGB = hs2rgb( + this.lightService.getCharacteristic(this.hapChar.Hue).value, + this.lightService.getCharacteristic(this.hapChar.Saturation).value, + ); + hexValues = [0x33, 0x1b, 0x01, this.cacheBright, ...newRGB]; + } else { + hexValues = [0x33, 0x1b, 0x00]; + } + + // Send the request to the platform sender function + await this.platform.sendDeviceUpdate(this.accessory, { + cmd: 'ptReal', + value: generateCodeFromHexValues(hexValues), + }); + + // Cache the new state and log if appropriate + if (this.cacheLightState !== newValue) { + this.cacheLightState = newValue; + this.accessory.log(`${platformLang.curLight} [${newValue}]`); + } + } catch (err) { + // Catch any errors during the process + this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`); + + // Throw a 'no response' error and set a timeout to revert this after 2 seconds + setTimeout(() => { + this.lightService.updateCharacteristic(this.hapChar.On, this.cacheLightState === 'on'); + }, 2000); + throw new this.hapErr(-70402); + } + } + + externalUpdate(params) { + // Check for an ON/OFF change + if (params.state && params.state !== this.cacheState) { + this.cacheState = params.state; + this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on'); + + // Log the change + this.accessory.log(`${platformLang.curState} [${this.cacheState}]`); + } + + // Check for some other scene/mode change + (params.commands || []).forEach((command) => { + const hexString = base64ToHex(command); + const hexParts = hexToTwoItems(hexString); + + // Return now if not a device query update code + if (getTwoItemPosition(hexParts, 1) !== 'aa') { + return; + } + + const deviceFunction = `${getTwoItemPosition(hexParts, 2)}${getTwoItemPosition(hexParts, 3)}`; + + switch (deviceFunction) { + case '1b00': // night light off + case '1b01': { // night light on + const newNight = deviceFunction === '1b01' ? 'on' : 'off'; + if (newNight !== this.cacheLightState) { + this.cacheLightState = newNight; + this.lightService.updateCharacteristic(this.hapChar.On, this.cacheLightState === 'on'); + this.accessory.log(`current night light state [${this.cacheLightState}]`); + } + break; + } + default: + this.accessory.logWarn(`${platformLang.newScene}: [${command}] [${hexString}]`); + break; + } + }); + } +} diff --git a/lib/device/humidifier-h7141.js b/lib/device/humidifier-H7141.js similarity index 100% rename from lib/device/humidifier-h7141.js rename to lib/device/humidifier-H7141.js diff --git a/lib/device/humidifier-h7142.js b/lib/device/humidifier-H7142.js similarity index 100% rename from lib/device/humidifier-h7142.js rename to lib/device/humidifier-H7142.js diff --git a/lib/device/humidifier.js b/lib/device/humidifier-H7143.js similarity index 90% rename from lib/device/humidifier.js rename to lib/device/humidifier-H7143.js index 8c440b14..1a432f76 100644 --- a/lib/device/humidifier.js +++ b/lib/device/humidifier-H7143.js @@ -6,45 +6,6 @@ import { } from '../utils/functions.js'; import platformLang from '../utils/lang-en.js'; -/* - H7160 - { - "mode": { - "options": [ - { - "name": "Manual", - "value": 1 - }, - { - "name": "Custom", - "value": 2 - }, - { - "name": "Auto", - "value": 3 - } - ] - }, - "gear": { - "options": [ - { - "name": "gear", - "value": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9 - ] - } - ] - } - } -*/ export default class { constructor(platform, accessory) { // Set up variables from the platform @@ -184,7 +145,9 @@ export default class { return; } - switch (command) { + const deviceFunction = `${getTwoItemPosition(hexParts, 2)}${getTwoItemPosition(hexParts, 3)}`; + + switch (deviceFunction) { default: this.accessory.logWarn(`${platformLang.newScene}: [${command}] [${hexString}]`); break; diff --git a/lib/device/humidifier-h7160.js b/lib/device/humidifier-H7160.js similarity index 100% rename from lib/device/humidifier-h7160.js rename to lib/device/humidifier-H7160.js diff --git a/lib/device/ice-maker.js b/lib/device/ice-maker-H7162.js similarity index 100% rename from lib/device/ice-maker.js rename to lib/device/ice-maker-H7162.js diff --git a/lib/device/index.js b/lib/device/index.js index acb9352e..25fccb60 100644 --- a/lib/device/index.js +++ b/lib/device/index.js @@ -1,26 +1,31 @@ import deviceCoolerSingle from './cooler-single.js'; -import deviceDehumidifier from './dehumidifier.js'; -import deviceDiffuser from './diffuser.js'; +import deviceDehumidifierH7150 from './dehumidifier-H7150.js'; +import deviceDehumidifierH7151 from './dehumidifier-H7151.js'; +import deviceDiffuserH7161 from './diffuser-H7161.js'; +import deviceDiffuserH7162 from './diffuser-H7162.js'; import deviceFan from './fan.js'; import deviceHeaterSingle from './heater-single.js'; import deviceHeater1A from './heater1a.js'; import deviceHeater1B from './heater1b.js'; import deviceHeater2 from './heater2.js'; -import deviceHumidifierH7141 from './humidifier-h7141.js'; -import deviceHumidifierH7142 from './humidifier-h7142.js'; -import deviceHumidifierH7160 from './humidifier-h7160.js'; -import deviceHumidifier from './humidifier.js'; -import deviceIceMaker from './ice-maker.js'; +import deviceHumidifierH7140 from './humidifier-H7140.js'; +import deviceHumidifierH7141 from './humidifier-H7141.js'; +import deviceHumidifierH7142 from './humidifier-H7142.js'; +import deviceHumidifierH7143 from './humidifier-H7143.js'; +import deviceHumidifierH7160 from './humidifier-H7160.js'; +import deviceIceMakerH7162 from './ice-maker-H7162.js'; import deviceKettle from './kettle.js'; import deviceLightSwitch from './light-switch.js'; import deviceLight from './light.js'; import deviceOutletDouble from './outlet-double.js'; import deviceOutletSingle from './outlet-single.js'; import deviceOutletTriple from './outlet-triple.js'; -import devicePurifierH7122 from './purifier-h7122.js'; -import devicePurifierH7123 from './purifier-h7123.js'; +import devicePurifierH7120 from './purifier-H7120.js'; +import devicePurifierH7121 from './purifier-H7121.js'; +import devicePurifierH7122 from './purifier-H7122.js'; +import devicePurifierH7123 from './purifier-H7123.js'; +import devicePurifierH7126 from './purifier-H7126.js'; import devicePurifierSingle from './purifier-single.js'; -import devicePurifier from './purifier.js'; import deviceSensorButton from './sensor-button.js'; import deviceSensorContact from './sensor-contact.js'; import deviceSensorLeak from './sensor-leak.js'; @@ -37,28 +42,33 @@ import deviceValveSingle from './valve-single.js'; export default { deviceCoolerSingle, - deviceDehumidifier, - deviceDiffuser, + deviceDehumidifierH7150, + deviceDehumidifierH7151, + deviceDiffuserH7161, + deviceDiffuserH7162, deviceFan, deviceHeaterSingle, deviceHeater1A, deviceHeater1B, deviceHeater2, + deviceHumidifierH7140, deviceHumidifierH7141, deviceHumidifierH7142, + deviceHumidifierH7143, deviceHumidifierH7160, - deviceHumidifier, - deviceIceMaker, + deviceIceMakerH7162, deviceKettle, deviceLight, deviceLightSwitch, deviceOutletDouble, deviceOutletSingle, deviceOutletTriple, + devicePurifierH7120, + devicePurifierH7121, devicePurifierH7122, devicePurifierH7123, + devicePurifierH7126, devicePurifierSingle, - devicePurifier, deviceSensorButton, deviceSensorContact, deviceSensorLeak, diff --git a/lib/device/purifier.js b/lib/device/purifier-H7120.js similarity index 96% rename from lib/device/purifier.js rename to lib/device/purifier-H7120.js index 86347733..b62289e3 100644 --- a/lib/device/purifier.js +++ b/lib/device/purifier-H7120.js @@ -30,30 +30,6 @@ import platformLang from '../utils/lang-en.js'; ] } } - - H7121 - { - "mode": { - "options": [ - { - "name": "Low", - "value": 1 - }, - { - "name": "Medium", - "value": 2 - }, - { - "name": "High", - "value": 3 - }, - { - "name": "Sleep", - "value": 16 - } - ] - } - } */ export default class { @@ -348,7 +324,9 @@ export default class { return; } - switch (command) { + const deviceFunction = `${getTwoItemPosition(hexParts, 2)}${getTwoItemPosition(hexParts, 3)}`; + + switch (deviceFunction) { default: this.accessory.logWarn(`${platformLang.newScene}: [${command}] [${hexString}]`); break; diff --git a/lib/device/purifier-H7121.js b/lib/device/purifier-H7121.js new file mode 100644 index 00000000..3cb17a92 --- /dev/null +++ b/lib/device/purifier-H7121.js @@ -0,0 +1,336 @@ +import { + base64ToHex, + getTwoItemPosition, + hexToTwoItems, + parseError, +} from '../utils/functions.js'; +import platformLang from '../utils/lang-en.js'; + +/* + H7121 + { + "mode": { + "options": [ + { + "name": "Low", + "value": 1 + }, + { + "name": "Medium", + "value": 2 + }, + { + "name": "High", + "value": 3 + }, + { + "name": "Sleep", + "value": 16 + } + ] + } + } + */ + +export default class { + constructor(platform, accessory) { + // Set up variables from the platform + this.cusChar = platform.cusChar; + this.hapChar = platform.api.hap.Characteristic; + this.hapErr = platform.api.hap.HapStatusError; + this.hapServ = platform.api.hap.Service; + this.platform = platform; + + // Set up variables from the accessory + this.accessory = accessory; + + // Rotation speed to value in {1, 2, 3, 4} + this.speed2Value = (speed) => Math.min(Math.max(parseInt(speed / 25, 10), 1), 4); + + // Speed codes + this.value2Code = { + 1: 'MwUQAAAAAAAAAAAAAAAAAAAAACY=', + 2: 'MwUBAAAAAAAAAAAAAAAAAAAAADc=', + 3: 'MwUCAAAAAAAAAAAAAAAAAAAAADQ=', + 4: 'MwUDAAAAAAAAAAAAAAAAAAAAADU=', + }; + + // Night light codes + this.night2Code = { + on: 'MxgBMgAAAAAAAAAAAAAAAAAAABg=', + off: 'MxgAMgAAAAAAAAAAAAAAAAAAABk=', + }; + + // Lock codes + this.lock2Code = { + on: 'MxABAAAAAAAAAAAAAAAAAAAAACI=', + off: 'MxAAAAAAAAAAAAAAAAAAAAAAACM=', + }; + + // Display codes + this.display2Code = { + on: 'MxYBAAAAAAAAAAAAAAAAAAAAACQ=', + off: 'MxYAAAAAAAAAAAAAAAAAAAAAACU=', + }; + + // Add the purifier service if it doesn't already exist + this.service = this.accessory.getService(this.hapServ.AirPurifier) + || this.accessory.addService(this.hapServ.AirPurifier); + + // Add the set handler to the switch on/off characteristic + this.service.getCharacteristic(this.hapChar.Active).onSet(async (value) => { + await this.internalStateUpdate(value); + }); + this.cacheState = this.service.getCharacteristic(this.hapChar.Active).value === 1 ? 'on' : 'off'; + + // Add options to the purifier target state characteristic + this.service + .getCharacteristic(this.hapChar.TargetAirPurifierState) + .updateValue(1) + .setProps({ + minValue: 1, + maxValue: 1, + validValues: [1], + }); + + // Add the set handler to the fan rotation speed characteristic + this.service + .getCharacteristic(this.hapChar.RotationSpeed) + .setProps({ + minStep: 25, + validValues: [0, 25, 50, 75, 100], + }) + .onSet(async (value) => this.internalSpeedUpdate(value)); + this.cacheSpeed = this.service.getCharacteristic(this.hapChar.RotationSpeed).value; + + // Add the set handler to the lock controls characteristic + this.service.getCharacteristic(this.hapChar.LockPhysicalControls).onSet(async (value) => { + await this.internalLockUpdate(value); + }); + this.cacheLock = this.service.getCharacteristic(this.hapChar.LockPhysicalControls).value === 1 ? 'on' : 'off'; + + // Add night light Eve characteristic if it doesn't exist already + if (!this.service.testCharacteristic(this.cusChar.NightLight)) { + this.service.addCharacteristic(this.cusChar.NightLight); + } + + // Add the set handler to the custom night light characteristic + this.service.getCharacteristic(this.cusChar.NightLight).onSet(async (value) => { + await this.internalNightLightUpdate(value); + }); + this.cacheLight = this.service.getCharacteristic(this.cusChar.NightLight).value ? 'on' : 'off'; + + // Add display light Eve characteristic if it doesn't exist already + if (!this.service.testCharacteristic(this.cusChar.DisplayLight)) { + this.service.addCharacteristic(this.cusChar.DisplayLight); + } + + // Add the set handler to the custom display light characteristic + this.service.getCharacteristic(this.cusChar.DisplayLight).onSet(async (value) => { + await this.internalDisplayLightUpdate(value); + }); + this.cacheDisplay = this.service.getCharacteristic(this.cusChar.DisplayLight).value + ? 'on' + : 'off'; + + // Output the customised options to the log + const opts = JSON.stringify({}); + platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts); + } + + async internalStateUpdate(value) { + try { + const newValue = value === 1 ? 'on' : 'off'; + + // Don't continue if the new value is the same as before + if (this.cacheState === newValue) { + return; + } + + // Send the request to the platform sender function + await this.platform.sendDeviceUpdate(this.accessory, { + cmd: 'statePuri', + value: value ? 1 : 0, + }); + + // Update the current state characteristic + this.service.updateCharacteristic(this.hapChar.CurrentAirPurifierState, value === 1 ? 2 : 0); + + // Cache the new state and log if appropriate + this.cacheState = newValue; + this.accessory.log(`${platformLang.curState} [${newValue}]`); + } catch (err) { + // Catch any errors during the process + this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`); + + // Throw a 'no response' error and set a timeout to revert this after 2 seconds + setTimeout(() => { + this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0); + }, 2000); + throw new this.hapErr(-70402); + } + } + + async internalSpeedUpdate(value) { + try { + // Don't continue if the speed is 0 + if (value === 0) { + return; + } + + // Get the single Govee value {1, 2, ..., 8} + const newValue = this.speed2Value(value); + + // Don't continue if the speed value won't have effect + if (newValue * 25 === this.cacheSpeed) { + return; + } + + // Get the scene code for this value + const newCode = this.value2Code[newValue]; + + // Send the request to the platform sender function + await this.platform.sendDeviceUpdate(this.accessory, { + cmd: 'ptReal', + value: newCode, + }); + + // Cache the new state and log if appropriate + this.cacheSpeed = newValue * 25; + this.accessory.log(`${platformLang.curSpeed} [${this.cacheSpeed}%]`); + } catch (err) { + // Catch any errors during the process + this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`); + + // Throw a 'no response' error and set a timeout to revert this after 2 seconds + setTimeout(() => { + this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed); + }, 2000); + throw new this.hapErr(-70402); + } + } + + async internalNightLightUpdate(value) { + try { + const newValue = value ? 'on' : 'off'; + + // Don't continue if the new value is the same as before + if (this.cacheLight === newValue) { + return; + } + + // Send the request to the platform sender function + await this.platform.sendDeviceUpdate(this.accessory, { + cmd: 'ptReal', + value: this.night2Code[newValue], + }); + + // Cache the new state and log if appropriate + this.cacheLight = newValue; + this.accessory.log(`${platformLang.curLight} [${newValue}]`); + } catch (err) { + // Catch any errors during the process + this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`); + + // Throw a 'no response' error and set a timeout to revert this after 2 seconds + setTimeout(() => { + this.service.updateCharacteristic(this.cusChar.NightLight, this.cacheLight === 'on'); + }, 2000); + throw new this.hapErr(-70402); + } + } + + async internalLockUpdate(value) { + try { + const newValue = value === 1 ? 'on' : 'off'; + + // Don't continue if the new value is the same as before + if (this.cacheLock === newValue) { + return; + } + + // Send the request to the platform sender function + await this.platform.sendDeviceUpdate(this.accessory, { + cmd: 'ptReal', + value: this.lock2Code[newValue], + }); + + // Cache the new state and log if appropriate + this.cacheLock = newValue; + this.accessory.log(`${platformLang.curLock} [${newValue}]`); + } catch (err) { + // Catch any errors during the process + this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`); + + // Throw a 'no response' error and set a timeout to revert this after 2 seconds + setTimeout(() => { + this.service.updateCharacteristic( + this.hapChar.LockPhysicalControls, + this.cacheLock === 'on' ? 1 : 0, + ); + }, 2000); + throw new this.hapErr(-70402); + } + } + + async internalDisplayLightUpdate(value) { + try { + const newValue = value ? 'on' : 'off'; + + // Don't continue if the new value is the same as before + if (this.cacheDisplay === newValue) { + return; + } + + // Send the request to the platform sender function + await this.platform.sendDeviceUpdate(this.accessory, { + cmd: 'ptReal', + value: this.display2Code[newValue], + }); + + // Cache the new state and log if appropriate + this.cacheDisplay = newValue; + this.accessory.log(`${platformLang.curDisplay} [${newValue}]`); + } catch (err) { + // Catch any errors during the process + this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`); + + // Throw a 'no response' error and set a timeout to revert this after 2 seconds + setTimeout(() => { + this.service.updateCharacteristic(this.cusChar.DisplayLight, this.cacheLight === 'on'); + }, 2000); + throw new this.hapErr(-70402); + } + } + + externalUpdate(params) { + // Check for an ON/OFF change + if (params.state && params.state !== this.cacheState) { + this.cacheState = params.state; + this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on'); + this.service.updateCharacteristic(this.hapChar.CurrentAirPurifierState, this.cacheState === 'on' ? 2 : 0); + + // Log the change + this.accessory.log(`${platformLang.curState} [${this.cacheState}]`); + } + + // Check for some other scene/mode change + (params.commands || []).forEach((command) => { + const hexString = base64ToHex(command); + const hexParts = hexToTwoItems(hexString); + + // Return now if not a device query update code + if (getTwoItemPosition(hexParts, 1) !== 'aa') { + return; + } + + const deviceFunction = `${getTwoItemPosition(hexParts, 2)}${getTwoItemPosition(hexParts, 3)}`; + + switch (deviceFunction) { + default: + this.accessory.logWarn(`${platformLang.newScene}: [${command}] [${hexString}]`); + break; + } + }); + } +} diff --git a/lib/device/purifier-h7122.js b/lib/device/purifier-H7122.js similarity index 99% rename from lib/device/purifier-h7122.js rename to lib/device/purifier-H7122.js index bf1b281a..ded5d84b 100644 --- a/lib/device/purifier-h7122.js +++ b/lib/device/purifier-H7122.js @@ -299,6 +299,7 @@ export default class { const hexParts = hexToTwoItems(hexString); const deviceFunction = `${getTwoItemPosition(hexParts, 1)}${getTwoItemPosition(hexParts, 2)}`; + switch (deviceFunction) { case 'aa05': // speed case '3a05': { // speed diff --git a/lib/device/purifier-h7123.js b/lib/device/purifier-H7123.js similarity index 99% rename from lib/device/purifier-h7123.js rename to lib/device/purifier-H7123.js index b14e2442..bedd87cb 100644 --- a/lib/device/purifier-h7123.js +++ b/lib/device/purifier-H7123.js @@ -302,6 +302,7 @@ export default class { const hexParts = hexToTwoItems(hexString); const deviceFunction = `${getTwoItemPosition(hexParts, 1)}${getTwoItemPosition(hexParts, 2)}`; + switch (deviceFunction) { case 'aa05': // speed case '3a05': { // speed diff --git a/lib/device/purifier-H7126.js b/lib/device/purifier-H7126.js new file mode 100644 index 00000000..78a6aad0 --- /dev/null +++ b/lib/device/purifier-H7126.js @@ -0,0 +1,310 @@ +import { + base64ToHex, + getTwoItemPosition, + hexToTwoItems, + parseError, +} from '../utils/functions.js'; +import platformLang from '../utils/lang-en.js'; + +export default class { + constructor(platform, accessory) { + // Set up variables from the platform + this.cusChar = platform.cusChar; + this.hapChar = platform.api.hap.Characteristic; + this.hapErr = platform.api.hap.HapStatusError; + this.hapServ = platform.api.hap.Service; + this.platform = platform; + + // Set up variables from the accessory + this.accessory = accessory; + + // Rotation speed to value in {1, 2, 3, 4} + this.speed2Value = (speed) => Math.min(Math.max(parseInt(speed / 25, 10), 1), 4); + + // Speed codes + this.value2Code = { + 1: 'MwUQAAAAAAAAAAAAAAAAAAAAACY=', + 2: 'MwUBAAAAAAAAAAAAAAAAAAAAADc=', + 3: 'MwUCAAAAAAAAAAAAAAAAAAAAADQ=', + 4: 'MwUDAAAAAAAAAAAAAAAAAAAAADU=', + }; + + // Night light codes + this.night2Code = { + on: 'MxgBMgAAAAAAAAAAAAAAAAAAABg=', + off: 'MxgAMgAAAAAAAAAAAAAAAAAAABk=', + }; + + // Lock codes + this.lock2Code = { + on: 'MxABAAAAAAAAAAAAAAAAAAAAACI=', + off: 'MxAAAAAAAAAAAAAAAAAAAAAAACM=', + }; + + // Display codes + this.display2Code = { + on: 'MxYBAAAAAAAAAAAAAAAAAAAAACQ=', + off: 'MxYAAAAAAAAAAAAAAAAAAAAAACU=', + }; + + // Add the purifier service if it doesn't already exist + this.service = this.accessory.getService(this.hapServ.AirPurifier) + || this.accessory.addService(this.hapServ.AirPurifier); + + // Add the set handler to the switch on/off characteristic + this.service.getCharacteristic(this.hapChar.Active).onSet(async (value) => { + await this.internalStateUpdate(value); + }); + this.cacheState = this.service.getCharacteristic(this.hapChar.Active).value === 1 ? 'on' : 'off'; + + // Add options to the purifier target state characteristic + this.service + .getCharacteristic(this.hapChar.TargetAirPurifierState) + .updateValue(1) + .setProps({ + minValue: 1, + maxValue: 1, + validValues: [1], + }); + + // Add the set handler to the fan rotation speed characteristic + this.service + .getCharacteristic(this.hapChar.RotationSpeed) + .setProps({ + minStep: 25, + validValues: [0, 25, 50, 75, 100], + }) + .onSet(async (value) => this.internalSpeedUpdate(value)); + this.cacheSpeed = this.service.getCharacteristic(this.hapChar.RotationSpeed).value; + + // Add the set handler to the lock controls characteristic + this.service.getCharacteristic(this.hapChar.LockPhysicalControls).onSet(async (value) => { + await this.internalLockUpdate(value); + }); + this.cacheLock = this.service.getCharacteristic(this.hapChar.LockPhysicalControls).value === 1 ? 'on' : 'off'; + + // Add night light Eve characteristic if it doesn't exist already + if (!this.service.testCharacteristic(this.cusChar.NightLight)) { + this.service.addCharacteristic(this.cusChar.NightLight); + } + + // Add the set handler to the custom night light characteristic + this.service.getCharacteristic(this.cusChar.NightLight).onSet(async (value) => { + await this.internalNightLightUpdate(value); + }); + this.cacheLight = this.service.getCharacteristic(this.cusChar.NightLight).value ? 'on' : 'off'; + + // Add display light Eve characteristic if it doesn't exist already + if (!this.service.testCharacteristic(this.cusChar.DisplayLight)) { + this.service.addCharacteristic(this.cusChar.DisplayLight); + } + + // Add the set handler to the custom display light characteristic + this.service.getCharacteristic(this.cusChar.DisplayLight).onSet(async (value) => { + await this.internalDisplayLightUpdate(value); + }); + this.cacheDisplay = this.service.getCharacteristic(this.cusChar.DisplayLight).value + ? 'on' + : 'off'; + + // Output the customised options to the log + const opts = JSON.stringify({}); + platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts); + } + + async internalStateUpdate(value) { + try { + const newValue = value === 1 ? 'on' : 'off'; + + // Don't continue if the new value is the same as before + if (this.cacheState === newValue) { + return; + } + + // Send the request to the platform sender function + await this.platform.sendDeviceUpdate(this.accessory, { + cmd: 'statePuri', + value: value ? 1 : 0, + }); + + // Update the current state characteristic + this.service.updateCharacteristic(this.hapChar.CurrentAirPurifierState, value === 1 ? 2 : 0); + + // Cache the new state and log if appropriate + this.cacheState = newValue; + this.accessory.log(`${platformLang.curState} [${newValue}]`); + } catch (err) { + // Catch any errors during the process + this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`); + + // Throw a 'no response' error and set a timeout to revert this after 2 seconds + setTimeout(() => { + this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0); + }, 2000); + throw new this.hapErr(-70402); + } + } + + async internalSpeedUpdate(value) { + try { + // Don't continue if the speed is 0 + if (value === 0) { + return; + } + + // Get the single Govee value {1, 2, ..., 8} + const newValue = this.speed2Value(value); + + // Don't continue if the speed value won't have effect + if (newValue * 25 === this.cacheSpeed) { + return; + } + + // Get the scene code for this value + const newCode = this.value2Code[newValue]; + + // Send the request to the platform sender function + await this.platform.sendDeviceUpdate(this.accessory, { + cmd: 'ptReal', + value: newCode, + }); + + // Cache the new state and log if appropriate + this.cacheSpeed = newValue * 25; + this.accessory.log(`${platformLang.curSpeed} [${this.cacheSpeed}%]`); + } catch (err) { + // Catch any errors during the process + this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`); + + // Throw a 'no response' error and set a timeout to revert this after 2 seconds + setTimeout(() => { + this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed); + }, 2000); + throw new this.hapErr(-70402); + } + } + + async internalNightLightUpdate(value) { + try { + const newValue = value ? 'on' : 'off'; + + // Don't continue if the new value is the same as before + if (this.cacheLight === newValue) { + return; + } + + // Send the request to the platform sender function + await this.platform.sendDeviceUpdate(this.accessory, { + cmd: 'ptReal', + value: this.night2Code[newValue], + }); + + // Cache the new state and log if appropriate + this.cacheLight = newValue; + this.accessory.log(`${platformLang.curLight} [${newValue}]`); + } catch (err) { + // Catch any errors during the process + this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`); + + // Throw a 'no response' error and set a timeout to revert this after 2 seconds + setTimeout(() => { + this.service.updateCharacteristic(this.cusChar.NightLight, this.cacheLight === 'on'); + }, 2000); + throw new this.hapErr(-70402); + } + } + + async internalLockUpdate(value) { + try { + const newValue = value === 1 ? 'on' : 'off'; + + // Don't continue if the new value is the same as before + if (this.cacheLock === newValue) { + return; + } + + // Send the request to the platform sender function + await this.platform.sendDeviceUpdate(this.accessory, { + cmd: 'ptReal', + value: this.lock2Code[newValue], + }); + + // Cache the new state and log if appropriate + this.cacheLock = newValue; + this.accessory.log(`${platformLang.curLock} [${newValue}]`); + } catch (err) { + // Catch any errors during the process + this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`); + + // Throw a 'no response' error and set a timeout to revert this after 2 seconds + setTimeout(() => { + this.service.updateCharacteristic( + this.hapChar.LockPhysicalControls, + this.cacheLock === 'on' ? 1 : 0, + ); + }, 2000); + throw new this.hapErr(-70402); + } + } + + async internalDisplayLightUpdate(value) { + try { + const newValue = value ? 'on' : 'off'; + + // Don't continue if the new value is the same as before + if (this.cacheDisplay === newValue) { + return; + } + + // Send the request to the platform sender function + await this.platform.sendDeviceUpdate(this.accessory, { + cmd: 'ptReal', + value: this.display2Code[newValue], + }); + + // Cache the new state and log if appropriate + this.cacheDisplay = newValue; + this.accessory.log(`${platformLang.curDisplay} [${newValue}]`); + } catch (err) { + // Catch any errors during the process + this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`); + + // Throw a 'no response' error and set a timeout to revert this after 2 seconds + setTimeout(() => { + this.service.updateCharacteristic(this.cusChar.DisplayLight, this.cacheLight === 'on'); + }, 2000); + throw new this.hapErr(-70402); + } + } + + externalUpdate(params) { + // Check for an ON/OFF change + if (params.state && params.state !== this.cacheState) { + this.cacheState = params.state; + this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on'); + this.service.updateCharacteristic(this.hapChar.CurrentAirPurifierState, this.cacheState === 'on' ? 2 : 0); + + // Log the change + this.accessory.log(`${platformLang.curState} [${this.cacheState}]`); + } + + // Check for some other scene/mode change + (params.commands || []).forEach((command) => { + const hexString = base64ToHex(command); + const hexParts = hexToTwoItems(hexString); + + // Return now if not a device query update code + if (getTwoItemPosition(hexParts, 1) !== 'aa') { + return; + } + + const deviceFunction = `${getTwoItemPosition(hexParts, 2)}${getTwoItemPosition(hexParts, 3)}`; + + switch (deviceFunction) { + default: + this.accessory.logWarn(`${platformLang.newScene}: [${command}] [${hexString}]`); + break; + } + }); + } +} diff --git a/lib/device/sensor-monitor.js b/lib/device/sensor-monitor.js index edecea19..a132ccc6 100644 --- a/lib/device/sensor-monitor.js +++ b/lib/device/sensor-monitor.js @@ -65,6 +65,7 @@ export default class { const hexParts = hexToTwoItems(hexString); const deviceFunction = `${getTwoItemPosition(hexParts, 1)}${getTwoItemPosition(hexParts, 2)}`; + switch (deviceFunction) { case '0000': case '0003': diff --git a/lib/platform.js b/lib/platform.js index 3ec78e36..3d7aba71 100644 --- a/lib/platform.js +++ b/lib/platform.js @@ -983,44 +983,22 @@ export default class { accessory = devicesInHB.get(uuid) || this.addAccessory(device); } else if (platformConsts.models.humidifier.includes(device.model)) { // Device is a humidifier - switch (device.model) { - case 'H7141': - devInstance = deviceTypes.deviceHumidifierH7141; - break; - case 'H7142': - devInstance = deviceTypes.deviceHumidifierH7142; - break; - case 'H7160': - devInstance = deviceTypes.deviceHumidifierH7160; - break; - default: // currently unused - devInstance = deviceTypes.deviceHumidifier; - break; - } doAWSPolling = true; + devInstance = deviceTypes[`deviceHumidifier${device.model}`]; accessory = devicesInHB.get(uuid) || this.addAccessory(device); } else if (platformConsts.models.dehumidifier.includes(device.model)) { // Device is a dehumidifier - devInstance = deviceTypes.deviceDehumidifier; + devInstance = deviceTypes[`deviceDehumidifier${device.model}`]; doAWSPolling = true; accessory = devicesInHB.get(uuid) || this.addAccessory(device); } else if (platformConsts.models.purifier.includes(device.model)) { // Device is a purifier - switch (device.model) { - case 'H7122': - devInstance = deviceTypes.devicePurifierH7122; - break; - case 'H7123': - devInstance = deviceTypes.devicePurifierH7123; - break; - default: - devInstance = deviceTypes.devicePurifier; - } + devInstance = deviceTypes[`devicePurifier${device.model}`]; doAWSPolling = true; accessory = devicesInHB.get(uuid) || this.addAccessory(device); } else if (platformConsts.models.diffuser.includes(device.model)) { // Device is a diffuser - devInstance = deviceTypes.deviceDiffuser; + devInstance = deviceTypes[`deviceDiffuser${device.model}`]; doAWSPolling = true; accessory = devicesInHB.get(uuid) || this.addAccessory(device); } else if (platformConsts.models.sensorButton.includes(device.model)) { @@ -1037,7 +1015,7 @@ export default class { accessory = devicesInHB.get(uuid) || this.addAccessory(device); } else if (platformConsts.models.iceMaker.includes(device.model)) { // Device is an ice maker - devInstance = deviceTypes.deviceIceMaker; + devInstance = deviceTypes[`deviceIceMaker${device.model}`]; accessory = devicesInHB.get(uuid) || this.addAccessory(device); } else if (platformConsts.models.template.includes(device.model)) { // Device is a work-in-progress diff --git a/lib/utils/constants.js b/lib/utils/constants.js index 08e32418..3130f349 100644 --- a/lib/utils/constants.js +++ b/lib/utils/constants.js @@ -411,7 +411,7 @@ export default { sensorButton: ['H5122'], sensorContact: ['H5123'], kettle: ['H7170', 'H7171', 'H7173', 'H7175'], - template: ['H1162', 'H5043', 'H5122', 'H7162'], // H7162 is a diffuser + template: ['H1162', 'H5043', 'H5122'], }, lanModels: [