iobroker.tint 0.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.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +201 -0
  3. package/admin/build/assets/__virtual_mf___mfe_internal__tintComponents__loadShare__react__loadShare__.js_commonjs-proxy-Cl6Kn7gP.js +9 -0
  4. package/admin/build/assets/_virtual_mf-localSharedImportMap___mfe_internal__tintComponents-B1A16Tgp.js +1 -0
  5. package/admin/build/assets/_virtual_mf___mfe_internal__tintComponents__loadShare___mf_0_emotion_mf_1_react__loadShare__.js-C8Vyx7Bj.js +8 -0
  6. package/admin/build/assets/_virtual_mf___mfe_internal__tintComponents__loadShare___mf_0_emotion_mf_1_styled__loadShare__.js-ByxO1Xun.js +1 -0
  7. package/admin/build/assets/_virtual_mf___mfe_internal__tintComponents__loadShare___mf_0_mui_mf_1_material__loadShare__.js-Dg1UrPxy.js +248 -0
  8. package/admin/build/assets/_virtual_mf___mfe_internal__tintComponents__loadShare__react__loadShare__.js-CAwea2Mm.js +1 -0
  9. package/admin/build/assets/_virtual_mf___mfe_internal__tintComponents__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-B7t36uFG.js +9 -0
  10. package/admin/build/assets/_virtual_mf___mfe_internal__tintComponents__loadShare__react_mf_2_dom__loadShare__.js-rV2HHyiS.js +24 -0
  11. package/admin/build/assets/bootstrap-DdKMNh18.js +1 -0
  12. package/admin/build/assets/hostInit-C5jswnkw.js +1 -0
  13. package/admin/build/assets/index-C-tjmgJM.js +1 -0
  14. package/admin/build/assets/preload-helper-BlTxHScW.js +1 -0
  15. package/admin/build/assets/virtualExposes-Bu4cv-kd.js +1 -0
  16. package/admin/build/customComponents.js +7 -0
  17. package/admin/build/customComponents.ssr.js +48 -0
  18. package/admin/i18n/de.json +35 -0
  19. package/admin/i18n/en.json +35 -0
  20. package/admin/i18n/es.json +35 -0
  21. package/admin/i18n/fr.json +35 -0
  22. package/admin/i18n/it.json +35 -0
  23. package/admin/i18n/nl.json +35 -0
  24. package/admin/i18n/pl.json +35 -0
  25. package/admin/i18n/pt.json +35 -0
  26. package/admin/i18n/ru.json +35 -0
  27. package/admin/i18n/uk.json +35 -0
  28. package/admin/i18n/zh-cn.json +35 -0
  29. package/admin/jsonConfig.json +329 -0
  30. package/admin/tint.png +0 -0
  31. package/io-package.json +227 -0
  32. package/lib/adapter-config.d.ts +20 -0
  33. package/lib/admin-projections.js +61 -0
  34. package/lib/color-utils.js +230 -0
  35. package/lib/deconz-api.js +379 -0
  36. package/lib/deconz-ws.js +151 -0
  37. package/lib/device-category.js +42 -0
  38. package/lib/objects.js +1002 -0
  39. package/lib/remote-handler.js +218 -0
  40. package/main.js +1924 -0
  41. package/package.json +84 -0
