@homebridge-plugins/homebridge-govee 11.32.2-beta.2 → 11.32.2-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/config.schema.json +1 -1
- package/lib/connection/ble.js +26 -1
- package/lib/connection/openapi.js +18 -0
- package/lib/device/appliance-basic.js +377 -0
- package/lib/device/dehumidifier-H7150.js +9 -3
- package/lib/device/diffuser-H7161.js +7 -1
- package/lib/device/fan-H1370.js +7 -1
- package/lib/device/fan-H7100.js +36 -4
- package/lib/device/fan-H7105.js +7 -1
- package/lib/device/fan-H7107.js +7 -1
- package/lib/device/heater1a.js +52 -12
- package/lib/device/heater1b.js +14 -3
- package/lib/device/heater2.js +7 -1
- package/lib/device/humidifier-H7140.js +7 -1
- package/lib/device/humidifier-H7141.js +7 -1
- package/lib/device/humidifier-H7142.js +7 -1
- package/lib/device/humidifier-H7143.js +7 -1
- package/lib/device/humidifier-H7160.js +7 -1
- package/lib/device/ice-maker-H7172.js +19 -7
- package/lib/device/index.js +44 -51
- package/lib/device/kettle.js +7 -1
- package/lib/device/outlet-single.js +7 -1
- package/lib/device/purifier-H7120.js +14 -25
- package/lib/device/purifier-H7122.js +7 -1
- package/lib/device/purifier-H7123.js +9 -3
- package/lib/device/purifier-H7126.js +7 -1
- package/lib/device/{sensor-button.js → sensor-basic.js} +14 -2
- package/lib/device/sensor-presence.js +7 -1
- package/lib/device/sensor-thermo4.js +13 -2
- package/lib/device/switch-double.js +34 -15
- package/lib/device/switch-triple.js +36 -17
- package/lib/device/template.js +15 -2
- package/lib/platform.js +83 -799
- package/lib/utils/capabilities.js +220 -0
- package/lib/utils/command-builder.js +6 -4
- package/lib/utils/config-parser.js +280 -0
- package/lib/utils/constants.js +120 -8
- package/lib/utils/decode.js +4 -1
- package/lib/utils/device-capabilities.js +77 -3
- package/lib/utils/device-context.js +179 -0
- package/lib/utils/device-merge.js +251 -0
- package/lib/utils/dispatch.js +159 -0
- package/lib/utils/functions.js +9 -0
- package/lib/utils/lang-en.js +0 -2
- package/lib/utils/report-unknown.js +156 -0
- package/package.json +1 -1
- package/lib/device/dehumidifier-H7151.js +0 -189
- package/lib/device/dehumidifier-H7152.js +0 -180
- package/lib/device/diffuser-H7162.js +0 -123
- package/lib/device/fan-H1310.js +0 -284
- package/lib/device/fan-H7101.js +0 -340
- package/lib/device/fan-H7102.js +0 -284
- package/lib/device/fan-H7106.js +0 -284
- package/lib/device/fan-H7111.js +0 -345
- package/lib/device/humidifier-H7145.js +0 -187
- package/lib/device/humidifier-H7147.js +0 -187
- package/lib/device/humidifier-H7148.js +0 -187
- package/lib/device/humidifier-H7149.js +0 -187
- package/lib/device/humidifier-H714E.js +0 -187
- package/lib/device/ice-maker-H717D.js +0 -218
- package/lib/device/ice-maker-H8120.js +0 -218
- package/lib/device/outlet-double.js +0 -188
- package/lib/device/outlet-triple.js +0 -160
- package/lib/device/purifier-H7121.js +0 -406
- package/lib/device/purifier-H7124.js +0 -504
- package/lib/device/purifier-H7127.js +0 -359
- package/lib/device/purifier-H7128.js +0 -359
- package/lib/device/purifier-H7129.js +0 -359
- package/lib/device/purifier-H712C.js +0 -359
- package/lib/device/sensor-contact.js +0 -22
- package/lib/utils/ble-timeouts.test.js +0 -44
- package/lib/utils/functions.test.js +0 -292
package/lib/utils/constants.js
CHANGED
|
@@ -129,17 +129,56 @@ export default {
|
|
|
129
129
|
|
|
130
130
|
models: {
|
|
131
131
|
rgb: [
|
|
132
|
+
'B7080', // 4 pcs Rock Lights
|
|
133
|
+
'B7081', // 8 pcs Rock Lights
|
|
134
|
+
'B7082', // 6 pcs Rock Lights
|
|
135
|
+
'H1161', // Govee Sync
|
|
136
|
+
'H1163', // Music Sync Box 2
|
|
137
|
+
'H1168', // Sync Box
|
|
138
|
+
'H1232', // Ceiling Light
|
|
132
139
|
'H1250', // 18-Inch Ceiling Light Pro, https://github.com/homebridge-plugins/homebridge-govee/issues/1333
|
|
140
|
+
'H1252', // Ceiling Light
|
|
133
141
|
'H1270', // Ceiling Light Ultra
|
|
142
|
+
'H12D0', // Govee Ceiling Light
|
|
134
143
|
'H1401',
|
|
144
|
+
'H14A1', // Smart LED Bulb
|
|
135
145
|
'H14C0', // https://github.com/homebridge-plugins/homebridge-govee/issues/1301
|
|
136
146
|
'H14C1', // https://github.com/homebridge-plugins/homebridge-govee/issues/1319
|
|
147
|
+
'H14C2', // Edison Bulb
|
|
137
148
|
'H1630',
|
|
138
149
|
'H16B0', // https://github.com/homebridge-plugins/homebridge-govee/issues/1278
|
|
139
150
|
'H16C0', // https://github.com/homebridge-plugins/homebridge-govee/issues/1286
|
|
140
151
|
'H1741', // https://github.com/homebridge-plugins/homebridge-govee/issues/1278
|
|
152
|
+
'H1771', // Table Lamp
|
|
153
|
+
'H1811', // Projector Light
|
|
154
|
+
'H1A42', // Strip Light
|
|
155
|
+
'H1A43', // Strip Light
|
|
156
|
+
'H1A44', // Strip Light
|
|
157
|
+
'H1A45', // Strip Light
|
|
158
|
+
'H1AA2', // Strip Light
|
|
159
|
+
'H1AA5', // Strip Light
|
|
160
|
+
'H1AB1', // Strip Light
|
|
161
|
+
'H1AB2', // Strip Light
|
|
162
|
+
'H1AB3', // Strip Light
|
|
163
|
+
'H1B6A', // Strip Light
|
|
164
|
+
'H2800', // Monitor Light Bar
|
|
165
|
+
'H2A40', // TV Backlight 3
|
|
166
|
+
'H2A41', // TV Backlight 3
|
|
141
167
|
'H3001', // bluetooth-only solar string lights, https://github.com/homebridge-plugins/homebridge-govee/issues/1328
|
|
168
|
+
'H30D0', // Bulb String Lights
|
|
169
|
+
'H30D1', // Bulb String Lights
|
|
142
170
|
'H3200', // https://github.com/homebridge-plugins/homebridge-govee/issues/1292
|
|
171
|
+
'H3351', // Wall Floodlight
|
|
172
|
+
'H3401', // Outdoor Deck Lights
|
|
173
|
+
'H3500', // RGBIC Path Lights
|
|
174
|
+
'H3501', // RGBIC Path Lights
|
|
175
|
+
'H3510', // Cylinder Pathway Light
|
|
176
|
+
'H3511', // Cylinder Pathway Light
|
|
177
|
+
'H3751', // Wall Light Pro
|
|
178
|
+
'H3860', // Projector Light
|
|
179
|
+
'H3A51', // Permanent Lights 2 Pro
|
|
180
|
+
'H3A52', // Permanent Lights 2 Pro
|
|
181
|
+
'H3A53', // Permanent Lights 2 Pro
|
|
143
182
|
'H6001',
|
|
144
183
|
'H6002',
|
|
145
184
|
'H6003',
|
|
@@ -219,6 +258,7 @@ export default {
|
|
|
219
258
|
'H6091',
|
|
220
259
|
'H6092',
|
|
221
260
|
'H6093',
|
|
261
|
+
'H6094', // Star Light Projector
|
|
222
262
|
'H6095',
|
|
223
263
|
'H6097',
|
|
224
264
|
'H6098',
|
|
@@ -236,14 +276,18 @@ export default {
|
|
|
236
276
|
'H6101',
|
|
237
277
|
'H6102',
|
|
238
278
|
'H6104',
|
|
279
|
+
'H6105', // TV Backlight
|
|
239
280
|
'H6107',
|
|
240
281
|
'H6109',
|
|
241
282
|
'H610A',
|
|
242
283
|
'H610B',
|
|
243
284
|
'H6110',
|
|
285
|
+
'H6113', // Car Light
|
|
244
286
|
'H6114',
|
|
245
287
|
'H6116',
|
|
246
288
|
'H6117',
|
|
289
|
+
'H6118', // Car Led Lights
|
|
290
|
+
'H6119', // Car Led Lights
|
|
247
291
|
'H611A',
|
|
248
292
|
'H611B',
|
|
249
293
|
'H611C',
|
|
@@ -294,9 +338,12 @@ export default {
|
|
|
294
338
|
'H6160',
|
|
295
339
|
'H6161',
|
|
296
340
|
'H6163',
|
|
341
|
+
'H6165', // Rock Light
|
|
342
|
+
'H6166', // Rock Light
|
|
297
343
|
'H6167',
|
|
298
344
|
'H6168',
|
|
299
345
|
'H6169',
|
|
346
|
+
'H616B', // RGB Strip Lights
|
|
300
347
|
'H616C',
|
|
301
348
|
'H616D',
|
|
302
349
|
'H616E',
|
|
@@ -312,14 +359,19 @@ export default {
|
|
|
312
359
|
'H617C',
|
|
313
360
|
'H617E',
|
|
314
361
|
'H617F',
|
|
362
|
+
'H617G', // RGBIC LED Strip Light
|
|
315
363
|
'H6181',
|
|
316
364
|
'H6182',
|
|
365
|
+
'H6184', // Car Underglow Lights
|
|
317
366
|
'H6185',
|
|
318
367
|
'H6188',
|
|
319
368
|
'H618A',
|
|
320
369
|
'H618C',
|
|
321
370
|
'H618E',
|
|
322
371
|
'H618F',
|
|
372
|
+
'H618G', // RGBIC LED Strip Light
|
|
373
|
+
'H6192', // Motorcycle LED Lights
|
|
374
|
+
'H6194', // Motorcycle LED Lights
|
|
323
375
|
'H6195',
|
|
324
376
|
'H6196',
|
|
325
377
|
'H6198',
|
|
@@ -350,6 +402,7 @@ export default {
|
|
|
350
402
|
'H61C2',
|
|
351
403
|
'H61C3',
|
|
352
404
|
'H61C5',
|
|
405
|
+
'H61D2', // Neon Rope Light
|
|
353
406
|
'H61D3',
|
|
354
407
|
'H61D5',
|
|
355
408
|
'H61D6',
|
|
@@ -360,9 +413,13 @@ export default {
|
|
|
360
413
|
'H61F2',
|
|
361
414
|
'H61F5',
|
|
362
415
|
'H61F6',
|
|
416
|
+
'H6350', // Net Lights
|
|
417
|
+
'H6351', // Net Lights
|
|
363
418
|
'H6601',
|
|
364
419
|
'H6602',
|
|
420
|
+
'H6603', // AI Sync Box Kit
|
|
365
421
|
'H6604',
|
|
422
|
+
'H6608', // Gaming Light Kit G1
|
|
366
423
|
'H6609',
|
|
367
424
|
'H6630',
|
|
368
425
|
'H6631',
|
|
@@ -370,16 +427,25 @@ export default {
|
|
|
370
427
|
'H6641',
|
|
371
428
|
'H6671',
|
|
372
429
|
'H6672',
|
|
430
|
+
'H6690', // TV Backlight 3 Lite
|
|
373
431
|
'H66A0',
|
|
374
432
|
'H66A1',
|
|
375
433
|
'H6800',
|
|
376
434
|
'H6810',
|
|
377
435
|
'H6811',
|
|
436
|
+
'H6821', // Meteor Shower Lights
|
|
378
437
|
'H6840',
|
|
379
438
|
'H6841',
|
|
439
|
+
'H6842', // Cone Tree Lights
|
|
440
|
+
'H6843', // Cone Tree Lights
|
|
441
|
+
'H6850', // Govee Ball Lights
|
|
442
|
+
'H6860', // C9 String Lights
|
|
443
|
+
'H6861', // C9 String Lights
|
|
444
|
+
'H6870', // RGBWIC String Lights
|
|
380
445
|
'H6871',
|
|
381
446
|
'H7001',
|
|
382
447
|
'H7002',
|
|
448
|
+
'H7004', // Plant Grow Lights
|
|
383
449
|
'H7005',
|
|
384
450
|
'H7006',
|
|
385
451
|
'H7007',
|
|
@@ -413,8 +479,10 @@ export default {
|
|
|
413
479
|
'H7039',
|
|
414
480
|
'H703A',
|
|
415
481
|
'H703B',
|
|
482
|
+
'H7040', // Camping lantern
|
|
416
483
|
'H7041',
|
|
417
484
|
'H7042',
|
|
485
|
+
'H7045', // String Lights
|
|
418
486
|
'H7046', // https://github.com/homebridge-plugins/homebridge-govee/issues/1297
|
|
419
487
|
'H7050',
|
|
420
488
|
'H7051',
|
|
@@ -443,11 +511,15 @@ export default {
|
|
|
443
511
|
'H706B',
|
|
444
512
|
'H706C',
|
|
445
513
|
'H7070',
|
|
514
|
+
'H7071', // Decoration Projector
|
|
515
|
+
'H7072', // Lamp Post Lights
|
|
446
516
|
'H7073',
|
|
447
517
|
'H7075',
|
|
448
518
|
'H7076',
|
|
449
519
|
'H7078',
|
|
450
520
|
'H707A',
|
|
521
|
+
'H707B', // Permanent Lights Prism
|
|
522
|
+
'H707C', // Permanent Lights Prism
|
|
451
523
|
'H7086',
|
|
452
524
|
'H7087',
|
|
453
525
|
'H7090',
|
|
@@ -463,6 +535,7 @@ export default {
|
|
|
463
535
|
'H70B4',
|
|
464
536
|
'H70B5',
|
|
465
537
|
'H70B6',
|
|
538
|
+
'H70B8', // Lightwall
|
|
466
539
|
'H70BC',
|
|
467
540
|
'H70C1',
|
|
468
541
|
'H70C2',
|
|
@@ -474,26 +547,49 @@ export default {
|
|
|
474
547
|
'H70D1',
|
|
475
548
|
'H70D2',
|
|
476
549
|
'H70D3',
|
|
550
|
+
'H7308', // Copper Wire Light
|
|
551
|
+
'H7309', // Copper Wire Light
|
|
552
|
+
'H7310', // Copper Wire Light
|
|
553
|
+
'H7311', // Copper Wire Light
|
|
554
|
+
'H7312', // Copper Wire Light
|
|
555
|
+
'H7313', // Copper Wire Light
|
|
556
|
+
'H7315', // LED Curtain Lights
|
|
557
|
+
'H7317', // RGB Copper Wire Lights
|
|
558
|
+
'H7318', // RGB Copper Wire Lights
|
|
559
|
+
'H800B', // Govee Smart Bulb
|
|
477
560
|
'H8015',
|
|
561
|
+
'H801A', // Downlight
|
|
478
562
|
'H801B',
|
|
479
563
|
'H801C',
|
|
480
564
|
'H801D', // https://github.com/homebridge-plugins/homebridge-govee/issues/1320
|
|
481
565
|
'H8022',
|
|
482
566
|
'H8025',
|
|
567
|
+
'H8026', // LED Bulb String Lights
|
|
483
568
|
'H802A', // https://github.com/homebridge-plugins/homebridge-govee/issues/1295
|
|
569
|
+
'H8048', // Gaming Light Bars
|
|
570
|
+
'H8057', // Flood Lights
|
|
484
571
|
'H805A',
|
|
485
572
|
'H805B',
|
|
486
573
|
'H805C',
|
|
574
|
+
'H805D', // Permanent Lights Elite
|
|
487
575
|
'H8066',
|
|
576
|
+
'H8067', // Outdoor Spotlights
|
|
577
|
+
'H8069', // Mini Panel Lights
|
|
488
578
|
'H806A',
|
|
579
|
+
'H806C', // Permanent Lights Pro
|
|
489
580
|
'H8072',
|
|
490
581
|
'H8076',
|
|
582
|
+
'H807C', // Floor Lamp 2
|
|
491
583
|
'H808A',
|
|
584
|
+
'H8098', // RGBIC TV Backlight 3S
|
|
492
585
|
'H80A1',
|
|
493
586
|
'H80A4',
|
|
587
|
+
'H80B5', // Strip Light
|
|
494
588
|
'H80C4',
|
|
495
589
|
'H80C5',
|
|
590
|
+
'H80D1', // Icicle Lights
|
|
496
591
|
'H8604',
|
|
592
|
+
'H8630', // Gaming Pixel Light
|
|
497
593
|
'H8811',
|
|
498
594
|
'H8840',
|
|
499
595
|
'H8841',
|
|
@@ -508,14 +604,27 @@ export default {
|
|
|
508
604
|
'R1630',
|
|
509
605
|
'R16D0',
|
|
510
606
|
'R1741',
|
|
607
|
+
'R1810', // Star Light Projector
|
|
608
|
+
'R2A80', // TV Backlight 3 Pro
|
|
609
|
+
'R2A81', // TV Backlight 3 Pro
|
|
610
|
+
'R3A51', // Permanent Lights
|
|
611
|
+
'R60B3', // Uplighter Floor Lamp
|
|
612
|
+
'R617G', // RGBIC LED Strip Light
|
|
613
|
+
'R618D', // RGBIC LED Strip Light
|
|
614
|
+
'R6842', // Cone Tree Lights
|
|
615
|
+
'R6861', // C9 String Lights
|
|
616
|
+
'R6871', // RGBWIC String Lights
|
|
617
|
+
'R707A', // Permanent Lights Prism
|
|
618
|
+
'R707B', // Permanent Lights Prism
|
|
619
|
+
'R707C', // Permanent Lights Prism
|
|
511
620
|
],
|
|
512
621
|
// H5901 is a water timer, controlled only through the OpenAPI - it has no
|
|
513
622
|
// usable AWS, BLE or LAN path, so it needs an API key configured. Set
|
|
514
623
|
// showAs to 'valve' or 'tap' for a more fitting HomeKit tile (#1324)
|
|
515
|
-
switchSingle: ['H5001', 'H5080', 'H5081', 'H5083', 'H5086', 'H5901', 'H7014'],
|
|
624
|
+
switchSingle: ['H5001', 'H5080', 'H5081', 'H5083', 'H5085', 'H5086', 'H5901', 'H7014'],
|
|
516
625
|
switchDouble: ['H5082', 'H5089'],
|
|
517
626
|
switchTriple: ['H5160'],
|
|
518
|
-
sensorLeak: ['H5054', 'H5058', 'H5059'],
|
|
627
|
+
sensorLeak: ['H5054', 'H5058', 'H5059', 'H5830'],
|
|
519
628
|
sensorThermo: [
|
|
520
629
|
'B5178',
|
|
521
630
|
'H5051',
|
|
@@ -536,6 +645,7 @@ export default {
|
|
|
536
645
|
'H5108',
|
|
537
646
|
'H5109', // https://github.com/homebridge-plugins/homebridge-govee/issues/1099
|
|
538
647
|
'H5110', // https://github.com/homebridge-plugins/homebridge-govee/issues/1217
|
|
648
|
+
'H5111', // same broadcast format as the H5101 family
|
|
539
649
|
'H5112', // https://github.com/homebridge-plugins/homebridge-govee/issues/1197
|
|
540
650
|
'H5171', // https://github.com/homebridge-plugins/homebridge-govee/issues/1243
|
|
541
651
|
'H5174',
|
|
@@ -543,19 +653,21 @@ export default {
|
|
|
543
653
|
'H5179',
|
|
544
654
|
'H5183',
|
|
545
655
|
'H5190',
|
|
656
|
+
'H5220', // same broadcast format as the H5101 family
|
|
546
657
|
'H5310', // https://github.com/homebridge-plugins/homebridge-govee/issues/1293
|
|
658
|
+
'R5112', // the refreshed H5112
|
|
547
659
|
],
|
|
548
660
|
sensorThermo4: ['H5198'],
|
|
549
661
|
sensorMonitor: ['H5106'],
|
|
550
662
|
sensorCO2: ['H5140'], // CO2 + temp + humidity monitor, AWS opcode 0x0A — closes #1179
|
|
551
|
-
fan: ['H1310', 'H1370', 'H7100', 'H7101', 'H7102', 'H7105', 'H7106', 'H7107', 'H7111', 'R1310'],
|
|
552
|
-
heater1: ['H7130', 'H713A', 'H713B', 'H713C'],
|
|
663
|
+
fan: ['H1310', 'H1370', 'H7100', 'H7101', 'H7102', 'H7103', 'H7105', 'H7106', 'H7107', 'H7111', 'H7112', 'R1310'],
|
|
664
|
+
heater1: ['H7130', 'H713A', 'H713B', 'H713C', 'H7137', 'H713E'],
|
|
553
665
|
heater2: ['H7131', 'H7132', 'H7133', 'H7134', 'H7135'],
|
|
554
666
|
dehumidifier: ['H7150', 'H7151', 'H7152'],
|
|
555
|
-
humidifier: ['H7140', 'H7141', 'H7142', 'H7143', 'H7145', 'H7147', 'H7148', 'H7149', 'H714E', 'H7160'],
|
|
667
|
+
humidifier: ['H7140', 'H7141', 'H7142', 'H7143', 'H7145', 'H7146', 'H7147', 'H7148', 'H7149', 'H714E', 'H7160'],
|
|
556
668
|
purifier: ['H7120', 'H7121', 'H7122', 'H7123', 'H7124', 'H7126', 'H7127', 'H7128', 'H7129', 'H712C'],
|
|
557
669
|
diffuser: ['H7161', 'H7162'],
|
|
558
|
-
iceMaker: ['H7172', 'H717D', 'H8120'],
|
|
670
|
+
iceMaker: ['H7172', 'H717D', 'H8102', 'H8120', 'H8121', 'H8122', 'H8131'],
|
|
559
671
|
sensorButton: ['H5122'],
|
|
560
672
|
sensorContact: ['H5123'],
|
|
561
673
|
sensorPresence: ['H5127'],
|
|
@@ -567,8 +679,8 @@ export default {
|
|
|
567
679
|
'H5024', // https://github.com/homebridge-plugins/homebridge-govee/issues/835
|
|
568
680
|
'H5042', // https://github.com/homebridge-plugins/homebridge-govee/issues/849
|
|
569
681
|
'H5043', // https://github.com/homebridge-plugins/homebridge-govee/issues/558
|
|
570
|
-
|
|
571
|
-
|
|
682
|
+
// https://github.com/homebridge-plugins/homebridge-govee/issues/951
|
|
683
|
+
// https://github.com/homebridge-plugins/homebridge-govee/issues/1117
|
|
572
684
|
'H5121', // https://github.com/homebridge-plugins/homebridge-govee/issues/913
|
|
573
685
|
'H5124', // https://github.com/homebridge-plugins/homebridge-govee/issues/1119
|
|
574
686
|
'H5126', // https://github.com/homebridge-plugins/homebridge-govee/issues/910
|
package/lib/utils/decode.js
CHANGED
|
@@ -84,7 +84,10 @@ export function decodeH5179Values(streamUpdate) {
|
|
|
84
84
|
throw new Error(`H5179 stream too short: ${streamUpdate.length} chars (need 22)`)
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
// Temperature and humidity are each a little-endian pair, so the high byte is
|
|
88
|
+
// read before the low one. They must not share a byte: the temperature pair
|
|
89
|
+
// is bytes 6 and 7, the humidity pair bytes 8 and 9, and the battery byte 10.
|
|
90
|
+
const temp_lsb = streamUpdate.substring(14, 16) + streamUpdate.substring(12, 14)
|
|
88
91
|
const hum_lsb = streamUpdate.substring(18, 20) + streamUpdate.substring(16, 18)
|
|
89
92
|
|
|
90
93
|
const tempInC = twos_complement(Number.parseInt(temp_lsb, 16)) / 100
|
|
@@ -11,7 +11,6 @@ const modelOverrides = {
|
|
|
11
11
|
H6005: { bleColorCmd: [COLOR_SUB.RGB_ALT] },
|
|
12
12
|
H6052: { bleColorCmd: [COLOR_SUB.RGB_ALT], bleBrightnessScale: 0x64 },
|
|
13
13
|
H6058: { bleColorCmd: [COLOR_SUB.RGB_ALT], bleBrightnessScale: 0x64 },
|
|
14
|
-
H6102: { bleColorCmd: [COLOR_SUB.RGB_ALT], bleBrightnessScale: 0x64 },
|
|
15
14
|
H613B: { bleColorCmd: [COLOR_SUB.RGB_ALT], bleBrightnessScale: 0x64 },
|
|
16
15
|
H613D: { bleColorCmd: [COLOR_SUB.RGB_ALT], bleBrightnessScale: 0x64 },
|
|
17
16
|
|
|
@@ -28,6 +27,26 @@ const modelOverrides = {
|
|
|
28
27
|
// segment-based extended format, as seen in its own TTR rule data (#1290)
|
|
29
28
|
H617E: { bleColorCmd: COLOR_SUB.RGB_EXTENDED, bleColorCmdSuffix: [0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F], bleBrightnessScale: 0x64 },
|
|
30
29
|
|
|
30
|
+
// The H6102 is the same RGBIC generation as the H617A above. It was on the
|
|
31
|
+
// 0x0D command, which it accepts but silently ignores - on, off and
|
|
32
|
+
// brightness worked while colour did nothing. Which colour command it wants
|
|
33
|
+
// depends on its firmware, so the choice is made in firmwareOverrides below
|
|
34
|
+
// and only the brightness scale is fixed here (#1332)
|
|
35
|
+
H6102: { bleBrightnessScale: 0x64 },
|
|
36
|
+
|
|
37
|
+
// The H1310 ceiling fan shares the H7100's handler, but its oscillation
|
|
38
|
+
// status message has never been confirmed to mean the same thing, so reading
|
|
39
|
+
// it back stays off. While it is off, an owner's fan reporting one produces a
|
|
40
|
+
// line in the log saying so - which is the evidence needed to turn this on
|
|
41
|
+
H1310: { readsSwingStatus: false },
|
|
42
|
+
R1310: { readsSwingStatus: false },
|
|
43
|
+
|
|
44
|
+
// Later ice makers number their ice sizes the natural way round. The older
|
|
45
|
+
// ones run the other way, small being the highest byte, so the two families
|
|
46
|
+
// share a handler and differ only here
|
|
47
|
+
H8121: { iceSizeAscending: true },
|
|
48
|
+
H8122: { iceSizeAscending: true },
|
|
49
|
+
|
|
31
50
|
// AWS outlet uses 17/16 for on/off instead of 1/0
|
|
32
51
|
H5080: { awsPowerOn: 17, awsPowerOff: 16 },
|
|
33
52
|
H5083: { awsPowerOn: 17, awsPowerOff: 16 },
|
|
@@ -48,6 +67,44 @@ const modelOverrides = {
|
|
|
48
67
|
H6022: { awsBrightnessNoScale: true },
|
|
49
68
|
}
|
|
50
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Overrides that depend on the device's firmware version as well as its model.
|
|
72
|
+
*
|
|
73
|
+
* Each entry gives a `minVersion` and the capabilities to apply from that
|
|
74
|
+
* version upwards. Versions are the dotted `versionSoft` string reported by the
|
|
75
|
+
* device, compared part by part, so "1.03.01" sorts above "1.02.99". A device
|
|
76
|
+
* whose firmware is unknown keeps the plain model defaults, which is the safer
|
|
77
|
+
* of the two branches.
|
|
78
|
+
*/
|
|
79
|
+
const firmwareOverrides = {
|
|
80
|
+
// Older H6102 firmware takes the standard 0x02 colour command. From 1.03.01
|
|
81
|
+
// the strip moves to the newer extended format, the same one the H617A and
|
|
82
|
+
// H617E need (#1332)
|
|
83
|
+
H6102: [
|
|
84
|
+
{
|
|
85
|
+
minVersion: '1.03.01',
|
|
86
|
+
caps: { bleColorCmd: COLOR_SUB.RGB_EXTENDED, bleColorCmdSuffix: [0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F] },
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Compare two dotted version strings. Returns a positive number if `a` is
|
|
93
|
+
* newer than `b`, negative if older, and zero if they match. Missing parts
|
|
94
|
+
* count as zero, so "1.03" and "1.03.00" are equal.
|
|
95
|
+
*/
|
|
96
|
+
export function compareVersions(a, b) {
|
|
97
|
+
const aParts = String(a).split('.')
|
|
98
|
+
const bParts = String(b).split('.')
|
|
99
|
+
for (let i = 0; i < Math.max(aParts.length, bParts.length); i += 1) {
|
|
100
|
+
const diff = (Number.parseInt(aParts[i], 10) || 0) - (Number.parseInt(bParts[i], 10) || 0)
|
|
101
|
+
if (diff !== 0) {
|
|
102
|
+
return diff
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return 0
|
|
106
|
+
}
|
|
107
|
+
|
|
51
108
|
const defaults = {
|
|
52
109
|
bleColorCmd: [COLOR_SUB.RGB_DEFAULT],
|
|
53
110
|
bleColorCmdSuffix: [],
|
|
@@ -57,9 +114,26 @@ const defaults = {
|
|
|
57
114
|
bleWriteUuid: UUID.WRITE_DEFAULT,
|
|
58
115
|
awsStatusCmdVersion: 2,
|
|
59
116
|
awsBrightnessNoScale: false,
|
|
117
|
+
readsSwingStatus: true,
|
|
118
|
+
iceSizeAscending: false,
|
|
60
119
|
}
|
|
61
120
|
|
|
62
|
-
export function getDeviceCapabilities(model) {
|
|
121
|
+
export function getDeviceCapabilities(model, firmware) {
|
|
63
122
|
const overrides = modelOverrides[model] || {}
|
|
64
|
-
|
|
123
|
+
|
|
124
|
+
// Layer on any firmware-gated capabilities, oldest matching rule first so a
|
|
125
|
+
// newer rule wins. Skipped entirely when the device has not told us its
|
|
126
|
+
// firmware version.
|
|
127
|
+
const firmwareCaps = {}
|
|
128
|
+
if (firmware) {
|
|
129
|
+
const rules = [...(firmwareOverrides[model] || [])]
|
|
130
|
+
.sort((a, b) => compareVersions(a.minVersion, b.minVersion))
|
|
131
|
+
rules.forEach((rule) => {
|
|
132
|
+
if (compareVersions(firmware, rule.minVersion) >= 0) {
|
|
133
|
+
Object.assign(firmwareCaps, rule.caps)
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return { ...defaults, ...overrides, ...firmwareCaps }
|
|
65
139
|
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import platformConsts from './constants.js'
|
|
2
|
+
import { getDeviceCapabilities } from './device-capabilities.js'
|
|
3
|
+
import { hasProperty } from './functions.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Fills in everything a handler needs to know about a device before it is
|
|
7
|
+
* built: which connections are available, what firmware it reports, the limits
|
|
8
|
+
* it works within, and what Govee's api says it can do.
|
|
9
|
+
*
|
|
10
|
+
* Lifted out of the platform unchanged. It is data assembly rather than
|
|
11
|
+
* anything to do with Homebridge, and it was making the one method that sets a
|
|
12
|
+
* device up twice as long as it needed to be.
|
|
13
|
+
*
|
|
14
|
+
* @param {object} platform the platform, for logging and settings
|
|
15
|
+
* @param {object} accessory the accessory being set up
|
|
16
|
+
* @param {object} device the device as Govee describes it
|
|
17
|
+
* @param {object} deviceConf this device's settings
|
|
18
|
+
* @param {object} joins where to record the connections this device can use -
|
|
19
|
+
* `awsDevices`, `awsDevicesToPoll`, and whether this kind of device needs its
|
|
20
|
+
* status asking for over AWS
|
|
21
|
+
*/
|
|
22
|
+
export function applyDeviceContext(platform, accessory, device, deviceConf, joins) {
|
|
23
|
+
const { awsDevices, awsDevicesToPoll, doAWSPolling } = joins
|
|
24
|
+
// Add the temperatureSource config to the context if exists
|
|
25
|
+
if (deviceConf.temperatureSource) {
|
|
26
|
+
accessory.context.temperatureSource = deviceConf.temperatureSource
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Add the openApiTempUnit config to the context if set to something other than auto
|
|
30
|
+
if (deviceConf.openApiTempUnit && deviceConf.openApiTempUnit !== 'auto') {
|
|
31
|
+
accessory.context.openApiTempUnit = deviceConf.openApiTempUnit
|
|
32
|
+
} else {
|
|
33
|
+
delete accessory.context.openApiTempUnit
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Get a supported command list if provided, with their options
|
|
37
|
+
if (device.supportCmds && Array.isArray(device.supportCmds)) {
|
|
38
|
+
accessory.context.supportedCmds = device.supportCmds
|
|
39
|
+
accessory.context.supportedCmdsOpts = {}
|
|
40
|
+
|
|
41
|
+
device.supportCmds.forEach((cmd) => {
|
|
42
|
+
if (device?.properties?.[cmd]) {
|
|
43
|
+
accessory.context.supportedCmdsOpts[cmd] = device.properties[cmd]
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Add some initial context information which is changed later
|
|
49
|
+
accessory.context.hasAwsControl = false
|
|
50
|
+
accessory.context.useAwsControl = false
|
|
51
|
+
accessory.context.hasOpenApiControl = false
|
|
52
|
+
accessory.context.useOpenApiControl = false
|
|
53
|
+
accessory.context.hasBleControl = false
|
|
54
|
+
accessory.context.useBleControl = false
|
|
55
|
+
accessory.context.hasLanControl = device.isLanDevice
|
|
56
|
+
accessory.context.useLanControl = accessory.context.hasLanControl
|
|
57
|
+
accessory.context.firmware = false
|
|
58
|
+
accessory.context.hardware = false
|
|
59
|
+
accessory.context.image = false
|
|
60
|
+
|
|
61
|
+
// Overrides for when a custom IP is provided, for a light which is not BLE only
|
|
62
|
+
if (
|
|
63
|
+
deviceConf.customIPAddress
|
|
64
|
+
&& accessory.context.hasLanControl
|
|
65
|
+
&& accessory.context.hasAwsControl
|
|
66
|
+
&& platformConsts.models.rgb.includes(device.model)
|
|
67
|
+
) {
|
|
68
|
+
accessory.context.hasLanControl = true
|
|
69
|
+
accessory.context.useLanControl = true
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// If the device is LAN-only, then sync the display name with the label in the configuration
|
|
73
|
+
if (device.isLanOnly) {
|
|
74
|
+
accessory.displayName = device.deviceName
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// See if we have extra HTTP client info for this device
|
|
78
|
+
if (device.httpInfo) {
|
|
79
|
+
// Save the hardware and firmware versions
|
|
80
|
+
accessory.context.firmware = device.httpInfo.versionSoft
|
|
81
|
+
accessory.context.hardware = device.httpInfo.versionHard
|
|
82
|
+
|
|
83
|
+
// It's possible to show a nice little icon of the device in the Homebridge UI
|
|
84
|
+
if (device.httpInfo.deviceExt && device.httpInfo.deviceExt.extResources) {
|
|
85
|
+
try {
|
|
86
|
+
const parsed = JSON.parse(device.httpInfo.deviceExt.extResources)
|
|
87
|
+
if (parsed && parsed.skuUrl) {
|
|
88
|
+
accessory.context.image = parsed.skuUrl
|
|
89
|
+
}
|
|
90
|
+
} catch {
|
|
91
|
+
// Ignore malformed extResources
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// HTTP info lets us see if AWS/BLE connection methods are available
|
|
96
|
+
if (device.httpInfo.deviceExt && device.httpInfo.deviceExt.deviceSettings) {
|
|
97
|
+
let parsed
|
|
98
|
+
try {
|
|
99
|
+
parsed = JSON.parse(device.httpInfo.deviceExt.deviceSettings)
|
|
100
|
+
} catch {
|
|
101
|
+
platform.log.debugWarn('[%s] failed to parse deviceSettings, skipping AWS/BLE setup.', accessory.displayName)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Check to see if AWS is possible
|
|
105
|
+
if (parsed) {
|
|
106
|
+
if (parsed.topic) {
|
|
107
|
+
accessory.context.hasAwsControl = true
|
|
108
|
+
accessory.context.awsTopic = parsed.topic
|
|
109
|
+
|
|
110
|
+
if (platform.awsClient) {
|
|
111
|
+
accessory.context.useAwsControl = true
|
|
112
|
+
accessory.context.awsBrightnessNoScale = deviceConf.awsBrightnessNoScale
|
|
113
|
+
accessory.context.awsColourMode = deviceConf.awsColourMode || platformConsts.defaultValues.awsColourMode
|
|
114
|
+
awsDevices.push(device.device)
|
|
115
|
+
|
|
116
|
+
// Certain models need AWS polling
|
|
117
|
+
if (doAWSPolling) {
|
|
118
|
+
awsDevicesToPoll.push(device.device)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Check to see if BLE is possible
|
|
124
|
+
if (parsed.bleName) {
|
|
125
|
+
const providedBle = parsed.address ? parsed.address.toLowerCase() : device.device.substring(6).toLowerCase()
|
|
126
|
+
accessory.context.hasBleControl = !!parsed.bleName
|
|
127
|
+
accessory.context.bleAddress = deviceConf.customAddress
|
|
128
|
+
? deviceConf.customAddress.toLowerCase()
|
|
129
|
+
: providedBle
|
|
130
|
+
accessory.context.bleName = parsed.bleName
|
|
131
|
+
accessory.context.bleWriteUuid = getDeviceCapabilities(accessory.context.gvModel).bleWriteUuid
|
|
132
|
+
if (platform.bleClient) {
|
|
133
|
+
accessory.context.useBleControl = true
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Gateway subdevices (e.g. leak sensors paired to an H5044) include
|
|
138
|
+
// their gateway id and slot number, which we need to match real-time
|
|
139
|
+
// leak events relayed by the gateway over AWS (#1276)
|
|
140
|
+
if (hasProperty(parsed, 'sno') && parsed.gatewayInfo?.device) {
|
|
141
|
+
accessory.context.gatewaySno = parsed.sno
|
|
142
|
+
accessory.context.gatewayDevice = parsed.gatewayInfo.device
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Get a min and max temperature/humidity range to show in the homebridge-ui
|
|
146
|
+
if (hasProperty(parsed, 'temCali')) {
|
|
147
|
+
accessory.context.minTemp = parsed.temMin / 100
|
|
148
|
+
accessory.context.maxTemp = parsed.temMax / 100
|
|
149
|
+
accessory.context.offTemp = parsed.temCali
|
|
150
|
+
}
|
|
151
|
+
if (hasProperty(parsed, 'humCali')) {
|
|
152
|
+
accessory.context.minHumi = parsed.humMin / 100
|
|
153
|
+
accessory.context.maxHumi = parsed.humMax / 100
|
|
154
|
+
accessory.context.offHumi = parsed.humCali
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (device.openApiInfo) {
|
|
161
|
+
accessory.context.hasOpenApiControl = true
|
|
162
|
+
accessory.context.useOpenApiControl = !!platform.openApiClient
|
|
163
|
+
accessory.context.openApiCapabilities = device.openApiInfo.byInstance || {}
|
|
164
|
+
|
|
165
|
+
// Log what Govee says this device can do. Working out whether a model
|
|
166
|
+
// exposes something like a night light otherwise means reverse
|
|
167
|
+
// engineering its status messages, when the answer is right here
|
|
168
|
+
const instances = Object.entries(accessory.context.openApiCapabilities)
|
|
169
|
+
.map(([instance, capability]) => `${instance} (${capability?.type ?? 'unknown type'})`)
|
|
170
|
+
platform.log.debug(
|
|
171
|
+
'[%s] openapi category [%s] capabilities [%s].',
|
|
172
|
+
accessory.displayName,
|
|
173
|
+
device.openApiInfo.category || 'unknown',
|
|
174
|
+
instances.join(', ') || 'none',
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Create the instance for this device type
|
|
179
|
+
}
|