@homebridge-plugins/homebridge-govee 11.2.0 → 11.2.1-beta.0
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 +6 -0
- package/config.schema.json +10 -1
- package/lib/device/fan-H7105.js +103 -151
- package/lib/platform.js +1 -0
- package/lib/utils/constants.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/config.schema.json
CHANGED
|
@@ -1153,6 +1153,14 @@
|
|
|
1153
1153
|
"condition": {
|
|
1154
1154
|
"functionBody": "return (model.fanDevices && model.fanDevices[arrayIndices] && model.fanDevices[arrayIndices].deviceId && model.fanDevices[arrayIndices].deviceId.length === 23);"
|
|
1155
1155
|
}
|
|
1156
|
+
},
|
|
1157
|
+
"hideLight": {
|
|
1158
|
+
"type": "boolean",
|
|
1159
|
+
"title": "Hide Light",
|
|
1160
|
+
"description": "Enable this to not expose the light service in Homebridge/Homekit if your fan has one.",
|
|
1161
|
+
"condition": {
|
|
1162
|
+
"functionBody": "return (model.fanDevices && model.fanDevices[arrayIndices] && model.fanDevices[arrayIndices].deviceId && model.fanDevices[arrayIndices].deviceId.length === 23 && !model.fanDevices[arrayIndices].ignoreDevice);"
|
|
1163
|
+
}
|
|
1156
1164
|
}
|
|
1157
1165
|
}
|
|
1158
1166
|
}
|
|
@@ -1604,7 +1612,8 @@
|
|
|
1604
1612
|
"items": [
|
|
1605
1613
|
"fanDevices[].label",
|
|
1606
1614
|
"fanDevices[].deviceId",
|
|
1607
|
-
"fanDevices[].ignoreDevice"
|
|
1615
|
+
"fanDevices[].ignoreDevice",
|
|
1616
|
+
"fanDevices[].hideLight"
|
|
1608
1617
|
]
|
|
1609
1618
|
}
|
|
1610
1619
|
]
|
package/lib/device/fan-H7105.js
CHANGED
|
@@ -22,20 +22,24 @@ export default class {
|
|
|
22
22
|
// Set up variables from the accessory
|
|
23
23
|
this.accessory = accessory
|
|
24
24
|
|
|
25
|
+
// Set up custom variables for this device type
|
|
26
|
+
const deviceConf = platform.deviceConf[accessory.context.gvDeviceId]
|
|
27
|
+
this.hideLight = deviceConf && deviceConf.hideLight
|
|
28
|
+
|
|
25
29
|
// Codes etc
|
|
26
30
|
this.speedCodes = {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
1: 'MwUBAQAAAAAAAAAAAAAAAAAAADY=',
|
|
32
|
+
2: 'MwUBAgAAAAAAAAAAAAAAAAAAADU=',
|
|
33
|
+
3: 'MwUBAwAAAAAAAAAAAAAAAAAAADQ=',
|
|
34
|
+
4: 'MwUBBAAAAAAAAAAAAAAAAAAAADM=',
|
|
35
|
+
5: 'MwUBBQAAAAAAAAAAAAAAAAAAADI=',
|
|
36
|
+
6: 'MwUBBgAAAAAAAAAAAAAAAAAAADE=',
|
|
37
|
+
7: 'MwUBBwAAAAAAAAAAAAAAAAAAADA=',
|
|
38
|
+
8: 'MwUBCAAAAAAAAAAAAAAAAAAAAD8=',
|
|
39
|
+
9: 'MwUBCQAAAAAAAAAAAAAAAAAAAD4=',
|
|
40
|
+
10: 'MwUBCgAAAAAAAAAAAAAAAAAAAD0=',
|
|
41
|
+
11: 'MwUBCwAAAAAAAAAAAAAAAAAAADw=',
|
|
42
|
+
12: 'MwUBDAAAAAAAAAAAAAAAAAAAADs=',
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
// Remove any old original Fan services
|
|
@@ -46,9 +50,6 @@ export default class {
|
|
|
46
50
|
// Add the fan service for the fan if it doesn't already exist
|
|
47
51
|
this.service = this.accessory.getService(this.hapServ.Fanv2) || this.accessory.addService(this.hapServ.Fanv2)
|
|
48
52
|
|
|
49
|
-
// Add the night light service if it doesn't already exist
|
|
50
|
-
this.lightService = this.accessory.getService(this.hapServ.Lightbulb) || this.accessory.addService(this.hapServ.Lightbulb)
|
|
51
|
-
|
|
52
53
|
// Add the set handler to the fan on/off characteristic
|
|
53
54
|
this.service
|
|
54
55
|
.getCharacteristic(this.hapChar.Active)
|
|
@@ -59,13 +60,13 @@ export default class {
|
|
|
59
60
|
this.service
|
|
60
61
|
.getCharacteristic(this.hapChar.RotationSpeed)
|
|
61
62
|
.setProps({
|
|
62
|
-
|
|
63
|
+
maxValue: 12,
|
|
64
|
+
minStep: 1,
|
|
63
65
|
minValue: 0,
|
|
64
|
-
|
|
66
|
+
unit: 'unitless', // This is actually from HAP for Bluetooth LE Specification, but fits
|
|
65
67
|
})
|
|
66
68
|
.onSet(async value => this.internalSpeedUpdate(value))
|
|
67
69
|
this.cacheSpeed = this.service.getCharacteristic(this.hapChar.RotationSpeed).value
|
|
68
|
-
this.cacheMode = this.cacheSpeed >= 91 ? 'auto' : 'manual'
|
|
69
70
|
|
|
70
71
|
// Add the set handler to the fan swing mode
|
|
71
72
|
this.service
|
|
@@ -73,29 +74,41 @@ export default class {
|
|
|
73
74
|
.onSet(async value => this.internalSwingUpdate(value))
|
|
74
75
|
this.cacheSwing = this.service.getCharacteristic(this.hapChar.SwingMode).value === 1 ? 'on' : 'off'
|
|
75
76
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
if (this.hideLight) {
|
|
78
|
+
if (this.accessory.getService(this.hapServ.Lightbulb)) {
|
|
79
|
+
// Remove the light service if it exists
|
|
80
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.Lightbulb))
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
// Add the night light service if it doesn't already exist
|
|
84
|
+
this.lightService = this.accessory.getService(this.hapServ.Lightbulb) || this.accessory.addService(this.hapServ.Lightbulb)
|
|
81
85
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
.onSet(async (value) => {
|
|
86
|
-
await this.internalBrightnessUpdate(value)
|
|
86
|
+
// Add the set handler to the lightbulb on/off characteristic
|
|
87
|
+
this.lightService.getCharacteristic(this.hapChar.On).onSet(async (value) => {
|
|
88
|
+
await this.internalLightStateUpdate(value)
|
|
87
89
|
})
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
90
|
+
this.cacheLightState = this.lightService.getCharacteristic(this.hapChar.On).value ? 'on' : 'off'
|
|
91
|
+
|
|
92
|
+
// Add the set handler to the lightbulb brightness characteristic
|
|
93
|
+
this.lightService
|
|
94
|
+
.getCharacteristic(this.hapChar.Brightness)
|
|
95
|
+
.onSet(async (value) => {
|
|
96
|
+
await this.internalBrightnessUpdate(value)
|
|
97
|
+
})
|
|
98
|
+
this.cacheBright = this.lightService.getCharacteristic(this.hapChar.Brightness).value
|
|
99
|
+
|
|
100
|
+
// Add the set handler to the lightbulb hue characteristic
|
|
101
|
+
this.lightService.getCharacteristic(this.hapChar.Hue).onSet(async (value) => {
|
|
102
|
+
await this.internalColourUpdate(value)
|
|
103
|
+
})
|
|
104
|
+
this.cacheHue = this.lightService.getCharacteristic(this.hapChar.Hue).value
|
|
105
|
+
this.cacheSat = this.lightService.getCharacteristic(this.hapChar.Saturation).value
|
|
106
|
+
}
|
|
96
107
|
|
|
97
108
|
// Output the customised options to the log
|
|
98
|
-
const opts = JSON.stringify({
|
|
109
|
+
const opts = JSON.stringify({
|
|
110
|
+
hideLight: this.hideLight,
|
|
111
|
+
})
|
|
99
112
|
platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
|
|
100
113
|
}
|
|
101
114
|
|
|
@@ -133,74 +146,20 @@ export default class {
|
|
|
133
146
|
|
|
134
147
|
async internalSpeedUpdate(value) {
|
|
135
148
|
try {
|
|
136
|
-
if (value < 3) {
|
|
137
|
-
return
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
let newValue
|
|
141
|
-
if (value < 10) {
|
|
142
|
-
newValue = 7
|
|
143
|
-
} else if (value < 17) {
|
|
144
|
-
newValue = 14
|
|
145
|
-
} else if (value < 24) {
|
|
146
|
-
newValue = 21
|
|
147
|
-
} else if (value < 31) {
|
|
148
|
-
newValue = 28
|
|
149
|
-
} else if (value < 38) {
|
|
150
|
-
newValue = 35
|
|
151
|
-
} else if (value < 45) {
|
|
152
|
-
newValue = 42
|
|
153
|
-
} else if (value < 52) {
|
|
154
|
-
newValue = 49
|
|
155
|
-
} else if (value < 59) {
|
|
156
|
-
newValue = 56
|
|
157
|
-
} else if (value < 66) {
|
|
158
|
-
newValue = 63
|
|
159
|
-
} else if (value < 73) {
|
|
160
|
-
newValue = 70
|
|
161
|
-
} else if (value < 80) {
|
|
162
|
-
newValue = 77
|
|
163
|
-
} else if (value < 87) {
|
|
164
|
-
newValue = 84
|
|
165
|
-
} else {
|
|
166
|
-
newValue = 91
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
let newMode = value === 91 ? 'auto' : 'manual'
|
|
170
|
-
|
|
171
149
|
// Don't continue if the new value is the same as before
|
|
172
|
-
if (this.cacheSpeed ===
|
|
150
|
+
if (this.cacheSpeed === value || value === 0) {
|
|
173
151
|
return
|
|
174
152
|
}
|
|
175
153
|
|
|
176
|
-
// Don't continue if trying to access auto mode but there is no sensor attached
|
|
177
|
-
let codeToSend
|
|
178
|
-
if (newMode === 'auto') {
|
|
179
|
-
if (!this.accessory.context.sensorAttached || !this.cacheAutoCode) {
|
|
180
|
-
this.accessory.logWarn('auto mode not supported without a linked sensor')
|
|
181
|
-
codeToSend = this.speedCodes[84]
|
|
182
|
-
newMode = 'manual'
|
|
183
|
-
newValue = 84
|
|
184
|
-
} else {
|
|
185
|
-
codeToSend = this.cacheAutoCode
|
|
186
|
-
}
|
|
187
|
-
} else {
|
|
188
|
-
codeToSend = this.speedCodes[newValue]
|
|
189
|
-
}
|
|
190
|
-
|
|
191
154
|
await this.platform.sendDeviceUpdate(this.accessory, {
|
|
192
155
|
cmd: 'ptReal',
|
|
193
|
-
value:
|
|
156
|
+
value: this.speedCodes[value],
|
|
194
157
|
})
|
|
195
158
|
|
|
196
159
|
// Cache the new state and log if appropriate
|
|
197
|
-
if (this.
|
|
198
|
-
this.
|
|
199
|
-
this.accessory.log(`${platformLang.
|
|
200
|
-
}
|
|
201
|
-
if (this.cacheSpeed !== newValue) {
|
|
202
|
-
this.cacheSpeed = newValue
|
|
203
|
-
this.accessory.log(`${platformLang.curSpeed} [${newValue}%]`)
|
|
160
|
+
if (this.cacheSpeed !== value) {
|
|
161
|
+
this.cacheSpeed = value
|
|
162
|
+
this.accessory.log(`${platformLang.curSpeed} [${value}]`)
|
|
204
163
|
}
|
|
205
164
|
} catch (err) {
|
|
206
165
|
// Catch any errors during the process
|
|
@@ -224,7 +183,7 @@ export default class {
|
|
|
224
183
|
|
|
225
184
|
await this.platform.sendDeviceUpdate(this.accessory, {
|
|
226
185
|
cmd: 'ptReal',
|
|
227
|
-
value: value ? '
|
|
186
|
+
value: value ? 'Mx0BAZYDhAAAAAAAAAAAAAAAAD8=' : 'Mx0AAZYDhAAAAAAAAAAAAAAAAD4=',
|
|
228
187
|
})
|
|
229
188
|
|
|
230
189
|
// Cache the new state and log if appropriate
|
|
@@ -408,16 +367,11 @@ export default class {
|
|
|
408
367
|
case '0501': {
|
|
409
368
|
// Fan speed
|
|
410
369
|
const newSpeed = getTwoItemPosition(hexParts, 4)
|
|
411
|
-
const newSpeedInt = Number.parseInt(newSpeed, 16)
|
|
412
|
-
const newMode = 'manual'
|
|
413
|
-
if (this.cacheMode !== newMode) {
|
|
414
|
-
this.cacheMode = newMode
|
|
415
|
-
this.accessory.log(`${platformLang.curMode} [${this.cacheMode}]`)
|
|
416
|
-
}
|
|
370
|
+
const newSpeedInt = Number.parseInt(newSpeed, 16)
|
|
417
371
|
if (this.cacheSpeed !== newSpeedInt) {
|
|
418
372
|
this.cacheSpeed = newSpeedInt
|
|
419
373
|
this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed)
|
|
420
|
-
this.accessory.log(`${platformLang.curSpeed} [${this.cacheSpeed}
|
|
374
|
+
this.accessory.log(`${platformLang.curSpeed} [${this.cacheSpeed}]`)
|
|
421
375
|
}
|
|
422
376
|
break
|
|
423
377
|
}
|
|
@@ -430,66 +384,64 @@ export default class {
|
|
|
430
384
|
// Sleep: 5
|
|
431
385
|
// Nature: 6
|
|
432
386
|
// Turbo: 7
|
|
433
|
-
const newMode = getTwoItemPosition(hexParts, 4) === '03' ? 'auto' : 'manual'
|
|
434
|
-
if (this.cacheMode !== newMode) {
|
|
435
|
-
this.cacheMode = newMode
|
|
436
|
-
this.accessory.log(`${platformLang.curMode} [${this.cacheMode}]`)
|
|
437
|
-
|
|
438
|
-
if (this.cacheMode === 'auto' && this.cacheSpeed < 91) {
|
|
439
|
-
this.cacheSpeed = 91
|
|
440
|
-
this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed)
|
|
441
|
-
this.accessory.log(`${platformLang.curSpeed} [${this.cacheSpeed}%]`)
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
break
|
|
445
|
-
}
|
|
446
|
-
case '0503': {
|
|
447
|
-
// Auto mode, we need to keep this code to send it back to the device
|
|
448
|
-
const code = hexToTwoItems(`33${hexString.substring(2, hexString.length - 2)}`)
|
|
449
|
-
this.cacheAutoCode = generateCodeFromHexValues(code.map(p => Number.parseInt(p, 16)))
|
|
450
387
|
break
|
|
451
388
|
}
|
|
452
389
|
case '1b01': {
|
|
453
|
-
|
|
454
|
-
if (this.
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
390
|
+
// Night light on/off
|
|
391
|
+
if (!this.hideLight) {
|
|
392
|
+
const newLightState = getTwoItemPosition(hexParts, 4) === '01' ? 'on' : 'off'
|
|
393
|
+
if (this.cacheLightState !== newLightState) {
|
|
394
|
+
this.cacheLightState = newLightState
|
|
395
|
+
this.lightService.updateCharacteristic(this.hapChar.On, this.cacheLightState === 'on')
|
|
396
|
+
this.accessory.log(`${platformLang.curLight} [${this.cacheLightState}]`)
|
|
397
|
+
}
|
|
398
|
+
const newBrightness = hexToDecimal(getTwoItemPosition(hexParts, 5))
|
|
399
|
+
if (this.cacheBright !== newBrightness) {
|
|
400
|
+
this.cacheBright = newBrightness
|
|
401
|
+
this.lightService.updateCharacteristic(this.hapChar.Brightness, this.cacheBright)
|
|
402
|
+
this.accessory.log(`${platformLang.curBright} [${this.cacheBright}%]`)
|
|
403
|
+
}
|
|
464
404
|
}
|
|
465
405
|
break
|
|
466
406
|
}
|
|
467
407
|
case '1b05': {
|
|
468
408
|
// Night light colour
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
409
|
+
if (!this.hideLight) {
|
|
410
|
+
const newR = hexToDecimal(getTwoItemPosition(hexParts, 5))
|
|
411
|
+
const newG = hexToDecimal(getTwoItemPosition(hexParts, 6))
|
|
412
|
+
const newB = hexToDecimal(getTwoItemPosition(hexParts, 7))
|
|
413
|
+
|
|
414
|
+
const hs = rgb2hs(newR, newG, newB)
|
|
415
|
+
|
|
416
|
+
// Check for a colour change
|
|
417
|
+
if (hs[0] !== this.cacheHue) {
|
|
418
|
+
// Colour is different so update Homebridge with new values
|
|
419
|
+
this.lightService.updateCharacteristic(this.hapChar.Hue, hs[0])
|
|
420
|
+
this.lightService.updateCharacteristic(this.hapChar.Saturation, hs[1]);
|
|
421
|
+
[this.cacheHue] = hs
|
|
422
|
+
|
|
423
|
+
// Log the change
|
|
424
|
+
this.accessory.log(`${platformLang.curColour} [rgb ${newR} ${newG} ${newB}]`)
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
break
|
|
428
|
+
}
|
|
429
|
+
case '1d00':{
|
|
430
|
+
// Swing Mode Off
|
|
431
|
+
const newSwing = 'off'
|
|
432
|
+
if (this.cacheSwing !== newSwing) {
|
|
433
|
+
this.cacheSwing = newSwing
|
|
434
|
+
this.service.updateCharacteristic(this.hapChar.SwingMode, 0)
|
|
435
|
+
this.accessory.log(`${platformLang.curSwing} [${this.cacheSwing}]`)
|
|
484
436
|
}
|
|
485
437
|
break
|
|
486
438
|
}
|
|
487
|
-
case '
|
|
488
|
-
// Swing Mode
|
|
489
|
-
const newSwing =
|
|
439
|
+
case '1d01':{
|
|
440
|
+
// Swing Mode On
|
|
441
|
+
const newSwing = 'on'
|
|
490
442
|
if (this.cacheSwing !== newSwing) {
|
|
491
443
|
this.cacheSwing = newSwing
|
|
492
|
-
this.service.updateCharacteristic(this.hapChar.SwingMode,
|
|
444
|
+
this.service.updateCharacteristic(this.hapChar.SwingMode, 1)
|
|
493
445
|
this.accessory.log(`${platformLang.curSwing} [${this.cacheSwing}]`)
|
|
494
446
|
}
|
|
495
447
|
break
|
package/lib/platform.js
CHANGED
package/lib/utils/constants.js
CHANGED
|
@@ -91,7 +91,7 @@ export default {
|
|
|
91
91
|
],
|
|
92
92
|
leakDevices: ['label', 'deviceId', 'ignoreDevice', 'lowBattThreshold'],
|
|
93
93
|
thermoDevices: ['label', 'deviceId', 'ignoreDevice', 'lowBattThreshold', 'showExtraSwitch'],
|
|
94
|
-
fanDevices: ['label', 'deviceId', 'ignoreDevice'],
|
|
94
|
+
fanDevices: ['label', 'deviceId', 'ignoreDevice', 'hideLight'],
|
|
95
95
|
heaterDevices: ['label', 'deviceId', 'ignoreDevice', 'tempReporting'],
|
|
96
96
|
humidifierDevices: ['label', 'deviceId', 'ignoreDevice'],
|
|
97
97
|
dehumidifierDevices: ['label', 'deviceId', 'ignoreDevice'],
|
package/package.json
CHANGED