iobroker.esphome 0.7.0-beta.4 → 0.7.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/README.md CHANGED
@@ -340,6 +340,39 @@ Example config, for more examples see [The DrozmotiX Docu Page](https://Drozmoti
340
340
  output: 'gpio_12'
341
341
  </details>
342
342
 
343
+ ## Controlling RGBW Lights
344
+
345
+ ### RGB vs RGBW — What's the Difference?
346
+
347
+ **RGB lights** use three channels (red, green, blue) to produce colours, including white by mixing all three at maximum. **RGBW lights** add a dedicated fourth white channel (`white`) that provides a cleaner, brighter white than mixing RGB.
348
+
349
+ ### Available states for a light entity
350
+
351
+ | State | Description |
352
+ |---|---|
353
+ | `colorHEX` | Writable hex colour string, e.g. `#ff6600`. Writing here updates red/green/blue and sends the command. |
354
+ | `red` / `green` / `blue` | Individual colour channels (0 – 255). |
355
+ | `white` | Dedicated white channel (0 – 255). Only present on RGBW-capable lights. |
356
+ | `brightness` | Overall brightness (0 – 255). |
357
+ | `config.rgbAutoWhite` | **RGBW only** — when set to `true`, writing `#ffffff` to `colorHEX` automatically activates the white channel and sets RGB to zero. Writing any other colour disables the white channel and uses RGB. |
358
+
359
+ ### Auto white-channel switching (`rgbAutoWhite`)
360
+
361
+ When an RGBW-capable light is detected (i.e. it exposes a `white` state), the adapter automatically creates a writable `config.rgbAutoWhite` toggle state for that entity. It defaults to `false` (disabled).
362
+
363
+ **To enable:**
364
+ 1. Open the ioBroker **Objects** view and navigate to your light entity, e.g. `esphome.0.MyLight.Light.1.config.rgbAutoWhite`.
365
+ 2. Set the value to `true`.
366
+
367
+ **Behaviour when enabled:**
368
+
369
+ | `colorHEX` input | Result |
370
+ |---|---|
371
+ | `#ffffff` | `white` → 1 (full), `red` / `green` / `blue` → 0 |
372
+ | Any other colour | `white` → 0, RGB channels set to the colour values |
373
+
374
+ **Behaviour when disabled (default):** the `white` channel is never touched automatically; users control it independently.
375
+
343
376
  ## Tasmota / ESPEasy migration
344
377
 
345
378
  Migrating from previous Sonoff Tasmota or ESPEasy setups is very easy. You just need to have ESPHome create a binary for you and then upload that in the web interface.
@@ -360,9 +393,16 @@ If you like my work, please consider a personal donation
360
393
  ### __WORK IN PROGRESS__
361
394
  * (DutchmanNL)
362
395
  -->
396
+ ### 0.7.0 (2026-05-17)
397
+ * (@SimonFischer04) **FIXED** copilot hallucinations
398
+ * (@SimonFischer04) **NEW** 'Always last available' for pillow version
399
+ * (@copilot) **FIXED**: Invalid jsonConfig warning on adapter installation
400
+ * (DutchmanNL) **FIXED**: ESLint errors by code refactoring
401
+
363
402
  ### 0.7.0-beta.4 (2026-02-21)
364
403
  * (DutchmanNL) **FIXED**: ESLint errors by code refactoring
365
404
  * (@copilot) **FIXED**: Restore missing `configStates` option in admin UI to allow configuring whether configuration states are shown per entity
405
+ * (@copilot) **NEW**: Per-device `rgbAutoWhite` toggle in the light config channel for automatic white-channel routing on RGBW lights (see [Controlling RGBW Lights](#controlling-rgbw-lights))
366
406
 
367
407
  ### 0.7.0-beta.3 (2026-02-20)
368
408
  * (@copilot) **NEW**: Added support for `colorBrightness`, `coldWhite`, `warmWhite`, and `colorMode` states for lights using the new ESPHome color mode API
@@ -387,14 +427,6 @@ If you like my work, please consider a personal donation
387
427
  * (@SimonFischer04) automatic migration from versions prior to ESPHomeDashboardUrl introduction (pre v0.6.1)
388
428
  * (@copilot) **FIXED**: Invalid jsonConfig schema - removed unsupported `doNotSave` property from table elements
389
429
 
390
- ### 0.6.3 (2025-09-16)
391
- * (@DutchmanNL) Fixed an admin error related to `jsonConfig` validation. #287
392
- * (@DutchmanNL) Various general fixes and dependency updates to improve stability.
393
- * (@DutchmanNL) Improved responsive design for better usability across devices. #284
394
- * (@DutchmanNL) Introduced GitHub Actions to automatically verify the ESPHome Dashboard. #290
395
- * (@DutchmanNL) Added a comprehensive FAQ section to the README to help users with common questions. #286
396
- * (@DutchmanNL) Updated the `esphome-native-api` library to V1.3.3, which may resolve connection issues. #201
397
-
398
430
  ## License
399
431
  MIT License
400
432
 
@@ -69,4 +69,4 @@
69
69
  "cnfClearCacheCancel": "Cancel",
70
70
  "lblConfigStates": "Show configuration states",
71
71
  "hlpConfigStates": "Create configuration states for each entity to show device configuration details"
72
- }
72
+ }
@@ -69,4 +69,4 @@
69
69
  "cnfClearCacheCancel": "Cancel",
70
70
  "lblConfigStates": "Show configuration states",
71
71
  "hlpConfigStates": "Create configuration states for each entity to show device configuration details"
72
- }
72
+ }
@@ -69,4 +69,4 @@
69
69
  "cnfClearCacheCancel": "Cancel",
70
70
  "lblConfigStates": "Show configuration states",
71
71
  "hlpConfigStates": "Create configuration states for each entity to show device configuration details"
72
- }
72
+ }
@@ -69,4 +69,4 @@
69
69
  "cnfClearCacheCancel": "Cancel",
70
70
  "lblConfigStates": "Show configuration states",
71
71
  "hlpConfigStates": "Create configuration states for each entity to show device configuration details"
