iobroker.lovelace 4.1.4 → 4.1.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 CHANGED
@@ -11,16 +11,16 @@
11
11
 
12
12
  ## lovelace adapter for ioBroker
13
13
 
14
- With this adapter you can build visualization for ioBroker with Home Assistant Lovelace UI.
14
+ With this adapter, you can build visualization for ioBroker with Home Assistant Lovelace UI.
15
15
 
16
16
  [Deutsche Dokumentation](docs/de/README.md)
17
17
 
18
18
  ## Instance objects
19
- In the folder instances there are some objects that can be used to control the UI. For every browser a new subfolder will
20
- be created with a random ID. This ID is stored in the client browser's web storage. If you delete the web storage a new
19
+ In the folder instances, there are some objects that can be used to control the UI. For every browser, a new subfolder will
20
+ be created with a random ID. This ID is stored in the client browser's web storage. If you delete the web storage, a new
21
21
  instance will be created. If you use Fully Kiosk Browser make sure the function `Delete webstorage on reload` is **disabled**.
22
22
 
23
- This functionality uses browser_mod, which is installed and updated by the adapter. Do not add your own version of browser_mod as custom card.
23
+ This functionality uses browser_mod, which is installed and updated by the adapter. Do not add your own version of browser_mod as a custom card.
24
24
 
25
25
  ## Configuration
26
26
  There are two ways how the entities could be configured:
@@ -35,7 +35,7 @@ In auto mode the similar process will be applied like for `google home` or `mate
35
35
  You can define friendly names and this will be used in entities.
36
36
 
37
37
  ### Manual
38
- The objects can be defined manually in object tree like sql or histroy. The type of entity must be provided and optionally the name of object.
38
+ The objects can be defined manually in an object tree like sql or histroy. The type of entity must be provided and optionally the name of object.
39
39
  With this method only simple entities, like input_number, input_text or input_boolean could be created. It may not have more than one state or attribute.
40
40
 
41
41
  ## Panels
@@ -96,8 +96,8 @@ common: {
96
96
  ```
97
97
 
98
98
  ### Select input
99
- This can be done manually if input_select entity type in custom dialog is selected.
100
- The list of options to select from should be provide in standard commom.states object:
99
+ This can be done manually if `input_select` entity type in custom dialog is selected.
100
+ The list of options to select from should be provided in a standard `common.states` object:
101
101
 
102
102
  ```
103
103
  "common": {
@@ -115,10 +115,10 @@ The list of options to select from should be provide in standard commom.states o
115
115
  }
116
116
  }
117
117
  ```
118
- in other words in should also be input select in IoB.
118
+ in other words, there should also be select input in IoB.
119
119
 
120
120
  ### Timer
121
- Timer could be simulated by following script:
121
+ Timer could be simulated by the following script:
122
122
 
123
123
  ```
124
124
  createState(
@@ -202,11 +202,11 @@ createState(
202
202
  ```
203
203
 
204
204
  ### Weather
205
- Tested with yr and daswetter. One or more of following objects must have `Function=Weather` and `Room=Any` set to be available in configuration:
206
- - daswetter.0.NextDays.Location_1
207
- - yr.0.forecast
205
+ Tested with `yr` and `daswetter`. One or more of the following objects must have `Function=Weather` and `Room=Any` set to be available in configuration:
206
+ - `daswetter.0.NextDays.Location_1`
207
+ - `yr.0.forecast`
208
208
 
209
- Tested with AccuWeather driver v1.1.0 https://github.com/iobroker-community-adapters/ioBroker.accuweather.
209
+ Tested with `AccuWeather` driver v1.1.0 https://github.com/iobroker-community-adapters/ioBroker.accuweather.
210
210
  Custom Lovelace card created in support of accuweather forecast - https://github.com/algar42/IoB.lovelace.accuweather-card
211
211
 
212
212
  ### Shopping list
@@ -235,7 +235,7 @@ createState('location', '39.5681295;2.6432632', false, {
235
235
  });
236
236
  ```
237
237
 
238
- or this two objects:
238
+ or these two objects:
239
239
 
240
240
  ```
