@homebridge-plugins/homebridge-govee 11.32.2-beta.2 → 11.32.2-beta.21

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 (73) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/config.schema.json +1 -1
  3. package/lib/connection/ble.js +26 -1
  4. package/lib/connection/openapi.js +18 -0
  5. package/lib/device/appliance-basic.js +377 -0
  6. package/lib/device/dehumidifier-H7150.js +9 -3
  7. package/lib/device/diffuser-H7161.js +7 -1
  8. package/lib/device/fan-H1370.js +7 -1
  9. package/lib/device/fan-H7100.js +36 -4
  10. package/lib/device/fan-H7105.js +7 -1
  11. package/lib/device/fan-H7107.js +7 -1
  12. package/lib/device/heater1a.js +52 -12
  13. package/lib/device/heater1b.js +14 -3
  14. package/lib/device/heater2.js +7 -1
  15. package/lib/device/humidifier-H7140.js +7 -1
  16. package/lib/device/humidifier-H7141.js +7 -1
  17. package/lib/device/humidifier-H7142.js +7 -1
  18. package/lib/device/humidifier-H7143.js +7 -1
  19. package/lib/device/humidifier-H7160.js +7 -1
  20. package/lib/device/ice-maker-H7172.js +19 -7
  21. package/lib/device/index.js +44 -51
  22. package/lib/device/kettle.js +7 -1
  23. package/lib/device/outlet-single.js +7 -1
  24. package/lib/device/purifier-H7120.js +14 -25
  25. package/lib/device/purifier-H7122.js +7 -1
  26. package/lib/device/purifier-H7123.js +9 -3
  27. package/lib/device/purifier-H7126.js +7 -1
  28. package/lib/device/{sensor-button.js → sensor-basic.js} +14 -2
  29. package/lib/device/sensor-presence.js +7 -1
  30. package/lib/device/sensor-thermo4.js +13 -2
  31. package/lib/device/switch-double.js +34 -15
  32. package/lib/device/switch-triple.js +36 -17
  33. package/lib/device/template.js +15 -2
  34. package/lib/platform.js +83 -799
  35. package/lib/utils/capabilities.js +220 -0
  36. package/lib/utils/command-builder.js +6 -4
  37. package/lib/utils/config-parser.js +280 -0
  38. package/lib/utils/constants.js +120 -8
  39. package/lib/utils/decode.js +4 -1
  40. package/lib/utils/device-capabilities.js +77 -3
  41. package/lib/utils/device-context.js +179 -0
  42. package/lib/utils/device-merge.js +251 -0
  43. package/lib/utils/dispatch.js +159 -0
  44. package/lib/utils/functions.js +9 -0
  45. package/lib/utils/lang-en.js +0 -2
  46. package/lib/utils/report-unknown.js +156 -0
  47. package/package.json +1 -1
  48. package/lib/device/dehumidifier-H7151.js +0 -189
  49. package/lib/device/dehumidifier-H7152.js +0 -180
  50. package/lib/device/diffuser-H7162.js +0 -123
  51. package/lib/device/fan-H1310.js +0 -284
  52. package/lib/device/fan-H7101.js +0 -340
  53. package/lib/device/fan-H7102.js +0 -284
  54. package/lib/device/fan-H7106.js +0 -284
  55. package/lib/device/fan-H7111.js +0 -345
  56. package/lib/device/humidifier-H7145.js +0 -187
  57. package/lib/device/humidifier-H7147.js +0 -187
  58. package/lib/device/humidifier-H7148.js +0 -187
  59. package/lib/device/humidifier-H7149.js +0 -187
  60. package/lib/device/humidifier-H714E.js +0 -187
  61. package/lib/device/ice-maker-H717D.js +0 -218
  62. package/lib/device/ice-maker-H8120.js +0 -218
  63. package/lib/device/outlet-double.js +0 -188
  64. package/lib/device/outlet-triple.js +0 -160
  65. package/lib/device/purifier-H7121.js +0 -406
  66. package/lib/device/purifier-H7124.js +0 -504
  67. package/lib/device/purifier-H7127.js +0 -359
  68. package/lib/device/purifier-H7128.js +0 -359
  69. package/lib/device/purifier-H7129.js +0 -359
  70. package/lib/device/purifier-H712C.js +0 -359
  71. package/lib/device/sensor-contact.js +0 -22
  72. package/lib/utils/ble-timeouts.test.js +0 -44
  73. package/lib/utils/functions.test.js +0 -292
