iobroker.lovelace 4.1.0 → 4.1.2
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 +10 -10
- package/io-package.json +18 -18
- package/lib/converters/climate.js +6 -2
- package/lib/converters/genericConverter.js +9 -7
- package/lib/modules/browser_mod.js +3 -0
- package/lib/modules/history.js +12 -9
- package/lib/modules/person.js +38 -0
- package/lib/modules/todo.js +3 -0
- package/lib/server.js +9 -30
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -473,6 +473,15 @@ After that checkout modified version in `./build` folder. Then.
|
|
|
473
473
|
PLACEHOLDER for next version:
|
|
474
474
|
### **WORK IN PROGRESS**
|
|
475
475
|
-->
|
|
476
|
+
### 4.1.2 (2024-01-09)
|
|
477
|
+
* (Garfonso) fix: time in timestamp display
|
|
478
|
+
|
|
479
|
+
### 4.1.1 (2024-01-02)
|
|
480
|
+
* (Garfonso) changed: determining user id
|
|
481
|
+
* (Garfosno) changed: history attributes handling
|
|
482
|
+
* (Garfonso) added: handle browser_mod/recall_id service call.
|
|
483
|
+
* (Garfonso) changed: all states are strings (fixes #483)
|
|
484
|
+
|
|
476
485
|
### 4.1.0 (2023-12-18)
|
|
477
486
|
* (Garfons) add an option to show users on login screen (off by default)
|
|
478
487
|
|
|
@@ -482,18 +491,9 @@ After that checkout modified version in `./build` folder. Then.
|
|
|
482
491
|
### 4.0.11 (2023-12-15)
|
|
483
492
|
* (Garfonso) updated dependencies
|
|
484
493
|
|
|
485
|
-
### 4.0.10 (2023-12-15)
|
|
486
|
-
* (Garfonso) brought back shopping list. Now also supports shopping/todo lists from manual entities.
|
|
487
|
-
* (Garfonso) fix: browser console errors
|
|
488
|
-
* (Garfonso) fix: login & authorization
|
|
489
|
-
* (Garfonso) added: user images & names on login screen
|
|
490
|
-
|
|
491
|
-
### 4.0.9 (2023-12-12)
|
|
492
|
-
* (Garfonso) fixed: timestamp in legacy history data
|
|
493
|
-
|
|
494
494
|
## License
|
|
495
495
|
|
|
496
|
-
Copyright 2019-
|
|
496
|
+
Copyright 2019-2024, bluefox <dogafox@gmail.com>
|
|
497
497
|
|
|
498
498
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
499
499
|
you may not use this file except in compliance with the License.
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "lovelace",
|
|
4
|
-
"version": "4.1.
|
|
4
|
+
"version": "4.1.2",
|
|
5
5
|
"news": {
|
|
6
|
+
"4.1.2": {
|
|
7
|
+
"en": "fix: time in timestamp display",
|
|
8
|
+
"de": "fix: zeit im zeitstempel-display",
|
|
9
|
+
"ru": "фиксация: время дисплея",
|
|
10
|
+
"pt": "correção: tempo em exibição do timestamp",
|
|
11
|
+
"nl": "fix: tijd in tijdstempelweergave",
|
|
12
|
+
"fr": "correction : temps dans l'affichage de l'horodatage",
|
|
13
|
+
"it": "correzione: tempo in visualizzazione timestamp",
|
|
14
|
+
"es": "fijación: tiempo en la pantalla de tiempo",
|
|
15
|
+
"pl": "fix: czas wyświetlania znacznika czasu",
|
|
16
|
+
"uk": "виправити: час в часовому режимі відображення",
|
|
17
|
+
"zh-cn": "修正:时间戳显示的时间"
|
|
18
|
+
},
|
|
19
|
+
"4.1.1": {
|
|
20
|
+
"en": "changed: determining user id\nchanged: history attributes handling\nadded: handle browser_mod/recall_id service call.\nchanged: all states are strings!",
|
|
21
|
+
"de": "geändert: bestimmung der benutzer-id\ngeändert: historie für attribute\nhinzugefügt: handle browser_mod/recall_id service call.\ngeändert: alle zustände sind strings!"
|
|
22
|
+
},
|
|
6
23
|
"4.1.0": {
|
|
7
24
|
"en": "add an option to show users on login screen (off by default)",
|
|
8
25
|
"de": "Neu Option um Benutzer auf dem Login-Bildschirm anzuzeigen"
|
|
@@ -40,23 +57,6 @@
|
|
|
40
57
|
"4.0.9": {
|
|
41
58
|
"en": "fixed: timestamp in legacy history data",
|
|
42
59
|
"de": "fixed: zeitstempel in alten History daten"
|
|
43
|
-
},
|
|
44
|
-
"4.0.8": {
|
|
45
|
-
"en": "re-add legacy history for custom cards",
|
|
46
|
-
"de": "re-add die alten history methoden für benutzerdefinierte karten"
|
|
47
|
-
},
|
|
48
|
-
"4.0.7": {
|
|
49
|
-
"en": "history should be working again.",
|
|
50
|
-
"de": "history sollte wieder funktionieren.",
|
|
51
|
-
"ru": "история должна работать снова.",
|
|
52
|
-
"pt": "a história deve estar a trabalhar de novo.",
|
|
53
|
-
"nl": "de geschiedenis zou weer moeten werken.",
|
|
54
|
-
"fr": "l'histoire devrait retravailler.",
|
|
55
|
-
"it": "la storia dovrebbe funzionare di nuovo.",
|
|
56
|
-
"es": "la historia debe estar trabajando de nuevo.",
|
|
57
|
-
"pl": "historia powinna być kontynuowana.",
|
|
58
|
-
"uk": "історія повинна працювати знову.",
|
|
59
|
-
"zh-cn": "历史应该再次发挥作用。."
|
|
60
60
|
}
|
|
61
61
|
},
|
|
62
62
|
"title": "Visualization with Lovelace-UI",
|
|
@@ -237,11 +237,15 @@ function fillClimateEntityFromStates(states, objects, entity, iobType) {
|
|
|
237
237
|
|
|
238
238
|
//controls hvac_mode which can be 'off' but not 'on', so translate 'on' to heat / cool depending on type.
|
|
239
239
|
if (states.state || states.stateRead) {
|
|
240
|
+
if (!entity.attributes.hvac_modes) {
|
|
241
|
+
entity.attributes.hvac_modes = [];
|
|
242
|
+
}
|
|
243
|
+
entity.attributes.hvac_modes.push('off');
|
|
240
244
|
if (!states.hvac_mode) {
|
|
241
245
|
if (iobType === typeDetector.Types.airCondition) {
|
|
242
|
-
entity.attributes.hvac_modes
|
|
246
|
+
entity.attributes.hvac_modes.push('cool');
|
|
243
247
|
} else {
|
|
244
|
-
entity.attributes.hvac_modes
|
|
248
|
+
entity.attributes.hvac_modes.push('heat');
|
|
245
249
|
}
|
|
246
250
|
}
|
|
247
251
|
entity.context.STATE.getParser = function (entity, attr, state) {
|
|
@@ -48,8 +48,6 @@ exports.numericDeviceClasses = [
|
|
|
48
48
|
'distance'
|
|
49
49
|
];
|
|
50
50
|
|
|
51
|
-
const numericDeviceClassesIob = exports.numericDeviceClasses.concat(['timestamp']);
|
|
52
|
-
|
|
53
51
|
exports.iobState2EntityState = function (entity, val, attribute) {
|
|
54
52
|
let type = entity.context.type;
|
|
55
53
|
const pos = type.lastIndexOf('.');
|
|
@@ -61,14 +59,18 @@ exports.iobState2EntityState = function (entity, val, attribute) {
|
|
|
61
59
|
return val ? 'on' : 'off';
|
|
62
60
|
} else if (type === 'binary_sensor') {
|
|
63
61
|
return val ? 'on' : 'off';
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
62
|
+
}else if (typeof val === 'number' && entity.attributes && ['date', 'timestamp'].includes(entity.attributes.device_class)) {
|
|
63
|
+
//convert to date string
|
|
64
|
+
const date = new Date(val);
|
|
65
|
+
let dateStr = date.toDateString();
|
|
66
|
+
if (entity.attributes.device_class === 'timestamp') {
|
|
67
|
+
dateStr = date.toISOString();
|
|
68
|
+
}
|
|
69
|
+
console.log('Sending', dateStr, '-', typeof dateStr);
|
|
68
70
|
return dateStr === 'Invalid Date' ? 'unknown' : dateStr;
|
|
69
71
|
} else if (type === 'lock') {
|
|
70
72
|
return val ? 'unlocked' : 'locked';
|
|
71
|
-
} else if (typeof val === 'boolean' && type !== 'media_player') {
|
|
73
|
+
} else if (typeof val === 'boolean' && type !== 'media_player' && !attribute) { //attributes can have true/false.
|
|
72
74
|
return val ? 'on' : 'off';
|
|
73
75
|
} else if (typeof val === 'number' && entity.context.STATE.map2lovelace) {
|
|
74
76
|
return entity.context.STATE.map2lovelace[val] || val;
|
|
@@ -344,6 +344,7 @@ class BrowserModModule {
|
|
|
344
344
|
instance: message.browserID,
|
|
345
345
|
ws
|
|
346
346
|
};
|
|
347
|
+
ws.browserID = message.browserID; //store browserID in ws object to handle recall service call later.
|
|
347
348
|
|
|
348
349
|
ws.send(JSON.stringify([{id: message.id, type: 'result', success: true, result: null}, {
|
|
349
350
|
id: message.id, type: 'event', event: {
|
|
@@ -399,6 +400,8 @@ class BrowserModModule {
|
|
|
399
400
|
this.adapter.log.debug('Updated browser_mod settings: ' + message.key + ' to ' + message.value);
|
|
400
401
|
}
|
|
401
402
|
//think about making this permanent somehow? -> but only if we find a way to allow browser_mod_settings panel.
|
|
403
|
+
} else if (method === 'recall_id') {
|
|
404
|
+
ws.send(JSON.stringify({id: message.id, type: 'result', success: true, result: ws.browserID}));
|
|
402
405
|
} else {
|
|
403
406
|
this.adapter.log.warn('Unknown browser_mod method: ' + JSON.stringify(message));
|
|
404
407
|
}
|
package/lib/modules/history.js
CHANGED
|
@@ -67,7 +67,7 @@ async function getHistory(adapter, entities, start, end, noAttributes, user) {
|
|
|
67
67
|
}
|
|
68
68
|
let found = false;
|
|
69
69
|
let best = null;
|
|
70
|
-
let bestDiff =
|
|
70
|
+
let bestDiff = 10000;
|
|
71
71
|
const results = attributesResult[attribute.attribute].result;
|
|
72
72
|
for (const result of results) {
|
|
73
73
|
if (result.val !== null) {
|
|
@@ -81,10 +81,10 @@ async function getHistory(adapter, entities, start, end, noAttributes, user) {
|
|
|
81
81
|
}
|
|
82
82
|
if (found) {
|
|
83
83
|
attributeValues[attribute.attribute] = typeof attribute.historyParser === 'function' ? attribute.historyParser(id, best.val) : best.val;
|
|
84
|
-
best.used = true;
|
|
85
|
-
} else {
|
|
84
|
+
best.used = true; //will be checked later, all "unused" attributes will be added without state later.
|
|
85
|
+
} /*else { //let's try to leave attribute empty, for now, if no value in history that is closer than 10 seconds.
|
|
86
86
|
attributeValues[attribute.attribute] = entity.attributes[attribute.attribute]; //use current value as default if none found.
|
|
87
|
-
}
|
|
87
|
+
}*/
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
for (const key of Object.keys(entity.attributes)) {
|
|
@@ -103,7 +103,7 @@ async function getHistory(adapter, entities, start, end, noAttributes, user) {
|
|
|
103
103
|
s: typeof entity.context.STATE.historyParser === 'function' ?
|
|
104
104
|
entity.context.STATE.historyParser(id, e.val).toString() :
|
|
105
105
|
iobState2EntityState(entity, e.val),
|
|
106
|
-
a: noAttributes ?
|
|
106
|
+
a: noAttributes ? {} : getAttributeValues(e, attributesResult, attributesUsed),
|
|
107
107
|
lc: 1,
|
|
108
108
|
lu: 1
|
|
109
109
|
};
|
|
@@ -113,6 +113,8 @@ async function getHistory(adapter, entities, start, end, noAttributes, user) {
|
|
|
113
113
|
//add unused attribute values:
|
|
114
114
|
if (!noAttributes && entity.context.ATTRIBUTES) {
|
|
115
115
|
for (const attribute of entity.context.ATTRIBUTES) {
|
|
116
|
+
//find other attributes for this type. Will use this attribute as "state" for the getAttributeValues function.
|
|
117
|
+
// so we don't want to find this attribute again. Will add all matching attributes anyway. So in later runs this attribute will be "empty", i.e. all used.
|
|
116
118
|
attributesUsed.push(attribute.attribute);
|
|
117
119
|
const results = attributesResult[attribute.attribute].result;
|
|
118
120
|
for (const result of results) {
|
|
@@ -125,7 +127,7 @@ async function getHistory(adapter, entities, start, end, noAttributes, user) {
|
|
|
125
127
|
//state: null,
|
|
126
128
|
lc: 1,
|
|
127
129
|
lu: 1,
|
|
128
|
-
a: noAttributes ?
|
|
130
|
+
a: noAttributes ? {} : getAttributeValues(result, attributesResult, attributesUsed, attributeValues)
|
|
129
131
|
};
|
|
130
132
|
updateTimestamps(data, result, true);
|
|
131
133
|
historyPerEntity.push(data);
|
|
@@ -137,6 +139,7 @@ async function getHistory(adapter, entities, start, end, noAttributes, user) {
|
|
|
137
139
|
if (historyPerEntity.length === 0) {
|
|
138
140
|
historyPerEntity.push({
|
|
139
141
|
s: entity.state,
|
|
142
|
+
a: {},
|
|
140
143
|
lu: start / 1000
|
|
141
144
|
});
|
|
142
145
|
}
|
|
@@ -177,12 +180,12 @@ function sendHistoryResponse(ws, id, historyData, parameters) {
|
|
|
177
180
|
state.s = 'unknown';
|
|
178
181
|
}
|
|
179
182
|
|
|
180
|
-
if (parameters.noAttributes) {
|
|
183
|
+
/*if (parameters.noAttributes) {
|
|
181
184
|
delete state.a;
|
|
182
185
|
}
|
|
183
186
|
if (parameters.minimalResponse) {
|
|
184
187
|
delete state.lc;
|
|
185
|
-
}
|
|
188
|
+
}*/
|
|
186
189
|
}
|
|
187
190
|
}
|
|
188
191
|
|
|
@@ -275,7 +278,7 @@ class HistoryModule {
|
|
|
275
278
|
id: Number(message.id)
|
|
276
279
|
};
|
|
277
280
|
|
|
278
|
-
// add
|
|
281
|
+
// add subscription here.
|
|
279
282
|
ws._subscribes.history = ws._subscribes.history || [];
|
|
280
283
|
ws._subscribes.history.push(parameters);
|
|
281
284
|
} else if (message.type === 'history/history_during_period') {
|
package/lib/modules/person.js
CHANGED
|
@@ -22,6 +22,27 @@ class PersonModule {
|
|
|
22
22
|
return result;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Get the user id from the username
|
|
27
|
+
* @param {string} name
|
|
28
|
+
* @returns {string}
|
|
29
|
+
*/
|
|
30
|
+
getUserIDFromName(name) {
|
|
31
|
+
for (const userObj of Object.values(this.usersCache)) {
|
|
32
|
+
if (userObj.name === name) {
|
|
33
|
+
return userObj.iobId;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
//fallback, default user "admin" is misleading, if user renamed admin.. hm. :-/
|
|
38
|
+
if (this.adapter.config.auth && name === 'admin') {
|
|
39
|
+
return 'system.user.admin';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.adapter.log.warn(`Could not get user id for ${name} - Trying with username` + JSON.stringify(this.usersCache['system.user.' + name.toLowerCase()]));
|
|
43
|
+
return 'system.user.' + name.toLowerCase(); //hack and not correct since js-controller 3.2
|
|
44
|
+
}
|
|
45
|
+
|
|
25
46
|
onObjectChange(id, obj) {
|
|
26
47
|
if (id.startsWith('system.user.')) {
|
|
27
48
|
if (obj && obj.common && obj.common.enabled()) {
|
|
@@ -41,6 +62,7 @@ class PersonModule {
|
|
|
41
62
|
|
|
42
63
|
async init() {
|
|
43
64
|
const userObjects = await this.adapter.getForeignObjectsAsync('system.user.*', 'user');
|
|
65
|
+
let defaultUserObject = null;
|
|
44
66
|
for (const [id, obj] of Object.entries(userObjects)) {
|
|
45
67
|
if (obj.common && obj.common.enabled) { //only show enabled persons?
|
|
46
68
|
this.usersCache[id] = {
|
|
@@ -50,8 +72,24 @@ class PersonModule {
|
|
|
50
72
|
picture: obj.common.icon,
|
|
51
73
|
description: obj.common.desc
|
|
52
74
|
};
|
|
75
|
+
if (obj.common.name === this.adapter.config.defaultUser) {
|
|
76
|
+
defaultUserObject = obj;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
//default user only relevant for !auth.
|
|
82
|
+
if (!defaultUserObject) {
|
|
83
|
+
//Ok, we did not find defaultUser object. Might be renamed admin?
|
|
84
|
+
defaultUserObject = userObjects['system.user.admin'];
|
|
85
|
+
this.adapter.config.defaultUser = defaultUserObject.common.name;
|
|
86
|
+
if (this.adapter.config.defaultUser !== 'admin' && !this.adapter.config.auth) {
|
|
87
|
+
//Activating auth will hide this setting. Not sure what to do then... In general: all users will be able to read everything in this case.
|
|
88
|
+
this.adapter.log.warn(`Could not find default user ${this.adapter.config.defaultUser} - Using admin - Please update your configuration.`);
|
|
53
89
|
}
|
|
54
90
|
}
|
|
91
|
+
|
|
92
|
+
|
|
55
93
|
await this.adapter.subscribeObjectsAsync('system.user.*');
|
|
56
94
|
}
|
|
57
95
|
}
|
package/lib/modules/todo.js
CHANGED
|
@@ -181,6 +181,9 @@ class TodoModule {
|
|
|
181
181
|
if (state && state.val) {
|
|
182
182
|
try {
|
|
183
183
|
todoList.items = JSON.parse(state.val);
|
|
184
|
+
if (!todoList.items || !Array.isArray(todoList.items)) {
|
|
185
|
+
todoList.items = [];
|
|
186
|
+
}
|
|
184
187
|
//convert legacy items:
|
|
185
188
|
for (const item of todoList.items) {
|
|
186
189
|
if (item.name && !item.summary) {
|
package/lib/server.js
CHANGED
|
@@ -518,7 +518,7 @@ class WebServer {
|
|
|
518
518
|
}
|
|
519
519
|
|
|
520
520
|
async _processSingleCall(ws, data, entity_id) {
|
|
521
|
-
const user =
|
|
521
|
+
const user = this._modules.person.getUserIDFromName(ws.__auth.username || this.config.defaultUser);
|
|
522
522
|
|
|
523
523
|
const entity = entityData.entityId2Entity[entity_id];
|
|
524
524
|
const id = entity.context.STATE.setId;
|
|
@@ -681,7 +681,7 @@ class WebServer {
|
|
|
681
681
|
entity.state = 'unknown';
|
|
682
682
|
if (entity.context.STATE && entity.context.STATE.getId) {
|
|
683
683
|
try {
|
|
684
|
-
const user =
|
|
684
|
+
const user = this._modules.person.getUserIDFromName(this.config.defaultUser); //TODO: why is this always defaultUser?
|
|
685
685
|
const state = await this.adapter.getForeignStateAsync(entity.context.STATE.getId, {user});
|
|
686
686
|
if (state) {
|
|
687
687
|
await this.onStateChange(entity.context.STATE.getId, state);
|
|
@@ -1477,7 +1477,7 @@ class WebServer {
|
|
|
1477
1477
|
file = file.substring(0, pos);
|
|
1478
1478
|
}
|
|
1479
1479
|
try {
|
|
1480
|
-
const user =
|
|
1480
|
+
const user = this._modules.person.getUserIDFromName(this.config.defaultUser); //TODO: why is this always default user?
|
|
1481
1481
|
let data;
|
|
1482
1482
|
if (file.startsWith('/lovelace/')) {
|
|
1483
1483
|
file = file.replace('/lovelace/', '');
|
|
@@ -1501,7 +1501,7 @@ class WebServer {
|
|
|
1501
1501
|
file = file.substring(0, pos);
|
|
1502
1502
|
}
|
|
1503
1503
|
try {
|
|
1504
|
-
const user =
|
|
1504
|
+
const user = this._modules.person.getUserIDFromName(this.config.defaultUser); //TODO: why is this always default user?
|
|
1505
1505
|
const data = await this.adapter.readFileAsync(this.adapter.namespace, file.replace('/local/custom_ui/', '/cards/'), {user});
|
|
1506
1506
|
const pos = req.url.lastIndexOf('.');
|
|
1507
1507
|
res.setHeader('content-type', (mime.getType || mime.lookup).call(data.mimeType, file.substring(pos + 1).toLowerCase()));
|
|
@@ -1844,7 +1844,7 @@ class WebServer {
|
|
|
1844
1844
|
}
|
|
1845
1845
|
|
|
1846
1846
|
try {
|
|
1847
|
-
const user =
|
|
1847
|
+
const user = this._modules.person.getUserIDFromName(this.config.defaultUser); //TODO: why is this always default user?
|
|
1848
1848
|
const image = await this.adapter.readFileAsync(id, url, {user});
|
|
1849
1849
|
if (image.file === null || image.file === undefined) {
|
|
1850
1850
|
throw new Error('File empty');
|
|
@@ -1868,7 +1868,7 @@ class WebServer {
|
|
|
1868
1868
|
if (obj && obj.common.type === 'file') {
|
|
1869
1869
|
contentType = (mime.getType || mime.lookup).call(mime, fileName[0]);
|
|
1870
1870
|
}
|
|
1871
|
-
const user =
|
|
1871
|
+
const user = this._modules.person.getUserIDFromName(this.config.defaultUser);
|
|
1872
1872
|
const data = await this.adapter.getBinaryStateAsync(fileName[0], {user});
|
|
1873
1873
|
if (data !== null && obj !== undefined) {
|
|
1874
1874
|
if (data && typeof data === 'object' && data.val !== undefined && data.ack !== undefined) {
|
|
@@ -1937,7 +1937,7 @@ class WebServer {
|
|
|
1937
1937
|
return res.status(404).json({error: 'Start or end misformated'});
|
|
1938
1938
|
}
|
|
1939
1939
|
|
|
1940
|
-
const user =
|
|
1940
|
+
const user = this._modules.person.getUserIDFromName(this.config.defaultUser);
|
|
1941
1941
|
try {
|
|
1942
1942
|
const state = await this.adapter.getForeignStateAsync(entity.context.STATE.getId, {user});
|
|
1943
1943
|
if (state && state.val) {
|
|
@@ -2018,29 +2018,8 @@ class WebServer {
|
|
|
2018
2018
|
});
|
|
2019
2019
|
}
|
|
2020
2020
|
|
|
2021
|
-
async _getUserId(user) {
|
|
2022
|
-
let userId = this._userNamesToIds[user];
|
|
2023
|
-
if (userId) {
|
|
2024
|
-
return userId;
|
|
2025
|
-
}
|
|
2026
|
-
|
|
2027
|
-
if (typeof this.adapter.getUserID === 'function') {
|
|
2028
|
-
try {
|
|
2029
|
-
userId = await this.adapter.getUserID(user);
|
|
2030
|
-
this._userNamesToIds[user] = userId;
|
|
2031
|
-
} catch (err) {
|
|
2032
|
-
this.log.warn(`Could not get user id for ${user} - ${err}`);
|
|
2033
|
-
}
|
|
2034
|
-
}
|
|
2035
|
-
if (!userId) {
|
|
2036
|
-
this.log.warn(`Could not get user id for ${user} - Trying with username`);
|
|
2037
|
-
userId = 'system.user.' + user.toLowerCase(); //hack and not correct since js-controller 3.2
|
|
2038
|
-
}
|
|
2039
|
-
return userId;
|
|
2040
|
-
}
|
|
2041
|
-
|
|
2042
2021
|
async _getCurrentUser(ws) {
|
|
2043
|
-
const user =
|
|
2022
|
+
const user = this._modules.person.getUserIDFromName(ws.__auth.username || this.config.defaultUser);
|
|
2044
2023
|
const userObj = {
|
|
2045
2024
|
id: user,
|
|
2046
2025
|
name: ws.__auth.username || this.config.defaultUser,
|
|
@@ -2159,7 +2138,7 @@ class WebServer {
|
|
|
2159
2138
|
}
|
|
2160
2139
|
if (id) {
|
|
2161
2140
|
try {
|
|
2162
|
-
const user =
|
|
2141
|
+
const user = this._modules.person.getUserIDFromName(userName);
|
|
2163
2142
|
const state = await this.adapter.getForeignStateAsync(id, {user});
|
|
2164
2143
|
if (state && state.val && typeof state.val === 'string') {
|
|
2165
2144
|
const val = state.val.split('?')[0] || '';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.lovelace",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.2",
|
|
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": "^3.0.4",
|
|
23
|
-
"axios": "^1.6.
|
|
23
|
+
"axios": "^1.6.3",
|
|
24
24
|
"body-parser": "^1.20.2",
|
|
25
25
|
"express": "^4.18.2",
|
|
26
26
|
"iobroker.type-detector": "^3.0.5",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"nyc": "^15.1.0",
|
|
32
32
|
"pinyin": "^3.1.0",
|
|
33
33
|
"translit-rus-eng": "^1.0.8",
|
|
34
|
-
"ws": "^8.
|
|
34
|
+
"ws": "^8.16.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@alcalzone/release-script": "^3.7.0",
|
|
@@ -44,13 +44,13 @@
|
|
|
44
44
|
"@types/chai-as-promised": "^7.1.8",
|
|
45
45
|
"@types/gulp": "^4.0.17",
|
|
46
46
|
"@types/mocha": "^10.0.6",
|
|
47
|
-
"@types/node": "^16.18.
|
|
47
|
+
"@types/node": "^16.18.69 < 17",
|
|
48
48
|
"@types/proxyquire": "^1.3.31",
|
|
49
49
|
"@types/sinon": "^17.0.2",
|
|
50
50
|
"@types/sinon-chai": "^3.2.12",
|
|
51
51
|
"chai": "^4.3.10",
|
|
52
52
|
"chai-as-promised": "^7.1.1",
|
|
53
|
-
"eslint": "^8.
|
|
53
|
+
"eslint": "^8.56.0",
|
|
54
54
|
"gulp": "^4.0.2",
|
|
55
55
|
"mocha": "^10.2.0",
|
|
56
56
|
"proxyquire": "^2.1.3",
|