@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 +5 -0
- package/lib/device/appliance-basic.js +94 -7
- package/lib/device/dehumidifier-H7150.js +2 -2
- package/lib/device/fan-H7100.js +18 -2
- package/lib/device/fan-H7101.js +4 -3
- package/lib/device/heater1a.js +10 -2
- package/lib/device/ice-maker-H8121.js +3 -3
- package/lib/device/index.js +11 -17
- package/lib/device/purifier-H7120.js +7 -24
- package/lib/device/purifier-H7123.js +2 -2
- package/lib/device/{sensor-button.js → sensor-basic.js} +8 -1
- package/lib/utils/capabilities.js +220 -0
- package/lib/utils/device-capabilities.js +9 -1
- package/package.json +1 -1
- package/lib/device/dehumidifier-H7151.js +0 -195
- package/lib/device/fan-H1310.js +0 -290
- package/lib/device/fan-H7111.js +0 -351
- package/lib/device/ice-maker-H8122.js +0 -228
- package/lib/device/purifier-H7121.js +0 -412
- package/lib/device/purifier-H7124.js +0 -510
- package/lib/device/sensor-contact.js +0 -27
- package/lib/utils/appliance-capabilities.js +0 -45
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
|
|
38
|
-
//
|
|
39
|
-
const hasSensor = config.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
package/lib/device/fan-H7100.js
CHANGED
|
@@ -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
|
-
//
|
|
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
|
package/lib/device/fan-H7101.js
CHANGED
|
@@ -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
|
}
|
package/lib/device/heater1a.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
-
|
|
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,
|
|
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
|
|
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=',
|
package/lib/device/index.js
CHANGED
|
@@ -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
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
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
|