@homebridge-plugins/homebridge-govee 10.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/CHANGELOG.md +1937 -0
  2. package/LICENSE +21 -0
  3. package/README.md +72 -0
  4. package/config.schema.json +1727 -0
  5. package/eslint.config.js +49 -0
  6. package/lib/connection/aws.js +174 -0
  7. package/lib/connection/ble.js +208 -0
  8. package/lib/connection/cert/AmazonRootCA1.pem +20 -0
  9. package/lib/connection/http.js +240 -0
  10. package/lib/connection/lan.js +284 -0
  11. package/lib/device/cooler-single.js +300 -0
  12. package/lib/device/dehumidifier-H7150.js +182 -0
  13. package/lib/device/dehumidifier-H7151.js +157 -0
  14. package/lib/device/diffuser-H7161.js +117 -0
  15. package/lib/device/diffuser-H7162.js +117 -0
  16. package/lib/device/fan-H7100.js +274 -0
  17. package/lib/device/fan-H7101.js +330 -0
  18. package/lib/device/fan-H7102.js +274 -0
  19. package/lib/device/fan-H7105.js +503 -0
  20. package/lib/device/fan-H7106.js +274 -0
  21. package/lib/device/fan-H7111.js +335 -0
  22. package/lib/device/heater-single.js +300 -0
  23. package/lib/device/heater1a.js +353 -0
  24. package/lib/device/heater1b.js +616 -0
  25. package/lib/device/heater2.js +838 -0
  26. package/lib/device/humidifier-H7140.js +224 -0
  27. package/lib/device/humidifier-H7141.js +257 -0
  28. package/lib/device/humidifier-H7142.js +522 -0
  29. package/lib/device/humidifier-H7143.js +157 -0
  30. package/lib/device/humidifier-H7148.js +157 -0
  31. package/lib/device/humidifier-H7160.js +446 -0
  32. package/lib/device/ice-maker-H7162.js +46 -0
  33. package/lib/device/index.js +105 -0
  34. package/lib/device/kettle.js +269 -0
  35. package/lib/device/light-switch.js +86 -0
  36. package/lib/device/light.js +617 -0
  37. package/lib/device/outlet-double.js +121 -0
  38. package/lib/device/outlet-single.js +172 -0
  39. package/lib/device/outlet-triple.js +160 -0
  40. package/lib/device/purifier-H7120.js +336 -0
  41. package/lib/device/purifier-H7121.js +336 -0
  42. package/lib/device/purifier-H7122.js +449 -0
  43. package/lib/device/purifier-H7123.js +411 -0
  44. package/lib/device/purifier-H7124.js +411 -0
  45. package/lib/device/purifier-H7126.js +296 -0
  46. package/lib/device/purifier-H7127.js +296 -0
  47. package/lib/device/purifier-H712C.js +296 -0
  48. package/lib/device/purifier-single.js +119 -0
  49. package/lib/device/sensor-button.js +22 -0
  50. package/lib/device/sensor-contact.js +22 -0
  51. package/lib/device/sensor-leak.js +87 -0
  52. package/lib/device/sensor-monitor.js +190 -0
  53. package/lib/device/sensor-presence.js +53 -0
  54. package/lib/device/sensor-thermo.js +144 -0
  55. package/lib/device/sensor-thermo4.js +55 -0
  56. package/lib/device/switch-double.js +121 -0
  57. package/lib/device/switch-single.js +95 -0
  58. package/lib/device/switch-triple.js +160 -0
  59. package/lib/device/tap-single.js +108 -0
  60. package/lib/device/template.js +43 -0
  61. package/lib/device/tv-single.js +84 -0
  62. package/lib/device/valve-single.js +155 -0
  63. package/lib/fakegato/LICENSE +21 -0
  64. package/lib/fakegato/fakegato-history.js +814 -0
  65. package/lib/fakegato/fakegato-storage.js +108 -0
  66. package/lib/fakegato/fakegato-timer.js +125 -0
  67. package/lib/fakegato/uuid.js +27 -0
  68. package/lib/homebridge-ui/public/index.html +433 -0
  69. package/lib/homebridge-ui/server.js +10 -0
  70. package/lib/index.js +8 -0
  71. package/lib/platform.js +1967 -0
  72. package/lib/utils/colour.js +564 -0
  73. package/lib/utils/constants.js +579 -0
  74. package/lib/utils/custom-chars.js +225 -0
  75. package/lib/utils/eve-chars.js +68 -0
  76. package/lib/utils/functions.js +117 -0
  77. package/lib/utils/lang-en.js +131 -0
  78. package/package.json +75 -0
