iobroker.lovelace 4.0.4 → 4.0.5
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 +4 -11
- package/io-package.json +14 -14
- package/lib/converters/genericConverter.js +2 -1
- package/lib/entities/utils.js +10 -4
- package/lib/modules/history.js +22 -27
- package/lib/server.js +4 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -471,6 +471,10 @@ After that checkout modified version in `./build` folder. Then.
|
|
|
471
471
|
PLACEHOLDER for next version:
|
|
472
472
|
### **WORK IN PROGRESS**
|
|
473
473
|
-->
|
|
474
|
+
### 4.0.5 (2023-12-09)
|
|
475
|
+
* (Garfonso) revert shopping list
|
|
476
|
+
* (Garfonso) prevent invalid date error
|
|
477
|
+
|
|
474
478
|
### 4.0.4 (2023-12-09)
|
|
475
479
|
* (Garfonso) fix: crash
|
|
476
480
|
|
|
@@ -483,17 +487,6 @@ After that checkout modified version in `./build` folder. Then.
|
|
|
483
487
|
### 4.0.1 (2023-12-08)
|
|
484
488
|
* (Garfonso) fix: hideHeader object is writable
|
|
485
489
|
|
|
486
|
-
### 4.0.0 (2023-12-08)
|
|
487
|
-
* (Garfonso) Breaking: Update frontent to 2023.12.08.1
|
|
488
|
-
* (Garfonso) Breaking: all states default to string now. Added some exceptions (like timestamps). Check your filters.
|
|
489
|
-
* (Garfonso) Use better random numbers for tokens.
|
|
490
|
-
* (Garfonso) Support media_play_pause (mini-media-player card play / pause) again.
|
|
491
|
-
* (Garfonso) Support for input_select
|
|
492
|
-
* (Garfonso) Improve support for sensor with device_class=date
|
|
493
|
-
* (Garfonso) Remove hideToolbar from settings. Now using browser_mod to allow per instance control.
|
|
494
|
-
* (Garfonso) repaired persistent notifications.
|
|
495
|
-
* (Garfonso) Use browser_mod to hide sidebar.
|
|
496
|
-
|
|
497
490
|
## License
|
|
498
491
|
|
|
499
492
|
Copyright 2019-2023, bluefox <dogafox@gmail.com>
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "lovelace",
|
|
4
|
-
"version": "4.0.
|
|
4
|
+
"version": "4.0.5",
|
|
5
5
|
"news": {
|
|
6
|
+
"4.0.5": {
|
|
7
|
+
"en": "revert shopping list (not working right now)\nprevent invalid date error",
|
|
8
|
+
"de": "Shoppignlist Änderungen rückgängig gemacht (funktionieren nicht)\nungültiger datumsfehler verhindern",
|
|
9
|
+
"ru": "перевернуть список покупок\nпредотвратить недопустимую ошибку",
|
|
10
|
+
"pt": "lista de compras reverter\nevitar erro de data inválido",
|
|
11
|
+
"nl": "revert shoppen\nongeldige datum fout",
|
|
12
|
+
"fr": "retourner la liste des courses\nprévenir l'erreur de date invalide",
|
|
13
|
+
"it": "rifare la lista della spesa\nprevenire errore di data non valido",
|
|
14
|
+
"es": "revertir la lista de compras\nprevenir el error de fecha inválida",
|
|
15
|
+
"pl": "lista zakupów\nzapobieganie błędom",
|
|
16
|
+
"uk": "перевернути список покупок\nзапобігання недійсної помилки дати",
|
|
17
|
+
"zh-cn": "回购单\n防止无效日期"
|
|
18
|
+
},
|
|
6
19
|
"4.0.4": {
|
|
7
20
|
"en": "fix: crash",
|
|
8
21
|
"de": "fix: absturz",
|
|
@@ -71,19 +84,6 @@
|
|
|
71
84
|
"pl": "nie dochodzi do skutku, jeśli nie zostanie wybrana historia.\nponowne wyniki pracują ponownie.\nremontowany kolorową temperaturę.",
|
|
72
85
|
"uk": "не вдається, якщо вибрано екземпляр історії.\nповідомлення про роботу знову.\nобробка кольорової температури.",
|
|
73
86
|
"zh-cn": "如果没有选择过历史的事例,就不会发生事故。.\n再次发出通知。.\n修理的气温处理。."
|
|
74
|
-
},
|
|
75
|
-
"3.0.0": {
|
|
76
|
-
"en": "added: per instance language support\nchanged: updated frontend to 20221027.0. Needs theme adjustment (add code-editor-background-color) and probably card updates\nadded: browser_mod (2.1.3) is now integrated. Please remove manual installed versions of custom browser_mod card.\nadded: 'instances.refresh' can be used to reload page in connected browsers.\nremoved: lovelace_reload and window_reload states\nremoved: name state, not supported by browser_mod anymore\nadded: Support for toasts with action button (either json or ;-string)\nadded: activity state will show if user is currently using a certain browser\nadded: Support for subfolders in /cards/ for images and stuff custom cards load (please keep cards in root folder).",
|
|
77
|
-
"de": "hinzugefügt: per Instanz sprachunterstützung\ngeändert: aktualisiertes Frontend auf 20221027.0 Benötigt Thema Anpassung (z.B. neu code-editor-background-color) und wahrscheinlich Karten-Updates\nadd: browser_mod (2.1.3) ist jetzt integriert. Bitte entfernen Sie manuell installierte Versionen der browser_mod-Karte.\nhinzugefügt: instances.refresh kann verwendet werden, um die Seite in verbundenen Browsern neu zu laden.\nentfernt: lovelace_reload und windows_reload\nentfernt: name-State, nicht mehr von browser_mod unterstützt\nadded: Unterstützung für Toasts mit Aktionsknopf (entweder json oder -;string)\nadded: Aktivitätszustand, der anzeigt, ob der Nutzer derzeit einen bestimmten Browser bedient\nadded: Unterstützung für Unterordner in /cards/ für Bilder und Materialien benutzerdefinierte Karten (bitte die Karten selber im Wurzelordner lassen).",
|
|
78
|
-
"ru": "добавлено: в пример языковой поддержки\nизменено: обновление frontend до 20221027.0 Нужна настройка темы (add code-editor-background-color) и, вероятно, обновления карты\nдобавлено: browser_mod (2.1.3) теперь интегрирован. Пожалуйста, удалите вручную установленные версии пользовательского браузера_mod карты.\nдобавлено: instances.refresh можно использовать для перезагрузки страницы в подключенных браузерах.\nудалено: lovelace_reload and window_reload состояния\nудалено: имя состояние, не поддерживается браузером_mod более\nдобавлено: Поддержка тостов с кнопкой действия (либо json или -;string)\nдобавлено: состояние активности покажет, если пользователь в настоящее время использует определенный браузер\nдобавлено: Поддержка субпастеров в картах для загрузки изображений и настраиваемых карт (пожалуйста, держите карты в папке root).",
|
|
79
|
-
"pt": "adicionado: por exemplo suporte de idioma\nalterado: frontend atualizado para 20221027.0 Precisa de ajuste de tema (add code-editor-background-color) e, provavelmente, atualizações de cartão\nadicionado: browser_mod (2.1.3) agora está integrado. Por favor, remova as versões manuais instaladas do cartão browser_mod personalizado.\nadicionado: instances.refresh a atualização pode ser usada para recarregar a página em navegadores conectados.\nremovido: lovelace_reload and window_reload states\nremovido: name state, não suportado pelo browser_mod mais\nadicionado: Suporte para torradas com botão de ação (quer json ou -;string)\nadicionado: estado de atividade irá mostrar se o usuário está usando um determinado navegador\nadicionado: Suporte para subpastas em cartões para imagens e coisas cartões personalizados de carga (por favor, mantenha cartões na pasta raiz).",
|
|
80
|
-
"nl": "vertaling:\nverandering: Heeft thema aanpassing nodig (add code-aditor-background-color) en waarschijnlijk kaart updates\ntoegevoegd: browsermod (2.1.3) is nu geïntegreerd. Verwijder handmatig geïnstalleerde versies van de gewone browsermod kaart.\ntoegevoegd: instances.refresh kan gebruikt worden om pagina te herladen in verbonden browsers.\n_\nverwijdert: naam staat, niet ondersteund door browsermod\nversterking voor toasts met actieknop\nde activiteitsstaat laat zien of gebruiker momenteel een bepaalde browser gebruikt\nsteun voor subfolders in kaarten voor foto's en klantenkaarten laden in wortelvouder.",
|
|
81
|
-
"fr": "ajouté: par exemple le soutien linguistique\nchangé: mise à jour du frontend à 20221027.0 Besoins réglage de thème (add code-editor-background-color) et probablement mises à jour de carte\najouté: browser_mod (2.1.3) est maintenant intégré. Veuillez supprimer les versions manuelles installées de la carte personnalisée browser_mod.\najouté: instances. rafraîchissement peut être utilisé pour recharger la page dans les navigateurs connectés.\nsupprimé: lovelace_reload et windows_reload états\nenlevé: état de nom, non pris en charge par browser_mod plus\najouté: Support pour les toasts avec bouton d'action (soit json ou -;string)\najouté: état d'activité montrera si l'utilisateur utilise actuellement un certain navigateur\najouté: Support pour les sous-dossiers dans les cartes pour les images et la charge de cartes personnalisées (veuillez garder les cartes dans le dossier racine).",
|
|
82
|
-
"it": "aggiunto: per esempio supporto linguistico\nmodificato: frontend aggiornato a 20221027.0 Ha bisogno di regolazione del tema (add code-editor-background-color) e probabilmente aggiornamenti della carta\naggiunto: browser_mod (2.1.3) è ora integrato. Si prega di rimuovere le versioni di browser_mod personalizzato.\naggiunto: instances.refresh può essere utilizzato per ricaricare la pagina nei browser collegati.\nrimosso: lovelace_reload e window_reload stati\nrimosso: nome stato, non supportato da browser_mod più\naggiunto: Supporto per toast con pulsante d'azione (sia json che -;string)\naggiunto: lo stato di attività mostrerà se l'utente sta attualmente utilizzando un certo browser\naggiunto: Supporto per le sottocartelle nelle schede per immagini e roba carico di carte personalizzate (mantenere le carte nella cartella principale).",
|
|
83
|
-
"es": "añadido: por ejemplo apoyo al idioma\ncambiado: actualización de frontend a 20221027.0 Necesidades de ajuste de tema (add code-editor-background-color) y probablemente actualizaciones de tarjetas\nañadido: browser_mod (2.1.3) está ahora integrado. Por favor, retire las versiones instaladas manualmente de la tarjeta browser_mod personalizada.\nañadido: instances.refresh se puede utilizar para recargar página en los navegadores conectados.\neliminados: estados lovelace_reload y window_reload\neliminado: estado de nombre, no soportado por browser_mod más\nañadido: Soporte para tostadas con botón de acción (ya sea json o -;string)\nañadido: estado de actividad mostrará si el usuario está utilizando un determinado navegador\nañadido: Soporte para subcarpetas en tarjetas para la carga de imágenes y material de tarjetas personalizadas (por favor, mantenga las tarjetas en la carpeta raíz).",
|
|
84
|
-
"pl": "upoważnianie języka\nzmieniło się: zaktualizowano front do 20221027. Konstrukcja tematu (dodawanie kod-editor-ground-color) oraz prawdopodobnie aktualizacja kart\ndodano: przeglądarkę_mod (2.1.3). Zastosowanie ręcznych wersji karty przeglądarki_mod.\ndostęp: instances.refresh być używany do przeładowania strony w połączonych przeglądarkach.\nusunięte: miłość_reload and window_reload\nusunięta: nazwa nie jest wspierana przez przeglądarkę_mod anymore\ndodał: Wspieranie toastów z przyciskiem (json lub -;string)\ndodano: stan aktywności pokazuje, że użytkownik jest obecnie używany przez określoną przeglądarkę\ndodał: Wsparcie dla subklerów w kartach dla obrazów i kart przechowywania kart (please keep cards in root folder).",
|
|
85
|
-
"uk": "додано: підтримка мови екземпляра\nзмінено: оновлений фронтенд до 20221027.0 Потрібні налаштування теми (add code-editor-phone-color) і, ймовірно, оновлення карт\nдодано: браузер_mod (2.1.3) тепер інтегрований. Будь ласка, видаліть ручні встановлені версії користувацького браузера_mod карти.\nдодано: instances.refresh перезавантажити сторінку в підключених браузерах.\nвидалити: lovelace_reload і windows_reload стани\nвидалити: стан імен, не підтримується браузером_mod додатково\nдоданий: Підтримка тастів з кнопкою дії (або json або -;string)\nдодано: стан роботи покаже, якщо користувач наразі використовує певний браузер\nдодано: Підтримка підпапок у картках для зображень та начинок на замовлення, завантаження карт (збережіть картки у папці кореневих).",
|
|
86
|
-
"zh-cn": "增加:每一类语文支助\n修改:更新前线到20221027.0。 需求专题调整(附加编码的外地领地)以及可能提供最新资料\n增加:现正在综合编(2.1.3)。 请取消制造的习俗包件的手册。.\n增加:情况。 可以用来复制连带代的页。.\n删除:亲王:重载和窗口。\n删除:姓名国,未获括号内的支持;莫斯·马约尔\n增加:支持以行动、但顿(既不是 json,也不是;示范)\n增加:如果用户目前使用某些代行,活动国将显示活动情况。\n增加:支持在图像和制成品的卡里的投影器(装有根带的卡)。."
|
|
87
87
|
}
|
|
88
88
|
},
|
|
89
89
|
"title": "Visualization with Lovelace-UI",
|
|
@@ -13,7 +13,8 @@ exports.iobState2EntityState = function (entity, val, attribute) {
|
|
|
13
13
|
} else if (typeof val === 'number' && entity.attributes && ['timestamp'].includes(entity.attributes.device_class)) {
|
|
14
14
|
return val; //do not convert timestamps.
|
|
15
15
|
} else if (typeof val === 'number' && entity.attributes && ['date'].includes(entity.attributes.device_class)) {
|
|
16
|
-
|
|
16
|
+
const dateStr = new Date(val).toDateString(); //convert to date string
|
|
17
|
+
return dateStr === 'Invalid Date' ? 'unknown' : dateStr;
|
|
17
18
|
} else if (type === 'lock') {
|
|
18
19
|
return val ? 'unlocked' : 'locked';
|
|
19
20
|
} else if (typeof val === 'boolean' && type !== 'media_player') {
|
package/lib/entities/utils.js
CHANGED
|
@@ -446,22 +446,28 @@ function updateTimestamps(entity, state) {
|
|
|
446
446
|
}
|
|
447
447
|
|
|
448
448
|
try {
|
|
449
|
-
new Date(lc).getTime();
|
|
449
|
+
const ts = new Date(lc).getTime();
|
|
450
|
+
if (isNaN(ts)) {
|
|
451
|
+
throw 'Invalid Date';
|
|
452
|
+
}
|
|
450
453
|
} catch (e) {
|
|
451
454
|
entityData.adapter.log.debug('Invalid lc time for ' + state._id + ' in ' + entity.entity_id + ': ' + e);
|
|
452
455
|
lc = Date.now();
|
|
453
456
|
}
|
|
454
457
|
try {
|
|
455
|
-
new Date(
|
|
458
|
+
const ts = new Date(lc).getTime();
|
|
459
|
+
if (isNaN(ts)) {
|
|
460
|
+
throw 'Invalid Date';
|
|
461
|
+
}
|
|
456
462
|
} catch (e) {
|
|
457
463
|
entityData.adapter.log.debug('Invalid lu time for ' + state._id + ' in ' + entity.entity_id + ': ' + e);
|
|
458
464
|
lu = Date.now();
|
|
459
465
|
}
|
|
460
466
|
|
|
461
|
-
if (lc / 1000 > entity.last_changed) {
|
|
467
|
+
if (lc / 1000 > entity.last_changed || isNaN(entity.last_changed) || new Date(entity.last_changed * 1000).toString() === 'Invalid Date') {
|
|
462
468
|
entity.last_changed = lc / 1000;
|
|
463
469
|
}
|
|
464
|
-
if (lu / 1000 > entity.last_updated) {
|
|
470
|
+
if (lu / 1000 > entity.last_updated || isNaN(entity.last_updated) || new Date(entity.last_updated * 1000).toString() === 'Invalid Date') {
|
|
465
471
|
entity.last_updated = lu / 1000;
|
|
466
472
|
}
|
|
467
473
|
}
|
package/lib/modules/history.js
CHANGED
|
@@ -1,18 +1,5 @@
|
|
|
1
1
|
const iobState2EntityState = require('../converters/genericConverter').iobState2EntityState;
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* convert .ts of state e to ISOString with try/catch and now as fallback.
|
|
5
|
-
* @param {ioBroker.state} e
|
|
6
|
-
* @returns {string}
|
|
7
|
-
* @private
|
|
8
|
-
*/
|
|
9
|
-
function _convertStateTStoISOString(e) {
|
|
10
|
-
try {
|
|
11
|
-
return new Date(e.ts).toISOString();
|
|
12
|
-
} catch (error) {
|
|
13
|
-
return new Date().toISOString();
|
|
14
|
-
}
|
|
15
|
-
}
|
|
2
|
+
const updateTimestamps = require('../entities/utils').updateTimestamps;
|
|
16
3
|
|
|
17
4
|
/**
|
|
18
5
|
* getHistory from history instances.
|
|
@@ -62,8 +49,16 @@ async function getHistory(adapter, entities, start, end, noAttributes, user) {
|
|
|
62
49
|
}
|
|
63
50
|
}
|
|
64
51
|
|
|
65
|
-
|
|
66
|
-
|
|
52
|
+
/**
|
|
53
|
+
* match attributes to states by ts:
|
|
54
|
+
* @param state {ioBroker.State}
|
|
55
|
+
* @param attributesResult
|
|
56
|
+
* @param attributesUsed
|
|
57
|
+
* @param attributeValues
|
|
58
|
+
* @returns {{}}
|
|
59
|
+
*/
|
|
60
|
+
const getAttributeValues = (state, attributesResult, attributesUsed = [], attributeValues = {}) => {
|
|
61
|
+
const ts = state.ts;
|
|
67
62
|
if (entity.context.ATTRIBUTES) {
|
|
68
63
|
for (const attribute of entity.context.ATTRIBUTES) {
|
|
69
64
|
if (attributesUsed.indexOf(attribute.attribute) >= 0) {
|
|
@@ -75,7 +70,7 @@ async function getHistory(adapter, entities, start, end, noAttributes, user) {
|
|
|
75
70
|
const results = attributesResult[attribute.attribute].result;
|
|
76
71
|
for (const result of results) {
|
|
77
72
|
if (result.val !== null) {
|
|
78
|
-
const diff = Math.abs(result.ts -
|
|
73
|
+
const diff = Math.abs(result.ts - ts);
|
|
79
74
|
if (diff < bestDiff) {
|
|
80
75
|
best = result;
|
|
81
76
|
bestDiff = diff;
|
|
@@ -104,16 +99,16 @@ async function getHistory(adapter, entities, start, end, noAttributes, user) {
|
|
|
104
99
|
const attributesUsed = [];
|
|
105
100
|
for (const e of stateResult.result) {
|
|
106
101
|
if (e.val !== null) {
|
|
107
|
-
const ts = _convertStateTStoISOString(e);
|
|
108
102
|
const result = {
|
|
109
103
|
entity_id: entity.entity_id,
|
|
110
104
|
state: typeof entity.context.STATE.historyParser === 'function' ?
|
|
111
105
|
entity.context.STATE.historyParser(id, e.val).toString() :
|
|
112
106
|
iobState2EntityState(entity, e.val).toString(),
|
|
113
|
-
last_changed:
|
|
114
|
-
last_updated:
|
|
115
|
-
attributes: getAttributeValues(
|
|
107
|
+
last_changed: 0,
|
|
108
|
+
last_updated: 0,
|
|
109
|
+
attributes: getAttributeValues(e, attributesResult, attributesUsed)
|
|
116
110
|
};
|
|
111
|
+
updateTimestamps(result, e);
|
|
117
112
|
arr.push(result);
|
|
118
113
|
}
|
|
119
114
|
}
|
|
@@ -125,17 +120,17 @@ async function getHistory(adapter, entities, start, end, noAttributes, user) {
|
|
|
125
120
|
for (const result of results) {
|
|
126
121
|
if (result.val !== null && !result.used) {
|
|
127
122
|
const attributeValues = {};
|
|
128
|
-
const ts = _convertStateTStoISOString(result);
|
|
129
123
|
attributeValues[attribute.attribute] = typeof attribute.historyParser === 'function' ? attribute.historyParser(id, result.val) : result.val;
|
|
130
124
|
result.used = true;
|
|
131
125
|
//fill in other attributes:
|
|
132
126
|
const data = {
|
|
133
127
|
entity_id: entity.entity_id,
|
|
134
128
|
//state: null,
|
|
135
|
-
last_changed:
|
|
136
|
-
last_updated:
|
|
137
|
-
attributes: getAttributeValues(
|
|
129
|
+
last_changed: 0,
|
|
130
|
+
last_updated: 0,
|
|
131
|
+
attributes: getAttributeValues(result, attributesResult, attributesUsed, attributeValues)
|
|
138
132
|
};
|
|
133
|
+
updateTimestamps(data, result);
|
|
139
134
|
arr.push(data);
|
|
140
135
|
}
|
|
141
136
|
}
|
|
@@ -174,8 +169,8 @@ function convertHistoryResultToWebsocketApi(entities, result) {
|
|
|
174
169
|
const entityHistoryState = {
|
|
175
170
|
s: res.state,
|
|
176
171
|
a: res.attributes,
|
|
177
|
-
lc:
|
|
178
|
-
lu:
|
|
172
|
+
lc: res.last_changed, //changed that already in old code.
|
|
173
|
+
lu: res.last_updated
|
|
179
174
|
};
|
|
180
175
|
entityHistoryStates.push(entityHistoryState);
|
|
181
176
|
}
|
package/lib/server.js
CHANGED
|
@@ -918,17 +918,16 @@ class WebServer {
|
|
|
918
918
|
}
|
|
919
919
|
entityHome.attributes.latitude = parseFloat(this.systemConfig.latitude);
|
|
920
920
|
entityHome.attributes.longitude = parseFloat(this.systemConfig.longitude);
|
|
921
|
-
entityHome.last_changed = this.systemConfig.ts;
|
|
922
|
-
entityHome.last_updated = this.systemConfig.ts;
|
|
921
|
+
entityHome.last_changed = (this.systemConfig.ts || Date.now()) / 1000;
|
|
922
|
+
entityHome.last_updated = (this.systemConfig.ts || Date.now()) / 1000;
|
|
923
923
|
|
|
924
924
|
//shoppindlist:
|
|
925
|
-
let entityShoppingList = entityData.entityId2Entity['todo.shoppinglist'];
|
|
925
|
+
/*let entityShoppingList = entityData.entityId2Entity['todo.shoppinglist'];
|
|
926
926
|
if (!entityShoppingList) {
|
|
927
927
|
entityShoppingList = {
|
|
928
928
|
'entity_id': 'todo.shoppinglist',
|
|
929
929
|
'state': 'unknown',
|
|
930
930
|
'attributes': {
|
|
931
|
-
'hidden': true,
|
|
932
931
|
'friendly_name': 'Shopping List',
|
|
933
932
|
'icon': 'mdi:cart'
|
|
934
933
|
},
|
|
@@ -940,7 +939,7 @@ class WebServer {
|
|
|
940
939
|
};
|
|
941
940
|
entityData.entities.push(entityShoppingList);
|
|
942
941
|
entityData.entityId2Entity[entityShoppingList.entity_id] = entityShoppingList;
|
|
943
|
-
}
|
|
942
|
+
}*/
|
|
944
943
|
}
|
|
945
944
|
|
|
946
945
|
/**
|