@homebridge-plugins/homebridge-govee 11.2.1-beta.2 → 11.3.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 +7 -1
- package/config.schema.json +1 -10
- package/lib/device/fan-H7105.js +152 -116
- package/lib/homebridge-ui/public/index.html +37 -1
- package/lib/platform.js +0 -1
- package/lib/utils/constants.js +1 -1
- package/lib/utils/custom-chars.js +211 -176
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to homebridge-govee will be documented in this file.
|
|
4
4
|
|
|
5
|
-
## v11.
|
|
5
|
+
## v11.3.0 (2025-07-13)
|
|
6
|
+
|
|
7
|
+
### Notable Changes
|
|
8
|
+
|
|
9
|
+
- fix custom plugin config modal styles in ui 5
|
|
10
|
+
- fix custom characteristics for hb 2
|
|
6
11
|
|
|
7
12
|
### Other Changes
|
|
8
13
|
|
|
9
14
|
- fix permission in release workflow
|
|
15
|
+
- improvements to the deprecate workflow
|
|
10
16
|
|
|
11
17
|
## v11.2.0 (2025-07-12)
|
|
12
18
|
|
package/config.schema.json
CHANGED
|
@@ -1153,14 +1153,6 @@
|
|
|
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
|
-
}
|
|
1164
1156
|
}
|
|
1165
1157
|
}
|
|
1166
1158
|
}
|
|
@@ -1612,8 +1604,7 @@
|
|
|
1612
1604
|
"items": [
|
|
1613
1605
|
"fanDevices[].label",
|
|
1614
1606
|
"fanDevices[].deviceId",
|
|
1615
|
-
"fanDevices[].ignoreDevice"
|
|
1616
|
-
"fanDevices[].hideLight"
|
|
1607
|
+
"fanDevices[].ignoreDevice"
|
|
1617
1608
|
]
|
|
1618
1609
|
}
|
|
1619
1610
|
]
|
package/lib/device/fan-H7105.js
CHANGED
|
@@ -22,24 +22,20 @@ 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
|
-
|
|
29
25
|
// Codes etc
|
|
30
26
|
this.speedCodes = {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
27
|
+
7: 'MwUBAQAAAAAAAAAAAAAAAAAAADY=',
|
|
28
|
+
14: 'MwUBAgAAAAAAAAAAAAAAAAAAADU=',
|
|
29
|
+
21: 'MwUBAwAAAAAAAAAAAAAAAAAAADQ=',
|
|
30
|
+
28: 'MwUBBAAAAAAAAAAAAAAAAAAAADM=',
|
|
31
|
+
35: 'MwUBBQAAAAAAAAAAAAAAAAAAADI=',
|
|
32
|
+
42: 'MwUBBgAAAAAAAAAAAAAAAAAAADE=',
|
|
33
|
+
49: 'MwUBBwAAAAAAAAAAAAAAAAAAADA=',
|
|
34
|
+
56: 'MwUBCAAAAAAAAAAAAAAAAAAAAD8=',
|
|
35
|
+
63: 'MwUBCQAAAAAAAAAAAAAAAAAAAD4=',
|
|
36
|
+
70: 'MwUBCgAAAAAAAAAAAAAAAAAAAD0=', // guessed
|
|
37
|
+
77: 'MwUBCwAAAAAAAAAAAAAAAAAAADw=', // guessed
|
|
38
|
+
84: 'MwUBDAAAAAAAAAAAAAAAAAAAADs=', // guessed
|
|
43
39
|
}
|
|
44
40
|
|
|
45
41
|
// Remove any old original Fan services
|
|
@@ -50,6 +46,9 @@ export default class {
|
|
|
50
46
|
// Add the fan service for the fan if it doesn't already exist
|
|
51
47
|
this.service = this.accessory.getService(this.hapServ.Fanv2) || this.accessory.addService(this.hapServ.Fanv2)
|
|
52
48
|
|
|
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
|
+
|
|
53
52
|
// Add the set handler to the fan on/off characteristic
|
|
54
53
|
this.service
|
|
55
54
|
.getCharacteristic(this.hapChar.Active)
|
|
@@ -60,56 +59,43 @@ export default class {
|
|
|
60
59
|
this.service
|
|
61
60
|
.getCharacteristic(this.hapChar.RotationSpeed)
|
|
62
61
|
.setProps({
|
|
63
|
-
|
|
64
|
-
minStep: 1,
|
|
62
|
+
minStep: 7,
|
|
65
63
|
minValue: 0,
|
|
66
|
-
|
|
64
|
+
validValues: [0, 7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91],
|
|
67
65
|
})
|
|
68
66
|
.onSet(async value => this.internalSpeedUpdate(value))
|
|
69
67
|
this.cacheSpeed = this.service.getCharacteristic(this.hapChar.RotationSpeed).value
|
|
68
|
+
this.cacheMode = this.cacheSpeed >= 91 ? 'auto' : 'manual'
|
|
70
69
|
|
|
71
70
|
// Add the set handler to the fan swing mode
|
|
72
71
|
this.service
|
|
73
72
|
.getCharacteristic(this.hapChar.SwingMode)
|
|
74
73
|
.onSet(async value => this.internalSwingUpdate(value))
|
|
75
74
|
this.cacheSwing = this.service.getCharacteristic(this.hapChar.SwingMode).value === 1 ? 'on' : 'off'
|
|
76
|
-
this.cacheSwingCode = ''
|
|
77
75
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
} else {
|
|
84
|
-
// Add the night light service if it doesn't already exist
|
|
85
|
-
this.lightService = this.accessory.getService(this.hapServ.Lightbulb) || this.accessory.addService(this.hapServ.Lightbulb)
|
|
76
|
+
// Add the set handler to the lightbulb on/off characteristic
|
|
77
|
+
this.lightService.getCharacteristic(this.hapChar.On).onSet(async (value) => {
|
|
78
|
+
await this.internalLightStateUpdate(value)
|
|
79
|
+
})
|
|
80
|
+
this.cacheLightState = this.lightService.getCharacteristic(this.hapChar.On).value ? 'on' : 'off'
|
|
86
81
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
// Add the set handler to the lightbulb brightness characteristic
|
|
94
|
-
this.lightService
|
|
95
|
-
.getCharacteristic(this.hapChar.Brightness)
|
|
96
|
-
.onSet(async (value) => {
|
|
97
|
-
await this.internalBrightnessUpdate(value)
|
|
98
|
-
})
|
|
99
|
-
this.cacheBright = this.lightService.getCharacteristic(this.hapChar.Brightness).value
|
|
100
|
-
|
|
101
|
-
// Add the set handler to the lightbulb hue characteristic
|
|
102
|
-
this.lightService.getCharacteristic(this.hapChar.Hue).onSet(async (value) => {
|
|
103
|
-
await this.internalColourUpdate(value)
|
|
82
|
+
// Add the set handler to the lightbulb brightness characteristic
|
|
83
|
+
this.lightService
|
|
84
|
+
.getCharacteristic(this.hapChar.Brightness)
|
|
85
|
+
.onSet(async (value) => {
|
|
86
|
+
await this.internalBrightnessUpdate(value)
|
|
104
87
|
})
|
|
105
|
-
|
|
106
|
-
this.cacheSat = this.lightService.getCharacteristic(this.hapChar.Saturation).value
|
|
107
|
-
}
|
|
88
|
+
this.cacheBright = this.lightService.getCharacteristic(this.hapChar.Brightness).value
|
|
108
89
|
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
-
|
|
90
|
+
// Add the set handler to the lightbulb hue characteristic
|
|
91
|
+
this.lightService.getCharacteristic(this.hapChar.Hue).onSet(async (value) => {
|
|
92
|
+
await this.internalColourUpdate(value)
|
|
112
93
|
})
|
|
94
|
+
this.cacheHue = this.lightService.getCharacteristic(this.hapChar.Hue).value
|
|
95
|
+
this.cacheSat = this.lightService.getCharacteristic(this.hapChar.Saturation).value
|
|
96
|
+
|
|
97
|
+
// Output the customised options to the log
|
|
98
|
+
const opts = JSON.stringify({})
|
|
113
99
|
platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
|
|
114
100
|
}
|
|
115
101
|
|
|
@@ -147,20 +133,74 @@ export default class {
|
|
|
147
133
|
|
|
148
134
|
async internalSpeedUpdate(value) {
|
|
149
135
|
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
|
+
|
|
150
171
|
// Don't continue if the new value is the same as before
|
|
151
|
-
if (this.cacheSpeed ===
|
|
172
|
+
if (this.cacheSpeed === newValue) {
|
|
152
173
|
return
|
|
153
174
|
}
|
|
154
175
|
|
|
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
|
+
|
|
155
191
|
await this.platform.sendDeviceUpdate(this.accessory, {
|
|
156
192
|
cmd: 'ptReal',
|
|
157
|
-
value:
|
|
193
|
+
value: codeToSend,
|
|
158
194
|
})
|
|
159
195
|
|
|
160
196
|
// Cache the new state and log if appropriate
|
|
161
|
-
if (this.
|
|
162
|
-
this.
|
|
163
|
-
this.accessory.log(`${platformLang.
|
|
197
|
+
if (this.cacheMode !== newMode) {
|
|
198
|
+
this.cacheMode = newMode
|
|
199
|
+
this.accessory.log(`${platformLang.curMode} [${this.cacheMode}]`)
|
|
200
|
+
}
|
|
201
|
+
if (this.cacheSpeed !== newValue) {
|
|
202
|
+
this.cacheSpeed = newValue
|
|
203
|
+
this.accessory.log(`${platformLang.curSpeed} [${newValue}%]`)
|
|
164
204
|
}
|
|
165
205
|
} catch (err) {
|
|
166
206
|
// Catch any errors during the process
|
|
@@ -178,22 +218,13 @@ export default class {
|
|
|
178
218
|
try {
|
|
179
219
|
const newValue = value ? 'on' : 'off'
|
|
180
220
|
// Don't continue if the new value is the same as before
|
|
181
|
-
if (this.cacheSwing === value
|
|
221
|
+
if (this.cacheSwing === value) {
|
|
182
222
|
return
|
|
183
223
|
}
|
|
184
224
|
|
|
185
|
-
// The existing cacheSwingCode might be something like aa1d0101960384000000000000000000000000a6
|
|
186
|
-
// We need to change the third hex value to 00 for off or 01 for on
|
|
187
|
-
const hexValues = [
|
|
188
|
-
0x3A,
|
|
189
|
-
0x1D,
|
|
190
|
-
value ? 0x01 : 0x00,
|
|
191
|
-
...this.cacheSwingCode.slice(6, 14).match(/.{1,2}/g).map(byte => Number.parseInt(byte, 16)),
|
|
192
|
-
]
|
|
193
|
-
|
|
194
225
|
await this.platform.sendDeviceUpdate(this.accessory, {
|
|
195
226
|
cmd: 'ptReal',
|
|
196
|
-
value:
|
|
227
|
+
value: value ? 'Mx8BAQAAAAAAAAAAAAAAAAAAACw=' : 'Mx8BAAAAAAAAAAAAAAAAAAAAAC0=',
|
|
197
228
|
})
|
|
198
229
|
|
|
199
230
|
// Cache the new state and log if appropriate
|
|
@@ -377,11 +408,16 @@ export default class {
|
|
|
377
408
|
case '0501': {
|
|
378
409
|
// Fan speed
|
|
379
410
|
const newSpeed = getTwoItemPosition(hexParts, 4)
|
|
380
|
-
const newSpeedInt = Number.parseInt(newSpeed, 16)
|
|
411
|
+
const newSpeedInt = Number.parseInt(newSpeed, 16) * 7
|
|
412
|
+
const newMode = 'manual'
|
|
413
|
+
if (this.cacheMode !== newMode) {
|
|
414
|
+
this.cacheMode = newMode
|
|
415
|
+
this.accessory.log(`${platformLang.curMode} [${this.cacheMode}]`)
|
|
416
|
+
}
|
|
381
417
|
if (this.cacheSpeed !== newSpeedInt) {
|
|
382
418
|
this.cacheSpeed = newSpeedInt
|
|
383
419
|
this.service.updateCharacteristic(this.hapChar.RotationSpeed, this.cacheSpeed)
|
|
384
|
-
this.accessory.log(`${platformLang.curSpeed} [${this.cacheSpeed}]`)
|
|
420
|
+
this.accessory.log(`${platformLang.curSpeed} [${this.cacheSpeed}%]`)
|
|
385
421
|
}
|
|
386
422
|
break
|
|
387
423
|
}
|
|
@@ -394,66 +430,66 @@ export default class {
|
|
|
394
430
|
// Sleep: 5
|
|
395
431
|
// Nature: 6
|
|
396
432
|
// 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)))
|
|
397
450
|
break
|
|
398
451
|
}
|
|
399
452
|
case '1b01': {
|
|
400
|
-
|
|
401
|
-
if (
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
this.lightService.updateCharacteristic(this.hapChar.Brightness, this.cacheBright)
|
|
412
|
-
this.accessory.log(`${platformLang.curBright} [${this.cacheBright}%]`)
|
|
413
|
-
}
|
|
453
|
+
const newLightState = getTwoItemPosition(hexParts, 4) === '01' ? 'on' : 'off'
|
|
454
|
+
if (this.cacheLightState !== newLightState) {
|
|
455
|
+
this.cacheLightState = newLightState
|
|
456
|
+
this.lightService.updateCharacteristic(this.hapChar.On, this.cacheLightState === 'on')
|
|
457
|
+
this.accessory.log(`${platformLang.curLight} [${this.cacheLightState}]`)
|
|
458
|
+
}
|
|
459
|
+
const newBrightness = hexToDecimal(getTwoItemPosition(hexParts, 5))
|
|
460
|
+
if (this.cacheBright !== newBrightness) {
|
|
461
|
+
this.cacheBright = newBrightness
|
|
462
|
+
this.lightService.updateCharacteristic(this.hapChar.Brightness, this.cacheBright)
|
|
463
|
+
this.accessory.log(`${platformLang.curBright} [${this.cacheBright}%]`)
|
|
414
464
|
}
|
|
415
465
|
break
|
|
416
466
|
}
|
|
417
467
|
case '1b05': {
|
|
418
468
|
// Night light colour
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
this.accessory.log(`${platformLang.curColour} [rgb ${newR} ${newG} ${newB}]`)
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
break
|
|
438
|
-
}
|
|
439
|
-
case '1d00':{
|
|
440
|
-
// Swing Mode Off
|
|
441
|
-
const newSwing = 'off'
|
|
442
|
-
this.cacheSwingCode = hexString
|
|
443
|
-
if (this.cacheSwing !== newSwing) {
|
|
444
|
-
this.cacheSwing = newSwing
|
|
445
|
-
this.service.updateCharacteristic(this.hapChar.SwingMode, 0)
|
|
446
|
-
this.accessory.log(`${platformLang.curSwing} [${this.cacheSwing}]`)
|
|
469
|
+
const newR = hexToDecimal(getTwoItemPosition(hexParts, 5))
|
|
470
|
+
const newG = hexToDecimal(getTwoItemPosition(hexParts, 6))
|
|
471
|
+
const newB = hexToDecimal(getTwoItemPosition(hexParts, 7))
|
|
472
|
+
|
|
473
|
+
const hs = rgb2hs(newR, newG, newB)
|
|
474
|
+
|
|
475
|
+
// Check for a colour change
|
|
476
|
+
if (hs[0] !== this.cacheHue) {
|
|
477
|
+
// Colour is different so update Homebridge with new values
|
|
478
|
+
this.lightService.updateCharacteristic(this.hapChar.Hue, hs[0])
|
|
479
|
+
this.lightService.updateCharacteristic(this.hapChar.Saturation, hs[1]);
|
|
480
|
+
[this.cacheHue] = hs
|
|
481
|
+
|
|
482
|
+
// Log the change
|
|
483
|
+
this.accessory.log(`${platformLang.curColour} [rgb ${newR} ${newG} ${newB}]`)
|
|
447
484
|
}
|
|
448
485
|
break
|
|
449
486
|
}
|
|
450
|
-
case '
|
|
451
|
-
// Swing Mode
|
|
452
|
-
const newSwing = 'on'
|
|
453
|
-
this.cacheSwingCode = hexString
|
|
487
|
+
case '1f01': {
|
|
488
|
+
// Swing Mode
|
|
489
|
+
const newSwing = getTwoItemPosition(hexParts, 4) === '01' ? 'on' : 'off'
|
|
454
490
|
if (this.cacheSwing !== newSwing) {
|
|
455
491
|
this.cacheSwing = newSwing
|
|
456
|
-
this.service.updateCharacteristic(this.hapChar.SwingMode, 1)
|
|
492
|
+
this.service.updateCharacteristic(this.hapChar.SwingMode, this.cacheSwing === 'on' ? 1 : 0)
|
|
457
493
|
this.accessory.log(`${platformLang.curSwing} [${this.cacheSwing}]`)
|
|
458
494
|
}
|
|
459
495
|
break
|
|
@@ -1,3 +1,39 @@
|
|
|
1
|
+
<style>
|
|
2
|
+
.dark-mode {
|
|
3
|
+
background-color: #242424;
|
|
4
|
+
color: lightgrey;
|
|
5
|
+
|
|
6
|
+
.form-control {
|
|
7
|
+
background-color: #333333 !important;
|
|
8
|
+
border: none !important;
|
|
9
|
+
color: #eeeeee !important;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
thead, tbody, tr {
|
|
13
|
+
border-style: hidden;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
th {
|
|
17
|
+
color: #eeeeee !important;
|
|
18
|
+
font-weight: 500 !important;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
select {
|
|
22
|
+
background-image:
|
|
23
|
+
linear-gradient(45deg, transparent 50%, gray 50%),
|
|
24
|
+
linear-gradient(135deg, gray 50%, transparent 50%),
|
|
25
|
+
linear-gradient(to right, #ccc, #ccc);
|
|
26
|
+
background-position:
|
|
27
|
+
calc(100% - 20px) calc(1em + 2px),
|
|
28
|
+
calc(100% - 15px) calc(1em + 2px),
|
|
29
|
+
calc(100% - 2.5em) 0.5em;
|
|
30
|
+
background-size:
|
|
31
|
+
5px 5px,
|
|
32
|
+
5px 5px,
|
|
33
|
+
1px 1.5em;
|
|
34
|
+
background-repeat: no-repeat;
|
|
35
|
+
}
|
|
36
|
+
</style>
|
|
1
37
|
<p class="text-center">
|
|
2
38
|
<img
|
|
3
39
|
src="https://user-images.githubusercontent.com/43026681/101324574-5e997d80-3862-11eb-81b0-932330f6e242.png"
|
|
@@ -30,7 +66,7 @@
|
|
|
30
66
|
<select class="form-control" id="deviceSelect"></select>
|
|
31
67
|
</div>
|
|
32
68
|
</form>
|
|
33
|
-
<table class="table w-100" id="deviceTable" style="display: none;">
|
|
69
|
+
<table class="table w-100 mt-3" id="deviceTable" style="display: none;">
|
|
34
70
|
<thead>
|
|
35
71
|
<tr class="table-active">
|
|
36
72
|
<th scope="col" style="width: 40%;">Device Name</th>
|
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'],
|
|
95
95
|
heaterDevices: ['label', 'deviceId', 'ignoreDevice', 'tempReporting'],
|
|
96
96
|
humidifierDevices: ['label', 'deviceId', 'ignoreDevice'],
|
|
97
97
|
dehumidifierDevices: ['label', 'deviceId', 'ignoreDevice'],
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import { inherits } from 'node:util'
|
|
2
|
-
|
|
3
1
|
export default class {
|
|
4
2
|
constructor(api) {
|
|
5
|
-
this.hapServ = api.hap.Service
|
|
6
|
-
this.hapChar = api.hap.Characteristic
|
|
7
3
|
this.uuids = {
|
|
8
4
|
/* deprecated
|
|
9
5
|
bluetooth: 'E964F001-079E-48FF-8F27-9C2605A29F52'
|
|
@@ -30,178 +26,217 @@ export default class {
|
|
|
30
26
|
nightLight: 'E964F021-079E-48FF-8F27-9C2605A29F52',
|
|
31
27
|
displayLight: 'E964F022-079E-48FF-8F27-9C2605A29F52',
|
|
32
28
|
}
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
this.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
this.
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
29
|
+
const uuids = this.uuids
|
|
30
|
+
|
|
31
|
+
this.ColourMode = class extends api.hap.Characteristic {
|
|
32
|
+
constructor() {
|
|
33
|
+
super('Colour Mode', uuids.colourMode)
|
|
34
|
+
this.setProps({
|
|
35
|
+
format: api.hap.Formats.BOOL,
|
|
36
|
+
perms: [api.hap.Perms.PAIRED_READ, api.hap.Perms.PAIRED_WRITE, api.hap.Perms.NOTIFY],
|
|
37
|
+
})
|
|
38
|
+
this.value = this.getDefaultValue()
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.MusicMode = class extends api.hap.Characteristic {
|
|
43
|
+
constructor() {
|
|
44
|
+
super('Music Mode', uuids.musicMode)
|
|
45
|
+
this.setProps({
|
|
46
|
+
format: api.hap.Formats.BOOL,
|
|
47
|
+
perms: [api.hap.Perms.PAIRED_READ, api.hap.Perms.PAIRED_WRITE, api.hap.Perms.NOTIFY],
|
|
48
|
+
})
|
|
49
|
+
this.value = this.getDefaultValue()
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
this.MusicModeTwo = class extends api.hap.Characteristic {
|
|
54
|
+
constructor() {
|
|
55
|
+
super('Music Mode 2', uuids.musicModeTwo)
|
|
56
|
+
this.setProps({
|
|
57
|
+
format: api.hap.Formats.BOOL,
|
|
58
|
+
perms: [api.hap.Perms.PAIRED_READ, api.hap.Perms.PAIRED_WRITE, api.hap.Perms.NOTIFY],
|
|
59
|
+
})
|
|
60
|
+
this.value = this.getDefaultValue()
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this.Scene = class extends api.hap.Characteristic {
|
|
65
|
+
constructor() {
|
|
66
|
+
super('Scene', uuids.scene)
|
|
67
|
+
this.setProps({
|
|
68
|
+
format: api.hap.Formats.BOOL,
|
|
69
|
+
perms: [api.hap.Perms.PAIRED_READ, api.hap.Perms.PAIRED_WRITE, api.hap.Perms.NOTIFY],
|
|
70
|
+
})
|
|
71
|
+
this.value = this.getDefaultValue()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
this.SceneTwo = class extends api.hap.Characteristic {
|
|
76
|
+
constructor() {
|
|
77
|
+
super('Scene 2', uuids.sceneTwo)
|
|
78
|
+
this.setProps({
|
|
79
|
+
format: api.hap.Formats.BOOL,
|
|
80
|
+
perms: [api.hap.Perms.PAIRED_READ, api.hap.Perms.PAIRED_WRITE, api.hap.Perms.NOTIFY],
|
|
81
|
+
})
|
|
82
|
+
this.value = this.getDefaultValue()
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
this.SceneThree = class extends api.hap.Characteristic {
|
|
87
|
+
constructor() {
|
|
88
|
+
super('Scene 3', uuids.sceneThree)
|
|
89
|
+
this.setProps({
|
|
90
|
+
format: api.hap.Formats.BOOL,
|
|
91
|
+
perms: [api.hap.Perms.PAIRED_READ, api.hap.Perms.PAIRED_WRITE, api.hap.Perms.NOTIFY],
|
|
92
|
+
})
|
|
93
|
+
this.value = this.getDefaultValue()
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
this.SceneFour = class extends api.hap.Characteristic {
|
|
98
|
+
constructor() {
|
|
99
|
+
super('Scene 4', uuids.sceneFour)
|
|
100
|
+
this.setProps({
|
|
101
|
+
format: api.hap.Formats.BOOL,
|
|
102
|
+
perms: [api.hap.Perms.PAIRED_READ, api.hap.Perms.PAIRED_WRITE, api.hap.Perms.NOTIFY],
|
|
103
|
+
})
|
|
104
|
+
this.value = this.getDefaultValue()
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
this.DiyMode = class extends api.hap.Characteristic {
|
|
109
|
+
constructor() {
|
|
110
|
+
super('DIY Mode', uuids.diyMode)
|
|
111
|
+
this.setProps({
|
|
112
|
+
format: api.hap.Formats.BOOL,
|
|
113
|
+
perms: [api.hap.Perms.PAIRED_READ, api.hap.Perms.PAIRED_WRITE, api.hap.Perms.NOTIFY],
|
|
114
|
+
})
|
|
115
|
+
this.value = this.getDefaultValue()
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
this.DiyModeTwo = class extends api.hap.Characteristic {
|
|
120
|
+
constructor() {
|
|
121
|
+
super('DIY Mode 2', uuids.diyModeTwo)
|
|
122
|
+
this.setProps({
|
|
123
|
+
format: api.hap.Formats.BOOL,
|
|
124
|
+
perms: [api.hap.Perms.PAIRED_READ, api.hap.Perms.PAIRED_WRITE, api.hap.Perms.NOTIFY],
|
|
125
|
+
})
|
|
126
|
+
this.value = this.getDefaultValue()
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
this.DiyModeThree = class extends api.hap.Characteristic {
|
|
131
|
+
constructor() {
|
|
132
|
+
super('DIY Mode 3', uuids.diyModeThree)
|
|
133
|
+
this.setProps({
|
|
134
|
+
format: api.hap.Formats.BOOL,
|
|
135
|
+
perms: [api.hap.Perms.PAIRED_READ, api.hap.Perms.PAIRED_WRITE, api.hap.Perms.NOTIFY],
|
|
136
|
+
})
|
|
137
|
+
this.value = this.getDefaultValue()
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
this.DiyModeFour = class extends api.hap.Characteristic {
|
|
142
|
+
constructor() {
|
|
143
|
+
super('DIY Mode 4', uuids.diyModeFour)
|
|
144
|
+
this.setProps({
|
|
145
|
+
format: api.hap.Formats.BOOL,
|
|
146
|
+
perms: [api.hap.Perms.PAIRED_READ, api.hap.Perms.PAIRED_WRITE, api.hap.Perms.NOTIFY],
|
|
147
|
+
})
|
|
148
|
+
this.value = this.getDefaultValue()
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
this.Segmented = class extends api.hap.Characteristic {
|
|
153
|
+
constructor() {
|
|
154
|
+
super('Segmented', uuids.segmented)
|
|
155
|
+
this.setProps({
|
|
156
|
+
format: api.hap.Formats.BOOL,
|
|
157
|
+
perms: [api.hap.Perms.PAIRED_READ, api.hap.Perms.PAIRED_WRITE, api.hap.Perms.NOTIFY],
|
|
158
|
+
})
|
|
159
|
+
this.value = this.getDefaultValue()
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
this.SegmentedTwo = class extends api.hap.Characteristic {
|
|
164
|
+
constructor() {
|
|
165
|
+
super('Segmented 2', uuids.segmentedTwo)
|
|
166
|
+
this.setProps({
|
|
167
|
+
format: api.hap.Formats.BOOL,
|
|
168
|
+
perms: [api.hap.Perms.PAIRED_READ, api.hap.Perms.PAIRED_WRITE, api.hap.Perms.NOTIFY],
|
|
169
|
+
})
|
|
170
|
+
this.value = this.getDefaultValue()
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
this.SegmentedThree = class extends api.hap.Characteristic {
|
|
175
|
+
constructor() {
|
|
176
|
+
super('Segmented 3', uuids.segmentedThree)
|
|
177
|
+
this.setProps({
|
|
178
|
+
format: api.hap.Formats.BOOL,
|
|
179
|
+
perms: [api.hap.Perms.PAIRED_READ, api.hap.Perms.PAIRED_WRITE, api.hap.Perms.NOTIFY],
|
|
180
|
+
})
|
|
181
|
+
this.value = this.getDefaultValue()
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
this.SegmentedFour = class extends api.hap.Characteristic {
|
|
186
|
+
constructor() {
|
|
187
|
+
super('Segmented 4', uuids.segmentedFour)
|
|
188
|
+
this.setProps({
|
|
189
|
+
format: api.hap.Formats.BOOL,
|
|
190
|
+
perms: [api.hap.Perms.PAIRED_READ, api.hap.Perms.PAIRED_WRITE, api.hap.Perms.NOTIFY],
|
|
191
|
+
})
|
|
192
|
+
this.value = this.getDefaultValue()
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
this.VideoMode = class extends api.hap.Characteristic {
|
|
197
|
+
constructor() {
|
|
198
|
+
super('Video Mode', uuids.videoMode)
|
|
199
|
+
this.setProps({
|
|
200
|
+
format: api.hap.Formats.BOOL,
|
|
201
|
+
perms: [api.hap.Perms.PAIRED_READ, api.hap.Perms.PAIRED_WRITE, api.hap.Perms.NOTIFY],
|
|
202
|
+
})
|
|
203
|
+
this.value = this.getDefaultValue()
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
this.VideoModeTwo = class extends api.hap.Characteristic {
|
|
208
|
+
constructor() {
|
|
209
|
+
super('Video Mode 2', uuids.videoModeTwo)
|
|
210
|
+
this.setProps({
|
|
211
|
+
format: api.hap.Formats.BOOL,
|
|
212
|
+
perms: [api.hap.Perms.PAIRED_READ, api.hap.Perms.PAIRED_WRITE, api.hap.Perms.NOTIFY],
|
|
213
|
+
})
|
|
214
|
+
this.value = this.getDefaultValue()
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
this.NightLight = class extends api.hap.Characteristic {
|
|
219
|
+
constructor() {
|
|
220
|
+
super('Night Light', uuids.nightLight)
|
|
221
|
+
this.setProps({
|
|
222
|
+
format: api.hap.Formats.BOOL,
|
|
223
|
+
perms: [api.hap.Perms.PAIRED_READ, api.hap.Perms.PAIRED_WRITE, api.hap.Perms.NOTIFY],
|
|
224
|
+
})
|
|
225
|
+
this.value = this.getDefaultValue()
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
this.DisplayLight = class extends api.hap.Characteristic {
|
|
230
|
+
constructor() {
|
|
231
|
+
super('Display Light', uuids.displayLight)
|
|
232
|
+
this.setProps({
|
|
233
|
+
format: api.hap.Formats.BOOL,
|
|
234
|
+
perms: [api.hap.Perms.PAIRED_READ, api.hap.Perms.PAIRED_WRITE, api.hap.Perms.NOTIFY],
|
|
235
|
+
})
|
|
236
|
+
this.value = this.getDefaultValue()
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
205
240
|
this.ColourMode.UUID = this.uuids.colourMode
|
|
206
241
|
this.MusicMode.UUID = this.uuids.musicMode
|
|
207
242
|
this.MusicModeTwo.UUID = this.uuids.musicModeTwo
|
package/package.json
CHANGED