@@ -7,9 +7,10 @@ import {
7
7
  statusToActionCode,
8
8
  } from '../utils/functions.js'
9
9
  import platformLang from '../utils/lang-en.js'
10
+ import { logUnknownData } from '../utils/report-unknown.js'
10
11
 
11
12
  /*
12
- H7123
13
+ H7123 and H7124
13
14
  {
14
15
  "mode": {
15
16
  "options": [
@@ -38,7 +39,7 @@ import platformLang from '../utils/lang-en.js'
38
39
  }
39
40
  */
40
41
 
41
- export default class {
42
+ export default class GoveePurifierH7123 {
42
43
  constructor(platform, accessory) {
43
44
  // Set up variables from the platform
44
45
  this.cusChar = platform.cusChar
@@ -497,7 +498,12 @@ export default class {
497
498
  break
498
499
  }
499
500
  default:
500
- this.accessory.logDebugWarn(`${platformLang.newScene}: [${command}] [${hexString}]`)
501
+ logUnknownData(this.accessory, {
502
+ kind: 'scene',
503
+ source: params.source,
504
+ raw: command,
505
+ hex: hexString,
506
+ })
501
507
  break
502
508
  }
503
509
  })
@@ -5,6 +5,7 @@ import {
5
5
  parseError,
6
6
  } from '../utils/functions.js'
7
7
  import platformLang from '../utils/lang-en.js'
8
+ import { logUnknownData } from '../utils/report-unknown.js'
8
9
 
9
10
  export default class {
10
11
  constructor(platform, accessory) {
@@ -351,7 +352,12 @@ export default class {
351
352
  break
352
353
  }
353
354
  default:
354
- this.accessory.logDebugWarn(`${platformLang.newScene}: [${command}] [${hexString}]`)
355
+ logUnknownData(this.accessory, {
356
+ kind: 'scene',
357
+ source: params.source,
358
+ raw: command,
359
+ hex: hexString,
360
+ })
355
361
  break
356
362
  }
357
363
  })
@@ -1,6 +1,14 @@
1
1
  import platformLang from '../utils/lang-en.js'
2
+ import { logUnknownData } from '../utils/report-unknown.js'
2
3
 