package/lib/objects.js ADDED
@@ -0,0 +1,1002 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * ioBroker object definitions for ioBroker.tint
5
+ * All roles are taken from the official ioBroker STATE_ROLES list
6
+ */
7
+
8
+ // ─── Light objects ────────────────────────────────────────────────────────────
9
+
10
+ /**
11
+ * Build a device object for a light.
12
+ *
13
+ * @param {string} id - deCONZ light id
14
+ * @param {string} name - Display name
15
+ * @returns {object} ioBroker object definition
16
+ */
17
+ function lightDevice(id, name) {
18
+ return {
19
+ _id: `lights.${id}`,
20
+ type: 'device',
21
+ common: { name, role: '' },
22
+ native: { deconzId: id },
23
+ };
24
+ }
25
+
26
+ /**
27
+ * Build the info channel object for a light.
28
+ *
29
+ * @param {string} id - deCONZ light id
30
+ * @returns {object} ioBroker channel object definition
31
+ */
32
+ function lightInfoChannel(id) {
33
+ return {
34
+ _id: `lights.${id}.info`,
35
+ type: 'channel',
36
+ common: { name: 'Info' },
37
+ native: {},
38
+ };
39
+ }
40
+
41
+ /**
42
+ * Build the state channel object for a light.
43
+ *
44
+ * @param {string} id - deCONZ light id
45
+ * @returns {object} ioBroker channel object definition
46
+ */
47
+ function lightStateChannel(id) {
48
+ return {
49
+ _id: `lights.${id}.state`,
50
+ type: 'channel',
51
+ common: { name: 'State' },
52
+ native: {},
53
+ };
54
+ }
55
+
56
+ const LIGHT_STATES = [
57
+ // info
58
+ {
59
+ sub: 'info.name',
60
+ type: 'string',
61
+ role: 'info.name',
62
+ read: true,
63
+ write: false,
64
+ },
65
+ {
66
+ sub: 'info.modelid',
67
+ type: 'string',
68
+ role: 'info.hardware.serial',
69
+ read: true,
70
+ write: false,
71
+ },
72
+ {
73
+ sub: 'info.manufacturer',
74
+ type: 'string',
75
+ role: 'info.hardware.model',
76
+ read: true,
77
+ write: false,
78
+ },
79
+ {
80
+ sub: 'info.reachable',
81
+ type: 'boolean',
82
+ role: 'indicator.reachable',
83
+ read: true,
84
+ write: false,
85
+ },
86
+ {
87
+ sub: 'info.uniqueid',
88
+ type: 'string',
89
+ role: 'info.address.ieee',
90
+ read: true,
91
+ write: false,
92
+ },
93
+ // state – writable
94
+ {
95
+ sub: 'state.on',
96
+ type: 'boolean',
97
+ role: 'switch.light',
98
+ read: true,
99
+ write: true,
100
+ },
101
+ {
102
+ sub: 'state.brightness',
103
+ type: 'number',
104
+ role: 'level.dimmer',
105
+ read: true,
106
+ write: true,
107
+ unit: '%',
108
+ min: 0,
109
+ max: 100,
110
+ },
111
+ {
112
+ sub: 'state.colorTemp',
113
+ type: 'number',
114
+ role: 'level.color.temperature',
115
+ read: true,
116
+ write: true,
117
+ unit: 'K',
118
+ min: 2000,
119
+ max: 6500,
120
+ },
121
+ {
122
+ sub: 'state.hue',
123
+ type: 'number',
124
+ role: 'level.color.hue',
125
+ read: true,
126
+ write: true,
127
+ min: 0,
128
+ max: 65535,
129
+ },
130
+ {
131
+ sub: 'state.saturation',
132
+ type: 'number',
133
+ role: 'level.color.saturation',
134
+ read: true,
135
+ write: true,
136
+ min: 0,
137
+ max: 254,
138
+ },
139
+ {
140
+ sub: 'state.hex',
141
+ type: 'string',
142
+ role: 'level.color.rgb',
143
+ read: true,
144
+ write: true,
145
+ },
146
+ {
147
+ sub: 'state.effect',
148
+ type: 'string',
149
+ role: 'text',
150
+ read: true,
151
+ write: true,
152
+ states: {
153
+ none: 'none',
154
+ colorloop: 'colorloop',
155
+ sunset: 'sunset',
156
+ party: 'party',
157
+ worklight: 'worklight',
158
+ campfire: 'campfire',
159
+ romance: 'romance',
160
+ nightlight: 'nightlight',
161
+ },
162
+ },
163
+ {
164
+ sub: 'state.effectSpeed',
165
+ type: 'number',
166
+ role: 'value',
167
+ read: true,
168
+ write: true,
169
+ min: 0,
170
+ max: 255,
171
+ },
172
+ {
173
+ sub: 'state.colorMode',
174
+ type: 'string',
175
+ role: 'text',
176
+ read: true,
177
+ write: false,
178
+ },
179
+ {
180
+ sub: 'state.transitionTime',
181
+ type: 'number',
182
+ role: 'value',
183
+ read: true,
184
+ write: true,
185
+ def: 4,
186
+ unit: '×100ms',
187
+ },
188
+ // xy (raw, for advanced use)
189
+ { sub: 'state.x', type: 'number', role: 'value', read: true, write: true },
190
+ { sub: 'state.y', type: 'number', role: 'value', read: true, write: true },
191
+ ];
192
+
193
+ // ─── Plug objects ─────────────────────────────────────────────────────────────
194
+
195
+ /**
196
+ * Build a device object for a smart plug/switch.
197
+ *
198
+ * @param {string} id - deCONZ light id
199
+ * @param {string} name - Display name
200
+ * @returns {object} ioBroker object definition
201
+ */
202
+ function plugDevice(id, name) {
203
+ return {
204
+ _id: `plugs.${id}`,
205
+ type: 'device',
206
+ common: { name, role: '' },
207
+ native: { deconzId: id },
208
+ };
209
+ }
210
+
211
+ /**
212
+ * Build the info channel object for a plug.
213
+ *
214
+ * @param {string} id - deCONZ light id
215
+ * @returns {object} ioBroker channel object definition
216
+ */
217
+ function plugInfoChannel(id) {
218
+ return {
219
+ _id: `plugs.${id}.info`,
220
+ type: 'channel',
221
+ common: { name: 'Info' },
222
+ native: {},
223
+ };
224
+ }
225
+
226
+ /**
227
+ * Build the state channel object for a plug.
228
+ *
229
+ * @param {string} id - deCONZ light id
230
+ * @returns {object} ioBroker channel object definition
231
+ */
232
+ function plugStateChannel(id) {
233
+ return {
234
+ _id: `plugs.${id}.state`,
235
+ type: 'channel',
236
+ common: { name: 'State' },
237
+ native: {},
238
+ };
239
+ }
240
+
241
+ const PLUG_STATES = [
242
+ // info
243
+ {
244
+ sub: 'info.name',
245
+ type: 'string',
246
+ role: 'info.name',
247
+ read: true,
248
+ write: false,
249
+ },
250
+ {
251
+ sub: 'info.modelid',
252
+ type: 'string',
253
+ role: 'info.hardware.serial',
254
+ read: true,
255
+ write: false,
256
+ },
257
+ {
258
+ sub: 'info.manufacturer',
259
+ type: 'string',
260
+ role: 'info.hardware.model',
261
+ read: true,
262
+ write: false,
263
+ },
264
+ {
265
+ sub: 'info.reachable',
266
+ type: 'boolean',
267
+ role: 'indicator.reachable',
268
+ read: true,
269
+ write: false,
270
+ },
271
+ {
272
+ sub: 'info.uniqueid',
273
+ type: 'string',
274
+ role: 'info.address.ieee',
275
+ read: true,
276
+ write: false,
277
+ },
278
+ // state – writable (no brightness/color: plugs don't support it)
279
+ {
280
+ sub: 'state.on',
281
+ type: 'boolean',
282
+ role: 'switch',
283
+ read: true,
284
+ write: true,
285
+ },
286
+ ];
287
+
288
+ // ─── Group objects ────────────────────────────────────────────────────────────
289
+
290
+ /**
291
+ * Build a device object for a group.
292
+ *
293
+ * @param {string} id - deCONZ group id
294
+ * @param {string} name - Display name
295
+ * @returns {object} ioBroker object definition
296
+ */
297
+ function groupDevice(id, name) {
298
+ return {
299
+ _id: `groups.${id}`,
300
+ type: 'device',
301
+ common: { name, role: '' },
302
+ native: { deconzId: id },
303
+ };
304
+ }
305
+
306
+ /**
307
+ * Build the info channel object for a group.
308
+ *
309
+ * @param {string} id - deCONZ group id
310
+ * @returns {object} ioBroker channel object definition
311
+ */
312
+ function groupInfoChannel(id) {
313
+ return {
314
+ _id: `groups.${id}.info`,
315
+ type: 'channel',
316
+ common: { name: 'Info' },
317
+ native: {},
318
+ };
319
+ }
320
+
321
+ /**
322
+ * Build the action channel object for a group.
323
+ *
324
+ * @param {string} id - deCONZ group id
325
+ * @returns {object} ioBroker channel object definition
326
+ */
327
+ function groupActionChannel(id) {
328
+ return {
329
+ _id: `groups.${id}.action`,
330
+ type: 'channel',
331
+ common: { name: 'Action' },
332
+ native: {},
333
+ };
334
+ }
335
+
336
+ /**
337
+ * Build the scenes channel object for a group.
338
+ *
339
+ * @param {string} id - deCONZ group id
340
+ * @returns {object} ioBroker channel object definition
341
+ */
342
+ function groupScenesChannel(id) {
343
+ return {
344
+ _id: `groups.${id}.scenes`,
345
+ type: 'channel',
346
+ common: { name: 'Scenes' },
347
+ native: {},
348
+ };
349
+ }
350
+
351
+ const GROUP_INFO_STATES = [
352
+ {
353
+ sub: 'info.name',
354
+ type: 'string',
355
+ role: 'info.name',
356
+ read: true,
357
+ write: false,
358
+ },
359
+ {
360
+ sub: 'info.memberCount',
361
+ type: 'number',
362
+ role: 'value',
363
+ read: true,
364
+ write: false,
365
+ },
366
+ {
367
+ sub: 'info.allOn',
368
+ type: 'boolean',
369
+ role: 'indicator',
370
+ read: true,
371
+ write: false,
372
+ },
373
+ {
374
+ sub: 'info.anyOn',
375
+ type: 'boolean',
376
+ role: 'indicator',
377
+ read: true,
378
+ write: false,
379
+ },
380
+ ];
381
+
382
+ const GROUP_ACTION_STATES = [
383
+ {
384
+ sub: 'action.on',
385
+ type: 'boolean',
386
+ role: 'switch.light',
387
+ read: true,
388
+ write: true,
389
+ },
390
+ {
391
+ sub: 'action.brightness',
392
+ type: 'number',
393
+ role: 'level.dimmer',
394
+ read: true,
395
+ write: true,
396
+ unit: '%',
397
+ min: 0,
398
+ max: 100,
399
+ },
400
+ {
401
+ sub: 'action.colorTemp',
402
+ type: 'number',
403
+ role: 'level.color.temperature',
404
+ read: true,
405
+ write: true,
406
+ unit: 'K',
407
+ min: 2000,
408
+ max: 6500,
409
+ },
410
+ {
411
+ sub: 'action.hex',
412
+ type: 'string',
413
+ role: 'level.color.rgb',
414
+ read: true,
415
+ write: true,
416
+ },
417
+ {
418
+ sub: 'action.effect',
419
+ type: 'string',
420
+ role: 'text',
421
+ read: true,
422
+ write: true,
423
+ states: {
424
+ none: 'none',
425
+ colorloop: 'colorloop',
426
+ sunset: 'sunset',
427
+ party: 'party',
428
+ worklight: 'worklight',
429
+ campfire: 'campfire',
430
+ romance: 'romance',
431
+ nightlight: 'nightlight',
432
+ },
433
+ },
434
+ {
435
+ sub: 'action.transitionTime',
436
+ type: 'number',
437
+ role: 'value',
438
+ read: true,
439
+ write: true,
440
+ def: 4,
441
+ unit: '×100ms',
442
+ },
443
+ {
444
+ sub: 'action.activateScene',
445
+ type: 'string',
446
+ role: 'text',
447
+ read: true,
448
+ write: true,
449
+ },
450
+ ];
451
+
452
+ // ─── Remote (Sensor) objects ──────────────────────────────────────────────────
453
+
454
+ /**
455
+ * Build a device object for a remote sensor.
456
+ *
457
+ * @param {string} id - deCONZ sensor id
458
+ * @param {string} name - Display name
459
+ * @returns {object} ioBroker object definition
460
+ */
461
+ function remoteDevice(id, name) {
462
+ return {
463
+ _id: `remotes.${id}`,
464
+ type: 'device',
465
+ common: { name, role: '' },
466
+ native: { deconzId: id },
467
+ };
468
+ }
469
+
470
+ /**
471
+ * Build a channel object for a remote sensor sub-channel.
472
+ *
473
+ * @param {string} id - deCONZ sensor id
474
+ * @param {string} sub - Channel name e.g. "info", "button"
475
+ * @param {string} name - Display name
476
+ * @returns {object} ioBroker channel object definition
477
+ */
478
+ function remoteChannel(id, sub, name) {
479
+ return {
480
+ _id: `remotes.${id}.${sub}`,
481
+ type: 'channel',
482
+ common: { name },
483
+ native: {},
484
+ };
485
+ }
486
+
487
+ const REMOTE_INFO_STATES = [
488
+ {
489
+ sub: 'info.name',
490
+ type: 'string',
491
+ role: 'info.name',
492
+ read: true,
493
+ write: false,
494
+ },
495
+ {
496
+ sub: 'info.battery',
497
+ type: 'number',
498
+ role: 'value.battery',
499
+ read: true,
500
+ write: false,
501
+ unit: '%',
502
+ min: 0,
503
+ max: 100,
504
+ },
505
+ {
506
+ sub: 'info.reachable',
507
+ type: 'boolean',
508
+ role: 'indicator.reachable',
509
+ read: true,
510
+ write: false,
511
+ },
512
+ {
513
+ sub: 'info.lastSeen',
514
+ type: 'string',
515
+ role: 'date',
516
+ read: true,
517
+ write: false,
518
+ },
519
+ ];
520
+
521
+ const REMOTE_BUTTON_STATES = [
522
+ {
523
+ sub: 'button.lastEvent',
524
+ type: 'number',
525
+ role: 'value',
526
+ read: true,
527
+ write: false,
528
+ },
529
+ {
530
+ sub: 'button.lastEventName',
531
+ type: 'string',
532
+ role: 'text',
533
+ read: true,
534
+ write: false,
535
+ },
536
+ {
537
+ sub: 'button.pressType',
538
+ type: 'string',
539
+ role: 'text',
540
+ read: true,
541
+ write: false,
542
+ states: { short: 'short', hold: 'hold', release: 'release' },
543
+ },
544
+ {
545
+ sub: 'button.activeZone',
546
+ type: 'number',
547
+ role: 'value',
548
+ read: true,
549
+ write: false,
550
+ states: { 0: 'all', 1: 'zone1', 2: 'zone2', 3: 'zone3' },
551
+ },
552
+ ];
553
+
554
+ const REMOTE_COLORWHEEL_STATES = [
555
+ {
556
+ sub: 'colorWheel.angle',
557
+ type: 'number',
558
+ role: 'value.angle',
559
+ read: true,
560
+ write: false,
561
+ unit: '°',
562
+ min: 0,
563
+ max: 359,
564
+ },
565
+ {
566
+ sub: 'colorWheel.x',
567
+ type: 'number',
568
+ role: 'value',
569
+ read: true,
570
+ write: false,
571
+ },
572
+ {
573
+ sub: 'colorWheel.y',
574
+ type: 'number',
575
+ role: 'value',
576
+ read: true,
577
+ write: false,
578
+ },
579
+ {
580
+ sub: 'colorWheel.hex',
581
+ type: 'string',
582
+ role: 'level.color.rgb',
583
+ read: true,
584
+ write: false,
585
+ },
586
+ {
587
+ sub: 'colorWheel.triggered',
588
+ type: 'boolean',
589
+ role: 'indicator',
590
+ read: true,
591
+ write: false,
592
+ def: false,
593
+ },
594
+ ];
595
+
596
+ const REMOTE_COLORTEMP_STATES = [
597
+ {
598
+ sub: 'colorTemp.value',
599
+ type: 'number',
600
+ role: 'level.color.temperature',
601
+ read: true,
602
+ write: false,
603
+ unit: 'K',
604
+ },
605
+ {
606
+ sub: 'colorTemp.mired',
607
+ type: 'number',
608
+ role: 'value',
609
+ read: true,
610
+ write: false,
611
+ },
612
+ {
613
+ sub: 'colorTemp.pressType',
614
+ type: 'string',
615
+ role: 'text',
616
+ read: true,
617
+ write: false,
618
+ states: { short: 'short', hold: 'hold' },
619
+ },
620
+ ];
621
+
622
+ // ─── Switch objects (generic Zigbee wall switches, not Tint remotes) ──────────
623
+
624
+ /**
625
+ * Build a device object for a generic switch.
626
+ *
627
+ * @param {string} id - deCONZ sensor id
628
+ * @param {string} name - Display name
629
+ * @returns {object} ioBroker object definition
630
+ */
631
+ function switchDevice(id, name) {
632
+ return {
633
+ _id: `switches.${id}`,
634
+ type: 'device',
635
+ common: { name, role: '' },
636
+ native: { deconzId: id },
637
+ };
638
+ }
639
+
640
+ /**
641
+ * Build a channel object for a switch sub-channel.
642
+ *
643
+ * @param {string} id - deCONZ sensor id
644
+ * @param {string} sub - Channel name e.g. "info", "button"
645
+ * @param {string} name - Display name
646
+ * @returns {object} ioBroker channel object definition
647
+ */
648
+ function switchChannel(id, sub, name) {
649
+ return {
650
+ _id: `switches.${id}.${sub}`,
651
+ type: 'channel',
652
+ common: { name },
653
+ native: {},
654
+ };
655
+ }
656
+
657
+ const SWITCH_INFO_STATES = [
658
+ { sub: 'info.name', type: 'string', role: 'info.name', read: true, write: false },
659
+ {
660
+ sub: 'info.battery',
661
+ type: 'number',
662
+ role: 'value.battery',
663
+ read: true,
664
+ write: false,
665
+ unit: '%',
666
+ min: 0,
667
+ max: 100,
668
+ },
669
+ { sub: 'info.reachable', type: 'boolean', role: 'indicator.reachable', read: true, write: false },
670
+ { sub: 'info.lastSeen', type: 'string', role: 'date', read: true, write: false },
671
+ ];
672
+
673
+ const SWITCH_BUTTON_STATES = [
674
+ { sub: 'button.lastEvent', type: 'number', role: 'value', read: true, write: false },
675
+ { sub: 'button.lastEventName', type: 'string', role: 'text', read: true, write: false },
676
+ ];
677
+
678
+ // ─── Sensor objects (temperature, humidity, motion, open/close, power, ...) ───
679
+
680
+ /**
681
+ * Build a device object for a generic sensor.
682
+ *
683
+ * @param {string} id - deCONZ sensor id
684
+ * @param {string} name - Display name
685
+ * @returns {object} ioBroker object definition
686
+ */
687
+ function sensorDevice(id, name) {
688
+ return {
689
+ _id: `sensors.${id}`,
690
+ type: 'device',
691
+ common: { name, role: '' },
692
+ native: { deconzId: id },
693
+ };
694
+ }
695
+
696
+ /**
697
+ * Build a channel object for a sensor sub-channel.
698
+ *
699
+ * @param {string} id - deCONZ sensor id
700
+ * @param {string} sub - Channel name e.g. "info", "value"
701
+ * @param {string} name - Display name
702
+ * @returns {object} ioBroker channel object definition
703
+ */
704
+ function sensorChannel(id, sub, name) {
705
+ return {
706
+ _id: `sensors.${id}.${sub}`,
707
+ type: 'channel',
708
+ common: { name },
709
+ native: {},
710
+ };
711
+ }
712
+
713
+ const SENSOR_INFO_STATES = [
714
+ { sub: 'info.name', type: 'string', role: 'info.name', read: true, write: false },
715
+ {
716
+ sub: 'info.battery',
717
+ type: 'number',
718
+ role: 'value.battery',
719
+ read: true,
720
+ write: false,
721
+ unit: '%',
722
+ min: 0,
723
+ max: 100,
724
+ },
725
+ { sub: 'info.reachable', type: 'boolean', role: 'indicator.reachable', read: true, write: false },
726
+ { sub: 'info.lastSeen', type: 'string', role: 'date', read: true, write: false },
727
+ ];
728
+
729
+ // Type-specific value states, keyed by deCONZ sensor "type". Only the
730
+ // states relevant to a given sensor type get created — see
731
+ // main.js#_createSensorObjects/#_updateSensorStates for the dispatch.
732
+ const SENSOR_VALUE_STATES = {
733
+ ZHATemperature: [
734
+ { sub: 'value.temperature', type: 'number', role: 'value.temperature', read: true, write: false, unit: '°C' },
735
+ ],
736
+ ZHAHumidity: [
737
+ { sub: 'value.humidity', type: 'number', role: 'value.humidity', read: true, write: false, unit: '%' },
738
+ ],
739
+ ZHAPressure: [
740
+ { sub: 'value.pressure', type: 'number', role: 'value.pressure', read: true, write: false, unit: 'hPa' },
741
+ ],
742
+ ZHAOpenClose: [{ sub: 'value.open', type: 'boolean', role: 'sensor.window', read: true, write: false }],
743
+ ZHAPresence: [{ sub: 'value.presence', type: 'boolean', role: 'sensor.motion', read: true, write: false }],
744
+ ZHALightLevel: [
745
+ { sub: 'value.brightness', type: 'number', role: 'value.brightness', read: true, write: false, unit: 'lux' },
746
+ ],
747
+ ZHAPower: [{ sub: 'value.power', type: 'number', role: 'value.power', read: true, write: false, unit: 'W' }],
748
+ ZHAConsumption: [
749
+ {
750
+ sub: 'value.consumption',
751
+ type: 'number',
752
+ role: 'value.power.consumption',
753
+ read: true,
754
+ write: false,
755
+ unit: 'kWh',
756
+ },
757
+ ],
758
+ };
759
+
760
+ // Fallback for sensor types not covered by SENSOR_VALUE_STATES, so an
761
+ // unrecognized device still shows up with its raw value instead of nothing.
762
+ const SENSOR_GENERIC_VALUE_STATE = { sub: 'value.raw', type: 'mixed', role: 'value', read: true, write: false };
763
+
764
+ // ─── Cover objects (window covering motors / shutters) ────────────────────────
765
+
766
+ /**
767
+ * Build a device object for a window covering.
768
+ *
769
+ * @param {string} id - deCONZ light id
770
+ * @param {string} name - Display name
771
+ * @returns {object} ioBroker object definition
772
+ */
773
+ function coverDevice(id, name) {
774
+ return {
775
+ _id: `covers.${id}`,
776
+ type: 'device',
777
+ common: { name, role: '' },
778
+ native: { deconzId: id },
779
+ };
780
+ }
781
+
782
+ /**
783
+ * Build the info channel object for a cover.
784
+ *
785
+ * @param {string} id - deCONZ light id
786
+ * @returns {object} ioBroker channel object definition
787
+ */
788
+ function coverInfoChannel(id) {
789
+ return {
790
+ _id: `covers.${id}.info`,
791
+ type: 'channel',
792
+ common: { name: 'Info' },
793
+ native: {},
794
+ };
795
+ }
796
+
797
+ /**
798
+ * Build the state channel object for a cover.
799
+ *
800
+ * @param {string} id - deCONZ light id
801
+ * @returns {object} ioBroker channel object definition
802
+ */
803
+ function coverStateChannel(id) {
804
+ return {
805
+ _id: `covers.${id}.state`,
806
+ type: 'channel',
807
+ common: { name: 'State' },
808
+ native: {},
809
+ };
810
+ }
811
+
812
+ const COVER_STATES = [
813
+ { sub: 'info.name', type: 'string', role: 'info.name', read: true, write: false },
814
+ { sub: 'info.modelid', type: 'string', role: 'info.hardware.serial', read: true, write: false },
815
+ { sub: 'info.manufacturer', type: 'string', role: 'info.hardware.model', read: true, write: false },
816
+ { sub: 'info.reachable', type: 'boolean', role: 'indicator.reachable', read: true, write: false },
817
+ { sub: 'info.uniqueid', type: 'string', role: 'info.address.ieee', read: true, write: false },
818
+ {
819
+ sub: 'state.position',
820
+ type: 'number',
821
+ role: 'level.blind',
822
+ read: true,
823
+ write: true,
824
+ unit: '%',
825
+ min: 0,
826
+ max: 100,
827
+ },
828
+ { sub: 'state.stop', type: 'boolean', role: 'button.stop', read: true, write: true, def: false },
829
+ ];
830
+
831
+ // ─── Thermostat objects ────────────────────────────────────────────────────────
832
+
833
+ /**
834
+ * Build a device object for a thermostat.
835
+ *
836
+ * @param {string} id - deCONZ sensor id
837
+ * @param {string} name - Display name
838
+ * @returns {object} ioBroker object definition
839
+ */
840
+ function thermostatDevice(id, name) {
841
+ return {
842
+ _id: `thermostats.${id}`,
843
+ type: 'device',
844
+ common: { name, role: '' },
845
+ native: { deconzId: id },
846
+ };
847
+ }
848
+
849
+ /**
850
+ * Build the info channel object for a thermostat.
851
+ *
852
+ * @param {string} id - deCONZ sensor id
853
+ * @returns {object} ioBroker channel object definition
854
+ */
855
+ function thermostatInfoChannel(id) {
856
+ return {
857
+ _id: `thermostats.${id}.info`,
858
+ type: 'channel',
859
+ common: { name: 'Info' },
860
+ native: {},
861
+ };
862
+ }
863
+
864
+ /**
865
+ * Build the state channel object for a thermostat.
866
+ *
867
+ * @param {string} id - deCONZ sensor id
868
+ * @returns {object} ioBroker channel object definition
869
+ */
870
+ function thermostatStateChannel(id) {
871
+ return {
872
+ _id: `thermostats.${id}.state`,
873
+ type: 'channel',
874
+ common: { name: 'State' },
875
+ native: {},
876
+ };
877
+ }
878
+
879
+ const THERMOSTAT_STATES = [
880
+ { sub: 'info.name', type: 'string', role: 'info.name', read: true, write: false },
881
+ {
882
+ sub: 'info.battery',
883
+ type: 'number',
884
+ role: 'value.battery',
885
+ read: true,
886
+ write: false,
887
+ unit: '%',
888
+ min: 0,
889
+ max: 100,
890
+ },
891
+ { sub: 'info.reachable', type: 'boolean', role: 'indicator.reachable', read: true, write: false },
892
+ {
893
+ sub: 'state.temperature',
894
+ type: 'number',
895
+ role: 'value.temperature',
896
+ read: true,
897
+ write: false,
898
+ unit: '°C',
899
+ },
900
+ { sub: 'state.valve', type: 'number', role: 'value.valve', read: true, write: false, unit: '%', min: 0, max: 100 },
901
+ {
902
+ sub: 'state.setpoint',
903
+ type: 'number',
904
+ role: 'level.temperature',
905
+ read: true,
906
+ write: true,
907
+ unit: '°C',
908
+ min: 5,
909
+ max: 32,
910
+ },
911
+ ];
912
+
913
+ // ─── Helper to build a state object definition ────────────────────────────────
914
+
915
+ /**
916
+ * Build a full ioBroker state object definition
917
+ *
918
+ * @param {string} prefix e.g. "lights.3"
919
+ * @param {object} def entry from one of the *_STATES arrays
920
+ * @returns {object} Complete ioBroker state object definition
921
+ */
922
+ function buildStateObj(prefix, def) {
923
+ const common = {
924
+ name: def.sub,
925
+ type: def.type,
926
+ role: def.role,
927
+ read: def.read,
928
+ write: def.write,
929
+ };
930
+ if (def.unit !== undefined) {
931
+ common.unit = def.unit;
932
+ }
933
+ if (def.min !== undefined) {
934
+ common.min = def.min;
935
+ }
936
+ if (def.max !== undefined) {
937
+ common.max = def.max;
938
+ }
939
+ if (def.def !== undefined) {
940
+ common.def = def.def;
941
+ }
942
+ if (def.states !== undefined) {
943
+ common.states = def.states;
944
+ }
945
+
946
+ return {
947
+ _id: `${prefix}.${def.sub}`,
948
+ type: 'state',
949
+ common,
950
+ native: {},
951
+ };
952
+ }
953
+
954
+ module.exports = {
955
+ // Light
956
+ lightDevice,
957
+ lightInfoChannel,
958
+ lightStateChannel,
959
+ LIGHT_STATES,
960
+ // Plug
961
+ plugDevice,
962
+ plugInfoChannel,
963
+ plugStateChannel,
964
+ PLUG_STATES,
965
+ // Group
966
+ groupDevice,
967
+ groupInfoChannel,
968
+ groupActionChannel,
969
+ groupScenesChannel,
970
+ GROUP_INFO_STATES,
971
+ GROUP_ACTION_STATES,
972
+ // Remote
973
+ remoteDevice,
974
+ remoteChannel,
975
+ REMOTE_INFO_STATES,
976
+ REMOTE_BUTTON_STATES,
977
+ REMOTE_COLORWHEEL_STATES,
978
+ REMOTE_COLORTEMP_STATES,
979
+ // Switch
980
+ switchDevice,
981
+ switchChannel,
982
+ SWITCH_INFO_STATES,
983
+ SWITCH_BUTTON_STATES,
984
+ // Sensor
985
+ sensorDevice,
986
+ sensorChannel,
987
+ SENSOR_INFO_STATES,
988
+ SENSOR_VALUE_STATES,
989
+ SENSOR_GENERIC_VALUE_STATE,
990
+ // Cover
991
+ coverDevice,
992
+ coverInfoChannel,
993
+ coverStateChannel,
994
+ COVER_STATES,
995
+ // Thermostat
996
+ thermostatDevice,
997
+ thermostatInfoChannel,
998
+ thermostatStateChannel,
999
+ THERMOSTAT_STATES,
1000
+ // Helper
1001
+ buildStateObj,
1002
+ };