@@ -0,0 +1,182 @@
1
+ import {
2
+ base64ToHex,
3
+ getTwoItemPosition,
4
+ hexToTwoItems,
5
+ parseError,
6
+ } from '../utils/functions.js'
7
+ import platformLang from '../utils/lang-en.js'
8
+
9
+ /*
10
+ H7150
11
+ {
12
+ "mode": {
13
+ "options": [
14
+ {
15
+ "name": "Low",
16
+ "value": "1"
17
+ },
18
+ {
19
+ "name": "High",
20
+ "value": "2"
21
+ },
22
+ {
23
+ "name": "Auto",
24
+ "value": "3"
25
+ },
26
+ {
27
+ "name": "Dryer",
28
+ "value": "8"
29
+ }
30
+ ]
31
+ }
32
+ }
33
+ */
34
+ export default class {
35
+ constructor(platform, accessory) {
36
+ // Set up variables from the platform
37
+ this.hapChar = platform.api.hap.Characteristic
38
+ this.hapErr = platform.api.hap.HapStatusError
39
+ this.hapServ = platform.api.hap.Service
40
+ this.platform = platform
41
+
42
+ // Set up variables from the accessory
43
+ this.accessory = accessory
44
+
45
+ // Rotation speed to value in {1, 2, ..., 8}
46
+ this.speed2Value = speed => Math.min(Math.max(Number.parseInt(Math.round(speed / 10), 10), 1), 8)
47
+
48
+ // Speed codes
49
+ this.value2Code = {
50
+ 1: 'MwUBAQAAAAAAAAAAAAAAAAAAADY=',
51
+ 2: 'MwUBAgAAAAAAAAAAAAAAAAAAADU=',
52
+ 3: 'MwUBAwAAAAAAAAAAAAAAAAAAADQ=',
53
+ 4: 'MwUBBAAAAAAAAAAAAAAAAAAAADM=',
54
+ 5: 'MwUBBQAAAAAAAAAAAAAAAAAAADI=',
55
+ 6: 'MwUBBgAAAAAAAAAAAAAAAAAAADE=',
56
+ 7: 'MwUBBwAAAAAAAAAAAAAAAAAAADA=',
57
+ 8: 'MwUBCAAAAAAAAAAAAAAAAAAAAD8=',
58
+ }
59
+
60
+ // Add the fan service if it doesn't already exist
61
+ this.service = this.accessory.getService(this.hapServ.Fan) || this.accessory.addService(this.hapServ.Fan)
62
+
63
+ // Add the set handler to the fan on/off characteristic
64
+ this.service
65
+ .getCharacteristic(this.hapChar.On)
66
+ .onSet(async value => this.internalStateUpdate(value))
67
+ this.cacheState = this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off'
68
+
69
+ // Add the set handler to the fan rotation speed characteristic
70
+ this.service
71
+ .getCharacteristic(this.hapChar.RotationSpeed)
72
+ .setProps({
73
+ minStep: 10,
74
+ validValues: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
75
+ })
76
+ .onSet(async value => this.internalSpeedUpdate(value))
77
+ this.cacheSpeed = this.service.getCharacteristic(this.hapChar.RotationSpeed).value
78
+
79
+ // Output the customised options to the log
80
+ const opts = JSON.stringify({})
81
+ platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
82
+ }
83
+
84
+ async internalStateUpdate(value) {
85
+ try {
86
+ const newValue = value ? 'on' : 'off'
87
+
88
+ // Don't continue if the new value is the same as before
89
+ if (this.cacheState === newValue) {
90
+ return
91
+ }
92
+
93
+ // Send the request to the platform sender function
94
+ await this.platform.sendDeviceUpdate(this.accessory, {
95
+ cmd: 'stateHumi',
96
+ value: value ? 1 : 0,
97
+ })
98
+
99
+ // Cache the new state and log if appropriate
100
+ this.cacheState = newValue
101
+ this.accessory.log(`${platformLang.curState} [${newValue}]`)
102
+ } catch (err) {
103
+ // Catch any errors during the process
104
+ this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
105
+
106
+ // Throw a 'no response' error and set a timeout to revert this after 2 seconds
107
+ setTimeout(() => {
108
+ this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
109
+ }, 2000)
110
+ throw new this.hapErr(-70402)
111
+ }
112
+ }
113
+
114
+ async internalSpeedUpdate(value) {
115
+ try {
116
+ // Don't continue if the speed is 0
117
+ if (value === 0) {
118
+ return
119
+ }
120
+
121
+ // Get the single Govee value {1, 2, ..., 8}
122
+ const newValue = this.speed2Value(value)
123
+
124
+ // Don't continue if the speed value won't have effect
125
+ if (newValue * 10 === this.cacheSpeed) {
126
+ return
127
+ }
128
+
129
+ // Get the scene code for this value
130
+ const newCode = this.value2Code[newValue]
131
+
132
+ // Send the request to the platform sender function
133
+ await this.platform.sendDeviceUpdate(this.accessory, {
134
+ cmd: 'ptReal',
135
+ value: newCode,
136
+ })
137
+
138
+ // Cache the new state and log if appropriate
139
+ this.cacheSpeed = newValue * 10
140
+ this.accessory.log(`${platformLang.curSpeed} [${newValue}]`)
141
+ } catch (err) {
142
+ // Catch any errors during the process
143
+ this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
144
+
145
+ // Throw a 'no response' error and set a timeout to revert this after 2 seconds
146
+ setTimeout(() => {
147
+ this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed)
148
+ }, 2000)
149
+ throw new this.hapErr(-70402)
150
+ }
151
+ }
152
+
153
+ externalUpdate(params) {
154
+ // Check for an ON/OFF change
155
+ if (params.state && params.state !== this.cacheState) {
156
+ this.cacheState = params.state
157
+ this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
158
+
159
+ // Log the change
160
+ this.accessory.log(`${platformLang.curState} [${this.cacheState}]`)
161
+ }
162
+
163
+ // Check for some other scene/mode change
164
+ (params.commands || []).forEach((command) => {
165
+ const hexString = base64ToHex(command)
166
+ const hexParts = hexToTwoItems(hexString)
167
+
168
+ // Return now if not a device query update code
169
+ if (getTwoItemPosition(hexParts, 1) !== 'aa') {
170
+ return
171
+ }
172
+
173
+ const deviceFunction = `${getTwoItemPosition(hexParts, 1)}${getTwoItemPosition(hexParts, 2)}`
174
+
175
+ switch (deviceFunction) {
176
+ default:
177
+ this.accessory.logDebugWarn(`${platformLang.newScene}: [${command}] [${hexString}]`)
178
+ break
179
+ }
180
+ })
181
+ }
182
+ }
@@ -0,0 +1,157 @@
1
+ import {
2
+ base64ToHex,
3
+ getTwoItemPosition,
4
+ hexToTwoItems,
5
+ parseError,
6
+ } from '../utils/functions.js'
7
+ import platformLang from '../utils/lang-en.js'
8
+
9
+ export default class {
10
+ constructor(platform, accessory) {
11
+ // Set up variables from the platform
12
+ this.hapChar = platform.api.hap.Characteristic
13
+ this.hapErr = platform.api.hap.HapStatusError
14
+ this.hapServ = platform.api.hap.Service
15
+ this.platform = platform
16
+
17
+ // Set up variables from the accessory
18
+ this.accessory = accessory
19
+
20
+ // Rotation speed to value in {1, 2, ..., 8}
21
+ this.speed2Value = speed => Math.min(Math.max(Number.parseInt(Math.round(speed / 10), 10), 1), 8)
22
+
23
+ // Speed codes
24
+ this.value2Code = {
25
+ 1: 'MwUBAQAAAAAAAAAAAAAAAAAAADY=',
26
+ 2: 'MwUBAgAAAAAAAAAAAAAAAAAAADU=',
27
+ 3: 'MwUBAwAAAAAAAAAAAAAAAAAAADQ=',
28
+ 4: 'MwUBBAAAAAAAAAAAAAAAAAAAADM=',
29
+ 5: 'MwUBBQAAAAAAAAAAAAAAAAAAADI=',
30
+ 6: 'MwUBBgAAAAAAAAAAAAAAAAAAADE=',
31
+ 7: 'MwUBBwAAAAAAAAAAAAAAAAAAADA=',
32
+ 8: 'MwUBCAAAAAAAAAAAAAAAAAAAAD8=',
33
+ }
34
+
35
+ // Add the fan service if it doesn't already exist
36
+ this.service = this.accessory.getService(this.hapServ.Fan) || this.accessory.addService(this.hapServ.Fan)
37
+
38
+ // Add the set handler to the fan on/off characteristic
39
+ this.service
40
+ .getCharacteristic(this.hapChar.On)
41
+ .onSet(async value => this.internalStateUpdate(value))
42
+ this.cacheState = this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off'
43
+
44
+ // Add the set handler to the fan rotation speed characteristic
45
+ this.service
46
+ .getCharacteristic(this.hapChar.RotationSpeed)
47
+ .setProps({
48
+ minStep: 10,
49
+ validValues: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
50
+ })
51
+ .onSet(async value => this.internalSpeedUpdate(value))
52
+ this.cacheSpeed = this.service.getCharacteristic(this.hapChar.RotationSpeed).value
53
+
54
+ // Output the customised options to the log
55
+ const opts = JSON.stringify({})
56
+ platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
57
+ }
58
+
59
+ async internalStateUpdate(value) {
60
+ try {
61
+ const newValue = value ? 'on' : 'off'
62
+
63
+ // Don't continue if the new value is the same as before
64
+ if (this.cacheState === newValue) {
65
+ return
66
+ }
67
+
68
+ // Send the request to the platform sender function
69
+ await this.platform.sendDeviceUpdate(this.accessory, {
70
+ cmd: 'stateHumi',
71
+ value: value ? 1 : 0,
72
+ })
73
+
74
+ // Cache the new state and log if appropriate
75
+ this.cacheState = newValue
76
+ this.accessory.log(`${platformLang.curState} [${newValue}]`)
77
+ } catch (err) {
78
+ // Catch any errors during the process
79
+ this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
80
+
81
+ // Throw a 'no response' error and set a timeout to revert this after 2 seconds
82
+ setTimeout(() => {
83
+ this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
84
+ }, 2000)
85
+ throw new this.hapErr(-70402)
86
+ }
87
+ }
88
+
89
+ async internalSpeedUpdate(value) {
90
+ try {
91
+ // Don't continue if the speed is 0
92
+ if (value === 0) {
93
+ return
94
+ }
95
+
96
+ // Get the single Govee value {1, 2, ..., 8}
97
+ const newValue = this.speed2Value(value)
98
+
99
+ // Don't continue if the speed value won't have effect
100
+ if (newValue * 10 === this.cacheSpeed) {
101
+ return
102
+ }
103
+
104
+ // Get the scene code for this value
105
+ const newCode = this.value2Code[newValue]
106
+
107
+ // Send the request to the platform sender function
108
+ await this.platform.sendDeviceUpdate(this.accessory, {
109
+ cmd: 'ptReal',
110
+ value: newCode,
111
+ })
112
+
113
+ // Cache the new state and log if appropriate
114
+ this.cacheSpeed = newValue * 10
115
+ this.accessory.log(`${platformLang.curSpeed} [${newValue}]`)
116
+ } catch (err) {
117
+ // Catch any errors during the process
118
+ this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
119
+
120
+ // Throw a 'no response' error and set a timeout to revert this after 2 seconds
121
+ setTimeout(() => {
122
+ this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed)
123
+ }, 2000)
124
+ throw new this.hapErr(-70402)
125
+ }
126
+ }
127
+
128
+ externalUpdate(params) {
129
+ // Check for an ON/OFF change
130
+ if (params.state && params.state !== this.cacheState) {
131
+ this.cacheState = params.state
132
+ this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
133
+
134
+ // Log the change
135
+ this.accessory.log(`${platformLang.curState} [${this.cacheState}]`)
136
+ }
137
+
138
+ // Check for some other scene/mode change
139
+ (params.commands || []).forEach((command) => {
140
+ const hexString = base64ToHex(command)
141
+ const hexParts = hexToTwoItems(hexString)
142
+
143
+ // Return now if not a device query update code
144
+ if (getTwoItemPosition(hexParts, 1) !== 'aa') {
145
+ return
146
+ }
147
+
148
+ const deviceFunction = `${getTwoItemPosition(hexParts, 1)}${getTwoItemPosition(hexParts, 2)}`
149
+
150
+ switch (deviceFunction) {
151
+ default:
152
+ this.accessory.logDebugWarn(`${platformLang.newScene}: [${command}] [${hexString}]`)
153
+ break
154
+ }
155
+ })
156
+ }
157
+ }
@@ -0,0 +1,117 @@
1
+ import {
2
+ base64ToHex,
3
+ getTwoItemPosition,
4
+ hexToTwoItems,
5
+ parseError,
6
+ } from '../utils/functions.js'
7
+ import platformLang from '../utils/lang-en.js'
8
+
9
+ export default class {
10
+ constructor(platform, accessory) {
11
+ // Set up variables from the platform
12
+ this.hapChar = platform.api.hap.Characteristic
13
+ this.hapErr = platform.api.hap.HapStatusError
14
+ this.hapServ = platform.api.hap.Service
15
+ this.platform = platform
16
+
17
+ // Set up variables from the accessory
18
+ this.accessory = accessory
19
+
20
+ // Remove fan service if exists
21
+ if (this.accessory.getService(this.hapServ.Fan)) {
22
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Fan))
23
+ }
24
+
25
+ // Add the purifier service if it doesn't already exist
26
+ this.service = this.accessory.getService(this.hapServ.AirPurifier)
27
+ || this.accessory.addService(this.hapServ.AirPurifier)
28
+
29
+ // Add the set handler to the switch on/off characteristic
30
+ this.service.getCharacteristic(this.hapChar.Active).onSet(async (value) => {
31
+ await this.internalStateUpdate(value)
32
+ })
33
+ this.cacheState = this.service.getCharacteristic(this.hapChar.Active).value === 1 ? 'on' : 'off'
34
+
35
+ // Add options to the purifier target state characteristic
36
+ this.service
37
+ .getCharacteristic(this.hapChar.TargetAirPurifierState)
38
+ .updateValue(1)
39
+ .setProps({
40
+ minValue: 1,
41
+ maxValue: 1,
42
+ validValues: [1],
43
+ })
44
+
45
+ // Output the customised options to the log
46
+ const opts = JSON.stringify({})
47
+ platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
48
+ }
49
+
50
+ async internalStateUpdate(value) {
51
+ try {
52
+ const newValue = value === 1 ? 'on' : 'off'
53
+
54
+ // Don't continue if the new value is the same as before
55
+ if (this.cacheState === newValue) {
56
+ return
57
+ }
58
+
59
+ // Send the request to the platform sender function
60
+ await this.platform.sendDeviceUpdate(this.accessory, {
61
+ cmd: 'stateHumi',
62
+ value,
63
+ })
64
+
65
+ // Cache the new state and log if appropriate
66
+ if (this.cacheState !== newValue) {
67
+ this.cacheState = newValue
68
+ this.accessory.log(`${platformLang.curState} [${this.cacheState}]`)
69
+ }
70
+
71
+ this.service.updateCharacteristic(this.hapChar.CurrentAirPurifierState, value === 1 ? 2 : 0)
72
+ } catch (err) {
73
+ // Catch any errors during the process
74
+ this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
75
+
76
+ // Throw a 'no response' error and set a timeout to revert this after 2 seconds
77
+ setTimeout(() => {
78
+ this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0)
79
+ }, 2000)
80
+ throw new this.hapErr(-70402)
81
+ }
82
+ }
83
+
84
+ externalUpdate(params) {
85
+ // Check for an ON/OFF change
86
+ if (params.state && params.state !== this.cacheState) {
87
+ this.cacheState = params.state
88
+ this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0)
89
+ this.service.updateCharacteristic(
90
+ this.hapChar.CurrentAirPurifierState,
91
+ this.cacheState === 'on' ? 2 : 0,
92
+ )
93
+
94
+ // Log the change
95
+ this.accessory.log(`${platformLang.curState} [${this.cacheState}]`)
96
+ }
97
+
98
+ // Check for some other scene/mode change
99
+ (params.commands || []).forEach((command) => {
100
+ const hexString = base64ToHex(command)
101
+ const hexParts = hexToTwoItems(hexString)
102
+
103
+ // Return now if not a device query update code
104
+ if (getTwoItemPosition(hexParts, 1) !== 'aa') {
105
+ return
106
+ }
107
+
108
+ const deviceFunction = `${getTwoItemPosition(hexParts, 1)}${getTwoItemPosition(hexParts, 2)}`
109
+
110
+ switch (deviceFunction) {
111
+ default:
112
+ this.accessory.logDebugWarn(`${platformLang.newScene}: [${command}] [${hexString}]`)
113
+ break
114
+ }
115
+ })
116
+ }
117
+ }
@@ -0,0 +1,117 @@
1
+ import {
2
+ base64ToHex,
3
+ getTwoItemPosition,
4
+ hexToTwoItems,
5
+ parseError,
6
+ } from '../utils/functions.js'
7
+ import platformLang from '../utils/lang-en.js'
8
+
9
+ export default class {
10
+ constructor(platform, accessory) {
11
+ // Set up variables from the platform
12
+ this.hapChar = platform.api.hap.Characteristic
13
+ this.hapErr = platform.api.hap.HapStatusError
14
+ this.hapServ = platform.api.hap.Service
15
+ this.platform = platform
16
+
17
+ // Set up variables from the accessory
18
+ this.accessory = accessory
19
+
20
+ // Remove fan service if exists
21
+ if (this.accessory.getService(this.hapServ.Fan)) {
22
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Fan))
23
+ }
24
+
25
+ // Add the purifier service if it doesn't already exist
26
+ this.service = this.accessory.getService(this.hapServ.AirPurifier)
27
+ || this.accessory.addService(this.hapServ.AirPurifier)
28
+
29
+ // Add the set handler to the switch on/off characteristic
30
+ this.service.getCharacteristic(this.hapChar.Active).onSet(async (value) => {
31
+ await this.internalStateUpdate(value)
32
+ })
33
+ this.cacheState = this.service.getCharacteristic(this.hapChar.Active).value === 1 ? 'on' : 'off'
34
+
35
+ // Add options to the purifier target state characteristic
36
+ this.service
37
+ .getCharacteristic(this.hapChar.TargetAirPurifierState)
38
+ .updateValue(1)
39
+ .setProps({
40
+ minValue: 1,
41
+ maxValue: 1,
42
+ validValues: [1],
43
+ })
44
+
45
+ // Output the customised options to the log
46
+ const opts = JSON.stringify({})
47
+ platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
48
+ }
49
+
50
+ async internalStateUpdate(value) {
51
+ try {
52
+ const newValue = value === 1 ? 'on' : 'off'
53
+
54
+ // Don't continue if the new value is the same as before
55
+ if (this.cacheState === newValue) {
56
+ return
57
+ }
58
+
59
+ // Send the request to the platform sender function
60
+ await this.platform.sendDeviceUpdate(this.accessory, {
61
+ cmd: 'stateHumi',
62
+ value,
63
+ })
64
+
65
+ // Cache the new state and log if appropriate
66
+ if (this.cacheState !== newValue) {
67
+ this.cacheState = newValue
68
+ this.accessory.log(`${platformLang.curState} [${this.cacheState}]`)
69
+ }
70
+
71
+ this.service.updateCharacteristic(this.hapChar.CurrentAirPurifierState, value === 1 ? 2 : 0)
72
+ } catch (err) {
73
+ // Catch any errors during the process
74
+ this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
75
+
76
+ // Throw a 'no response' error and set a timeout to revert this after 2 seconds
77
+ setTimeout(() => {
78
+ this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0)
79
+ }, 2000)
80
+ throw new this.hapErr(-70402)
81
+ }
82
+ }
83
+
84
+ externalUpdate(params) {
85
+ // Check for an ON/OFF change
86
+ if (params.state && params.state !== this.cacheState) {
87
+ this.cacheState = params.state
88
+ this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0)
89
+ this.service.updateCharacteristic(
90
+ this.hapChar.CurrentAirPurifierState,
91
+ this.cacheState === 'on' ? 2 : 0,
92
+ )
93
+
94
+ // Log the change
95
+ this.accessory.log(`${platformLang.curState} [${this.cacheState}]`)
96
+ }
97
+
98
+ // Check for some other scene/mode change
99
+ (params.commands || []).forEach((command) => {
100
+ const hexString = base64ToHex(command)
101
+ const hexParts = hexToTwoItems(hexString)
102
+
103
+ // Return now if not a device query update code
104
+ if (getTwoItemPosition(hexParts, 1) !== 'aa') {
105
+ return
106
+ }
107
+
108
+ const deviceFunction = `${getTwoItemPosition(hexParts, 1)}${getTwoItemPosition(hexParts, 2)}`
109
+
110
+ switch (deviceFunction) {
111
+ default:
112
+ this.accessory.logDebugWarn(`${platformLang.newScene}: [${command}] [${hexString}]`)
113
+ break
114
+ }
115
+ })
116
+ }
117
+ }