3
- export default class {
4
+ /**
5
+ * A sensor whose broadcasts are not decoded yet.
6
+ *
7
+ * It offers no tile, because a tile that never updates is worse than none. What
8
+ * it does is report every message it receives in one copy-paste line, so an
9
+ * owner can send in exactly what is needed to finish the model off.
10
+ */
11
+ export default class GoveeSensorBasic {
4
12
  constructor(platform, accessory) {
5
13
  // Set up variables from the platform
6
14
  this.hapChar = platform.api.hap.Characteristic
@@ -17,6 +25,10 @@ export default class {
17
25
  }
18
26
 
19
27
  externalUpdate(params) {
20
- this.accessory.logWarn(`${platformLang.newScene}: [${params.scene}]`)
28
+ logUnknownData(this.accessory, {
29
+ kind: 'scene',
30
+ source: params.source,
31
+ raw: params.scene,
32
+ })
21
33
  }
22
34
  }
@@ -1,5 +1,6 @@
1
1
  import { base64ToHex, getTwoItemPosition, hexToTwoItems } from '../utils/functions.js'
2
2
  import platformLang from '../utils/lang-en.js'
3
+ import { logUnknownData } from '../utils/report-unknown.js'
3
4
 
4
5
  export default class {
5
6
  constructor(platform, accessory) {
@@ -45,7 +46,12 @@ export default class {
45
46
  break
46
47
  }
47
48
  default:
48
- this.accessory.logDebugWarn(`${platformLang.newScene}: [${command}] [${hexString}]`)
49
+ logUnknownData(this.accessory, {
50
+ kind: 'scene',
51
+ source: params.source,
52
+ raw: command,
53
+ hex: hexString,
54
+ })
49
55
  break
50
56
  }
51
57
  })
@@ -1,5 +1,6 @@
1
1
  import { base64ToHex, getTwoItemPosition, hexToTwoItems } from '../utils/functions.js'
2
2
  import platformLang from '../utils/lang-en.js'
3
+ import { logUnknownData } from '../utils/report-unknown.js'
3
4
 
4
5
  export default class {
5
6
  constructor(platform, accessory) {
@@ -36,7 +37,12 @@ export default class {
36
37
  const hexString = base64ToHex(command)
37
38
  const hexParts = hexToTwoItems(hexString)
38
39
 
39
- this.accessory.logDebugWarn(`${platformLang.newScene}: [${command}] [${hexString}]`)
40
+ logUnknownData(this.accessory, {
41
+ kind: 'scene',
42
+ source: params.source,
43
+ raw: command,
44
+ hex: hexString,
45
+ })
40
46
 
41
47
  // Return now if not a device query update code
42
48
  if (getTwoItemPosition(hexParts, 1) !== 'aa') {
@@ -47,7 +53,12 @@ export default class {
47
53
 
48
54
  switch (deviceFunction) {
49
55
  default:
50
- this.accessory.logDebugWarn(`${platformLang.newScene}: [${command}] [${hexString}]`)
56
+ logUnknownData(this.accessory, {
57
+ kind: 'scene',
58
+ source: params.source,
59
+ raw: command,
60
+ hex: hexString,
61
+ })
51
62
  break
52
63
  }
53
64
  })
@@ -8,8 +8,8 @@ import platformLang from '../utils/lang-en.js'
8
8
  // outright rather than accepted and silently dropped (#1323).
9
9
  const nightLightModels = ['H5089']
10
10
 
11
- export default class {
12
- constructor(platform, accessory) {
11
+ class MultiSwitchDouble {
12
+ constructor(platform, accessory, config) {
13
13
  // Set up variables from the platform
14
14
  this.hapChar = platform.api.hap.Characteristic
15
15
  this.hapErr = platform.api.hap.HapStatusError
@@ -19,12 +19,13 @@ export default class {
19
19
  // Set up variables from the accessory
20
20
  this.accessory = accessory
21
21
 
22
- // Remove outlet services if they exist
23
- if (this.accessory.getService('Outlet 1')) {
24
- this.accessory.removeService(this.accessory.getService('Outlet 1'))
22
+ // Drop the tiles of the other kind, left behind if this device has been
23
+ // shown as the other one before
24
+ if (this.accessory.getService(`${config.other} 1`)) {
25
+ this.accessory.removeService(this.accessory.getService(`${config.other} 1`))
25
26
  }
26
- if (this.accessory.getService('Outlet 2')) {
27
- this.accessory.removeService(this.accessory.getService('Outlet 2'))
27
+ if (this.accessory.getService(`${config.other} 2`)) {
28
+ this.accessory.removeService(this.accessory.getService(`${config.other} 2`))
28
29
  }
29
30
 
30
31
  // A model that used to be treated as a single switch or outlet leaves an
@@ -35,15 +36,15 @@ export default class {
35
36
  && [this.hapServ.Switch.UUID, this.hapServ.Outlet.UUID].includes(service.UUID))
36
37
  .forEach(service => this.accessory.removeService(service))
37
38
 
38
- // Add the switch services if they don't already exist
39
- this.service1 = this.accessory.getService('Switch 1')
40
- || this.accessory.addService(this.hapServ.Switch, 'Switch 1', 'switch1')
41
- this.service2 = this.accessory.getService('Switch 2')
42
- || this.accessory.addService(this.hapServ.Switch, 'Switch 2', 'switch2')
39
+ // Add this device's tiles if they are not there already
40
+ this.service1 = this.accessory.getService(`${config.label} 1`)
41
+ || this.accessory.addService(this.hapServ[config.label], `${config.label} 1`, `${config.subtype}1`)
42
+ this.service2 = this.accessory.getService(`${config.label} 2`)
43
+ || this.accessory.addService(this.hapServ[config.label], `${config.label} 2`, `${config.subtype}2`)
43
44
 
44
45
  if (!this.service1.testCharacteristic(this.hapChar.ConfiguredName)) {
45
46
  this.service1.addCharacteristic(this.hapChar.ConfiguredName)
46
- this.service1.updateCharacteristic(this.hapChar.ConfiguredName, 'Switch 1')
47
+ this.service1.updateCharacteristic(this.hapChar.ConfiguredName, `${config.label} 1`)
47
48
  }
48
49
  if (!this.service1.testCharacteristic(this.hapChar.ServiceLabelIndex)) {
49
50
  this.service1.addCharacteristic(this.hapChar.ServiceLabelIndex)
@@ -51,7 +52,7 @@ export default class {
51
52
  }
52
53
  if (!this.service2.testCharacteristic(this.hapChar.ConfiguredName)) {
53
54
  this.service2.addCharacteristic(this.hapChar.ConfiguredName)
54
- this.service2.updateCharacteristic(this.hapChar.ConfiguredName, 'Switch 2')
55
+ this.service2.updateCharacteristic(this.hapChar.ConfiguredName, `${config.label} 2`)
55
56
  }
56
57
  if (!this.service2.testCharacteristic(this.hapChar.ServiceLabelIndex)) {
57
58
  this.service2.addCharacteristic(this.hapChar.ServiceLabelIndex)
@@ -86,7 +87,7 @@ export default class {
86
87
 
87
88
  // Output the customised options to the log
88
89
  const opts = JSON.stringify({
89
- showAs: 'switch',
90
+ showAs: config.showAs,
90
91
  })
91
92
  platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
92
93
 
@@ -186,3 +187,21 @@ export default class {
186
187
  }
187
188
  }
188
189
  }
190
+
191
+ /**
192
+ * A double switch and a double outlet are the same device with a different tile
193
+ * in the Home app, chosen by the owner's `showAs` setting. Only the service
194
+ * type, the tile names and the logged option differ, so they share this and are
195
+ * built from it rather than from a copy of it.
196
+ */
197
+ function make(config) {
198
+ return class extends MultiSwitchDouble {
199
+ constructor(platform, accessory) {
200
+ super(platform, accessory, config)
201
+ }
202
+ }
203
+ }
204
+
205
+ export default make({ label: 'Switch', subtype: 'switch', other: 'Outlet', showAs: 'switch' })
206
+
207
+ export const asOutlet = make({ label: 'Outlet', subtype: 'outlet', other: 'Switch', showAs: 'outlet' })
@@ -1,8 +1,8 @@
1
1
  import { parseError } from '../utils/functions.js'
2
2
  import platformLang from '../utils/lang-en.js'
3
3
 
4
- export default class {
5
- constructor(platform, accessory) {
4
+ class MultiSwitchTriple {
5
+ constructor(platform, accessory, config) {
6
6
  // Set up variables from the platform
7
7
  this.hapChar = platform.api.hap.Characteristic
8
8
  this.hapErr = platform.api.hap.HapStatusError
@@ -12,24 +12,25 @@ export default class {
12
12
  // Set up variables from the accessory
13
13
  this.accessory = accessory
14
14
 
15
- // Remove outlet services if they exist
16
- if (this.accessory.getService('Outlet 1')) {
17
- this.accessory.removeService(this.accessory.getService('Outlet 1'))
15
+ // Drop the tiles of the other kind, left behind if this device has been
16
+ // shown as the other one before
17
+ if (this.accessory.getService(`${config.other} 1`)) {
18
+ this.accessory.removeService(this.accessory.getService(`${config.other} 1`))
18
19
  }
19
- if (this.accessory.getService('Outlet 2')) {
20
- this.accessory.removeService(this.accessory.getService('Outlet 2'))
20
+ if (this.accessory.getService(`${config.other} 2`)) {
21
+ this.accessory.removeService(this.accessory.getService(`${config.other} 2`))
21
22
  }
22
- if (this.accessory.getService('Outlet 3')) {
23
- this.accessory.removeService(this.accessory.getService('Outlet 3'))
23
+ if (this.accessory.getService(`${config.other} 3`)) {
24
+ this.accessory.removeService(this.accessory.getService(`${config.other} 3`))
24
25
  }
25
26
 
26
- // Add the switch services if they don't already exist
27
- this.service1 = this.accessory.getService('Switch 1')
28
- || this.accessory.addService(this.hapServ.Switch, 'Switch 1', 'switch1')
29
- this.service2 = this.accessory.getService('Switch 2')
30
- || this.accessory.addService(this.hapServ.Switch, 'Switch 2', 'switch2')
31
- this.service3 = this.accessory.getService('Switch 3')
32
- || this.accessory.addService(this.hapServ.Switch, 'Switch 3', 'switch3')
27
+ // Add this device's tiles if they are not there already
28
+ this.service1 = this.accessory.getService(`${config.label} 1`)
29
+ || this.accessory.addService(this.hapServ[config.label], `${config.label} 1`, `${config.subtype}1`)
30
+ this.service2 = this.accessory.getService(`${config.label} 2`)
31
+ || this.accessory.addService(this.hapServ[config.label], `${config.label} 2`, `${config.subtype}2`)
32
+ this.service3 = this.accessory.getService(`${config.label} 3`)
33
+ || this.accessory.addService(this.hapServ[config.label], `${config.label} 3`, `${config.subtype}3`)
33
34
 
34
35
  // Add the set handler to the switch on/off characteristic
35
36
  this.service1.getCharacteristic(this.hapChar.On).onSet(async (value) => {
@@ -47,7 +48,7 @@ export default class {
47
48
 
48
49
  // Output the customised options to the log
49
50
  const opts = JSON.stringify({
50
- showAs: 'switch',
51
+ showAs: config.showAs,
51
52
  })
52
53
  platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
53
54
 
@@ -158,3 +159,21 @@ export default class {
158
159
  }
159
160
  }
160
161
  }
162
+
163
+ /**
164
+ * A triple switch and a triple outlet are the same device with a different tile
165
+ * in the Home app, chosen by the owner's `showAs` setting. Only the service
166
+ * type, the tile names and the logged option differ, so they share this and are
167
+ * built from it rather than from a copy of it.
168
+ */
169
+ function make(config) {
170
+ return class extends MultiSwitchTriple {
171
+ constructor(platform, accessory) {
172
+ super(platform, accessory, config)
173
+ }
174
+ }
175
+ }
176
+
177
+ export default make({ label: 'Switch', subtype: 'switch', other: 'Outlet', showAs: 'switch' })
178
+
179
+ export const asOutlet = make({ label: 'Outlet', subtype: 'outlet', other: 'Switch', showAs: 'outlet' })
@@ -1,5 +1,6 @@
1
1
  import { base64ToHex, getTwoItemPosition, hexToTwoItems } from '../utils/functions.js'
2
2
  import platformLang from '../utils/lang-en.js'
3
+ import { logUnknownData } from '../utils/report-unknown.js'
3
4
 
4
5
  export default class {
5
6
  constructor(platform, accessory) {
@@ -19,7 +20,14 @@ export default class {
19
20
  }
20
21
 
21
22
  externalUpdate(params) {
22
- this.accessory.logWarn(JSON.stringify(params))
23
+ // These are the models actively being worked out, so every payload is worth
24
+ // reporting in the full form rather than as a bare dump - it is the whole
25
+ // reason the accessory exists at this stage
26
+ logUnknownData(this.accessory, {
27
+ kind: 'payload',
28
+ source: params.source,
29
+ raw: params,
30
+ })
23
31
 
24
32
  // Check for some other scene/mode change
25
33
  ;(params.commands || []).forEach((command) => {
@@ -35,7 +43,12 @@ export default class {
35
43
 
36
44
  switch (deviceFunction) {
37
45
  default:
38
- this.accessory.logDebugWarn(`${platformLang.newScene}: [${command}] [${hexString}]`)
46
+ logUnknownData(this.accessory, {
47
+ kind: 'scene',
48
+ source: params.source,
49
+ raw: command,
50
+ hex: hexString,
51
+ })
39
52
  break
40
53
  }
41
54
  })