iobroker.lovelace 3.0.0 → 3.0.1

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
@@ -468,6 +468,11 @@ After that checkout modified version in `./build` folder. Then.
468
468
  PLACEHOLDER for next version:
469
469
  ### **WORK IN PROGRESS**
470
470
  -->
471
+ ### 3.0.1 (2022-11-03)
472
+ * (Garfonso) do not crash if no history instance selected.
473
+ * (Garfonso) notifications working again.
474
+ * (Garfonso) repaired color temperature handling.
475
+
471
476
  ### 3.0.0 (2022-10-28)
472
477
  * (agross) added: per instance language support
473
478
  * (Garfonso) entity_id for devices with only one non english name should be ok again.
@@ -501,9 +506,6 @@ After that checkout modified version in `./build` folder. Then.
501
506
  ### 2.1.3 (2022-01-07)
502
507
  * (Garfonso) Fixed: remove backup of old frontend (sorry)
503
508
 
504
- ### 2.1.2 (2022-01-06)
505
- * (Garfonso) Fixed: Menu was broken in frontend.
506
-
507
509
  ## License
508
510
 
509
511
  Copyright 2019-2022, bluefox <dogafox@gmail.com>
package/io-package.json CHANGED
@@ -1,8 +1,21 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "lovelace",
4
- "version": "3.0.0",
4
+ "version": "3.0.1",
5
5
  "news": {
6
+ "3.0.1": {
7
+ "en": "do not crash if no history instance selected.\nnotifications working again.\nrepaired color temperature handling.",
8
+ "de": "nicht abstürzen, wenn keine History-Instanz ausgewählt wird.\nBenachrichtigungen funktionieren wieder.\nReparatur der Farbtemperatursteuerung.",
9
+ "ru": "не мешайте, если не выбрана пример истории.\nуведомления, которые снова работают.\nотремонтированная обработка цветовой температуры.",
10
+ "pt": "não travar se nenhuma instância do histórico selecionada.\nnotificações trabalhando novamente.\ntratamento de temperatura de cor reparado.",
11
+ "nl": "niet crashen als geen geschiedenis instance geselecteerd is.\nde berichten werken weer.\ngerepareerde kleurtemperatuur.",
12
+ "fr": "ne pas s'écraser si aucune instance historique n'est sélectionnée.\nles notifications fonctionnent à nouveau.\nla manipulation de la température de couleur réparée.",
13
+ "it": "non crash se non viene selezionato un'istanza di storia.\nnotifiche che funzionano di nuovo.\ngestione della temperatura del colore riparato.",
14
+ "es": "no se estrellen si no se selecciona ningún caso histórico.\nnotificaciones que funcionan de nuevo.\nmanejo de temperatura de color reparado.",
15
+ "pl": "nie dochodzi do skutku, jeśli nie zostanie wybrana historia.\nponowne wyniki pracują ponownie.\nremontowany kolorową temperaturę.",
16
+ "uk": "не вдається, якщо вибрано екземпляр історії.\nповідомлення про роботу знову.\nобробка кольорової температури.",
17
+ "zh-cn": "如果没有选择过历史的事例,就不会发生事故。.\n再次发出通知。.\n修理的气温处理。."
18
+ },
6
19
  "3.0.0": {
7
20
  "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).",
8
21
  "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).",
@@ -75,18 +88,6 @@
75
88
  "es": "Corregido: actualización de la entidad en algunos casos.",
76
89
  "pl": "Naprawiono: Aktualizacja Entity w niektórych przypadkach.",
77
90
  "zh-cn": "修正:在某些情况下实体更新。"
78
- },
79
- "2.1.0": {
80
- "en": "* (Garfonso) Added: support for new things in frontend (like arm_vacation state, currency, ...).\n* (Garfonso) Change: Updated frontent to 20211229.0 (needs update of browser_mod, card_mod)",
81
- "de": "* (Garfonso) Hinzugefügt: Unterstützung für neue Dinge im Frontend (wie arm_vacation Zustand, Währung, ...).\n* (Garfonso) Änderung: Frontent auf 20211229.0 aktualisiert (benötigt möglicherweise Update von browser_mod, card_mod)",
82
- "ru": "* (Garfonso) Добавлено: поддержка новых вещей во внешнем интерфейсе (например, состояние arm_vacation, валюта, ...).\n* (Garfonso) Изменение: обновлен фронт до 20211229.0 (требуется обновление browser_mod, card_mod)",
83
- "pt": "* (Garfonso) Adicionado: suporte para coisas novas no frontend (como arm_vacation state, currency, ...).\n* (Garfonso) Alteração: frontent atualizado para 20211229.0 (precisa de atualização de browser_mod, card_mod)",
84
- "nl": "* (Garfonso) Toegevoegd: ondersteuning voor nieuwe dingen in frontend (zoals arm_vacation state, valuta, ...).\n* (Garfonso) Wijziging: frontent bijgewerkt naar 20211229.0 (update nodig van browser_mod, card_mod)",
85
- "fr": "* (Garfonso) Ajout : prise en charge de nouvelles choses en frontend (comme l'état arm_vacation, la devise, ...).\n* (Garfonso) Changement : frontent mis à jour vers 20211229.0 (nécessite une mise à jour de browser_mod, card_mod)",
86
- "it": "* (Garfonso) Aggiunto: supporto per nuove cose nel frontend (come arm_vacation state, currency, ...).\n* (Garfonso) Modifica: Frontent aggiornato a 20211229.0 (necessita di aggiornamento di browser_mod, card_mod)",
87
- "es": "* (Garfonso) Agregado: soporte para cosas nuevas en la interfaz (como estado arm_vacation, moneda, ...).\n* (Garfonso) Cambio: Interfaz actualizada a 20211229.0 (necesita actualización de browser_mod, card_mod)",
88
- "pl": "* (Garfonso) Dodano: wsparcie dla nowych rzeczy w interfejsie (takich jak stan arm_vacation, waluta, ...).\n* (Garfonso) Zmiana: Zaktualizowano frontent do 20211229.0 (wymaga aktualizacji browser_mod, card_mod)",
89
- "zh-cn": "* (Garfonso) 添加:支持前端的新事物(如 arm_vacation 状态、货币等)。\n* (Garfonso) 更改:将前端更新为 20211229.0(需要更新 browser_mod、card_mod)"
90
91
  }
91
92
  },