72
- }
72
+ }
@@ -69,4 +69,4 @@
69
69
  "cnfClearCacheCancel": "Cancel",
70
70
  "lblConfigStates": "Show configuration states",
71
71
  "hlpConfigStates": "Create configuration states for each entity to show device configuration details"
72
- }
72
+ }
@@ -69,4 +69,4 @@
69
69
  "cnfClearCacheCancel": "Cancel",
70
70
  "lblConfigStates": "Show configuration states",
71
71
  "hlpConfigStates": "Create configuration states for each entity to show device configuration details"
72
- }
72
+ }
@@ -69,4 +69,4 @@
69
69
  "cnfClearCacheCancel": "Cancel",
70
70
  "lblConfigStates": "Show configuration states",
71
71
  "hlpConfigStates": "Create configuration states for each entity to show device configuration details"
72
- }
72
+ }
@@ -69,4 +69,4 @@
69
69
  "cnfClearCacheCancel": "Cancel",
70
70
  "lblConfigStates": "Show configuration states",
71
71
  "hlpConfigStates": "Create configuration states for each entity to show device configuration details"
72
- }
72
+ }
@@ -69,4 +69,4 @@
69
69
  "cnfClearCacheCancel": "Cancel",
70
70
  "lblConfigStates": "Show configuration states",
71
71
  "hlpConfigStates": "Create configuration states for each entity to show device configuration details"
