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
@@ -0,0 +1,227 @@
1
+ {
2
+ "common": {
3
+ "name": "tint",
4
+ "version": "0.3.0",
5
+ "news": {
6
+ "0.3.0": {
7
+ "en": "Fix: device tabs no longer trigger a false \"switch host\" warning in admin (React 18 + MUI v6 now shared with admin instead of bundled separately); remove leftover legacy \"tint\" sidebar tab",
8
+ "de": "Bugfix: Geräte-Tabs lösen keine falsche \"Host wechseln\"-Warnung in Admin mehr aus (React 18 + MUI v6 werden jetzt mit Admin geteilt statt separat gebündelt); veralteten Sidebar-Tab \"tint\" entfernt",
9
+ "ru": "Исправление: вкладки устройств больше не вызывают ложное предупреждение \"сменить хост\" в админке (React 18 + MUI v6 теперь общие с админкой); удалена устаревшая вкладка \"tint\" в боковой панели",
10
+ "pt": "Correção: as abas de dispositivos já não geram um aviso falso de \"mudar de host\" no admin (React 18 + MUI v6 agora partilhados com o admin); removida a aba lateral \"tint\" obsoleta",
11
+ "nl": "Bugfix: apparaattabbladen geven niet langer een onterechte \"host wisselen\"-waarschuwing in admin (React 18 + MUI v6 nu gedeeld met admin); verouderd zijbalktabblad \"tint\" verwijderd",
12
+ "fr": "Correctif: les onglets d'appareils ne déclenchent plus un faux avertissement \"changer d'hôte\" dans admin (React 18 + MUI v6 désormais partagés avec admin); suppression de l'ancien onglet latéral \"tint\"",
13
+ "it": "Correzione: le schede dispositivo non generano più un falso avviso \"cambia host\" in admin (React 18 + MUI v6 ora condivisi con admin); rimossa la vecchia scheda laterale \"tint\"",
14
+ "es": "Corrección: las pestañas de dispositivos ya no generan una falsa advertencia de \"cambiar de host\" en admin (React 18 + MUI v6 ahora compartidos con admin); eliminada la pestaña lateral obsoleta \"tint\"",
15
+ "pl": "Poprawka: zakładki urządzeń nie wywołują już fałszywego ostrzeżenia \"zmień hosta\" w admin (React 18 + MUI v6 są teraz współdzielone z admin); usunięto przestarzałą zakładkę boczną \"tint\"",
16
+ "uk": "Виправлення: вкладки пристроїв більше не викликають хибне попередження \"змінити хост\" в admin (React 18 + MUI v6 тепер спільні з admin); видалено застарілу бічну вкладку \"tint\"",
17
+ "zh-cn": "修复:设备标签页不再在admin中触发错误的“切换主机”警告(React 18 + MUI v6现已与admin共享);移除遗留的侧边栏“tint”标签"
18
+ },
19
+ "0.2.6": {
20
+ "en": "Fix: replace sendTo button with custom PairButton component for reliable API key retrieval and visual feedback",
21
+ "de": "Bugfix: sendTo-Button durch eigene PairButton-Komponente ersetzt — zuverlässige API-Schlüssel-Abfrage mit Statusanzeige",
22
+ "ru": "Исправление: кнопка sendTo заменена собственным компонентом PairButton — надёжное получение API-ключа с визуальной обратной связью",
23
+ "pt": "Correção: botão sendTo substituído por componente PairButton personalizado — obtenção fiável da chave API com feedback visual",
24
+ "nl": "Bugfix: sendTo-knop vervangen door eigen PairButton-component — betrouwbaar ophalen van API-sleutel met statusweergave",
25
+ "fr": "Correctif: bouton sendTo remplacé par un composant PairButton personnalisé — récupération fiable de la clé API avec retour visuel",
26
+ "it": "Correzione: pulsante sendTo sostituito da componente PairButton personalizzato — recupero affidabile della chiave API con feedback visivo",
27
+ "es": "Corrección: botón sendTo reemplazado por componente PairButton personalizado — obtención fiable de clave API con feedback visual",
28
+ "pl": "Poprawka: przycisk sendTo zastąpiony własnym komponentem PairButton — niezawodne pobieranie klucza API z informacją zwrotną",
29
+ "uk": "Виправлення: кнопку sendTo замінено власним компонентом PairButton — надійне отримання API-ключа з візуальним відгуком",
30
+ "zh-cn": "修复:将sendTo按钮替换为自定义PairButton组件,可靠获取API密钥并提供视觉反馈"
31
+ },
32
+ "0.2.5": {
33
+ "en": "Fix: pairing button now uses a custom panel (always visible); commit panel bundles to git so GitHub installs work without a build step",
34
+ "de": "Bugfix: Pairing-Button als Custom-Panel (immer sichtbar); Panel-Bundles in Git eingecheckt, sodass GitHub-Installationen ohne Build-Schritt funktionieren",
35
+ "ru": "Исправление: кнопка сопряжения теперь использует пользовательский компонент (всегда видима); бандлы панелей добавлены в git",
36
+ "pt": "Correção: botão de emparelhamento agora usa painel personalizado (sempre visível); bundles de painel adicionados ao git",
37
+ "nl": "Bugfix: koppelknop gebruikt nu aangepast panel (altijd zichtbaar); panel-bundles in git gezet",
38
+ "fr": "Correctif: bouton de couplage utilise désormais un panneau personnalisé (toujours visible); bundles de panneau ajoutés à git",
39
+ "it": "Correzione: il pulsante di pairing ora usa un pannello personalizzato (sempre visibile); bundle panel aggiunti a git",
40
+ "es": "Corrección: el botón de emparejamiento ahora usa un panel personalizado (siempre visible); bundles de panel añadidos a git",
41
+ "pl": "Poprawka: przycisk parowania teraz używa niestandardowego panelu (zawsze widoczny); bundle paneli dodane do git",
42
+ "uk": "Виправлення: кнопка сполучення тепер використовує власну панель (завжди видима); бандли панелей додано до git",
43
+ "zh-cn": "修复:配对按钮现在使用自定义面板(始终可见);面板包已提交至git"
44
+ },
45
+ "0.2.4": {
46
+ "en": "Improve pairing UX: click button first, adapter polls deCONZ every 3 s until pairing window opens (up to 60 s) — no more time pressure",
47
+ "de": "Pairing-UX verbessert: zuerst Button klicken, Adapter prüft alle 3 s ob das Pairing-Fenster offen ist (bis 60 s) — kein Zeitdruck mehr",
48
+ "ru": "Улучшен UX сопряжения: сначала нажмите кнопку, адаптер опрашивает deCONZ каждые 3 с (до 60 с) — больше нет спешки",
49
+ "pt": "UX de emparelhamento melhorado: clique primeiro no botão, o adaptador verifica deCONZ a cada 3 s (até 60 s) — sem pressão de tempo",
50
+ "nl": "Koppel-UX verbeterd: klik eerst op knop, adapter controleert deCONZ elke 3 s (tot 60 s) — geen tijdsdruk meer",
51
+ "fr": "UX de couplage amélioré: cliquez d'abord sur le bouton, l'adaptateur interroge deCONZ toutes les 3 s (jusqu'à 60 s) — plus de pression temporelle",
52
+ "it": "UX accoppiamento migliorato: clicca prima il pulsante, l'adattatore controlla deCONZ ogni 3 s (fino a 60 s) — nessuna pressione temporale",
53
+ "es": "UX de emparejamiento mejorado: haga clic primero en el botón, el adaptador sondea deCONZ cada 3 s (hasta 60 s) — sin presión de tiempo",
54
+ "pl": "Poprawiony UX parowania: najpierw kliknij przycisk, adapter odpytuje deCONZ co 3 s (do 60 s) — bez presji czasu",
55
+ "uk": "Покращено UX сполучення: спочатку натисніть кнопку, адаптер опитує deCONZ кожні 3 с (до 60 с) — без поспіху",
56
+ "zh-cn": "改进配对用户体验:先点击按钮,适配器每3秒轮询deCONZ(最多60秒)——不再有时间压力"
57
+ },
58
+ "0.2.3": {
59
+ "en": "Add automatic API key pairing: button in Settings tab sends a pairing request to deCONZ and fills in the key",
60
+ "de": "Automatisches API-Schlüssel-Pairing: Button in Einstellungen sendet Pairinganfrage an deCONZ und trägt den Schlüssel automatisch ein",
61
+ "ru": "Автоматическое сопряжение API-ключа: кнопка в настройках отправляет запрос на сопряжение в deCONZ и заполняет ключ",
62
+ "pt": "Emparelhamento automático de chave API: botão nas definições envia pedido de emparelhamento ao deCONZ e preenche a chave",
63
+ "nl": "Automatisch API-sleutel koppelen: knop in instellingen stuurt een koppelingsverzoek naar deCONZ en vult de sleutel in",
64
+ "fr": "Couplage automatique de clé API: bouton dans les paramètres envoie une demande de couplage à deCONZ et remplit la clé",
65
+ "it": "Accoppiamento automatico chiave API: il pulsante nelle impostazioni invia una richiesta di accoppiamento a deCONZ e inserisce la chiave",
66
+ "es": "Emparejamiento automático de clave API: botón en ajustes envía solicitud de emparejamiento a deCONZ y rellena la clave",
67
+ "pl": "Automatyczne parowanie klucza API: przycisk w ustawieniach wysyła żądanie parowania do deCONZ i wypełnia klucz",
68
+ "uk": "Автоматичне сполучення API-ключа: кнопка в налаштуваннях надсилає запит на сполучення до deCONZ і заповнює ключ",
69
+ "zh-cn": "自动API密钥配对:设置中的按钮向deCONZ发送配对请求并自动填写密钥"
70
+ },
71
+ "0.2.2": {
72
+ "en": "Fix tab labels (Lights/Groups), add static descriptions, improve UX with alive-check and sendTo timeout",
73
+ "de": "Tab-Bezeichnungen korrigiert (Leuchten/Gruppen), statische Beschreibungen ergänzt, UX verbessert mit Alive-Prüfung und sendTo-Timeout",
74
+ "ru": "Исправлены названия вкладок, добавлены описания, улучшен UX с проверкой alive и таймаутом sendTo",
75
+ "pt": "Corrigidas etiquetas de separadores, adicionadas descrições estáticas, UX melhorado com verificação alive e timeout sendTo",
76
+ "nl": "Tablabels gecorrigeerd, statische beschrijvingen toegevoegd, UX verbeterd met alive-check en sendTo-timeout",
77
+ "fr": "Libellés d'onglets corrigés, descriptions statiques ajoutées, UX amélioré avec vérification alive et délai sendTo",
78
+ "it": "Corrette etichette delle schede, aggiunte descrizioni statiche, UX migliorato con controllo alive e timeout sendTo",
79
+ "es": "Corregidas etiquetas de pestañas, añadidas descripciones estáticas, UX mejorado con comprobación alive y timeout sendTo",
80
+ "pl": "Poprawiono etykiety zakładek, dodano opisy statyczne, poprawiono UX z kontrolą alive i limitem czasu sendTo",
81
+ "uk": "Виправлено підписи вкладок, додано статичні описи, покращено UX з перевіркою alive та таймаутом sendTo",
82
+ "zh-cn": "修正选项卡标签,添加静态描述,通过alive检查和sendTo超时改进用户体验"
83
+ },
84
+ "0.2.1": {
85
+ "en": "Fix: panels were empty because window.React is not a global in admin 7",
86
+ "de": "Bugfix: Panels waren leer, weil window.React in Admin 7 kein Global ist",
87
+ "ru": "Исправление: панели были пустыми, так как window.React не является глобальным в admin 7",
88
+ "pt": "Correção: os painéis estavam vazios porque window.React não é global no admin 7",
89
+ "nl": "Bugfix: panels waren leeg omdat window.React geen global is in admin 7",
90
+ "fr": "Correctif: les panneaux étaient vides car window.React n'est pas un global dans admin 7",
91
+ "it": "Correzione: i pannelli erano vuoti perché window.React non è un global in admin 7",
92
+ "es": "Corrección: los paneles estaban vacíos porque window.React no es un global en admin 7",
93
+ "pl": "Poprawka: panele były puste, ponieważ window.React nie jest globalnym w admin 7",
94
+ "uk": "Виправлення: панелі були порожніми, оскільки window.React не є глобальним в admin 7",
95
+ "zh-cn": "修复:面板为空,因为window.React在admin 7中不是全局变量"
96
+ },
97
+ "0.2.0": {
98
+ "en": "Admin UI: lights and groups tabs in adapter settings; group management (create, edit, delete); Node.js >= 22 required",
99
+ "de": "Admin-UI: Lampen- und Gruppen-Tabs in den Adaptereinstellungen; Gruppenverwaltung (erstellen, bearbeiten, löschen); Node.js >= 22 erforderlich",
100
+ "ru": "Admin UI: вкладки светильников и групп в настройках адаптера; управление группами (создание, редактирование, удаление); требуется Node.js >= 22",
101
+ "pt": "Admin UI: abas de luzes e grupos nas configurações do adaptador; gestão de grupos (criar, editar, eliminar); necessário Node.js >= 22",
102
+ "nl": "Admin UI: lampen- en groepentabbladen in adapterinstellingen; groepsbeheer (maken, bewerken, verwijderen); Node.js >= 22 vereist",
103
+ "fr": "Admin UI: onglets lampes et groupes dans les paramètres de l'adaptateur; gestion des groupes (créer, modifier, supprimer); Node.js >= 22 requis",
104
+ "it": "Admin UI: schede luci e gruppi nelle impostazioni dell'adattatore; gestione gruppi (creare, modificare, eliminare); Node.js >= 22 richiesto",
105
+ "es": "Admin UI: pestañas de luces y grupos en la configuración del adaptador; gestión de grupos (crear, editar, eliminar); Node.js >= 22 requerido",
106
+ "pl": "Admin UI: zakładki świateł i grup w ustawieniach adaptera; zarządzanie grupami (tworzenie, edycja, usuwanie); wymagany Node.js >= 22",
107
+ "uk": "Admin UI: вкладки ламп та груп у налаштуваннях адаптера; керування групами (створення, редагування, видалення); потрібен Node.js >= 22",
108
+ "zh-cn": "管理界面:适配器设置中的灯具和群组选项卡;群组管理(创建、编辑、删除);需要Node.js >= 22"
109
+ },
110
+ "0.1.0": {
111
+ "en": "Initial release: lights, groups, scenes, Tint remote with color wheel",
112
+ "de": "Erstveröffentlichung: Lampen, Gruppen, Szenen, Tint-Fernbedienung mit Farbrad",
113
+ "ru": "Первый выпуск: лампы, группы, сцены, пульт Tint с цветовым колесом",
114
+ "pt": "Lançamento inicial: luzes, grupos, cenas, controlo remoto Tint com roda de cores",
115
+ "nl": "Eerste versie: lampen, groepen, scènes, Tint-afstandsbediening met kleurenwiel",
116
+ "fr": "Version initiale: lampes, groupes, scènes, télécommande Tint avec roue chromatique",
117
+ "it": "Versione iniziale: luci, gruppi, scene, telecomando Tint con ruota dei colori",
118
+ "es": "Versión inicial: luces, grupos, escenas, mando a distancia Tint con rueda de colores",
119
+ "pl": "Pierwsza wersja: światła, grupy, sceny, pilot Tint z kołem kolorów",
120
+ "uk": "Перший випуск: лампи, групи, сцени, пульт Tint із колесом кольорів",
121
+ "zh-cn": "初始版本:灯具、群组、场景、带色轮的Tint遥控器"
122
+ }
123
+ },
124
+ "titleLang": {
125
+ "en": "Müller Licht tint",
126
+ "de": "Müller Licht tint",
127
+ "ru": "Müller Licht tint",
128
+ "pt": "Müller Licht tint",
129
+ "nl": "Müller Licht tint",
130
+ "fr": "Müller Licht tint",
131
+ "it": "Müller Licht tint",
132
+ "es": "Müller Licht tint",
133
+ "pl": "Müller Licht tint",
134
+ "uk": "Müller Licht tint",
135
+ "zh-cn": "Müller Licht tint"
136
+ },
137
+ "desc": {
138
+ "en": "Control Müller Licht tint Zigbee smart lights via deCONZ/ConBee including full Tint remote support with color wheel",
139
+ "de": "Steuerung von Müller Licht tint Zigbee-Leuchten über deCONZ/ConBee inkl. vollständiger Tint-Fernbedienungsunterstützung mit Farbrad",
140
+ "ru": "Управление умными светильниками Müller Licht tint Zigbee через deCONZ/ConBee, включая полную поддержку пульта Tint с цветовым колесом",
141
+ "pt": "Controle luzes inteligentes Müller Licht tint Zigbee via deCONZ/ConBee incluindo suporte completo ao controlo remoto Tint com roda de cores",
142
+ "nl": "Bedien Müller Licht tint Zigbee slimme lampen via deCONZ/ConBee inclusief volledige Tint-afstandsbediening met kleurenwiel",
143
+ "fr": "Contrôlez les éclairages intelligents Müller Licht tint Zigbee via deCONZ/ConBee avec support complet de la télécommande Tint et roue chromatique",
144
+ "it": "Controlla le luci intelligenti Müller Licht tint Zigbee tramite deCONZ/ConBee con pieno supporto del telecomando Tint con ruota dei colori",
145
+ "es": "Controle las luces inteligentes Müller Licht tint Zigbee a través de deCONZ/ConBee con soporte completo del mando Tint con rueda de colores",
146
+ "pl": "Steruj inteligentnymi lampami Müller Licht tint Zigbee przez deCONZ/ConBee z pełną obsługą pilota Tint z kołem kolorów",
147
+ "uk": "Керуйте розумними лампами Müller Licht tint Zigbee через deCONZ/ConBee з повною підтримкою пульта Tint із колесом кольорів",
148
+ "zh-cn": "通过deCONZ/ConBee控制Müller Licht tint Zigbee智能灯,包括完整的Tint遥控器色轮支持"
149
+ },
150
+ "authors": [
151
+ "ssbingo <s.sternitzke@online.de>"
152
+ ],
153
+ "keywords": [
154
+ "MüllerLicht",
155
+ "Tint",
156
+ "Zigbee",
157
+ "deCONZ",
158
+ "ConBee",
159
+ "RGBW"
160
+ ],
161
+ "licenseInformation": {
162
+ "type": "free",
163
+ "license": "MIT"
164
+ },
165
+ "platform": "Javascript/Node.js",
166
+ "icon": "tint.png",
167
+ "enabled": true,
168
+ "extIcon": "https://raw.githubusercontent.com/ssbingo/ioBroker.tint/main/admin/tint.png",
169
+ "readme": "https://github.com/ssbingo/ioBroker.tint/blob/main/README.md",
170
+ "loglevel": "info",
171
+ "tier": 3,
172
+ "mode": "daemon",
173
+ "type": "hardware",
174
+ "compact": true,
175
+ "messagebox": true,
176
+ "connectionType": "local",
177
+ "dataSource": "push",
178
+ "adminUI": {
179
+ "config": "json"
180
+ },
181
+ "dependencies": [
182
+ {
183
+ "js-controller": ">=6.0.11"
184
+ }
185
+ ],
186
+ "globalDependencies": [
187
+ {
188
+ "admin": ">=7.0.23"
189
+ }
190
+ ]
191
+ },
192
+ "native": {
193
+ "ip": "192.168.1.100",
194
+ "port": 80,
195
+ "wsPort": 443,
196
+ "apiKey": "",
197
+ "pollingInterval": 60,
198
+ "autoApplyColorWheel": true,
199
+ "transitionTime": 4,
200
+ "watchdogMinutes": 120
201
+ },
202
+ "encryptedNative": [
203
+ "apiKey"
204
+ ],
205
+ "protectedNative": [
206
+ "apiKey"
207
+ ],
208
+ "objects": [],
209
+ "instanceObjects": [
210
+ {
211
+ "_id": "info.connection",
212
+ "type": "state",
213
+ "common": {
214
+ "name": {
215
+ "en": "Connection to deCONZ",
216
+ "de": "Verbindung zu deCONZ"
217
+ },
218
+ "type": "boolean",
219
+ "role": "indicator.connected",
220
+ "read": true,
221
+ "write": false,
222
+ "def": false
223
+ },
224
+ "native": {}
225
+ }
226
+ ]
227
+ }
@@ -0,0 +1,20 @@
1
+ // This file extends the AdapterConfig type from "@types/iobroker"
2
+
3
+ // Inhere the actual properties of your adapter config
4
+ declare global {
5
+ namespace ioBroker {
6
+ interface AdapterConfig {
7
+ ip: string;
8
+ port: number;
9
+ wsPort: number;
10
+ apiKey: string;
11
+ pollingInterval: number;
12
+ autoApplyColorWheel: boolean;
13
+ transitionTime: number;
14
+ watchdogMinutes: number;
15
+ }
16
+ }
17
+ }
18
+
19
+ // this is required so the above global namespace changes take effect
20
+ export {};
@@ -0,0 +1,61 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Trims raw deCONZ light/group objects down to only the fields the admin
5
+ * UI tabs actually read (admin/src/components/LightsTab.jsx, PlugsTab.jsx,
6
+ * CoversTab.jsx, GroupsTab.jsx, GroupDialog.jsx, ScenesTab.jsx,
7
+ * deviceCategory.js).
8
+ *
9
+ * Why this exists: deCONZ's raw /lights payload includes large, unused
10
+ * fields per light — most notably "capabilities" (color gamut points,
11
+ * effect/alert enum lists, etc.), plus etag/lastannounced/swversion/
12
+ * uniqueid/hascolor that no admin tab displays. For an installation with
13
+ * ~30 lights this raw payload is tens of KB; sending it verbatim over the
14
+ * same socket.io connection admin uses to track host-alive heartbeats can
15
+ * make the browser's main thread busy parsing/rendering it long enough to
16
+ * delay heartbeat processing, which iobroker.admin's HostSelectors
17
+ * component (adminWww bootstrap bundle) interprets as the host going
18
+ * briefly "not alive" — surfacing as a red, "switch host" warning despite
19
+ * nothing actually being wrong. Trimming the response to only what's
20
+ * displayed removes the root cause instead of just the symptom.
21
+ */
22
+
23
+ /**
24
+ * @param {object} light - Raw deCONZ light object
25
+ * @returns {object} Minimal projection used by the admin Lights/Plugs/Covers tabs
26
+ */
27
+ function trimLightForAdmin(light) {
28
+ const s = light?.state || {};
29
+ return {
30
+ name: light?.name,
31
+ modelid: light?.modelid,
32
+ manufacturername: light?.manufacturername,
33
+ type: light?.type,
34
+ state: {
35
+ on: s.on,
36
+ bri: s.bri,
37
+ reachable: s.reachable,
38
+ lift: s.lift,
39
+ open: s.open,
40
+ },
41
+ };
42
+ }
43
+
44
+ /**
45
+ * @param {object} group - Raw deCONZ group object
46
+ * @returns {object} Minimal projection used by the admin Groups/Scenes tabs
47
+ */
48
+ function trimGroupForAdmin(group) {
49
+ const st = group?.state || {};
50
+ return {
51
+ name: group?.name,
52
+ lights: group?.lights,
53
+ scenes: group?.scenes,
54
+ state: {
55
+ all_on: st.all_on,
56
+ any_on: st.any_on,
57
+ },
58
+ };
59
+ }
60
+
61
+ module.exports = { trimLightForAdmin, trimGroupForAdmin };
@@ -0,0 +1,230 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Color utility functions for Müller Licht tint adapter
5
+ * - CIE xy ↔ sRGB Hex conversion
6
+ * - Tint Remote color wheel position map (36 positions × 10°)
7
+ * - Brightness % ↔ deCONZ bri (0–254)
8
+ * - Color temperature Kelvin ↔ Mired
9
+ */
10
+
11
+ // ─── Brightness ───────────────────────────────────────────────────────────────
12
+
13
+ /**
14
+ * deCONZ bri (0–254) → percentage (0–100)
15
+ *
16
+ * @param {number} bri - deCONZ brightness value (0–254)
17
+ * @returns {number} Brightness percentage (0–100)
18
+ */
19
+ function briToPercent(bri) {
20
+ return Math.round((Math.max(0, Math.min(254, bri)) / 254) * 100);
21
+ }
22
+
23
+ /**
24
+ * Percentage (0–100) → deCONZ bri (0–254)
25
+ *
26
+ * @param {number} pct - Brightness percentage (0–100)
27
+ * @returns {number} deCONZ brightness value (0–254)
28
+ */
29
+ function percentToBri(pct) {
30
+ return Math.round((Math.max(0, Math.min(100, pct)) / 100) * 254);
31
+ }
32
+
33
+ // ─── Color Temperature ────────────────────────────────────────────────────────
34
+
35
+ /**
36
+ * Mired → Kelvin
37
+ *
38
+ * deCONZ reports ct=0 for lights/groups that don't support color temperature
39
+ * (e.g. plugs, or a group with no CT-capable members) — clamp to the
40
+ * colorTemp state's declared range (2000–6500 K) instead of letting that
41
+ * sentinel produce a huge out-of-range value.
42
+ *
43
+ * @param {number} mired - Color temperature in Mired
44
+ * @returns {number} Color temperature in Kelvin
45
+ */
46
+ function miredToKelvin(mired) {
47
+ return Math.max(2000, Math.min(6500, Math.round(1000000 / Math.max(1, mired))));
48
+ }
49
+
50
+ /**
51
+ * Kelvin → Mired
52
+ *
53
+ * @param {number} kelvin - Color temperature in Kelvin
54
+ * @returns {number} Color temperature in Mired
55
+ */
56
+ function kelvinToMired(kelvin) {
57
+ return Math.round(1000000 / Math.max(1, kelvin));
58
+ }
59
+
60
+ // ─── CIE xy → sRGB Hex ───────────────────────────────────────────────────────
61
+
62
+ /**
63
+ * Convert CIE 1931 xy chromaticity + brightness to sRGB Hex string.
64
+ * Uses Wide Gamut D65 matrix (matches Philips Hue / Müller Licht tint)
65
+ *
66
+ * @param {number} x - CIE x chromaticity (0.0–1.0)
67
+ * @param {number} y - CIE y chromaticity (0.0–1.0)
68
+ * @param {number} [bri] - deCONZ brightness (0–254, default 254) (0–254)
69
+ * @returns {string} sRGB hex color string e.g. "#FF4400"
70
+ */
71
+ function xyToHex(x, y, bri = 254) {
72
+ if (y === 0) {
73
+ return '#000000';
74
+ }
75
+
76
+ const Y = bri / 254;
77
+ const X = (Y / y) * x;
78
+ const Z = (Y / y) * (1.0 - x - y);
79
+
80
+ // Wide Gamut D65 matrix (sRGB)
81
+ let r = X * 1.656492 - Y * 0.354851 - Z * 0.255038;
82
+ let g = -X * 0.707196 + Y * 1.655397 + Z * 0.036152;
83
+ let b = X * 0.051713 - Y * 0.121364 + Z * 1.01153;
84
+
85
+ // Clamp negatives
86
+ r = Math.max(0, r);
87
+ g = Math.max(0, g);
88
+ b = Math.max(0, b);
89
+
90
+ // Normalise so largest channel = 1.0
91
+ const max = Math.max(r, g, b, 1);
92
+ r /= max;
93
+ g /= max;
94
+ b /= max;
95
+
96
+ // Gamma correction (sRGB)
97
+ const gamma = v => (v <= 0.0031308 ? 12.92 * v : (1.0 + 0.055) * Math.pow(v, 1.0 / 2.4) - 0.055);
98
+
99
+ const R = Math.round(gamma(r) * 255);
100
+ const G = Math.round(gamma(g) * 255);
101
+ const B = Math.round(gamma(b) * 255);
102
+
103
+ return `#${[R, G, B]
104
+ .map(v => v.toString(16).padStart(2, '0'))
105
+ .join('')
106
+ .toUpperCase()}`;
107
+ }
108
+
109
+ /**
110
+ * sRGB Hex → CIE xy array [x, y].
111
+ * Useful for writing a hex color to a light.
112
+ *
113
+ * @param {string} hex - sRGB hex color e.g. "#FF4400" or "FF4400"
114
+ * @returns {[number, number]} CIE xy chromaticity pair
115
+ */
116
+ function hexToXy(hex) {
117
+ const clean = hex.replace('#', '');
118
+ const R = parseInt(clean.slice(0, 2), 16) / 255;
119
+ const G = parseInt(clean.slice(2, 4), 16) / 255;
120
+ const B = parseInt(clean.slice(4, 6), 16) / 255;
121
+
122
+ // Reverse gamma
123
+ const linear = v => (v > 0.04045 ? Math.pow((v + 0.055) / 1.055, 2.4) : v / 12.92);
124
+
125
+ const r = linear(R);
126
+ const g = linear(G);
127
+ const b = linear(B);
128
+
129
+ // Wide Gamut D65 (inverse of the matrix above, approximate)
130
+ const X = r * 0.664511 + g * 0.154324 + b * 0.162028;
131
+ const Y = r * 0.283881 + g * 0.668433 + b * 0.047685;
132
+ const Z = r * 0.000088 + g * 0.07231 + b * 0.986039;
133
+
134
+ const sum = X + Y + Z;
135
+ if (sum === 0) {
136
+ return [0, 0];
137
+ }
138
+
139
+ return [Math.round((X / sum) * 10000) / 10000, Math.round((Y / sum) * 10000) / 10000];
140
+ }
141
+
142
+ // ─── Tint Remote color wheel (36 positions, 10° steps) ───────────────────────
143
+ //
144
+ // Source: empirical measurements from the community
145
+ // (github.com/dresden-elektronik/deconz-rest-plugin, xaviml/controllerx)
146
+ // angle → CIE xy sent by the remote on buttonevent 6002
147
+
148
+ /**
149
+ * Tint Remote color wheel map: angle (0–350°, 10° steps) → CIE xy
150
+ *
151
+ * {Record<number, {x: number, y: number}>}
152
+ */
153
+ const COLOR_WHEEL_MAP = {
154
+ 0: { x: 0.7, y: 0.299 }, // Red
155
+ 10: { x: 0.68, y: 0.305 },
156
+ 20: { x: 0.65, y: 0.32 },
157
+ 30: { x: 0.61, y: 0.36 }, // Red-Orange
158
+ 40: { x: 0.57, y: 0.39 },
159
+ 50: { x: 0.53, y: 0.43 }, // Orange
160
+ 60: { x: 0.49, y: 0.45 },
161
+ 70: { x: 0.45, y: 0.47 }, // Yellow-Orange
162
+ 80: { x: 0.42, y: 0.5 },
163
+ 90: { x: 0.38, y: 0.52 }, // Yellow
164
+ 100: { x: 0.34, y: 0.54 },
165
+ 110: { x: 0.3, y: 0.54 },
166
+ 120: { x: 0.25, y: 0.53 }, // Yellow-Green
167
+ 130: { x: 0.21, y: 0.51 },
168
+ 140: { x: 0.18, y: 0.48 }, // Green
169
+ 150: { x: 0.16, y: 0.44 },
170
+ 160: { x: 0.15, y: 0.39 },
171
+ 170: { x: 0.155, y: 0.34 }, // Cyan-Green
172
+ 180: { x: 0.165, y: 0.29 }, // Cyan
173
+ 190: { x: 0.175, y: 0.25 },
174
+ 200: { x: 0.19, y: 0.21 },
175
+ 210: { x: 0.21, y: 0.175 }, // Cyan-Blue
176
+ 220: { x: 0.23, y: 0.15 },
177
+ 230: { x: 0.25, y: 0.13 }, // Blue
178
+ 240: { x: 0.2, y: 0.1 },
179
+ 250: { x: 0.16, y: 0.08 },
180
+ 260: { x: 0.14, y: 0.065 }, // Dark Blue
181
+ 270: { x: 0.16, y: 0.065 }, // Violet-Blue
182
+ 280: { x: 0.195, y: 0.075 },
183
+ 290: { x: 0.24, y: 0.085 }, // Violet
184
+ 300: { x: 0.28, y: 0.1 },
185
+ 310: { x: 0.33, y: 0.11 }, // Magenta
186
+ 320: { x: 0.39, y: 0.13 },
187
+ 330: { x: 0.46, y: 0.16 }, // Pink-Red
188
+ 340: { x: 0.54, y: 0.2 },
189
+ 350: { x: 0.62, y: 0.25 }, // Red-Pink
190
+ };
191
+
192
+ /**
193
+ * Tint Remote zone group IDs → zone number (1–3)
194
+ *
195
+ * {Record<number, number>}
196
+ */
197
+ const ZONE_GROUP_MAP = {
198
+ 16388: 1,
199
+ 16389: 2,
200
+ 16390: 3,
201
+ };
202
+
203
+ /**
204
+ * Decode the active zone from the sensor config.group string.
205
+ * Returns 0 when "all" or undetermined.
206
+ *
207
+ * @param {string} groupString - Comma-separated group ids e.g. "16388" or "16388,16389,16390"
208
+ * @returns {number} Zone number 0=all, 1=zone1, 2=zone2, 3=zone3
209
+ */
210
+ function decodeRemoteZone(groupString) {
211
+ if (!groupString) {
212
+ return 0;
213
+ }
214
+ const parts = groupString.split(',').map(Number);
215
+ if (parts.length === 1) {
216
+ return ZONE_GROUP_MAP[parts[0]] || 0;
217
+ }
218
+ return 0; // multiple groups = "all"
219
+ }
220
+
221
+ module.exports = {
222
+ briToPercent,
223
+ percentToBri,
224
+ miredToKelvin,
225
+ kelvinToMired,
226
+ xyToHex,
227
+ hexToXy,
228
+ COLOR_WHEEL_MAP,
229
+ decodeRemoteZone,
230
+ };