@homebridge-plugins/homebridge-govee 11.32.2-beta.11 → 11.32.2-beta.13

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.
package/CHANGELOG.md CHANGED
@@ -23,6 +23,11 @@ All notable changes to `@homebridge-plugins/homebridge-govee` will be documented
23
23
  - fix: stop shipping the test files to npm, since they are only needed in the repository
24
24
  - fix: refuse to send a bluetooth command too long to fit in a packet, rather than sending a longer one the device quietly ignores
25
25
  - test: record what every supported model turns into, so a change can be shown to have altered nothing
26
+ - feat: work out what an appliance can do from what the device itself reports, so a model nobody has written down still gets the right controls
27
+ - feat: offer oscillation and the child lock on any appliance that reports having them, driven through govee's api rather than needing that model's command codes
28
+ - refactor: point three more models at a shared handler instead of a near-copy of the same file, keeping each one's behaviour exactly as it was
29
+ - fix: give the H7124 the air quality handling the H7123 already had, so a poor reading is named properly and stops being logged over and over (#1261)
30
+ - refactor: point the H7151 and H7111 at the handlers they were byte-for-byte copies of
26
31
 
27
32
  ## v11.32.1 (2026-08-02)
28
33
 
@@ -1,3 +1,4 @@
1
+ import { describeSources, resolveControls } from '../utils/capabilities.js'
1
2
  import { base64ToHex, getTwoItemPosition, hexToTwoItems, parseError } from '../utils/functions.js'
2
3
  import platformLang from '../utils/lang-en.js'
3
4
  import { logUnknownData, reportUnsupportedControl } from '../utils/report-unknown.js'
@@ -31,13 +32,26 @@ class ApplianceBasic {
31
32
  this.accessory = accessory
32
33
  this.config = config
33
34
 
35
+ // Work out what this particular device can do, rather than what its model
36
+ // generally can - for a model nobody has written down, what the device
37
+ // itself reported is all there is to go on
38
+ const resolved = resolveControls({
39
+ model: accessory.context.gvModel,
40
+ family: config.family,
41
+ firmware: accessory.context.firmware,
42
+ openApiCapabilities: accessory.context.openApiCapabilities,
43
+ deviceConf: platform.deviceConf?.[accessory.context.gvDeviceId],
44
+ })
45
+ this.controls = resolved.controls
46
+ this.cacheToggles = {}
47
+ this.discoveredControls = []
48
+
34
49
  // Some appliances can have a richer tile, but only if the device reports
35
50
  // the reading that tile needs - HomeKit's humidifier, for example, has to
36
51
  // show a current humidity, and plenty of Govee humidifiers never send one.
37
- // Where Govee tells us the device has that sensor, use the better tile;
38
- // otherwise fall back to the plain one, which needs nothing extra.
39
- const hasSensor = config.richCapability
40
- && !!accessory.context.openApiCapabilities?.[config.richCapability]
52
+ // Where the device says it has that sensor, use the better tile; otherwise
53
+ // fall back to the plain one, which needs nothing extra.
54
+ const hasSensor = config.richControl && this.controls[config.richControl]
41
55
  const serviceName = (config.richService && hasSensor) ? config.richService : config.service
42
56
  this.usingRichService = serviceName === config.richService
43
57
 
@@ -94,10 +108,78 @@ class ApplianceBasic {
94
108
  this.cacheVariable = this.service.getCharacteristic(this.variableChar).value
95
109
  }
96
110
 
111
+ // A control the device told us about can be driven through Govee's own api
112
+ // by name, without knowing this model's command bytes. So unlike the
113
+ // settings above, these work rather than asking to be reported.
114
+ this.addDiscoveredToggle('swing', 'SwingMode', 'oscillationToggle')
115
+ this.addDiscoveredToggle('lock', 'LockPhysicalControls', 'lockToggle')
116
+
97
117
  // Output the customised options to the log
98
118
  const opts = JSON.stringify({})
99
119
  platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
100
- this.accessory.log(`on and off are supported for this model, the ${config.variableLabel || 'other settings'} are not known yet`)
120
+ this.accessory.logDebug(`controls: ${describeSources(resolved.sources)}`)
121
+
122
+ const working = ['on and off', ...this.discoveredControls]
123
+ this.accessory.log(`${working.join(', ')} ${working.length > 1 ? 'are' : 'is'} supported for this model, the ${config.variableLabel || 'other settings'} are not known yet`)
124
+ }
125
+
126
+ /**
127
+ * Offer a control the device said it has, driven through Govee's api by the
128
+ * name the device gave it.
129
+ *
130
+ * This is the one place a model nobody has tested gets something that really
131
+ * works beyond power: the api takes the capability name, so the command bytes
132
+ * for this model never have to be known.
133
+ */
134
+ addDiscoveredToggle(control, characteristic, instance) {
135
+ const char = this.hapChar[characteristic]
136
+
137
+ // The device has to have named this capability itself. Knowing the model
138
+ // usually has a turning head is not enough - the api is driven by the name
139
+ // the device reported, so without it there is nothing to send, and the
140
+ // switch would fail every time it was touched.
141
+ const reported = !!this.accessory.context.openApiCapabilities?.[instance]
142
+
143
+ if (!reported || !this.controls[control] || !char) {
144
+ if (this.service.testCharacteristic?.(char)) {
145
+ this.service.removeCharacteristic(this.service.getCharacteristic(char))
146
+ }
147
+ return
148
+ }
149
+
150
+ this.service
151
+ .getCharacteristic(char)
152
+ .onSet(async value => this.internalToggleUpdate(control, char, instance, value))
153
+ this.cacheToggles[control] = this.service.getCharacteristic(char).value
154
+
155
+ this.discoveredControls.push(control === 'swing' ? 'oscillation' : 'the child lock')
156
+ }
157
+
158
+ async internalToggleUpdate(control, characteristic, instance, value) {
159
+ const previous = this.cacheToggles[control]
160
+ try {
161
+ if (previous === value) {
162
+ return
163
+ }
164
+
165
+ await this.platform.sendDeviceUpdate(this.accessory, {
166
+ cmd: 'openApi',
167
+ openApi: {
168
+ instance,
169
+ capabilityType: 'devices.capabilities.toggle',
170
+ value: value ? 1 : 0,
171
+ },
172
+ })
173
+
174
+ this.cacheToggles[control] = value
175
+ this.accessory.log(`current ${control} [${value ? 'on' : 'off'}]`)
176
+ } catch (err) {
177
+ this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
178
+ setTimeout(() => {
179
+ this.service.updateCharacteristic(characteristic, previous)
180
+ }, 2000)
181
+ throw new this.hapErr(-70402)
182
+ }
101
183
  }
102
184
 
103
185
  async internalStateUpdate(value) {
@@ -229,6 +311,7 @@ export function makeBasicAppliance(config) {
229
311
 
230
312
  // Fan-shaped appliances: a speed slider that is not worked out yet
231
313
  export const deviceFanBasic = makeBasicAppliance({
314
+ family: 'fan',
232
315
  service: 'Fanv2',
233
316
  variableChar: 'RotationSpeed',
234
317
  variableLabel: 'fan speed',
@@ -236,6 +319,7 @@ export const deviceFanBasic = makeBasicAppliance({
236
319
 
237
320
  // Ice makers reuse the fan tile, with the slider standing in for ice size
238
321
  export const deviceIceMakerBasic = makeBasicAppliance({
322
+ family: 'iceMaker',
239
323
  service: 'Fanv2',
240
324
  variableChar: 'RotationSpeed',
241
325
  variableLabel: 'ice size',
@@ -245,11 +329,12 @@ export const deviceIceMakerBasic = makeBasicAppliance({
245
329
  // has to show a current humidity and many Govee humidifiers never report one.
246
330
  // A model that does report it gets the proper humidifier tile instead.
247
331
  export const deviceHumidifierBasic = makeBasicAppliance({
332
+ family: 'humidifier',
248
333
  service: 'Fan',
249
334
  variableChar: 'RotationSpeed',
250
335
  variableLabel: 'mist level',
251
336
  richService: 'HumidifierDehumidifier',
252
- richCapability: 'sensorHumidity',
337
+ richControl: 'humiditySensor',
253
338
  richVariableChar: 'RelativeHumidityHumidifierThreshold',
254
339
  richReadingChar: 'CurrentRelativeHumidity',
255
340
  currentStateChar: 'CurrentHumidifierDehumidifierState',
@@ -258,11 +343,12 @@ export const deviceHumidifierBasic = makeBasicAppliance({
258
343
  })
259
344
 
260
345
  export const deviceDehumidifierBasic = makeBasicAppliance({
346
+ family: 'dehumidifier',
261
347
  service: 'Fan',
262
348
  variableChar: 'RotationSpeed',
263
349
  variableLabel: 'fan speed',
264
350
  richService: 'HumidifierDehumidifier',
265
- richCapability: 'sensorHumidity',
351
+ richControl: 'humiditySensor',
266
352
  richVariableChar: 'RelativeHumidityDehumidifierThreshold',
267
353
  richReadingChar: 'CurrentRelativeHumidity',
268
354
  currentStateChar: 'CurrentHumidifierDehumidifierState',
@@ -271,6 +357,7 @@ export const deviceDehumidifierBasic = makeBasicAppliance({
271
357
  })
272
358
 
273
359
  export const devicePurifierBasic = makeBasicAppliance({
360
+ family: 'purifier',
274
361
  service: 'AirPurifier',
275
362
  variableChar: 'RotationSpeed',
276
363
  variableLabel: 'fan speed',
@@ -8,7 +8,7 @@ import platformLang from '../utils/lang-en.js'
8
8
  import { logUnknownData } from '../utils/report-unknown.js'
9
9
 
10
10
  /*
11
- H7150
11
+ H7150 and H7151
12
12
  {
13
13
  "mode": {
14
14
  "options": [
@@ -32,7 +32,7 @@ import { logUnknownData } from '../utils/report-unknown.js'
32
32
  }
33
33
  }
34
34
  */
35
- export default class {
35
+ export default class GoveeDehumidifierH7150 {
36
36
  constructor(platform, accessory) {
37
37
  // Set up variables from the platform
38
38
  this.hapChar = platform.api.hap.Characteristic
@@ -1,3 +1,4 @@
1
+ import { getDeviceCapabilities } from '../utils/device-capabilities.js'
1
2
  import {
2
3
  base64ToHex,
3
4
  fanSpeedToHkPercent,
@@ -9,7 +10,7 @@ import {
9
10
  import platformLang from '../utils/lang-en.js'
10
11
  import { logUnknownData } from '../utils/report-unknown.js'
11
12
 
12
- export default class {
13
+ export default class GoveeFanH7100 {
13
14
  constructor(platform, accessory) {
14
15
  // Set up variables from the platform
15
16
  this.hapChar = platform.api.hap.Characteristic
@@ -20,6 +21,10 @@ export default class {
20
21
  // Set up variables from the accessory
21
22
  this.accessory = accessory
22
23
 
24
+ // Which of the models on this handler have a confirmed meaning for the
25
+ // oscillation status message
26
+ this.readsSwingStatus = getDeviceCapabilities(accessory.context.gvModel).readsSwingStatus
27
+
23
28
  // Codes etc
24
29
  this.speedCodes = {
25
30
  1: 'MwUBAQAAAAAAAAAAAAAAAAAAADY=',
@@ -267,7 +272,18 @@ export default class {
267
272
  break
268
273
  }
269
274
  case '1f01': {
270
- // Swing Mode
275
+ // Not every model on this handler is known to mean oscillation by
276
+ // this message, so one that has not been confirmed falls through and
277
+ // reports it instead - which is how it gets confirmed
278
+ if (!this.readsSwingStatus) {
279
+ logUnknownData(this.accessory, {
280
+ kind: 'scene',
281
+ source: params.source,
282
+ raw: command,
283
+ hex: hexString,
284
+ })
285
+ break
286
+ }
271
287
  const newSwing = getTwoItemPosition(hexParts, 4) === '01' ? 'on' : 'off'
272
288
  if (this.cacheSwing !== newSwing) {
273
289
  this.cacheSwing = newSwing
@@ -10,7 +10,7 @@ import platformLang from '../utils/lang-en.js'
10
10
  import { logUnknownData } from '../utils/report-unknown.js'
11
11
 
12
12
  /*
13
- H7101
13
+ H7101 and H7111
14
14
  {
15
15
  "mode": {
16
16
  "options": [
@@ -53,6 +53,7 @@ import { logUnknownData } from '../utils/report-unknown.js'
53
53
 
54
54
  // NOTES
55
55
  H7101 -> Sleep, Nature, Turbo, Custom, Auto
56
+ H7111 -> Sleep, Nature, Custom, Auto (no turbo)
56
57
 
57
58
  sleep
58
59
  [31/10/2022, 20:52:08] [Govee] [Device1] [AWS] receiving update {"source":"AWS","result":1,"commands":["qgUFAAAAAAAAAAAAAAAAAAAAAKo=","qgUABQAAAAAAAAAAAAAAAAAAAKo="]}.
@@ -65,7 +66,7 @@ import { logUnknownData } from '../utils/report-unknown.js'
65
66
  [31/10/2022, 20:52:43] [Govee] [Device1] new scene code: [qgUABgAAAAAAAAAAAAAAAAAAAKk=] [aa050006000000000000000000000000000000a9].
66
67
  */
67
68
 
68
- export default class {
69
+ export default class GoveeFanH7101 {
69
70
  constructor(platform, accessory) {
70
71
  // Set up variables from the platform
71
72
  this.hapChar = platform.api.hap.Characteristic
@@ -318,7 +319,7 @@ export default class {
318
319
  this.cacheSpeed = this.autoSpeed
319
320
  // Cache auto so we can tell it apart from "user asked for max speed"
320
321
  this.service.updateCharacteristic(this.hapChar.RotationSpeed, 100)
321
- this.accessory.log(`${platformLang.curSpeed} [auto]`)
322
+ this.accessory.log(`${platformLang.curSpeed} [auto -> 100%]`)
322
323
  }
323
324
  break
324
325
  }
@@ -1,4 +1,4 @@
1
- import { getHeaterFeatures } from '../utils/appliance-capabilities.js'
1
+ import { describeSources, resolveControls } from '../utils/capabilities.js'
2
2
  import {
3
3
  base64ToHex,
4
4
  farToCen,
@@ -94,7 +94,15 @@ export default class {
94
94
 
95
95
  // Only offer the controls this model actually has, so a heater without a
96
96
  // turning head does not get an oscillation switch that does nothing
97
- this.features = getHeaterFeatures(this.accessory.context.gvModel)
97
+ const resolved = resolveControls({
98
+ model: this.accessory.context.gvModel,
99
+ family: 'heater1',
100
+ firmware: this.accessory.context.firmware,
101
+ openApiCapabilities: this.accessory.context.openApiCapabilities,
102
+ deviceConf: platform.deviceConf?.[this.accessory.context.gvDeviceId],
103
+ })
104
+ this.features = resolved.controls
105
+ this.accessory.logDebug(`controls: ${describeSources(resolved.sources)}`)
98
106
 
99
107
  // Add the set handler to the heater swing mode characteristic (for oscillation)
100
108
  if (this.features.swing) {
@@ -2,7 +2,7 @@ import { base64ToHex, getTwoItemPosition, hexToTwoItems, parseError } from '../u
2
2
  import platformLang from '../utils/lang-en.js'
3
3
  import { logUnknownData } from '../utils/report-unknown.js'
4
4
 
5
- export default class {
5
+ export default class GoveeIceMakerH8121 {
6
6
  constructor(platform, accessory) {
7
7
  // Set up variables from the platform
8
8
  this.hapChar = platform.api.hap.Characteristic
@@ -14,7 +14,7 @@ export default class {
14
14
  this.accessory = accessory
15
15
 
16
16
  // Ice size codes: small=1, medium=2, large=3, matching the OpenAPI workMode
17
- // values. Unlike the H8120, the H8121's BLE size byte runs in the SAME
17
+ // values. Unlike the H8120, this generation's BLE size byte runs in the SAME
18
18
  // direction as workMode (small=0x05 01 .. large=0x05 03), so the two paths
19
19
  // agree here and no inversion is needed.
20
20
  this.sizeCodes = {
@@ -89,7 +89,7 @@ export default class {
89
89
  } else {
90
90
  // Turn off. The OpenAPI workMode=0 path is authoritative; the BLE frame
91
91
  // mirrors the H8120 ice-maker-off command (33 19 00) as a best effort
92
- // and is pending confirmation from an H8121 owner.
92
+ // and is pending confirmation from an owner of either model.
93
93
  await this.platform.sendDeviceUpdate(this.accessory, {
94
94
  cmd: 'ptReal',
95
95
  value: 'MxkAAAAAAAAAAAAAAAAAAAAAACo=',
@@ -7,16 +7,13 @@ import {
7
7
  } from './appliance-basic.js'
8
8
  import deviceCoolerSingle from './cooler-single.js'
9
9
  import deviceDehumidifierH7150 from './dehumidifier-H7150.js'
10
- import deviceDehumidifierH7151 from './dehumidifier-H7151.js'
11
10
  import deviceDehumidifierH7152 from './dehumidifier-H7152.js'
12
11
  import deviceDiffuserH7161 from './diffuser-H7161.js'
13
- import deviceFanH1310 from './fan-H1310.js'
14
12
  import deviceFanH1370 from './fan-H1370.js'
15
13
  import deviceFanH7100 from './fan-H7100.js'
16
14
  import deviceFanH7101 from './fan-H7101.js'
17
15
  import deviceFanH7105 from './fan-H7105.js'
18
16
  import deviceFanH7107 from './fan-H7107.js'
19
- import deviceFanH7111 from './fan-H7111.js'
20
17
  import deviceHeater1A from './heater1a.js'
21
18
  import deviceHeater1B from './heater1b.js'
22
19
  import deviceHeater2 from './heater2.js'
@@ -28,7 +25,6 @@ import deviceHumidifierH7143 from './humidifier-H7143.js'
28
25
  import deviceHumidifierH7160 from './humidifier-H7160.js'
29
26
  import deviceIceMakerH7172 from './ice-maker-H7172.js'
30
27
  import deviceIceMakerH8121 from './ice-maker-H8121.js'
31
- import deviceIceMakerH8122 from './ice-maker-H8122.js'
32
28
  import deviceKettle from './kettle.js'
33
29
  import deviceLightSwitch from './light-switch.js'
34
30
  import deviceLight from './light.js'
@@ -36,15 +32,12 @@ import deviceOutletDouble from './outlet-double.js'
36
32
  import deviceOutletSingle from './outlet-single.js'
37
33
  import deviceOutletTriple from './outlet-triple.js'
38
34
  import devicePurifierH7120 from './purifier-H7120.js'
39
- import devicePurifierH7121 from './purifier-H7121.js'
40
35
  import devicePurifierH7122 from './purifier-H7122.js'
41
36
  import devicePurifierH7123 from './purifier-H7123.js'
42
- import devicePurifierH7124 from './purifier-H7124.js'
43
37
  import devicePurifierH7126 from './purifier-H7126.js'
44
38
  import devicePurifierSingle from './purifier-single.js'
45
- import deviceSensorButton from './sensor-button.js'
39
+ import deviceSensorBasic from './sensor-basic.js'
46
40
  import deviceSensorCO2 from './sensor-co2.js'
47
- import deviceSensorContact from './sensor-contact.js'
48
41
  import deviceSensorLeak from './sensor-leak.js'
49
42
  import deviceSensorMonitor from './sensor-monitor.js'
50
43
  import deviceSensorPresence from './sensor-presence.js'
@@ -62,22 +55,22 @@ import deviceValveSingle from './valve-single.js'
62
55
  export default {
63
56
  deviceCoolerSingle,
64
57
  deviceDehumidifierH7150,
65
- deviceDehumidifierH7151,
58
+ deviceDehumidifierH7151: deviceDehumidifierH7150, // identical to the H7150
66
59
  deviceDehumidifierH7152,
67
60
  deviceDiffuserH7161,
68
61
  deviceDiffuserH7162: deviceDiffuserH7161, // identical to the H7161
69
62
  deviceDehumidifierBasic,
70
63
  deviceFanBasic,
71
- deviceFanH1310,
64
+ deviceFanH1310: deviceFanH7100, // same fan, minus a confirmed swing status message
72
65
  deviceFanH1370,
73
- deviceFanR1310: deviceFanH1310, // R1310 is the newer naming of the H1310
66
+ deviceFanR1310: deviceFanH7100, // R1310 is the newer naming of the H1310
74
67
  deviceFanH7100,
75
68
  deviceFanH7102: deviceFanH7100, // identical to the H7100
76
69
  deviceFanH7106: deviceFanH7100, // identical to the H7100
77
70
  deviceFanH7101,
78
71
  deviceFanH7105,
79
72
  deviceFanH7107,
80
- deviceFanH7111,
73
+ deviceFanH7111: deviceFanH7101, // same fan without the turbo mode, which is not sent
81
74
  deviceHeaterSingle,
82
75
  deviceHeater1A,
83
76
  deviceHeater1B,
@@ -98,7 +91,7 @@ export default {
98
91
  deviceIceMakerH717D: deviceIceMakerH7172, // identical to the H7172
99
92
  deviceIceMakerH8120: deviceIceMakerH7172, // identical to the H7172
100
93
  deviceIceMakerH8121,
101
- deviceIceMakerH8122,
94
+ deviceIceMakerH8122: deviceIceMakerH8121, // identical to the H8121
102
95
  deviceKettle,
103
96
  deviceLight,
104
97
  deviceLightSwitch,
@@ -107,19 +100,20 @@ export default {
107
100
  deviceOutletTriple,
108
101
  devicePurifierBasic,
109
102
  devicePurifierH7120,
110
- devicePurifierH7121,
103
+ devicePurifierH7121: devicePurifierH7120, // identical apart from its sleep mode value, which is not sent
111
104
  devicePurifierH7122,
112
105
  devicePurifierH7123,
113
- devicePurifierH7124,
106
+ devicePurifierH7124: devicePurifierH7123, // same device; this also gives it the #1261 air quality fix
114
107
  devicePurifierH7126,
115
108
  devicePurifierH7127: devicePurifierH7126, // identical to the H7126
116
109
  devicePurifierH7128: devicePurifierH7126, // identical to the H7126
117
110
  devicePurifierH7129: devicePurifierH7126, // identical to the H7126
118
111
  devicePurifierH712C: devicePurifierH7126, // identical to the H7126
119
112
  devicePurifierSingle,
120
- deviceSensorButton,
113
+ deviceSensorBasic,
114
+ deviceSensorButton: deviceSensorBasic, // nothing decoded yet, so it reports instead
121
115
  deviceSensorCO2,
122
- deviceSensorContact,
116
+ deviceSensorContact: deviceSensorBasic, // nothing decoded yet, so it reports instead
123
117
  deviceSensorLeak,
124
118
  deviceSensorMonitor,
125
119
  deviceSensorPresence,
@@ -8,32 +8,15 @@ import platformLang from '../utils/lang-en.js'
8
8
  import { logUnknownData } from '../utils/report-unknown.js'
9
9
 
10
10
  /*
11
- H7120
12
- {
13
- "mode": {
14
- "options": [
15
- {
16
- "name": "Low",
17
- "value": 1
18
- },
19
- {
20
- "name": "Medium",
21
- "value": 2
22
- },
23
- {
24
- "name": "High",
25
- "value": 3
26
- },
27
- {
28
- "name": "Sleep mode",
29
- "value": 5
30
- }
31
- ]
32
- }
33
- }
11
+ The modes these purifiers report over the api. Low, medium and high are the
12
+ gear speeds the plugin drives; sleep is listed for reference and is the one
13
+ place the two models differ, so it must not be sent as a shared value.
14
+
15
+ H7120: Low 1, Medium 2, High 3, "Sleep mode" 5
16
+ H7121: Low 1, Medium 2, High 3, "Sleep" 16
34
17
  */
35
18
 
36
- export default class {
19
+ export default class GoveePurifierH7120 {
37
20
  constructor(platform, accessory) {
38
21
  // Set up variables from the platform
39
22
  this.cusChar = platform.cusChar
@@ -10,7 +10,7 @@ import platformLang from '../utils/lang-en.js'
10
10
  import { logUnknownData } from '../utils/report-unknown.js'
11
11
 
12
12
  /*
13
- H7123
13
+ H7123 and H7124
14
14
  {
15
15
  "mode": {
16
16
  "options": [
@@ -39,7 +39,7 @@ import { logUnknownData } from '../utils/report-unknown.js'
39
39
  }
40
40
  */
41
41
 
42
- export default class {
42
+ export default class GoveePurifierH7123 {
43
43
  constructor(platform, accessory) {
44
44
  // Set up variables from the platform
45
45
  this.cusChar = platform.cusChar
@@ -1,7 +1,14 @@
1
1
  import platformLang from '../utils/lang-en.js'
2
2
  import { logUnknownData } from '../utils/report-unknown.js'
3
3
 
4
- 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 {
5
12
  constructor(platform, accessory) {
6
13
  // Set up variables from the platform
7
14
  this.hapChar = platform.api.hap.Characteristic