72
- }
72
+ }
@@ -668,7 +668,7 @@
668
668
  "advanced": {
669
669
  "type": "panel",
670
670
  "label": "Advanced",
671
- "collapsible": true,
671
+ "collapsable": true,
672
672
  "xs": 12,
673
673
  "sm": 12,
674
674
  "md": 12,
@@ -827,9 +827,8 @@
827
827
  // YAML content input
828
828
  "uploadContent": {
829
829
  "newLine": true,
830
- "type": "text",
830
+ "type": "textarea",
831
831
  "label": "lblUploadContent",
832
- "multiline": true,
833
832
  "rows": 10,
834
833
  "placeholder": "esphome:\n name: my-device\n platform: ESP8266\n board: nodemcuv2",
835
834
  "xs": 12,
package/io-package.json CHANGED
@@ -1,8 +1,21 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "esphome",
4
- "version": "0.7.0-beta.4",
4
+ "version": "0.7.0",
5
5
  "news": {
6
+ "0.7.0": {
7
+ "en": "**FIXED** copilot hallucinations\n**NEW** 'Always last available' for pillow version\n**FIXED**: Invalid jsonConfig warning on adapter installation\n**FIXED**: ESLint errors by code refactoring",
8
+ "de": "**FIXED** Copilot Halluzinationen\n**NEW** 'Always last available' für Kissenversion\n**FIXED**: Invalid jsonConfig Warnung auf Adapterinstallation\n**FIXED**: ESLint-Fehler durch Code-Refactoring",
9
+ "ru": "** Исправленные** галлюцинации копилота\n** «Всегда последний доступный» для подушки\n** Фиксированный**: Недействительное предупреждение jsonConfig об установке адаптера\n**FIXED**: ошибки ESLint при рефакторинге кода",
10
+ "pt": "**FIXED** alucinações copiloto\n** NOVA** 'Sempre última disponível' para a versão do travesseiro\n**FIXED**: Aviso inválido do jsonConfig na instalação do adaptador\n**FIXED**: ESLint errors by code refatoring",
11
+ "nl": "** VASTE** copiloothallucinaties\n**NIEUW** 'Always last available' voor kussenversie\n** VAST**: Ongeldige jsonConfig waarschuwing bij adapter installatie\n** VAST**: ESLint fouten door code refactoring",
12
+ "fr": "**FIXED** hallucinations copilotes\n**NOUVEAU** 'Toujours dernier disponible' pour la version oreiller\n**FIXÉ**: Avertissement jsonConfig non valide sur l'installation de l'adaptateur\n**FIXED**: erreurs ESLint par refactoring de code",
13
+ "it": "**FISSO ** Allucinazioni copilota\n**NEW** 'Always last available' per cuscino versione\n**FISSO ** Avvertenza jsonConfig non valida per l'installazione dell'adattatore\n**FIXED**: Errori di ESLint per refactoring del codice",
14
+ "es": "**FIXED ** copiloto alucinaciones\n**NEW** 'Siempre disponible' para la versión de almohada\n**FIXED**: Invalid jsonConfig warning on adapter installation\n**FIXED**: errores ESLint por refactorización de código",
15
+ "pl": "* *FIXED* * omamy drugiego pilota \n* *NOWOŚĆ* * \"Zawsze ostatni dostępny\" dla wersji poduszki \n* *FIXED* * Nieprawidłowe ostrzeżenie jsonConfig na instalacji adaptera \n** FIXED*",
16
+ "uk": "**FIXED*** копілотні галюцинації\n**NEW**** 'Всі останні доступні' для версії подушки\n**FIXED***: Інвалідний jsonПопередження про встановлення адаптера\n**FIXED***: помилки ESLint від рефакторингу коду",
17
+ "zh-cn": "** 副驾驶幻觉\n** NEW** 枕头版本“ 永远可用”\n(单位:千美元) 在适配器安装上无效的 jsonConfig 警告\n**FIXED**:通过代码重构的ESLint错误"
18
+ },
6
19
  "0.7.0-beta.4": {
7
20
  "en": "**FIXED**: ESLint errors by code refactoring\n**FIXED**: Restore missing `configStates` option in admin UI to allow configuring whether configuration states are shown per entity",
8
21
  "de": "**FIXED**: ESLint-Fehler durch Code-Refactoring\n**FIXED**: Wiederherstellen fehlender `configStates` Option im Admin UI, um die Konfiguration zu ermöglichen, ob Konfigurationszustände pro Einheit angezeigt werden",
@@ -16,19 +29,6 @@
16
29
  "uk": "**FIXED***: помилки ESLint від рефакторингу коду\n**FIXED***: Відновити варіант `configStates` в admin UI, щоб дозволити налаштування станів конфігурації відображається на суб’єкті",
17
30
  "zh-cn": "**FIXED**:通过代码重构的ESLint错误\n** FIXED**:在管理UI中恢复缺失的“配置状态”选项,以便配置是否显示每个实体的配置状态"
18
31
  },
19
- "0.7.0-beta.3": {
20
- "en": "**NEW**: Added support for `colorBrightness`, `coldWhite`, `warmWhite`, and `colorMode` states for lights using the new ESPHome color mode API\n**FIXED**: RGB light control (brightness, color, white, colorTemperature) not working with newer ESPHome firmware that uses `supportedColorModesList` instead of deprecated legacy flags (#338)",
21
- "de": "**NEW**: Unterstützung für `colorBrightness`, `coldWhite`, `warmWhite` und `colorMode` Zustände für Lichter mit der neuen ESPHome Farbmodus API\n**FIXED**: RGB Lichtsteuerung (Brightness, Farbe, weiß, FarbeTemperature) nicht mit neuerer ESPHome Firmware, die `supportedColorModesList` anstelle von deprecated Legacy Fahnen verwendet (#338)",
22
- "ru": "**NEW**: Добавлена поддержка состояний «colorBrightness», «coldWhite», «warmWhite» и «colorMode» для огней с использованием нового API цветового режима ESPHome\n** FIXED**: Управление светом RGB (яркость, цвет, белый, цветовая температура) не работает с новой прошивкой ESPHome, которая использует «поддерживаемый ColorModesList» вместо устаревших флагов (#338)",
23
- "pt": "**NOVO**: Adicionado suporte para `colorBrightness`, `coldWhite`, `warmWhite`, e `colorMode` estados para luzes usando o novo modo de cores ESPHome API\n**FIXED**: Controle de luz RGB (brilho, cor, branco, corTemperatura) não trabalhando com firmware ESPHome mais recente que usa `supportedColorModesList` em vez de bandeiras legadas deprecadas (#338)",
24
- "nl": "**NIEUW**: Toegevoegde ondersteuning voor kleurBrightness, \n**FIXED**: RGB lichtcontrole (helderheid, kleur, wit, kleurTemperatuur) werkt niet met nieuwere ESPHome firmware die gebruik maakt van de ondersteundeColorModesListIn plaats van verouderde legacy vlaggen (#338)",
25
- "fr": "**NOUVEAU**: Ajout du support pour les états `colorBrightness`, `coldWhite`, `warmWhite` et `colorMode` pour les lumières en utilisant la nouvelle API en mode couleur ESPHome\n**FIXED**: RGB contrôle de la lumière (brightness, color, white, colorTemperature) ne fonctionne pas avec le nouveau firmware ESPHome qui utilise `supportedColorModesList` au lieu de drapeaux hérités dépréciés (#338)",
26
- "it": "**NEW**: Aggiunto il supporto per `colorBrightness`, `coldWhite`, `warmWhite`, e `colorMode` stati per le luci utilizzando il nuovo ESPHome colore modalità API\n**FIXED**: RGB light control (luce, colore, bianco, coloreTemperatura) non funziona con il nuovo firmware ESPHome che utilizza `supportedColorModesList` invece di bandiere legacy deprecate (#338)",
27
- "es": "**NEW**: Añadido soporte para `colorBrightness`, `coldWhite`, `warmWhite`, and `colorMode` states for lights using the new ESPHome color mode API\n**FIXED**: Control de luz RGB (brightness, color, blanco, colorTemperatura) no trabaja con el firmware ESPHome más nuevo que utiliza 'ColorModesList` compatible en lugar de banderas heredadas deprecatadas (#338)",
28
- "pl": "* *NOWOŚĆ* *: Dodano wsparcie dla 'colorBrighty', 'coldWhite', 'colorWhite' i 'colorMode' dla świateł przy użyciu nowego trybu kolorów ESPHome API \n* *FIXED* *: Sterowanie światłem RGB (jasność, kolor, biel, barwa) niepracujące z nowszymi firmware ESPHome, które używa 'supportedColorModesList' zamiast zdeprecjonowanych flag (# 338) ",
29
- "uk": "**NEW**: Додана підтримка `colorBrightness`, `coldWhite`, `warmWhite`, `colorMode` станів для вогнів, використовуючи новий ESPHome колірний режим API\n**FIXED**: RGB легкий контроль (яскравість, колір, білий, колірTemperature) не працює з новою прошивкою ESPHome, яка використовує `supportedColorModesList` замість відхилених прапорів спадщини (#338)",
30
- "zh-cn": "**NEW**: 添加支持使用新的ESPHome颜色模式API的“彩色亮度”、“冷白”、“暖白”和“彩色模式”照明装置\n** FIXED**:RGB灯光控制(亮度,颜色,白色,色质)不与使用`支持的ColorModesList ' 而不是被磨损的遗留旗帜的更新ESPHome固件合作(# 338)"
31
- },
32
32
  "0.7.0-beta.2": {
33
33
  "en": "improve README\nfix #394, actually fix #340, #356\n**FIXED**: Fan component not working #205\n**NEW**: Allow customization of Pillow version used by ESPHome Dashboard, similar to ESPHome version selector\n**NEW**: Add \"Clear Autopy Cache\" button in ESPHome Dashboard configuration tab to resolve dashboard loading issues (#209)",
34
34
  "de": "rEADME\nfix #394, eigentlich fix #340, #356\n**FIXED**: Fan-Komponente nicht funktioniert #205\n**NEW**: Erlauben Anpassung der Pillow-Version, die von ESPHome Dashboard verwendet wird, ähnlich wie ESPHome-Versionsauswahl\n**NEW**: Fügen Sie die Schaltfläche \"Klar Autopy Cache\" in ESPHome Dashboard Konfigurationstabelle hinzu, um dashboard Ladeprobleme zu lösen (#209)",
@@ -42,19 +42,6 @@
42
42
  "uk": "покращити резюме\nвиправити #394, насправді виправити #340, #356\n**FIXED***: Компонент вентилятора не працює #205\n**NEW**: Дозволяє налаштування версії Pillow, що використовується ESPHome Dashboard, схожим на ESPHome версія selector\n**NEW**: Додати кнопку \"Зареєструвати Autopy Cache\" у вкладці конфігурації ESPHome Dashboard для вирішення проблем завантаження панелі (#209)",
43
43
  "zh-cn": "改进读取\n修复394号,实际修复340号,356号\n** FIXED**:粉丝组件不工作#205\n**NEW**:允许定制ESPHome Dashboard使用的Pillow版本,类似于ESPHome版本选择器\n**NEW**:在ESPHome Dashboard配置标签中添加\"清除自动缓存\"按钮以解决仪表板加载问题(# 209)"
44
44
  },
45
- "0.7.0": {
46
- "en": "**NEW**: Add support for Lock entity type - Lock devices now properly display state and control options #353\n**NEW**: YAML file management interface in admin UI for upload/download/delete operations (#369)\nimprove dashboard testing\nimprove logging for #201\nupdate pillow\nfix readme link to lib\nfix connection status #311\nremove unneeded node-fetch dependency\nautomatic migration from versions prior to ESPHomeDashboardUrl introduction (pre v0.6.1)\n**FIXED**: Invalid jsonConfig schema - removed unsupported `doNotSave` property from table elements",
47
- "de": "**NEW**: Unterstützung für Lock-Entity-Typ hinzufügen - Lock-Geräte jetzt richtig anzeigen Zustand und Steueroptionen #353\n**NEW**: YAML-Dateiverwaltungsschnittstelle in admin UI für Upload/Download/Auslöschung (#369)\ndashboard testen\nverbesserung der protokollierung für #201\nupdate kissen\nreadme link zu lib reparieren\nfix-verbindungsstatus #311\nnicht benötigte knoten-fetch-abhängigkeit entfernen\nautomatische Migration von Versionen vor der Einführung von ESPHomeDashboardUrl (pre v0.6.1)\n**FIXED**: Invalid jsonConfig Schema - entfernte nicht unterstützte `doNotSave` Eigenschaft von Tabellenelementen",
48
- "ru": "**NEW**: Добавить поддержку типа объекта блокировки - устройства блокировки теперь должным образом отображают параметры состояния и управления #353\n**NEW**: интерфейс управления файлами YAML в интерфейсе администратора для операций загрузки/загрузки/удаления (#369)\nулучшить тестирование приборной панели\nулучшение регистрации для #201\nобновление подушки\nобсуждение readme link to lib\nстатус подключения #311\nустранение ненужной зависимости от узла\nавтоматическая миграция с версий до внедрения ESPHomeDashboardUrl (pre v0.6.1)\n** FIXED**: Недействительная схема jsonConfig - удалено неподдерживаемое свойство \"doNotSave\" из элементов таблицы",
49
- "pt": "**NOVO**: Adicionar suporte para o tipo de entidade Lock - Dispositivos Lock agora exibem corretamente as opções de estado e controle #353\n**NOVO**: Interface de gerenciamento de arquivos YAML na interface de administração UI para operações de upload/download/delete (#369)\nmelhorar o teste do painel\nmelhorar o registro para #201\natualizar almofada\ncorrigir o link readme para a lib\ncorrigir o estado da ligação # 311\nremover a dependência de busca de nó desnecessária\nmigração automática de versões anteriores à introdução ESPHomeDashboardUrl (pré v0.6.1)\n**FIXED**: Esquema inválido do jsonConfig - propriedade `doNotSave` não suportada",
50
- "nl": "**NEW**: Voeg ondersteuning toe voor het type Lock-entiteit - Vergrendel apparaten nu correct de status en controle opties #353\n**NIEUW**: YAML file management interface in admin UI voor upload/download/delete operaties (#369)\nverbeteren van dashboard testen\nverbeteren logging voor #201\nupdate kussen\nrepareren readme link naar lib\nfix verbindingsstatus #311\nverwijder ongewenste node-fetch afhankelijkheid\nautomatische migratie van versies voorafgaand aan ESPHomeDashboardUrl introductie (pre v0.6.1)\n** VAST**: Ongeldig jsonConfig schema - verwijderde niet-ondersteunde eigenschap van tabelelementen",
51
- "fr": "**NOUVEAU**: Ajout de la prise en charge du type d'entité de verrouillage - Verrouiller les appareils maintenant correctement afficher l'état et les options de contrôle #353\n**NOUVEAU**: Interface de gestion de fichiers YAML dans l'interface utilisateur admin pour les opérations de téléchargement/téléchargement/effacement (#369)\naméliorer les essais de tableau de bord\naméliorer l'enregistrement pour #201\nmettre à jour l'oreiller\ncorriger le lien readme vers lib\nfixer l'état de connexion #311\nsupprimer la dépendance inutile des nœuds\nmigration automatique des versions avant l'introduction de ESPHomeDashboardUrl (pre v0.6.1)\n**FIXED**: Schéma jsonConfig non valide - supprimé la propriété `doNotSave` non supportée des éléments de table",
52
- "it": "**NEW**: Aggiungi supporto per tipo di entità Lock - Dispositivi di blocco ora correttamente visualizzano le opzioni di stato e controllo #353\n**NEW**: interfaccia di gestione dei file YAML nell'interfaccia di amministrazione UI per operazioni di upload/download/delete (#369)\nmigliorare il test del cruscotto\nmigliorare logging per #201\naggiornamento cuscino\ncorrezione link di lettura per lib\nstato di connessione di correzione #311\nrimuovere la dipendenza da nodo-fetch non necessaria\nmigrazione automatica dalle versioni precedenti l'introduzione di ESPHomeDashboardUrl (pre v0.6.1)\n**FIXED**: Invalid jsonConfig schema - rimosso `doNotSave` immobili da elementi da tavolo",
53
- "es": "**NEW**: Añadir soporte para el tipo de entidad de bloqueo - Los dispositivos de bloqueo ahora muestran correctamente las opciones de estado y control #353\n**NEW**: Interfaz de gestión de archivos YAML en admin UI para operaciones de carga/descarga/delete (#369)\nmejorar las pruebas de dashboard\nmejorar el registro para #201\nactualización almohada\narreglar el vínculo readme con la lib\nestado de conexión de fijación #311\neliminar la dependencia sin necesidad\nmigración automática desde versiones anteriores a ESPHomeDashboardIntroducción del usuario (pre v0.6.1)\n**FIXED**: Invalid jsonConfig schema - eliminó propiedad no apoyada `doNotSave` de elementos de mesa",
54
- "pl": "* *NOWOŚĆ* *: Dodaj wsparcie dla typu podmiotu blokującego - Urządzenia blokujące teraz poprawnie wyświetlają stan i opcje sterowania # 353 \n* *NOWOŚĆ* *: Interfejs do zarządzania plikami YAML w UI administratora do wysyłania / pobierania / usuwania operacji (# 369) \npoprawić testowanie płyt rozdzielczych\npoprawić logowanie dla # 201\naktualizacji poduszki\nfix readme link do lib\nustaw status połączenia # 311\nusuń niepotrzebną zależność node-get\nautomatyczna migracja z wersji przed wprowadzeniem ESPHOmeDashboardUrl (pre v0.6.1)\n* *FIXED* *: Nieprawidłowy schemat jsonConfig - usunięte nieobsługiwane właściwości 'doNotSave' z elementów tabeli ",
55
- "uk": "**NEW**: Додати підтримку типу Lock - Lock devices тепер правильно відображати стан та параметри контролю #353\n**NEW**: Інтерфейс керування файлами YAML в адмін UI для завантаження / завантаження / видалення операцій (#369)\nполіпшити тестування панелі приладів\nпокращити залогів на #201\nоновлення подушки\nвиправити посилання для читання\nстатус на сервери\nвидалити невидиму залежність від вузла\nавтоматична міграція з версій до ESPHomeDashboardUrl введення (pre v0.6.1)\n**FIXED**: Invalid jsonConfig schema - вилучено непідтримуваний `doNotSave` майно з елементів таблиці",
56
- "zh-cn": "** NEW**: 添加对 Lock 实体类型的支持 - 锁定设备现在正确显示状态和控制选项 # 353\n**NEW**:用于上传/下载/删除操作的管理员UI中的YAML文件管理接口(# 369)\n改进仪表板测试\n改进201号记录\n更新枕头\n固定读取链接到 lib\n固定连接状态 # 311\n删除不需要的节点依赖\n从ESPHomeDashboardUrl引入前的版本自动迁移(pre v0.6.1)\n** FIXED**: 无效的jsonConfig schema - 从表格元素中删除未支持的“不拯救”属性"
57
- },
58
45
  "0.7.0-beta.1": {
59
46
  "en": "improve dashboard testing",
60
47
  "de": "dashboard testen",
@@ -0,0 +1,317 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * ESPHome Dashboard API client
5
+ * Inspired by https://github.com/esphome/dashboard-api
6
+ *
7
+ * Wraps all endpoints exposed by the ESPHome Dashboard HTTP/WebSocket API.
8
+ * The dashboard URL is taken from adapter settings (ESPHomeDashboardUrl).
9
+ *
10
+ * HTTP endpoints use the native fetch API (Node >= 18).
11
+ * WebSocket streaming endpoints (compile, upload) use the native WebSocket API on Node >= 22,
12
+ * or fall back to the `ws` npm package on Node 20 if it is installed.
13
+ */
14
+
15
+ /**
16
+ * Make an HTTP request to the ESPHome Dashboard and return the parsed JSON body.
17
+ *
18
+ * @param {string} method - HTTP method (e.g. 'GET', 'POST')
19
+ * @param {string} dashboardUrl - Base URL of the ESPHome Dashboard (e.g. http://192.168.1.100:6052)
20
+ * @param {string} path - API path (e.g. 'devices')
21
+ * @param {object} [params] - Optional query parameters
22
+ * @returns {Promise<object>} Parsed JSON response
23
+ */
24
+ async function request(method, dashboardUrl, path, params) {
25
+ const base = dashboardUrl.replace(/\/+$/, '');
26
+ const url = new URL(`${base}/${path}`);
27
+ if (params) {
28
+ for (const [key, value] of Object.entries(params)) {
29
+ url.searchParams.set(key, value);
30
+ }
31
+ }
32
+ const response = await fetch(url.toString(), { method });
33
+ if (!response.ok) {
34
+ const error = new Error(`Dashboard API ${method} /${path} failed: ${response.status} ${response.statusText}`);
35
+ // @ts-expect-error custom property not in Error type
36
+ error.status = response.status;
37
+ throw error;
38
+ }
39
+ return await response.json();
40
+ }
41
+
42
+ /**
43
+ * Stream output from a long-running ESPHome Dashboard command over a WebSocket.
44
+ *
45
+ * The dashboard sends JSON frames with an `event` field:
46
+ * - `{ event: 'line', data: '<text>' }` – a line of log output
47
+ * - `{ event: 'exit', code: <number> }` – the command finished
48
+ *
49
+ * Uses the native WebSocket API on Node >= 22, or falls back to the `ws` npm
50
+ * package on Node 20. If neither is available, an error is thrown.
51
+ *
52
+ * @param {string} dashboardUrl - Base URL of the ESPHome Dashboard
53
+ * @param {string} path - WebSocket endpoint path (e.g. 'compile', 'upload')
54
+ * @param {object} spawnParams - Parameters forwarded as `{ type: 'spawn', ...spawnParams }`
55
+ * @param {((line: string) => void) | null} [lineReceivedCb] - Optional callback invoked for each log line
56
+ * @returns {Promise<boolean>} Resolves to true when the command exits with code 0, false otherwise
57
+ */
58
+ async function streamLogs(dashboardUrl, path, spawnParams, lineReceivedCb) {
59
+ const wsUrl = `${dashboardUrl.replace(/\/+$/, '').replace(/^http/, 'ws')}/${path}`;
60
+
61
+ // Prefer native WebSocket (Node >= 22), but fall back to "ws" package on older Node versions
62
+ const hasNativeWebSocket = typeof WebSocket !== 'undefined';
63
+ let WebSocketImpl = hasNativeWebSocket ? WebSocket : null;
64
+
65
+ if (!WebSocketImpl) {
66
+ try {
67
+ WebSocketImpl = require('ws');
68
+ } catch {
69
+ throw new Error(
70
+ 'WebSocket streaming requires either Node.js >= 22 with native WebSocket support ' +
71
+ 'or the "ws" package installed. Please upgrade Node.js or install "ws" to use compile/upload functionality.',
72
+ );
73
+ }
74
+ }
75
+
76
+ return new Promise((resolve, reject) => {
77
+ let settled = false;
78
+ const ws = new WebSocketImpl(wsUrl);
79
+
80
+ const settle = fn => {
81
+ if (!settled) {
82
+ settled = true;
83
+ fn();
84
+ }
85
+ };
86
+
87
+ if (hasNativeWebSocket) {
88
+ // Native WebSocket (Node >= 22 / browser-like API)
89
+ ws.addEventListener('open', () => {
90
+ ws.send(JSON.stringify({ type: 'spawn', ...spawnParams }));
91
+ });
92
+
93
+ ws.addEventListener('message', event => {
94
+ let data;
95
+ try {
96
+ data = JSON.parse(event.data);
97
+ } catch (error) {
98
+ // Log at debug level to help diagnose malformed or unexpected messages
99
+ if (typeof console !== 'undefined' && typeof console.debug === 'function') {
100
+ console.debug(
101
+ `Failed to parse WebSocket message from /${path}:`,
102
+ error,
103
+ 'raw message:',
104
+ event.data,
105
+ );
106
+ }
107
+ return;
108
+ }
109
+
110
+ const wsEvent = data.event;
111
+
112
+ if (wsEvent === 'exit') {
113
+ ws.close();
114
+ settle(() => resolve(data.code === 0));
115
+ return;
116
+ }
117
+
118
+ if (wsEvent === 'line') {
119
+ if (lineReceivedCb) {
120
+ lineReceivedCb(data.data);
121
+ }
122
+ }
123
+ });
124
+
125
+ ws.addEventListener('error', err => {
126
+ const message =
127
+ err && typeof err === 'object' && typeof err.message === 'string' ? err.message : String(err);
128
+ settle(() => reject(new Error(`WebSocket error on /${path}: ${message}`)));
129
+ });
130
+
131
+ ws.addEventListener('close', event => {
132
+ if (!event.wasClean) {
133
+ settle(() => reject(new Error(`WebSocket closed unexpectedly on /${path}: code ${event.code}`)));
134
+ }
135
+ });
136
+ } else {
137
+ // "ws" package (Node >= 20 without native WebSocket)
138
+ ws.on('open', () => {
139
+ ws.send(JSON.stringify({ type: 'spawn', ...spawnParams }));
140
+ });
141
+
142
+ ws.on('message', message => {
143
+ let data;
144
+ try {
145
+ data = JSON.parse(message);
146
+ } catch (error) {
147
+ // Log at debug level to help diagnose malformed or unexpected messages
148
+ if (typeof console !== 'undefined' && typeof console.debug === 'function') {
149
+ console.debug(
150
+ `Failed to parse WebSocket message from /${path}:`,
151
+ error,
152
+ 'raw message:',
153
+ message,
154
+ );
155
+ }
156
+ return;
157
+ }
158
+
159
+ const wsEvent = data.event;
160
+
161
+ if (wsEvent === 'exit') {
162
+ ws.close();
163
+ settle(() => resolve(data.code === 0));
164
+ return;
165
+ }
166
+
167
+ if (wsEvent === 'line') {
168
+ if (lineReceivedCb) {
169
+ lineReceivedCb(data.data);
170
+ }
171
+ }
172
+ });
173
+
174
+ ws.on('error', err => {
175
+ const message = err && err.message ? err.message : String(err);
176
+ settle(() => reject(new Error(`WebSocket error on /${path}: ${message}`)));
177
+ });
178
+
179
+ ws.on('close', (code, reason) => {
180
+ // "ws" does not provide wasClean flag by default; treat non-normal close as unexpected
181
+ if (code !== 1000) {
182
+ settle(() =>
183
+ reject(
184
+ new Error(
185
+ `WebSocket closed unexpectedly on /${path}: code ${code}${
186
+ reason ? `, reason: ${reason.toString()}` : ''
187
+ }`,
188
+ ),
189
+ ),
190
+ );
191
+ }
192
+ });
193
+ }
194
+ });
195
+ }
196
+
197
+ /**
198
+ * Fetch all configured and importable devices from the ESPHome Dashboard.
199
+ *
200
+ * Response shape:
201
+ * ```
202
+ * {
203
+ * configured: [{
204
+ * address: string, // IP / hostname used for communication
205
+ * comment: string | null,
206
+ * configuration: string, // YAML filename (used for other API calls)
207
+ * current_version: string,
208
+ * deployed_version: string,
209
+ * loaded_integrations: string[],
210
+ * name: string,
211
+ * path: string,
212
+ * target_platform: string,
213
+ * web_port: string | null,
214
+ * }],
215
+ * importable: [{
216
+ * name: string,
217
+ * network: string,
218
+ * package_import_url: string,
219
+ * project_name: string,
220
+ * project_version: string,
221
+ * }]
222
+ * }
223
+ * ```
224
+ *
225
+ * @param {string} dashboardUrl - Base URL of the ESPHome Dashboard
226
+ * @returns {Promise<{configured: Array<object>, importable: Array<object>}>} Devices list
227
+ */
228
+ async function getDevices(dashboardUrl) {
229
+ return request('GET', dashboardUrl, 'devices');
230
+ }
231
+
232
+ /**
233
+ * Fetch the JSON representation of a device configuration from the ESPHome Dashboard.
234
+ *
235
+ * @param {string} dashboardUrl - Base URL of the ESPHome Dashboard
236
+ * @param {string} configuration - Configuration filename (e.g. my-device.yaml)
237
+ * @returns {Promise<object|null>} Parsed configuration object, or null when not found (404)
238
+ */
239
+ async function getConfig(dashboardUrl, configuration) {
240
+ try {
241
+ return await request('GET', dashboardUrl, 'json-config', { configuration });
242
+ } catch (error) {
243
+ // @ts-expect-error custom property not in Error type
244
+ if (error.status === 404) {
245
+ return null;
246
+ }
247
+ throw error;
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Extract the native API encryption key for a device configuration.
253
+ *
254
+ * Returns null when:
255
+ * - the configuration file does not exist
256
+ * - the YAML has no `api:` section
257
+ * - the `api:` section has no `encryption:` block
258
+ *
259
+ * @param {string} dashboardUrl - Base URL of the ESPHome Dashboard
260
+ * @param {string} configuration - Configuration filename (e.g. my-device.yaml)
261
+ * @returns {Promise<string|null>} Base64-encoded encryption key, or null
262
+ */
263
+ async function getEncryptionKey(dashboardUrl, configuration) {
264
+ const config = await getConfig(dashboardUrl, configuration);
265
+ if (!config) {
266
+ return null;
267
+ }
268
+ // An empty `api:` section in YAML becomes null in JSON
269
+ const api = config.api;
270
+ if (!api) {
271
+ return null;
272
+ }
273
+ const encryption = api.encryption;
274
+ if (!encryption) {
275
+ return null;
276
+ }
277
+ return encryption.key || null;
278
+ }
279
+
280
+ /**
281
+ * Compile the firmware for a device configuration.
282
+ *
283
+ * Uses the native WebSocket API (Node >= 22) or falls back to the `ws` npm package (Node 20).
284
+ *
285
+ * @param {string} dashboardUrl - Base URL of the ESPHome Dashboard
286
+ * @param {string} configuration - Configuration filename (e.g. my-device.yaml)
287
+ * @param {((line: string) => void) | null} [lineReceivedCb] - Optional callback invoked for each log line
288
+ * @returns {Promise<boolean>} Resolves to true on success, false on failure
289
+ */
290
+ async function compile(dashboardUrl, configuration, lineReceivedCb) {
291
+ return streamLogs(dashboardUrl, 'compile', { configuration }, lineReceivedCb);
292
+ }
293
+
294
+ /**
295
+ * Upload (flash) firmware to a device.
296
+ *
297
+ * Uses the native WebSocket API (Node >= 22) or falls back to the `ws` npm package (Node 20).
298
+ *
299
+ * @param {string} dashboardUrl - Base URL of the ESPHome Dashboard
300
+ * @param {string} configuration - Configuration filename (e.g. my-device.yaml)
301
+ * @param {string} port - Serial port or OTA target (e.g. '/dev/ttyUSB0' or device IP)
302
+ * @param {((line: string) => void) | null} [lineReceivedCb] - Optional callback invoked for each log line
303
+ * @returns {Promise<boolean>} Resolves to true on success, false on failure
304
+ */
305
+ async function upload(dashboardUrl, configuration, port, lineReceivedCb) {
306
+ return streamLogs(dashboardUrl, 'upload', { configuration, port }, lineReceivedCb);
307
+ }
308
+
309
+ module.exports = {
310
+ request,
311
+ streamLogs,
312
+ getDevices,
313
+ getConfig,
314
+ getEncryptionKey,
315
+ compile,
316
+ upload,
317
+ };
package/lib/stateAttr.js CHANGED
@@ -89,6 +89,13 @@ const stateAttrb = {
89
89
  write: true,
90
90
  role: 'switch',
91
91
  },
92
+ rgbAutoWhite: {
93
+ name: 'Auto white channel',
94
+ type: 'boolean',
95
+ read: true,
96
+ write: true,
97
+ role: 'switch',
98
+ },
92
99
  };
93
100
 
94
101
  module.exports = stateAttrb;
@@ -6,9 +6,9 @@
6
6
  * @module yamlFileManager
7
7
  */
8
8
 
9
- const fs = require('fs');
10
- const path = require('path');
11
- const { promisify } = require('util');
9
+ const fs = require('node:fs');
10
+ const path = require('node:path');
11
+ const { promisify } = require('node:util');
12
12
 
13
13
  const readdir = promisify(fs.readdir);
14
14
  const stat = promisify(fs.stat);
package/main.js CHANGED
@@ -14,10 +14,10 @@ const { Client, Discovery } = require('@2colors/esphome-native-api');
14
14
  const stateAttr = require(`${__dirname}/lib/stateAttr.js`); // Load attribute library
15
15
  const disableSentry = false; // Ensure to set to true during development!
16
16
  const warnMessages = {}; // Store warn messages to avoid multiple sending to sentry
17
- const fs = require('fs');
18
- const path = require('path');
19
- const os = require('os');
20
- const { clearTimeout } = require('timers');
17
+ const fs = require('node:fs');
18
+ const path = require('node:path');
19
+ const os = require('node:os');
20
+ const { clearTimeout } = require('node:timers');
21
21
  const resetTimers = {}; // Memory allocation for all running timers
22
22
  let autodiscovery, dashboardProcess, createConfigStates, discovery;
23
23
  const clientDetails = {}; // Memory cache of all devices and their connection status
@@ -252,17 +252,19 @@ class Esphome extends utils.Adapter {
252
252
  pillowVersions.push(...versions);
253
253
 
254
254
  // Determine Pillow version to use
255
- let usePillowVersion = '11.3.0'; // Default version
255
+ let usePillowVersion = '';
256
256
 
257
- // Check if user has configured a specific pillow version
257
+ // Use configured version unless "Always last available" is selected
258
258
  if (
259
259
  this.config.PillowVersion &&
260
260
  this.config.PillowVersion !== '' &&
261
261
  this.config.PillowVersion !== 'Always last available'
262
262
  ) {
263
263
  usePillowVersion = this.config.PillowVersion;
264
+ } else if (this.config.PillowVersion === 'Always last available' && versions.length > 0) {
265
+ // Mirror dashboard behavior: pick newest fetched/cached release
266
+ usePillowVersion = versions[0];
264
267
  }
265
- // If "Always last available" is selected, keep the default latest version
266
268
 
267
269
  this.log.debug(`Using Pillow version: ${usePillowVersion}`);
268
270
 
@@ -1164,6 +1166,38 @@ class Esphome extends utils.Adapter {
1164
1166
  clientDetails[host][entity.id].states.transitionLength = 0;
1165
1167
  }
1166
1168
  }
1169
+
1170
+ // Create rgbAutoWhite state only once for lights with a dedicated white channel
1171
+ if (stateName === 'white' && clientDetails[host][entity.id].rgbAutoWhite === undefined) {
1172
+ let rgbAutoWhiteVal = false;
1173
+ try {
1174
+ const existing = await this.getStateAsync(
1175
+ `${clientDetails[host].deviceName}.${entity.type}.${entity.id}.config.rgbAutoWhite`,
1176
+ );
1177
+ if (existing != null) {
1178
+ rgbAutoWhiteVal = !!existing.val;
1179
+ }
1180
+ } catch (e) {
1181
+ this.log.debug(`[handleStateArrays] Could not read rgbAutoWhite state: ${e}`);
1182
+ }
1183
+ clientDetails[host][entity.id].rgbAutoWhite = rgbAutoWhiteVal;
1184
+ // Ensure config channel exists before creating the state inside it
1185
+ await this.extendObjectAsync(
1186
+ `${clientDetails[host].deviceName}.${entity.type}.${entity.id}.config`,
1187
+ {
1188
+ type: 'channel',
1189
+ common: { name: 'Configuration data' },
1190
+ native: {},
1191
+ },
1192
+ );
1193
+ await this.stateSetCreate(
1194
+ `${clientDetails[host].deviceName}.${entity.type}.${entity.id}.config.rgbAutoWhite`,
1195
+ 'rgbAutoWhite',
1196
+ rgbAutoWhiteVal,
1197
+ '',
1198
+ true,
1199
+ );
1200
+ }
1167
1201
  }
1168
1202
 
1169
1203
  if (stateName !== 'key') {
@@ -2199,6 +2233,12 @@ class Esphome extends utils.Adapter {
2199
2233
  clientDetails[deviceIP][device[4]].states.effect = writeValue;
2200
2234
  } else if (device[5] === 'state') {
2201
2235
  clientDetails[deviceIP][device[4]].states.state = writeValue;
2236
+ } else if (device[5] === 'config' && device[6] === 'rgbAutoWhite') {
2237
+ // Store device-specific preference; no light command needed
2238
+ clientDetails[deviceIP][device[4]].rgbAutoWhite = writeValue;
2239
+ // Acknowledge the preference update so the state does not stay with ack=false
2240
+ this.setState(id, !!writeValue, true);
2241
+ return;
2202
2242
  }
2203
2243
 
2204
2244
  const data = {
@@ -2222,6 +2262,21 @@ class Esphome extends utils.Adapter {
2222
2262
  colorModesList.some(m => [4, 8].includes(m));
2223
2263
  const supportsColdWarmWhite = colorModesList.some(m => [5, 9].includes(m));
2224
2264
 
2265
+ // Auto white channel: when colorHEX is set to white (#ffffff) on RGBW lights,
2266
+ // automatically switch to white channel; otherwise switch to RGB mode
2267
+ if (clientDetails[deviceIP][device[4]].rgbAutoWhite && supportsWhite && device[5] === 'colorHEX') {
2268
+ if (writeValue.replace(/^#/, '').toLowerCase() === 'ffffff') {
2269
+ // White color detected: redirect to dedicated white channel
2270
+ clientDetails[deviceIP][device[4]].states.red = 0;
2271
+ clientDetails[deviceIP][device[4]].states.green = 0;
2272
+ clientDetails[deviceIP][device[4]].states.blue = 0;
2273
+ clientDetails[deviceIP][device[4]].states.white = 1;
2274
+ } else {
2275
+ // Non-white color: disable white channel
2276
+ clientDetails[deviceIP][device[4]].states.white = 0;
2277
+ }
2278
+ }
2279
+
2225
2280
  if (supportsBrightness) {
2226
2281
  data.brightness = clientDetails[deviceIP][device[4]].states.brightness;
2227
2282
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.esphome",
3
- "version": "0.7.0-beta.4",
3
+ "version": "0.7.0",
4
4
  "description": "Control your ESP8266/ESP32 with simple yet powerful configuration files created and managed by ESPHome",
5
5
  "author": {
6
6
  "name": "DutchmanNL",
@@ -30,20 +30,20 @@
30
30
  "node": ">= 20"
31
31
  },
32
32
  "dependencies": {
33
- "@2colors/esphome-native-api": "^1.3.5",
33
+ "@2colors/esphome-native-api": "^1.3.6",
34
34
  "@iobroker/adapter-core": "^3.3.2",
35
35
  "autopy": "github:SimonFischer04/autopy#fbe016f35e13e335e1c44783a1e7273bbb2a08c1"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@alcalzone/release-script": "^5.0.0",
39
- "@alcalzone/release-script-plugin-iobroker": "^4.0.0",
40
- "@alcalzone/release-script-plugin-license": "^4.0.0",
41
- "@alcalzone/release-script-plugin-manual-review": "^4.0.0",
39
+ "@alcalzone/release-script-plugin-iobroker": "^5.1.2",
40
+ "@alcalzone/release-script-plugin-license": "^5.1.1",
41
+ "@alcalzone/release-script-plugin-manual-review": "^5.1.1",
42
42
  "@iobroker/adapter-dev": "^1.5.0",
43
43
  "@iobroker/dev-server": "^0.8.0",
44
44
  "@iobroker/eslint-config": "^2.2.0",
45
45
  "@iobroker/testing": "^5.2.2",
46
- "@types/node": "^25.0.3",
46
+ "@types/node": "^25.6.0",
47
47
  "eslint": "^9.39.2",
48
48
  "promisify": "~0.0.3",
49
49
  "typescript": "~5.9.3"