iobroker.lovelace 5.0.1 → 5.0.3
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 +9 -6
- package/io-package.json +27 -27
- package/lib/converters/light.js +20 -10
- package/lib/server.js +34 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -473,6 +473,15 @@ After that checkout modified version in `./build` folder. Then.
|
|
|
473
473
|
PLACEHOLDER for the next version:
|
|
474
474
|
### **WORK IN PROGRESS**
|
|
475
475
|
-->
|
|
476
|
+
### 5.0.3 (2025-10-10)
|
|
477
|
+
* (Garfonso) make sure only existing themes are selectable in control.theme states.
|
|
478
|
+
* (Garfonso) bring back support for frontend_es5.
|
|
479
|
+
|
|
480
|
+
### 5.0.2 (2025-10-02)
|
|
481
|
+
* (Garfonso) some light entities did not restore their proper state on switch on. Fixed.
|
|
482
|
+
* (Garfonso) process folders-Objects for auto entities, too. (pirate-weather support)
|
|
483
|
+
* (Garfonso) prepare support for effects in light entities (will need new type-detector version).
|
|
484
|
+
|
|
476
485
|
### 5.0.1 (2025-09-09)
|
|
477
486
|
* (Garfonso) settings from entity registry are now loaded on startup
|
|
478
487
|
* (Garfonso) logbook: prevent entries from the future
|
|
@@ -495,12 +504,6 @@ After that checkout modified version in `./build` folder. Then.
|
|
|
495
504
|
### 4.1.15 (2025-03-10)
|
|
496
505
|
* (Garfonso) repaired image loading, again.
|
|
497
506
|
|
|
498
|
-
### 4.1.14 (2025-03-10)
|
|
499
|
-
* (Garfonso) repaired image loading. Fixes #577
|
|
500
|
-
|
|
501
|
-
### 4.1.13 (2025-03-06)
|
|
502
|
-
* (Garfonso) reworked image sending. Now weather icons work for normal users, too. Also, weather images are transferred from our server, so no access to admin is needed anymore.
|
|
503
|
-
|
|
504
507
|
## License
|
|
505
508
|
|
|
506
509
|
Copyright 2019-2025, bluefox <dogafox@gmail.com>
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "lovelace",
|
|
4
|
-
"version": "5.0.
|
|
4
|
+
"version": "5.0.3",
|
|
5
5
|
"news": {
|
|
6
|
+
"5.0.3": {
|
|
7
|
+
"en": "make sure only existing themes are selectable in control.theme states.\nbring back support for frontend_es5.",
|
|
8
|
+
"de": "sicher stellen, dass nur vorhandene themen in der steuerung über states wählbar sind.\nunterstützung für frontend_es5 wiederhergestellt.",
|
|
9
|
+
"ru": "убедитесь, что только существующие темы поддаются выбору. темы государств.\nподдержка интерфейса frontend_es5.",
|
|
10
|
+
"pt": "certifique-se de que apenas os temas existentes são selecionáveis no controle. estados temáticos.\ntrazer suporte para frontend_es5.",
|
|
11
|
+
"nl": "zorg ervoor dat alleen bestaande thema's zijn geselecteerd in controle. thema staat.\nondersteuning voor frontend_es5 terugbrengen.",
|
|
12
|
+
"fr": "assurez-vous que seuls les thèmes existants peuvent être sélectionnés dans le contrôle. les états thématiques.\nramener le support de frontend_es5.",
|
|
13
|
+
"it": "assicurarsi che solo i temi esistenti siano selezionabili in controllo. stati tematici.\nriportare il supporto per frontend_es5.",
|
|
14
|
+
"es": "asegúrese de que sólo los temas existentes son seleccionables en control. estados temáticos.\ntraer apoyo para frontend_es5.",
|
|
15
|
+
"pl": "upewnij się, że tylko istniejące motywy są wybierane pod kontrolą. stan tematyczny.\nprzywrócić wsparcie dla frontend _ es5.",
|
|
16
|
+
"uk": "переконайтеся, що тільки існуючі теми вибираються в управлінні. тематичні стани.\nповернути підтримку фронтенд_es5.",
|
|
17
|
+
"zh-cn": "确保控制中只选择现有主题。 主题状态.\n带回对前端_es5的支持."
|
|
18
|
+
},
|
|
19
|
+
"5.0.2": {
|
|
20
|
+
"en": "some light entities did not restore their proper state on switch on. Fixed.\nprocess folders-Objects for auto entities, too. (pirate-weather support)\nprepare support for effects in light entities (will need new type-detector version).",
|
|
21
|
+
"de": "einige Licht entities haben ihren Zustand beim Einschalten nicht wiederhergestellt. Behoben.\nOrdner-Objekte auch für Auto-Entitäten bearbeiten. (Pirate-Wetter-Unterstützung)\ndie unterstützung von effekten in Licht entities vorbereitet (benötigt neue typ-detektor-version).",
|
|
22
|
+
"ru": "некоторые легкие сущности не восстановили свое надлежащее состояние при включении. Исправлено.\nтакже обрабатывают папки-объекты для автообъектов. (поддержка пиратской погоды)\nподготовить поддержку эффектов в легких объектах (требуется новая версия детектора типа).",
|
|
23
|
+
"pt": "algumas entidades de luz não restauraram seu estado adequado no interruptor ligado. Consertado.\npastas de processo-Objects para entidades auto, também. (suporte de pirate-weather)\npreparar suporte para efeitos em entidades leves (necessitará de uma nova versão do detector de tipo).",
|
|
24
|
+
"nl": "sommige lichte entiteiten hebben hun juiste staat bij het inschakelen niet hersteld. Vast.\nproces mappen-objecten voor auto-entiteiten, ook. (Pirate-weather support)\nvoorbereiding van ondersteuning voor effecten in lichte entiteiten (zal nieuwe type-detector versie nodig hebben).",
|
|
25
|
+
"fr": "certaines entités lumineuses n'ont pas rétabli leur état d'activation. Corrigé.\ntraiter les dossiers-Objects pour les entités auto, aussi. (soutien en temps de pluie)\npréparer le support des effets dans les entités lumineuses (il faudra une nouvelle version de détecteur de type).",
|
|
26
|
+
"it": "alcune entità leggere non hanno ripristinato il loro stato corretto all'accensione. Risolto.\nprocess folders-Objects per entità auto, troppo. (Supporto pirata-matrimoniale)\npreparare il supporto per gli effetti in entità leggere (sarà necessario una nuova versione di tipo-detector).",
|
|
27
|
+
"es": "algunas entidades de luz no restauraron su estado adecuado encendido encendido encendido. Arreglado.\ncarpetas de proceso-Objetos para entidades de automóviles, también. (Apoyo de piratería-tetera)\npreparar soporte para efectos en entidades ligeras (necesitará nueva versión tipo-detector).",
|
|
28
|
+
"pl": "niektóre jednostki świetlne nie przywróciły swojego stanu włączania. Naprawione.\nfoldery procesu- Obiekty dla podmiotów samochodowych, też. (wsparcie pirackiej pogody)\nprzygotować wsparcie dla efektów w jednostkach świetlnych (potrzeba nowej wersji czujnika typu).",
|
|
29
|
+
"uk": "деякі світлові особи не відновили належний стан на перемикачі. Фіксований.\nобробляє папки-об'єкти для автооб'єктів. (приватно-пожежна підтримка)\nпідготувати підтримку ефектів у легких суб’єктах (необхідно потрібна нова версія-детектора).",
|
|
30
|
+
"zh-cn": "一些轻实体没有在开关时恢复正常状态。 固定着.\n用于自动实体的处理文件夹-对象。 (发作天气支持)\n为光实体中的效果准备支持(需要新的类型检测器版本)."
|
|
31
|
+
},
|
|
6
32
|
"5.0.1": {
|
|
7
33
|
"en": "* (Garfonso) settings from entity registry are now loaded on startup\n* (Garfonso) logbook: prevent entries from the future\n* (Garfonso) icons should now work as before, again.\n* (Garfonso) script entities now can be used again.\n* (Garfonso) subscribe to all object ids in a template.\n* (Garfonso) Update dependencies.",
|
|
8
34
|
"de": "* (Garfonso) Einstellungen aus der Entitätsregistrierung werden nun beim Start geladen\n* (Garfonso) Logbuch: Einträge aus der Zukunft verhindern\n* (Garfonso) Icons sollten nun wieder wie zuvor funktionieren.\n* (Garfonso) Skriptentitäten können nun wieder verwendet werden.\n* (Garfonso) alle Objekt-IDs in einer Vorlage abonnieren.\n* (Garfonso) Aktualisieren von Abhängigkeiten.",
|
|
@@ -67,32 +93,6 @@
|
|
|
67
93
|
"pl": "przerabiane wysyłanie obrazów. Teraz ikony pogodowe działają również dla zwykłych użytkowników. Również obrazy pogody są transfered z naszego serwera, więc nie jest już potrzebny dostęp do admin.",
|
|
68
94
|
"uk": "переробляти посилку зображення. Ікони погоди працюють для нормальних користувачів. Крім того, погодні зображення передаються з нашого сервера, тому не потрібно доступу до адміну.",
|
|
69
95
|
"zh-cn": "重新工作图像发送 。 现在天气图标也为正常用户服务. 还有天气图像是从我们的服务器传输的,所以不再需要访问管理员了."
|
|
70
|
-
},
|
|
71
|
-
"4.1.11": {
|
|
72
|
-
"en": "convert string state values to numbers, where necessary.",
|
|
73
|
-
"de": "string-zustandswerte gegebenenfalls in zahlen umwandeln.",
|
|
74
|
-
"ru": "конвертировать значения состояния строки в числа, когда это необходимо.",
|
|
75
|
-
"pt": "converter valores de estado de cadeia para números, quando necessário.",
|
|
76
|
-
"nl": "converteer string state waarden naar getallen, waar nodig.",
|
|
77
|
-
"fr": "convertir les valeurs d'état de chaîne en nombres, si nécessaire.",
|
|
78
|
-
"it": "convertire i valori di stato della stringa in numeri, ove necessario.",
|
|
79
|
-
"es": "convertir valores de estado de cadena a números, cuando sea necesario.",
|
|
80
|
-
"pl": "w razie potrzeby przekonwertować wartości stanu string do liczb.",
|
|
81
|
-
"uk": "перетворюйте значення стану рядків до чисел, де необхідно.",
|
|
82
|
-
"zh-cn": "必要时将字符串状态值转换为数字."
|
|
83
|
-
},
|
|
84
|
-
"4.1.10": {
|
|
85
|
-
"en": "device icons work again (if authorization is required).\ndefault user sometimes was not found in system.",
|
|
86
|
-
"de": "gerätesymbole funktionieren wieder (wenn authorisierung notwendig).\nder eingestellte standard-benutzer wurde manchmal nicht im system gefunden.",
|
|
87
|
-
"ru": "иконки устройства снова работают.\nпользователь по умолчанию иногда не был найден в системе.",
|
|
88
|
-
"pt": "ícones do dispositivo funcionam novamente.\nusuário padrão às vezes não foi encontrado no sistema.",
|
|
89
|
-
"nl": "apparaatpictogrammen werken opnieuw.\nde standaardgebruiker werd soms niet gevonden in het systeem.",
|
|
90
|
-
"fr": "les icônes du périphérique fonctionnent à nouveau.\nl'utilisateur par défaut n'a parfois pas été trouvé dans le système.",
|
|
91
|
-
"it": "le icone del dispositivo funzionano di nuovo.\nutente predefinito a volte non è stato trovato nel sistema.",
|
|
92
|
-
"es": "los iconos del dispositivo funcionan de nuevo.\nusuario predeterminado a veces no se encontró en el sistema.",
|
|
93
|
-
"pl": "ikony urządzenia działają ponownie.\ndomyślny użytkownik czasami nie został znaleziony w systemie.",
|
|
94
|
-
"uk": "знову працюють іконки пристрою.\nне знайдено типовий користувач.",
|
|
95
|
-
"zh-cn": "设备图标再次工作.\n默认用户有时在系统中找不到 ."
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
package/lib/converters/light.js
CHANGED
|
@@ -80,7 +80,7 @@ function clearOrRestoreAttributes(entity) {
|
|
|
80
80
|
entity.attributes[attr] = entity.context.STATE.storedValues[attr];
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
-
//adapterData.log.debug(`
|
|
83
|
+
//adapterData.log.debug(`Restored old values from previous switch off: ${JSON.stringify(entity.attributes)}`);
|
|
84
84
|
} else {
|
|
85
85
|
for (const attr of attributesToNullOnOff) {
|
|
86
86
|
if (entity.attributes[attr] !== undefined) {
|
|
@@ -88,7 +88,9 @@ function clearOrRestoreAttributes(entity) {
|
|
|
88
88
|
entity.attributes[attr] = null;
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
-
|
|
91
|
+
/*adapterData.log.debug(
|
|
92
|
+
`Stored old values for next switch on: ${JSON.stringify(entity.context.STATE.storedValues)}`,
|
|
93
|
+
);*/
|
|
92
94
|
}
|
|
93
95
|
}
|
|
94
96
|
|
|
@@ -108,8 +110,11 @@ function _lightAdvancedAddState(states, objects, entity) {
|
|
|
108
110
|
if (!state) {
|
|
109
111
|
state = { val: null };
|
|
110
112
|
}
|
|
113
|
+
const oldState = entity.state;
|
|
111
114
|
entity.state = state.val ? 'on' : 'off';
|
|
112
|
-
|
|
115
|
+
if (oldState !== entity.state) {
|
|
116
|
+
clearOrRestoreAttributes(entity);
|
|
117
|
+
}
|
|
113
118
|
};
|
|
114
119
|
|
|
115
120
|
//prevent zigbee 'available' to become getId:
|
|
@@ -248,8 +253,11 @@ function _lightAdvancedAddBrightness(states, objects, entity) {
|
|
|
248
253
|
}
|
|
249
254
|
|
|
250
255
|
if (states.state === states.brightness) {
|
|
256
|
+
const oldState = entity.state;
|
|
251
257
|
entity.state = targetAttributes.brightness > 0 ? 'on' : 'off';
|
|
252
|
-
|
|
258
|
+
if (oldState !== entity.state) {
|
|
259
|
+
clearOrRestoreAttributes(entity);
|
|
260
|
+
}
|
|
253
261
|
|
|
254
262
|
if (entity.attributes.color_mode === ONOFF) {
|
|
255
263
|
entity.attributes.color_mode = BRIGHTNESS;
|
|
@@ -490,9 +498,6 @@ async function _setLightAdvancedAttributesToIOBStates(data, entity, user) {
|
|
|
490
498
|
if (data.service_data.brightness_pct >= 0) {
|
|
491
499
|
const attr = entity.context.ATTRIBUTES.find(a => a.attribute === 'brightness');
|
|
492
500
|
entity.attributes.brightness = (data.service_data.brightness_pct / 100) * 255;
|
|
493
|
-
if (!entity.context.STATE.isBoolean) {
|
|
494
|
-
entity.state = data.service_data.brightness_pct > 0 ? 'on' : 'off';
|
|
495
|
-
}
|
|
496
501
|
if (!entity.attributes.color_mode || entity.attributes.color_mode === ONOFF) {
|
|
497
502
|
entity.attributes.color_mode = BRIGHTNESS;
|
|
498
503
|
}
|
|
@@ -631,6 +636,7 @@ function convertControlToStates(control) {
|
|
|
631
636
|
if (!states.brightness) {
|
|
632
637
|
states.brightness = findState('BRIGHTNESS');
|
|
633
638
|
}
|
|
639
|
+
states.effect = findState('EFFECT');
|
|
634
640
|
break;
|
|
635
641
|
case Types.dimmer:
|
|
636
642
|
states.state = findState('ON_SET');
|
|
@@ -643,10 +649,12 @@ function convertControlToStates(control) {
|
|
|
643
649
|
}
|
|
644
650
|
states.brightness = findState('SET');
|
|
645
651
|
states.brightnessRead = findState('ACTUAL');
|
|
652
|
+
states.effect = findState('EFFECT');
|
|
646
653
|
break;
|
|
647
654
|
case Types.light:
|
|
648
655
|
states.state = findState('SET');
|
|
649
656
|
states.stateRead = findState('ACTUAL');
|
|
657
|
+
states.effect = findState('EFFECT');
|
|
650
658
|
break;
|
|
651
659
|
}
|
|
652
660
|
states.color_temp = findState('TEMPERATURE');
|
|
@@ -733,9 +741,7 @@ async function fillLightEntityFromStates(states, objects, entity) {
|
|
|
733
741
|
|
|
734
742
|
if (states.effect) {
|
|
735
743
|
const effect_attr = entity.context.ATTRIBUTES.find(a => a.attributes === 'effect');
|
|
736
|
-
effect_attr.states =
|
|
737
|
-
objects[effect_attr.getId].common &&
|
|
738
|
-
objects[effect_attr.getId].common.states) || { 0: 'Please', 1: 'Fill', 2: 'States' };
|
|
744
|
+
effect_attr.states = objects[effect_attr.getId]?.common?.states || { 0: 'Please', 1: 'Fill', 2: 'States' };
|
|
739
745
|
entity.attributes.effect_list = Object.values(effect_attr.states);
|
|
740
746
|
effect_attr.getParser = (entity, attr, state) => {
|
|
741
747
|
state = state || { val: 0 };
|
|
@@ -767,10 +773,14 @@ async function fillLightEntityFromStates(states, objects, entity) {
|
|
|
767
773
|
});
|
|
768
774
|
entity.context.STATE.getParser = function (entity, attr, state) {
|
|
769
775
|
state = state || { val: null };
|
|
776
|
+
const oldState = entity.state;
|
|
770
777
|
entity.state = state.val > ((stateObj && stateObj.common && stateObj.common.min) || 0) ? 'on' : 'off';
|
|
771
778
|
if (!entity.attributes.color_mode) {
|
|
772
779
|
entity.attributes.color_mode = ONOFF;
|
|
773
780
|
}
|
|
781
|
+
if (oldState !== entity.state) {
|
|
782
|
+
clearOrRestoreAttributes(entity);
|
|
783
|
+
}
|
|
774
784
|
};
|
|
775
785
|
}
|
|
776
786
|
|
package/lib/server.js
CHANGED
|
@@ -1377,6 +1377,7 @@ class WebServer {
|
|
|
1377
1377
|
const _states = await this.adapter.getObjectViewAsync('system', 'state', params);
|
|
1378
1378
|
const _channels = await this.adapter.getObjectViewAsync('system', 'channel', params);
|
|
1379
1379
|
const _devices = await this.adapter.getObjectViewAsync('system', 'device', params);
|
|
1380
|
+
const _folders = await this.adapter.getObjectViewAsync('system', 'folder', {});
|
|
1380
1381
|
const _enums = await this.adapter.getObjectViewAsync('system', 'enum', {});
|
|
1381
1382
|
if (_devices && _devices.rows) {
|
|
1382
1383
|
for (let i = 0; i < _devices.rows.length; i++) {
|
|
@@ -1411,6 +1412,17 @@ class WebServer {
|
|
|
1411
1412
|
}
|
|
1412
1413
|
}
|
|
1413
1414
|
}
|
|
1415
|
+
if (_folders && _folders.rows) {
|
|
1416
|
+
for (let i = 0; i < _folders.rows.length; i++) {
|
|
1417
|
+
if (
|
|
1418
|
+
_folders.rows[i].value &&
|
|
1419
|
+
_folders.rows[i].value._id &&
|
|
1420
|
+
!ignoreIds.find(reg => reg.test(_folders.rows[i].value._id))
|
|
1421
|
+
) {
|
|
1422
|
+
objects[_folders.rows[i].value._id] = _folders.rows[i].value;
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1414
1426
|
if (_enums && _enums.rows) {
|
|
1415
1427
|
for (let i = 0; i < _enums.rows.length; i++) {
|
|
1416
1428
|
if (_enums.rows[i].value && _enums.rows[i].value._id) {
|
|
@@ -1932,8 +1944,20 @@ class WebServer {
|
|
|
1932
1944
|
for (const themeName of Object.keys(this._themes)) {
|
|
1933
1945
|
states[themeName] = themeName;
|
|
1934
1946
|
}
|
|
1935
|
-
await this.adapter.
|
|
1936
|
-
|
|
1947
|
+
const themeState = await this.adapter.getObjectAsync(`${this.adapter.namespace}.control.theme`);
|
|
1948
|
+
if (themeState && themeState.common) {
|
|
1949
|
+
themeState.common.states = states;
|
|
1950
|
+
await this.adapter.setObject(`${this.adapter.namespace}.control.theme`, themeState);
|
|
1951
|
+
} else {
|
|
1952
|
+
this.log.warn(`State ${this.adapter.namespace}.control.theme missing`);
|
|
1953
|
+
}
|
|
1954
|
+
const themeDarkState = await this.adapter.getObjectAsync(`${this.adapter.namespace}.control.themeDark`);
|
|
1955
|
+
if (themeDarkState && themeDarkState.common) {
|
|
1956
|
+
themeDarkState.common.states = states;
|
|
1957
|
+
await this.adapter.setObject(`${this.adapter.namespace}.control.themeDark`, themeDarkState);
|
|
1958
|
+
} else {
|
|
1959
|
+
this.log.warn(`State ${this.adapter.namespace}.control.themeDark missing`);
|
|
1960
|
+
}
|
|
1937
1961
|
|
|
1938
1962
|
const state = await this.adapter.getStateAsync(`${this.adapter.namespace}.control.theme`);
|
|
1939
1963
|
// remember the currently selected theme, if valid. Select default otherwise.
|
|
@@ -2265,6 +2289,12 @@ class WebServer {
|
|
|
2265
2289
|
const filePath = req.url.replace(/.*\/frontend_latest\//, 'frontend_latest/');
|
|
2266
2290
|
res.setHeader('Cache-Control', `public, max-age=${staticOptions.maxAge}`);
|
|
2267
2291
|
res.sendFile(`${getRootPath()}${filePath}`);
|
|
2292
|
+
} else if (req.url.includes('/frontend_es5/')) {
|
|
2293
|
+
//serve frontend:
|
|
2294
|
+
//remove all from before frontend_es5.
|
|
2295
|
+
const filePath = req.url.replace(/.*\/frontend_es5\//, 'frontend_es5/');
|
|
2296
|
+
res.setHeader('Cache-Control', `public, max-age=${staticOptions.maxAge}`);
|
|
2297
|
+
res.sendFile(`${getRootPath()}${filePath}`);
|
|
2268
2298
|
} else if (req.url.includes('/static/icons/')) {
|
|
2269
2299
|
//iobroker icons:
|
|
2270
2300
|
const filePath = req.url.replace(/.*\/static\/icons\//, '');
|
|
@@ -2407,7 +2437,7 @@ class WebServer {
|
|
|
2407
2437
|
});
|
|
2408
2438
|
|
|
2409
2439
|
this._app.use((req, res) => {
|
|
2410
|
-
this.log.
|
|
2440
|
+
this.log.info(`Unknown request for ${req.url}`);
|
|
2411
2441
|
//res.send('unknown');
|
|
2412
2442
|
res.send(this._renderIndex());
|
|
2413
2443
|
});
|
|
@@ -3098,7 +3128,7 @@ class WebServer {
|
|
|
3098
3128
|
}
|
|
3099
3129
|
}
|
|
3100
3130
|
if (!result) {
|
|
3101
|
-
|
|
3131
|
+
this.log.info(`Unknown request: ${JSON.stringify(message)}`);
|
|
3102
3132
|
ws.send(
|
|
3103
3133
|
JSON.stringify({
|
|
3104
3134
|
id: message.id,
|