241
241
  createState('location.longitude', 2.6432632, false, {
@@ -257,7 +257,7 @@ createState('location.latitude', 39.5681295, false, {
257
257
  ```
258
258
 
259
259
  ### Picture entity
260
- You can use static picture for it or use any state that delivers URL as state.
260
+ You can use static picture for it or use any state that delivers URL as a state.
261
261
  E.g.:
262
262
 
263
263
  ```
@@ -275,34 +275,34 @@ E.g.:
275
275
  }
276
276
  ```
277
277
 
278
- or just set manually the entity type to `camera` and write URL into it.
278
+ or just manually set the entity type to `camera` and write URL into it.
279
279
 
280
280
  ### Markdown
281
281
  You can use bindings in markdown like in [iobroker.vis](https://github.com/ioBroker/ioBroker.vis#bindings-of-objects).
282
282
 
283
- E.g. Text `Admin adapter is {a:system.adapter.admin.0.alive;a === true || a === 'true' ? ' ' : 'not '} *alive*.` will produce text `Admin adapter is alive` in markdown panel.
283
+ E.g., Text `Admin adapter is {a:system.adapter.admin.0.alive;a === true || a === 'true' ? ' ' : 'not '} *alive*.` will produce text `Admin adapter is alive` in a markdown panel.
284
284
 
285
285
  ## Custom cards
286
286
  ### Upload of custom cards
287
- To upload the custom card write following:
287
+ To upload the custom card, write the following:
288
288
 
289
289
  ```iobroker file write PATH_TO_FILE\bignumber-card.js /lovelace.0/cards/```
290
290
 
291
291
  After restart of lovelace adapter it will include all files from the `cards` directory automatically.
292
292
 
293
- Following custom cards could be tested successfully:
294
- - bignumber-card: https://github.com/custom-cards/bignumber-card/blob/master/bignumber-card.js
295
- - simple-thermostat: https://github.com/nervetattoo/simple-thermostat/releases (take the latest release)
296
- - thermostat: https://github.com/ciotlosm/custom-lovelace/tree/master/thermostat-card (both files .js and .lib.js are required)
293
+ The following custom cards could be tested successfully:
294
+ - `bignumber-card`: https://github.com/custom-cards/bignumber-card/blob/master/bignumber-card.js
295
+ - `simple-thermostat`: https://github.com/nervetattoo/simple-thermostat/releases (take the latest release)
296
+ - `thermostat`: https://github.com/ciotlosm/custom-lovelace/tree/master/thermostat-card (both files .js and .lib.js are required)
297
297
 
298
298
  I found this link https://github.com/jimz011/homeassistant as an interesting resource for custom cards.
299
299
 
300
- Often the custom cards are stored on github as sources and must be compiled before use.
301
- You should check the `Releases` menu on github and try to find compiled files there.
300
+ Often the custom cards are stored on GitHub as sources and must be compiled before use.
301
+ You should check the `Releases` menu on GitHub and try to find compiled files there.
302
302
  Like this one: [https://github.com/kalkih/mini-graph-card/releases](https://github.com/kalkih/mini-graph-card/releases) (Look for the file `mini-graph-card-bundle.js`)
303
303
 
304
304
  ## Own images
305
- The custom images (e.g. for background) could be loaded via the same configuration dialog like the custom cards. And use it like this:
305
+ The custom images (e.g., for a background) could be loaded via the same configuration dialog like the custom cards. And use it like this:
306
306
 
307
307
  `background: center / cover no-repeat url("/cards/background.jpg") fixed`
308
308
 
@@ -310,10 +310,10 @@ or
310
310
 
311
311
  `background: center / cover no-repeat url("/local/custom_ui/background.jpg") fixed`
312
312
 
313
- in lovelace configuration file. Read more about background in lovelace [here](https://www.home-assistant.io/lovelace/views/#background).
313
+ in lovelace configuration file. Read more about the background in lovelace [here](https://www.home-assistant.io/lovelace/views/#background).
314
314
 
315
315
  ## Themes
316
- The themes can be defined in configuration dialog of ioBroker.
316
+ The themes can be defined in the configuration dialog of ioBroker.
317
317
  Paste something like:
318
318
  ```
319
319
  midnight:
@@ -386,7 +386,7 @@ midnight:
386
386
  taken from [here](https://community.home-assistant.io/t/midnight-theme/28598/2).
387
387
 
388
388
  ## Icons
389
- Use icons in form `mdi:NAME`, like 'mdi:play-network'. Names can be taken from here: https://materialdesignicons.com/
389
+ Use icons in form `mdi:NAME`, like `mdi:play-network`. Names can be taken from here: https://materialdesignicons.com/
390
390
 
391
391
  ## Notifications
392
392
  You can add notifications via `sendTo` functionality or by writing the state into `lovelace.X.notifications.add`:
@@ -419,14 +419,14 @@ on({id: 'lovelace.0.conversation', ack: false, change: 'any'}, obj => {
419
419
 
420
420
  ## Trouble Shooting
421
421
  If you messed up the YAML Code and see a blank page but still have the top menu, you can enable edit mode (if not already enabled) from the menu and then open the menu again to access the "RAW Yaml Editor" in which you see the complete YAML code and can clean it up.
422
- If that does not help, you can open the object lovelace.*.configuration in raw-editor in ioBroker and have a look there.
422
+ If that does not help, you can open the object `lovelace.*.configuration` in raw-editor in ioBroker and have a look there.
423
423
  You can also restore that object from a backup. It contains the complete configuration of your visualization.
424
424
 
425
425
  ## Original sources for lovelace
426
426
  Used sources are here https://github.com/GermanBluefox/home-assistant-polymer .
427
427
 
428
428
  ## Todo
429
- Security must be taken from current user and not from default_user
429
+ Security must be taken from the current user and not from default_user
430
430
 
431
431
  ## Development
432
432
  ### Version
@@ -434,7 +434,7 @@ Used version of home-assistant-frontend@20231208.2
434
434
  Version of Browser Mod: 2.3.0
435
435
 
436
436
  ### How to build the new Lovelace version
437
- First of all the actual https://github.com/home-assistant/frontend (dev branch) must be **manually** merged into https://github.com/GermanBluefox/home-assistant-polymer.git (***iob*** branch!).
437
+ First of all, the actual https://github.com/home-assistant/frontend (dev branch) must be **manually** merged into https://github.com/GermanBluefox/home-assistant-polymer.git (***iob*** branch!).
438
438
 
439
439
  All changes for ioBroker are marked with comment `// IoB`.
440
440
  For now (20231208.2) following files were modified:
@@ -443,14 +443,14 @@ For now (20231208.2) following files were modified:
443
443
  - `src/data/weather.ts` - add support to display weather icon from url.
444
444
  - `src/dialogs/more-info/const.ts` - remove weather state & history
445
445
  - `src/dialogs/more-info/ha-more-info-dialog.ts` - remove entity settings button and tab
446
- - `src/dialogs/more-info/ha-more-info-history.ts` - remove 'show more' link in history
446
+ - `src/dialogs/more-info/ha-more-info-history.ts` - remove `show more` link in history
447
447
  - `src/dialogs/more-info/controls/more-info-weather.ts` - add support to display weather icon from url.
448
448
  - `src/dialogs/voice-command-dialog/ha-voice-command-dialog.ts` - disable configuration of voice assistants
449
449
  - `src/entrypoints/core.ts` - modified authentication process
450
450
  - `src/panels/lovelace/cards/hui-weather-forecast-card.ts` - add support to display weather icon from url.
451
451
  - `src/panels/lovelace/entity-rows/hui-weather-entity-row.ts` - add support to display weather icon from url with auth.
452
452
  - `src/panels/lovelace/hui-root.ts` - added notifications and voice control
453
- - `src/util/documentation-url.ts` - for link to iobroker help instead of homeassistant.
453
+ - `src/util/documentation-url.ts` - for link to iobroker help instead of home assistant.
454
454
  - `.gitignore` - add `.idea` ignore
455
455
  - `.husky/pre-commit` - remove git commit hooks.
456
456
  - `package.json` - remove husky commit hook
@@ -465,14 +465,17 @@ After that checkout modified version in `./build` folder. Then.
465
465
  6. `gulp build-app` for release or `gulp develop-iob` for the debugging version. To build web after changes you can call `webpack-dev-app` for faster build, but you need to call `build-app` anyway after the version is ready for use.
466
466
  7. copy all files from `./build/home-assistant-polymer/hass_frontend` into `./hass_frontend` in this repo
467
467
  8. Run `gulp rename` task multiple times (until no changes happen).
468
- 9. Update Version in Readme and also in server.js VERSION constant.
468
+ 9. Update version in `README.md` and also in `server.js` the `VERSION` constant.
469
469
 
470
470
  ## Changelog
471
471
 
472
472
  <!--
473
- PLACEHOLDER for next version:
473
+ PLACEHOLDER for the next version:
474
474
  ### **WORK IN PROGRESS**
475
475
  -->
476
+ ### 4.1.5 (2024-03-05)
477
+ * (Garfonso) fixed: possible crashes during startup
478
+
476
479
  ### 4.1.4 (2024-02-10)
477
480
  * (Garfonso) improved fix: lamp icons now turn gray on switch off.
478
481
 
@@ -490,9 +493,6 @@ After that checkout modified version in `./build` folder. Then.
490
493
  * (Garfonso) added: handle browser_mod/recall_id service call.
491
494
  * (Garfonso) changed: all states are strings (fixes #483)
492
495
 
493
- ### 4.1.0 (2023-12-18)
494
- * (Garfons) add an option to show users on login screen (off by default)
495
-
496
496
  ## License
497
497
 
498
498
  Copyright 2019-2024, 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.1.4",
4
+ "version": "4.1.5",
5
5
  "news": {
6
+ "4.1.5": {
7
+ "en": "fixed: possible crashes during startup",
8
+ "de": "behoben: mögliche abstürzen beim start",
9
+ "ru": "фиксированный: возможные аварии во время запуска",
10
+ "pt": "corrigido: possíveis falhas durante a inicialização",
11
+ "nl": "vast: mogelijke crashes tijdens opstarten",
12
+ "fr": "corrigé: crashs possibles pendant le démarrage",
13
+ "it": "fisso: possibili crash durante l'avvio",
14
+ "es": "fijo: posibles fallos durante la puesta en marcha",
15
+ "pl": "stałe: możliwe awarie podczas uruchamiania",
16
+ "uk": "виправлено: можливі аварії під час запуску",
17
+ "zh-cn": "固定: 启动时可能发生的崩溃"
18
+ },
6
19
  "4.1.4": {
7
20
  "en": "improved fix: lamp icons now turn gray on switch off.",
8
21
  "de": "verbesserter fix: lampensymbole werden nun grau beim ausschalten."
@@ -44,19 +57,6 @@
44
57
  "pl": "błędy lintowe",
45
58
  "uk": "виправлено помилки в розмітці",
46
59
  "zh-cn": "f 固定错误"
47
- },
48
- "4.0.11": {
49
- "en": "updated dependencies",
50
- "de": "aktualisierte abhängigkeiten",
51
- "ru": "обновленные зависимости",
52
- "pt": "dependências atualizadas",
53
- "nl": "vertaling:",
54
- "fr": "dépendances actualisées",
55
- "it": "dipendenze aggiornate",
56
- "es": "dependencias actualizadas",
57
- "pl": "zależności aktualizacji",
58
- "uk": "оновлені залежності",
59
- "zh-cn": "二. 最新依赖"
60
60
  }
61
61
  },
62
62
  "title": "Visualization with Lovelace-UI",
@@ -59,7 +59,7 @@ exports.iobState2EntityState = function (entity, val, attribute) {
59
59
  return val ? 'on' : 'off';
60
60
  } else if (type === 'binary_sensor') {
61
61
  return val ? 'on' : 'off';
62
- }else if (typeof val === 'number' && entity.attributes && ['date', 'timestamp'].includes(entity.attributes.device_class)) {
62
+ } else if (typeof val === 'number' && entity.attributes && ['date', 'timestamp'].includes(entity.attributes.device_class)) {
63
63
  //convert to date string
64
64
  const date = new Date(val);
65
65
  let dateStr = date.toDateString();
@@ -42,7 +42,26 @@ const SUPPORT_EFFECT = 4;
42
42
  //const SUPPORT_FLASH = 8;
43
43
  //const SUPPORT_TRANSITION = 32;
44
44
 
45
- const attributesToNullOnOff = ['color_mode', 'brightness', 'color_temp', 'hs_color', 'rgb_color', 'rgbw_color', 'xy_color', 'effect'];
45
+ const attributesToNullOnOff = ['color_mode', 'brightness', 'color_temp', 'color_temp_kelvin', 'hs_color', 'rgb_color', 'rgbw_color', 'xy_color', 'effect'];
46
+
47
+ function clearOrRestoreAttributes(entity) {
48
+ if (entity.state === 'on') {
49
+ for (const attr of attributesToNullOnOff) {
50
+ if (entity.attributes[attr] === null || entity.attributes[attr] === undefined) { //make sure the attribute was not yet read from somewhere else
51
+ entity.attributes[attr] = entity.context.STATE.storedValues[attr];
52
+ }
53
+ }
54
+ adapterData.log.info(`Stored old values for next switch on: ${JSON.stringify(entity.context.STATE.storedValues)}`);
55
+ } else {
56
+ for (const attr of attributesToNullOnOff) {
57
+ if (entity.attributes[attr] !== undefined) {
58
+ entity.context.STATE.storedValues[attr] = entity.attributes[attr];
59
+ entity.attributes[attr] = null;
60
+ }
61
+ }
62
+ adapterData.log.info(`Restored old values from previous switch off: ${JSON.stringify(entity.attributes)}`);
63
+ }
64
+ }
46
65
 
47
66
  function _lightAdvancedAddState(states, objects, entity) {
48
67
  const getState = states.stateRead;
@@ -53,31 +72,18 @@ function _lightAdvancedAddState(states, objects, entity) {
53
72
  if (!state) {
54
73
  state = {val: null};
55
74
  }
56
- const oldState = entity.state;
57
75
  entity.state = state.val ? 'on' : 'off';
58
- if (!state.val && oldState === 'on') {
59
- for (const attr of attributesToNullOnOff) {
60
- if (entity.attributes[attr] !== undefined) {
61
- entity.context.STATE.storedValues[attr] = entity.attributes[attr];
62
- entity.attributes[attr] = null;
63
- }
64
- }
65
- adapterData.log.debug(`Stored old values for next switch on: ${JSON.stringify(entity.context.STATE.storedValues)}`);
66
- }
67
- if (state.val && oldState !== 'on') {
68
- for (const attr of attributesToNullOnOff) {
69
- if (entity.attributes[attr] === null) { //make sure the attribute was not yet read from somewhere else
70
- entity.attributes[attr] = entity.context.STATE.storedValues[attr];
71
- }
72
- }
73
- adapterData.log.debug(`Restored old values from previous switch off: ${JSON.stringify(entity.context.STATE.storedValues)}`);
74
- }
76
+ clearOrRestoreAttributes(entity);
75
77
  };
76
78
 
77
79
  //prevent zigbee 'available' to become getId:
78
80
  if (getState && getState.startsWith('zigbee.') && (getState.endsWith('.available') || getState.endsWith('.device_query'))) {
79
81
  entity.context.STATE.getId = states.state;
80
82
  }
83
+
84
+ //clear initial attributes
85
+ clearOrRestoreAttributes(entity);
86
+
81
87
  if (states.state) {
82
88
  entity.context.STATE.isBoolean = objects[states.state] && objects[states.state].common && objects[states.state].common.type === 'boolean';
83
89
  entity.attributes.supported_color_modes.push(ONOFF);
@@ -96,8 +102,13 @@ function _lightAdvancedAddColorTemperature(states, objects, entity) {
96
102
  const tempObj = objects[states.color_temp];
97
103
  attribute.convert_to_mired = tempObj && tempObj.common ? (tempObj.common.unit === 'mired') : false;
98
104
  attribute.getParser = (entity, attr, state) => {
105
+ let targetAttributes = entity.attributes;
106
+ if (entity.state !== 'on') {
107
+ targetAttributes = entity.context.STATE.storedValues;
108
+ }
109
+
99
110
  if (!state || !state.val) {
100
- entity.attributes.color_temp = iobMinValueKelvin;
111
+ targetAttributes.color_temp = iobMinValueKelvin;
101
112
  return;
102
113
  }
103
114
  let targetCt = state.val;
@@ -111,9 +122,9 @@ function _lightAdvancedAddColorTemperature(states, objects, entity) {
111
122
  if (attr.convert_to_mired) {
112
123
  targetCt = 1e6 / targetCt;
113
124
  }
114
- entity.attributes.color_temp_kelvin = targetCt;
115
- entity.attributes.color_temp = 1e6 / targetCt;
116
- entity.attributes.color_mode = COLOR_TEMP;
125
+ targetAttributes.color_temp_kelvin = targetCt;
126
+ targetAttributes.color_temp = 1e6 / targetCt;
127
+ targetAttributes.color_mode = COLOR_TEMP;
117
128
  };
118
129
 
119
130
  entity.attributes.max_color_temp_kelvin = tempObj && tempObj.common && tempObj.common.max || iobMaxValueKelvin;
@@ -132,7 +143,7 @@ function _lightAdvancedAddColorTemperature(states, objects, entity) {
132
143
  adapterData.log.debug(entity.entity_id + ' ct needs mired conversion: ' + attribute.convert_to_mired);
133
144
 
134
145
  if (entity.attributes.min_color_temp_kelvin > entity.attributes.max_color_temp_kelvin) {
135
- //for kelvin conversion min and max need to be swapped.
146
+ //for kelvin conversion, min and max need to be swapped.
136
147
  const max = entity.attributes.min_color_temp_kelvin;
137
148
  entity.attributes.min_color_temp_kelvin = entity.attributes.max_color_temp_kelvin;
138
149
  entity.attributes.max_color_temp_kelvin = max;
@@ -153,13 +164,24 @@ function _lightAdvancedAddBrightness(states, objects, entity) {
153
164
  if (states.brightness) {
154
165
  const attribute = entity.context.ATTRIBUTES.find(a => a.attribute === 'brightness');
155
166
  attribute.getParser = (entity, attr, state) => {
167
+ let targetAttributes = entity.attributes;
168
+ if (entity.state !== 'on') {
169
+ targetAttributes = entity.context.STATE.storedValues;
170
+ }
171
+
156
172
  state = state || {val: 0};
157
- entity.attributes.brightness = ((state.val - attr.min) / (attr.max - attr.min)) * 255;
158
- if (states.state === states.brightness) {
159
- entity.state = entity.attributes.brightness > 0 ? 'on' : 'off';
173
+ targetAttributes.brightness = ((state.val - attr.min) / (attr.max - attr.min)) * 255;
174
+ if (!targetAttributes.color_mode || targetAttributes.color_mode === ONOFF) {
175
+ targetAttributes.color_mode = BRIGHTNESS;
160
176
  }
161
- if (!entity.attributes.color_mode || entity.attributes.color_mode === ONOFF) {
162
- entity.attributes.color_mode = BRIGHTNESS;
177
+
178
+ if (states.state === states.brightness) {
179
+ entity.state = targetAttributes.brightness > 0 ? 'on' : 'off';
180
+ clearOrRestoreAttributes(entity);
181
+
182
+ if (entity.attributes.color_mode === ONOFF) {
183
+ entity.attributes.color_mode = BRIGHTNESS;
184
+ }
163
185
  }
164
186
  };
165
187
  attribute.setId = states.brightness;
@@ -167,6 +189,11 @@ function _lightAdvancedAddBrightness(states, objects, entity) {
167
189
  attribute.min = (objects[attribute.getId] && objects[attribute.getId].common && objects[attribute.getId].common.min) || 0;
168
190
  attribute.max = (objects[attribute.getId] && objects[attribute.getId].common && objects[attribute.getId].common.max) || 100;
169
191
  entity.attributes.supported_color_modes.push(BRIGHTNESS);
192
+
193
+ if (states.state === states.brightness) {
194
+ //clear initial attributes
195
+ clearOrRestoreAttributes(entity);
196
+ }
170
197
  }
171
198
  }
172
199
 
@@ -175,12 +202,18 @@ function _lightAdvancedAddHueAndSat(states, objects, entity) {
175
202
  const hue_attr = entity.context.ATTRIBUTES.find(a => a.attribute === 'hue');
176
203
  hue_attr.max = objects[states.hue] && objects[states.hue].common && objects[states.hue].common.max || 360;
177
204
  hue_attr.getParser = (entity, attr, state) => {
205
+ let targetAttributes = entity.attributes;
206
+ if (entity.state !== 'on') {
207
+ targetAttributes = entity.context.STATE.storedValues;
208
+ }
209
+
178
210
  state = state || {val: 0};
179
- entity.attributes.hs_color[0] = state.val / attr.max * 360;
180
- entity.attributes.color_mode = HS;
211
+ targetAttributes.hs_color[0] = state.val / attr.max * 360;
212
+ targetAttributes.color_mode = HS;
181
213
  };
182
214
  entity.attributes.supported_color_modes.push(HS);
183
- entity.attributes.hs_color = [0,100];
215
+ entity.attributes.hs_color = [null,null];
216
+ entity.context.STATE.storedValues.hs_color = [0,100];
184
217
  }
185
218
 
186
219
  //add saturation as own attribute. Will update saturation values from ioBroker correctly.
@@ -193,9 +226,13 @@ function _lightAdvancedAddHueAndSat(states, objects, entity) {
193
226
  return;
194
227
  }
195
228
  sat_attr.getParser = (entity, attr, state) => {
229
+ let targetAttributes = entity.attributes;
230
+ if (entity.state !== 'on') {
231
+ targetAttributes = entity.context.STATE.storedValues;
232
+ }
196
233
  state = state || {val: 0};
197
- entity.attributes.hs_color[1] = state.val / attr.max * 100;
198
- entity.attributes.color_mode = HS;
234
+ targetAttributes.hs_color[1] = state.val / attr.max * 100;
235
+ targetAttributes.color_mode = HS;
199
236
  };
200
237
  } else {
201
238
  sat_attr.getParser = () => {}; //ignore saturation updates.
@@ -211,6 +248,10 @@ async function _lightAdvancedAddRGBSingle(states, objects, entity) {
211
248
  attribute.is_rgb_array = false;
212
249
  attribute.is_rgb_string = true;
213
250
  attribute.getParser = (entity, attr, state) => {
251
+ let targetAttributes = entity.attributes;
252
+ if (entity.state !== 'on') {
253
+ targetAttributes = entity.context.STATE.storedValues;
254
+ }
214
255
  let str = state ? (state.val || '#000000').toString() : '#000000';
215
256
  if (str[0] === '#') {
216
257
  str = str.substring(1);
@@ -229,23 +270,24 @@ async function _lightAdvancedAddRGBSingle(states, objects, entity) {
229
270
  b = parseInt(str.substring(4, 6), 16);
230
271
  }
231
272
 
232
- entity.attributes.color_mode = RGB;
233
- entity.attributes.rgb_color = [r, g, b];
273
+ targetAttributes.rgb_color = [r, g, b];
274
+ targetAttributes.color_mode = RGB;
234
275
  if (states.white) {
235
- entity.attributes.color_mode = RGBW;
236
- entity.attributes.rgbw_color[0] = r;
237
- entity.attributes.rgbw_color[1] = g;
238
- entity.attributes.rgbw_color[2] = b;
276
+ targetAttributes.color_mode = RGBW;
277
+ targetAttributes.rgbw_color[0] = r;
278
+ targetAttributes.rgbw_color[1] = g;
279
+ targetAttributes.rgbw_color[2] = b;
239
280
  }
240
281
  };
241
282
 
242
- //check if current state is rgb array.
283
+ //check if the current state is rgb array.
243
284
  const rgbState = await adapterData.adapter.getForeignStateAsync(states.rgb_color);
244
285
  if (rgbState && rgbState.val) {
245
286
  attribute.is_rgb_array = /([0-9]){1,3},([0-9]){1,3},([0-9]){1,3}/.test(rgbState.val.toString());
246
287
  }
247
288
 
248
- entity.attributes.rgb_color = [0,0,0];
289
+ entity.attributes.rgb_color = [null,null,null];
290
+ entity.context.STATE.storedValues.rgb_color = [0,0,0];
249
291
  entity.attributes.supported_color_modes.push(RGB);
250
292
  }
251
293
  }
@@ -257,13 +299,17 @@ function _lightAdvancedAddRGB(states, objects, entity) {
257
299
  const blue_attr = entity.context.ATTRIBUTES.find(a => a.attribute === 'blue');
258
300
 
259
301
  const rgbGetParser = (index, entity, attr, state) => {
302
+ let targetAttributes = entity.attributes;
303
+ if (entity.state !== 'on') {
304
+ targetAttributes = entity.context.STATE.storedValues;
305
+ }
260
306
  let val = state ? state.val || 0 : 0;
261
307
  val = val / attr.max * 255;
262
- entity.attributes.rgb_color[index] = val;
263
- if (entity.attributes.rgbw_color) {
264
- entity.attributes.rgbw_color[index] = val;
308
+ targetAttributes.rgb_color[index] = val;
309
+ if (targetAttributes.rgbw_color) {
310
+ targetAttributes.rgbw_color[index] = val;
265
311
  }
266
- entity.attributes.color_mode = states.white ? RGBW : RGB;
312
+ targetAttributes.color_mode = states.white ? RGBW : RGB;
267
313
  };
268
314
 
269
315
  red_attr.getParser = rgbGetParser.bind(this, 0);
@@ -274,7 +320,12 @@ function _lightAdvancedAddRGB(states, objects, entity) {
274
320
  blue_attr.max = objects[states.blue] && objects[states.blue].common && objects[states.blue].common.max || 100;
275
321
 
276
322
  entity.attributes.supported_color_modes.push(RGB);
277
- entity.attributes.rgb_color = [0,0,0];
323
+ entity.attributes.rgb_color = [null,null,null];
324
+ entity.context.STATE.storedValues.rgb_color = [0,0,0];
325
+ if (states.white) {
326
+ entity.attributes.rgbw_color = [null,null,null,null];
327
+ entity.context.STATE.storedValues.rgbw_color = [0,0,0,0];
328
+ }
278
329
  }
279
330
  }
280
331
 
@@ -387,7 +438,7 @@ async function _handleTurnOnCmd(entity, command, data, user) {
387
438
  // read actual state
388
439
  const state = await adapterData.adapter.getForeignStateAsync(entity.context.STATE.getId);
389
440
 
390
- // if lamp is not ON
441
+ // if the light is not ON
391
442
  if (!state || !state.val) {
392
443
  // turn ON:
393
444
  await adapterData.adapter.setForeignStateAsync(entity.context.STATE.setId, command.on, false, {user});
@@ -400,7 +451,7 @@ async function _handleTurnOnCmd(entity, command, data, user) {
400
451
  }
401
452
 
402
453
  /**
403
- * Extract relevant ids from type-detector control object.
454
+ * Extract relevant ids from the type-detector control object.
404
455
  * Result object has optional members:
405
456
  * state
406
457
  * brightness
@@ -484,6 +535,7 @@ async function fillLightEntityFromStates(states, objects, entity) {
484
535
  if (!entity.context.COMMANDS) {
485
536
  entity.context.COMMANDS = [];
486
537
  }
538
+ entity.context.STATE.storedValues = {};
487
539
 
488
540
  const white_attr = entity.context.ATTRIBUTES.find(a => a.attribute === 'white');
489
541
  if (states.white) {
@@ -493,8 +545,12 @@ async function fillLightEntityFromStates(states, objects, entity) {
493
545
  entity.attributes.supported_color_modes.push(RGBW);
494
546
  white_attr.getParser = (entity, attr, state) => {
495
547
  const val = state ? state.val || 0 : 0;
496
- entity.attributes.rgbw_color[3] = val / attr.max * 255;
497
- entity.attributes.color_mode = RGBW;
548
+ let targetAttributes = entity.attributes;
549
+ if (entity.state !== 'on') {
550
+ targetAttributes = entity.context.STATE.storedValues;
551
+ }
552
+ targetAttributes.rgbw_color[3] = val / attr.max * 255;
553
+ targetAttributes.color_mode = RGBW;
498
554
  };
499
555
  }
500
556
  }
@@ -505,7 +561,7 @@ async function fillLightEntityFromStates(states, objects, entity) {
505
561
  //fill in color temperature stuff.
506
562
  await _lightAdvancedAddColorTemperature(states, objects, entity);
507
563
 
508
- //if there is a "BRIGHTNESS" control, use it to dim lamp.
564
+ //if there is a "BRIGHTNESS" control, use it to dim the light.
509
565
  await _lightAdvancedAddBrightness(states, objects, entity);
510
566
 
511
567
  //add hue and sat:
@@ -523,7 +579,11 @@ async function fillLightEntityFromStates(states, objects, entity) {
523
579
  entity.attributes.effect_list = Object.values(effect_attr.states);
524
580
  effect_attr.getParser = (entity, attr, state) => {
525
581
  state = state || {val: 0};
526
- entity.attributes.effect = effect_attr.states[state.val];
582
+ let targetAttributes = entity.attributes;
583
+ if (entity.state !== 'on') {
584
+ targetAttributes = entity.context.STATE.storedValues;
585
+ }
586
+ targetAttributes.effect = effect_attr.states[state.val];
527
587
  };
528
588
  entity.supported_features |= SUPPORT_EFFECT;
529
589
  }
@@ -559,7 +619,7 @@ async function fillLightEntityFromStates(states, objects, entity) {
559
619
 
560
620
  /**
561
621
  * Create manual light entity.
562
- * @param id - id of "main" object, i.e. state.
622
+ * @param id - id of "main" object, i.e., state.
563
623
  * @param obj - iobroker object of id param
564
624
  * @param entity - already created entity
565
625
  * @param objects - id object cache