92
93
  "title": "Visualization with Lovelace-UI",
@@ -58,50 +58,54 @@ function _lightAdvancedAddState(states, objects, entity) {
58
58
  }
59
59
 
60
60
  function _lightAdvancedAddColorTemperature(states, objects, entity) {
61
- const iobMaxValue = 153;
62
- const iobMinValue = 450;
61
+ const iobMaxValueKelvin = 7000;
62
+ const iobMinValueKelvin = 1000;
63
63
 
64
64
  if (states.color_temp) {
65
65
  const attribute = entity.context.ATTRIBUTES.find(a => a.attribute === 'color_temp');
66
66
  const tempObj = objects[states.color_temp];
67
- attribute.convert_to_kelvin = tempObj && tempObj.common ? (tempObj.common.unit === 'K' || tempObj.common.unit === '°K') : false;
67
+ attribute.convert_to_mired = tempObj && tempObj.common ? (tempObj.common.unit === 'mired') : false;
68
68
  attribute.getParser = (entity, attr, state) => {
69
69
  if (!state || !state.val) {
70
- entity.attributes.color_temp = iobMinValue;
70
+ entity.attributes.color_temp = iobMinValueKelvin;
71
71
  return;
72
72
  }
73
73
  let targetCt = state.val;
74
- if (targetCt > 1000 && !attr.convert_to_kelvin) {
75
- attr.convert_to_kelvin = true;
76
- adapterData.log.warn('Need kelvin conversion for ' + states.color_temp + ' and did not detect that in setup. Please set unit to "K" in object settings.');
74
+ if (targetCt < 1000 && !attr.convert_to_mired) {
75
+ attr.convert_to_mired = true;
76
+ //adapterData.log.warn('Need mired conversion for ' + states.color_temp + ' and did not detect that in setup. Please set unit to "K" in object settings.');
77
77
  }
78
- if (attr.convert_to_kelvin) {
78
+ if (targetCt > 1000 & attr.convert_to_mired) {
79
+ attr.convert_to_mired = false;
80
+ }
81
+ if (attr.convert_to_mired) {
79
82
  targetCt = 1e6 / targetCt;
80
83
  }
81
- entity.attributes.color_temp = targetCt;
84
+ entity.attributes.color_temp_kelvin = targetCt;
85
+ entity.attributes.color_temp = 1e6 / targetCt;
82
86
  entity.attributes.color_mode = COLOR_TEMP;
83
87
  };
84
88
 
85
- entity.attributes.max_mireds = tempObj && tempObj.common && tempObj.common.max || iobMaxValue;
86
- entity.attributes.min_mireds = tempObj && tempObj.common && tempObj.common.min || iobMinValue;
87
- if (attribute.convert_to_kelvin || entity.attributes.max_mireds > 1000) {
88
- attribute.convert_to_kelvin = true;
89
- entity.attributes.max_mireds = tempObj && tempObj.common && tempObj.common.max ? 1e6 / tempObj.common.max : iobMaxValue;
90
- entity.attributes.min_mireds = tempObj && tempObj.common && tempObj.common.min ? 1e6 / tempObj.common.min : iobMinValue;
89
+ entity.attributes.max_color_temp_kelvin = tempObj && tempObj.common && tempObj.common.max || iobMaxValueKelvin;
90
+ entity.attributes.min_color_temp_kelvin = tempObj && tempObj.common && tempObj.common.min || iobMinValueKelvin;
91
+ if (attribute.convert_to_mired || entity.attributes.max_color_temp_kelvin < 1000) {
92
+ attribute.convert_to_mired = true;
93
+ entity.attributes.max_color_temp_kelvin = tempObj && tempObj.common && tempObj.common.min ? 1e6 / tempObj.common.min : iobMaxValueKelvin;
94
+ entity.attributes.min_color_temp_kelvin = tempObj && tempObj.common && tempObj.common.max ? 1e6 / tempObj.common.max : iobMinValueKelvin;
91
95
  }
92
- if (!entity.attributes.max_mireds || isNaN(entity.attributes.max_mireds)) {
93
- entity.attributes.max_mireds = iobMaxValue;
96
+ if (!entity.attributes.max_color_temp_kelvin || isNaN(entity.attributes.max_color_temp_kelvin)) {
97
+ entity.attributes.max_color_temp_kelvin = iobMaxValueKelvin;
94
98
  }
95
- if (!entity.attributes.min_mireds || isNaN(entity.attributes.min_mireds)) {
96
- entity.attributes.min_mireds = iobMinValue;
99
+ if (!entity.attributes.min_color_temp_kelvin || isNaN(entity.attributes.min_color_temp_kelvin)) {
100
+ entity.attributes.min_color_temp_kelvin = iobMinValueKelvin;
97
101
  }
98
- adapterData.log.debug(entity.entity_id + ' ct needs kelvin conversion: ' + attribute.convert_to_kelvin);
102
+ adapterData.log.debug(entity.entity_id + ' ct needs mired conversion: ' + attribute.convert_to_mired);
99
103
 
100
- if (entity.attributes.min_mireds > entity.attributes.max_mireds) {
104
+ if (entity.attributes.min_color_temp_kelvin > entity.attributes.max_color_temp_kelvin) {
101
105
  //for kelvin conversion min and max need to be swapped.
102
- const max = entity.attributes.min_mireds;
103
- entity.attributes.min_mireds = entity.attributes.max_mireds;
104
- entity.attributes.max_mireds = max;
106
+ const max = entity.attributes.min_color_temp_kelvin;
107
+ entity.attributes.min_color_temp_kelvin = entity.attributes.max_color_temp_kelvin;
108
+ entity.attributes.max_color_temp_kelvin = max;
105
109
  }
106
110
 
107
111
  entity.attributes.supported_color_modes.push(COLOR_TEMP);
@@ -255,10 +259,21 @@ async function _setLightAdvancedAttributesToIOBStates(data, entity, user) {
255
259
  }
256
260
 
257
261
  if (data.service_data.color_temp) { //will also be false for ct = 0 -> but ct = 0 is not a useful mired value and creates issues with the conversion.
258
- let ct = data.service_data.color_temp;
259
- entity.attributes.color_temp = ct;
262
+ let ct = 1e6 / data.service_data.color_temp;
263
+ entity.attributes.color_temp_kelvin = ct;
264
+ entity.attributes.color_temp = data.service_data.color_temp;
265
+ const attr = entity.context.ATTRIBUTES.find(a => a.attribute === 'color_temp');
266
+ if (attr.convert_to_mired) {
267
+ ct = data.service_data.color_temp;
268
+ }
269
+ entity.attributes.color_mode = COLOR_TEMP;
270
+ await adapterData.adapter.setForeignStateAsync(attr.getId, ct, false, {user});
271
+ }
272
+ if (data.service_data.color_temp_kelvin) { //will also be false for ct = 0 -> but ct = 0 is not a useful mired value and creates issues with the conversion.
273
+ let ct = data.service_data.color_temp_kelvin;
274
+ entity.attributes.color_temp_kelvin = ct;
260
275
  const attr = entity.context.ATTRIBUTES.find(a => a.attribute === 'color_temp');
261
- if (attr.convert_to_kelvin) {
276
+ if (attr.convert_to_mired) {
262
277
  ct = 1e6 / ct;
263
278
  }
264
279
  entity.attributes.color_mode = COLOR_TEMP;
@@ -214,7 +214,7 @@ class BrowserModModule {
214
214
  }
215
215
 
216
216
  //store infos about browser instance
217
- async _hanldeUpdate(ioBrokerDeviceId, message) {
217
+ async _handleUpdate(ioBrokerDeviceId, message) {
218
218
  if (message.data) {
219
219
  if (message.data.browser) {
220
220
  //check if all objects in ioBroker are created.
@@ -254,8 +254,8 @@ class BrowserModModule {
254
254
 
255
255
  async processBrowserModMessage(ws, message) {
256
256
  const method = message.type.split('/')[1];
257
- //console.log('Incomming browser_mod message:');
258
- //console.dir(message, {depth: null});
257
+ // console.log('Incoming browser_mod message:');
258
+ // console.dir(message, {depth: null});
259
259
 
260
260
  if (!message.browserID) {
261
261
  this.adapter.log.warn('No device ID in browser_mod request: ' + JSON.stringify(message));
@@ -264,8 +264,8 @@ class BrowserModModule {
264
264
  const ioBrokerDeviceId = instancesPath + message.browserID;
265
265
 
266
266
  if (method === 'update') {
267
- this._hanldeUpdate(ioBrokerDeviceId, message);
268
- } else if(method === 'connect') { //similar to 'subscribe'.
267
+ this._handleUpdate(ioBrokerDeviceId, message);
268
+ } else if (method === 'connect') { // similar to 'subscribe'.
269
269
  ws.on('close', async () => {
270
270
  this.adapter.log.debug(`Instance ${message.browserID} disconnected.`);
271
271
  delete this.clients[message.browserID];
@@ -292,10 +292,10 @@ class BrowserModModule {
292
292
  time_fired: new Date().toISOString()
293
293
  }}));
294
294
 
295
- if (this.objects[this.adapter.namespace + '.' + ioBrokerDeviceId + '.online']) {
295
+ if (this.objects[`${this.adapter.namespace}.${ioBrokerDeviceId}.online`]) {
296
296
  await this.adapter.setStateAsync(ioBrokerDeviceId + '.online', true, true);
297
297
  } else {
298
- console.log('No objects for instance, yet..', ioBrokerDeviceId + '.online', this.objects[ioBrokerDeviceId], this.objects);
298
+ console.log('No objects for instance, yet..', `${ioBrokerDeviceId}.online`, this.objects[ioBrokerDeviceId], this.objects);
299
299
  }
300
300
  } else if (method === 'log') {
301
301
  this.adapter.log.debug('Message from browser_mod: ' + message.message);
@@ -306,7 +306,7 @@ class BrowserModModule {
306
306
 
307
307
  async onStateChange(id, state) {
308
308
  //console.log(id);
309
- if (state && !state.ack && id.startsWith(this.adapter.namespace + '.' + instancesPath)) { //ok, is relevant for us.
309
+ if (state && !state.ack && id.startsWith(`${this.adapter.namespace}.${instancesPath}`)) { //ok, is relevant for us.
310
310
  const parts = id.split('.');
311
311
  const browserId = parts[3];
312
312
  let command = parts[4];
@@ -169,14 +169,16 @@ function convertHistoryResultToWebsocketApi(entities, result) {
169
169
  const entity = entities[i];
170
170
  if (typeof entity === 'object') {
171
171
  const entityHistoryStates = [];
172
- for(const res of result[i]) {
173
- const entityHistoryState = {
174
- s: res.state,
175
- a: res.attributes,
176
- lc: new Date(res.last_changed).getTime() / 1000,
177
- lu: new Date(res.last_updated).getTime() / 1000
178
- };
179
- entityHistoryStates.push(entityHistoryState);
172
+ if (result[i] && result[i] instanceof Array) {
173
+ for (const res of result[i]) {
174
+ const entityHistoryState = {
175
+ s: res.state,
176
+ a: res.attributes,
177
+ lc: new Date(res.last_changed).getTime() / 1000,
178
+ lu: new Date(res.last_updated).getTime() / 1000
179
+ };
180
+ entityHistoryStates.push(entityHistoryState);
181
+ }
180
182
  }
181
183
  newResult[entity.entity_id] = entityHistoryStates;
182
184
  } else {
package/lib/server.js CHANGED
@@ -1369,7 +1369,7 @@ class WebServer {
1369
1369
  _getConfig() {
1370
1370
  const tzone = jstz.determine().name();
1371
1371
  //this.log.debug("tz:" + tzone);
1372
- return {
1372
+ const configObj = {
1373
1373
  latitude: parseFloat(this.systemConfig.latitude),
1374
1374
  longitude: parseFloat(this.systemConfig.longitude),
1375
1375
  elevation: 0,
@@ -1385,12 +1385,18 @@ class WebServer {
1385
1385
  location_name: 'Home',
1386
1386
  time_zone: tzone,
1387
1387
  components: [ //TODO: experiment with notify.html5.
1388
- 'lovelace', 'conversation', 'history', 'shopping_list', 'energy', 'notify.html5'
1388
+ 'lovelace', 'conversation', 'shopping_list', 'energy', 'notify.html5'
1389
1389
  ],
1390
1390
  version: VERSION,
1391
1391
  state: 'RUNNING',
1392
1392
  currency: 'EUR'
1393
1393
  };
1394
+
1395
+ if (this.adapter.config.history) {
1396
+ configObj.components.push('history'); //only activate history in frontend if history instance is selected.
1397
+ }
1398
+
1399
+ return configObj;
1394
1400
  }
1395
1401
 
1396
1402
  _getThemes() {
@@ -2058,7 +2064,7 @@ class WebServer {
2058
2064
  }
2059
2065
 
2060
2066
  _sendUpdate(eventType) {
2061
- if (this._wss && this._wss.clients && this._wss.clients.length) {
2067
+ if (this._wss && this._wss.clients && this._wss.clients.size) {
2062
2068
  this._wss.clients.forEach(ws => {
2063
2069
  if (ws._subscribes && ws._subscribes[eventType]) {
2064
2070
  const t = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.lovelace",
3
- "version": "3.0.0",
3
+ "version": "3.0.1",
4
4
  "description": "With this adapter you can build visualization for ioBroker with Home Assistant Lovelace UI",
5
5
  "author": {
6
6
  "name": "bluefox",
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "dependencies": {
22
22
  "@iobroker/adapter-core": "^2.6.7",
23
- "axios": "^0.27.2",
23
+ "axios": "^1.1.3",
24
24
  "body-parser": "^1.20.1",
25
25
  "express": "^4.18.1",
26
26
  "iobroker.type-detector": "^1.1.0",
@@ -38,22 +38,22 @@
38
38
  "@alcalzone/release-script-plugin-iobroker": "^3.5.9",
39
39
  "@alcalzone/release-script-plugin-license": "^3.5.9",
40
40
  "@alcalzone/release-script-plugin-manual-review": "^3.5.9",
41
- "@iobroker/adapter-dev": "^1.1.0",
41
+ "@iobroker/adapter-dev": "^1.2.0",
42
42
  "@iobroker/dev-server": "^0.6.0",
43
43
  "@iobroker/testing": "^4.1.0",
44
44
  "@types/chai": "^4.3.3",
45
45
  "@types/chai-as-promised": "^7.1.5",
46
46
  "@types/gulp": "^4.0.9",
47
47
  "@types/mocha": "^10.0.0",
48
- "@types/node": "^18.8.3",
48
+ "@types/node": "^18.11.9",
49
49
  "@types/proxyquire": "^1.3.28",
50
50
  "@types/sinon": "^10.0.13",
51
51
  "@types/sinon-chai": "^3.2.8",
52
52
  "chai": "^4.3.6",
53
53
  "chai-as-promised": "^7.1.1",
54
- "eslint": "^8.25.0",
54
+ "eslint": "^8.26.0",
55
55
  "gulp": "^4.0.2",
56
- "mocha": "^10.0.0",
56
+ "mocha": "^10.1.0",
57
57
  "proxyquire": "^2.1.3",
58
58
  "sinon": "^14.0.1",
59
59
  "sinon-chai": "^3.7.0"