iobroker.lorawan 1.20.22 → 1.20.24
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 +6 -0
- package/admin/icons/PowerOn.png +0 -0
- package/admin/icons/sensor.contact.png +0 -0
- package/io-package.json +27 -27
- package/lib/modules/deviceManager.js +102 -82
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,12 @@ For now there is documentation in English here: https://wiki.hafenmeister.de
|
|
|
23
23
|
Placeholder for the next version (at the beginning of the line):
|
|
24
24
|
### **WORK IN PROGRESS**
|
|
25
25
|
-->
|
|
26
|
+
### 1.20.24 (2026-01-28)
|
|
27
|
+
* (BenAhrdt) change info Form to Detail button
|
|
28
|
+
|
|
29
|
+
### 1.20.23 (2026-01-28)
|
|
30
|
+
* (BenAhrdt) change role display and icons
|
|
31
|
+
|
|
26
32
|
### 1.20.22 (2026-01-27)
|
|
27
33
|
* (BenAhrdt) change preasure quere to pressure
|
|
28
34
|
|
|
Binary file
|
|
Binary file
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "lorawan",
|
|
4
|
-
"version": "1.20.
|
|
4
|
+
"version": "1.20.24",
|
|
5
5
|
"news": {
|
|
6
|
+
"1.20.24": {
|
|
7
|
+
"en": "change info Form to Detail button",
|
|
8
|
+
"de": "änderungen Formular zum Detail Knopf",
|
|
9
|
+
"ru": "изменить информацию Форма для детализации кнопки",
|
|
10
|
+
"pt": "alterar informações Botão de Formulário para Detalhe",
|
|
11
|
+
"nl": "info wijzigen Vorm naar detailknop",
|
|
12
|
+
"fr": "modifier les informations Formulaire au bouton Détail",
|
|
13
|
+
"it": "cambiare le informazioni Modulo per Dettaglio pulsante",
|
|
14
|
+
"es": "cambio de información Forma al botón Detalle",
|
|
15
|
+
"pl": "zmiana informacji Format do przycisku Szczegóły",
|
|
16
|
+
"uk": "зміна інформації Форма для докладної кнопки",
|
|
17
|
+
"zh-cn": "更改信息 详细按钮的窗体"
|
|
18
|
+
},
|
|
19
|
+
"1.20.23": {
|
|
20
|
+
"en": "change role display and icons",
|
|
21
|
+
"de": "rollenanzeige und icons ändern",
|
|
22
|
+
"ru": "изменить отображение ролей и иконки",
|
|
23
|
+
"pt": "alterar a exibição de funções e ícones",
|
|
24
|
+
"nl": "rolweergave en pictogrammen wijzigen",
|
|
25
|
+
"fr": "modifier l'affichage des rôles et les icônes",
|
|
26
|
+
"it": "modifica visualizzazione del ruolo e icone",
|
|
27
|
+
"es": "función de cambio de visualización e iconos",
|
|
28
|
+
"pl": "zmienić wyświetlacz ról i ikony",
|
|
29
|
+
"uk": "змінити відображення ролі та іконки",
|
|
30
|
+
"zh-cn": "更改角色显示和图标"
|
|
31
|
+
},
|
|
6
32
|
"1.20.22": {
|
|
7
33
|
"en": "change preasure quere to pressure",
|
|
8
34
|
"de": "voreinstellungsanfrage zum druck ändern",
|
|
@@ -67,32 +93,6 @@
|
|
|
67
93
|
"pl": "nadchodzące nazewnictwo bugfix Temat",
|
|
68
94
|
"uk": "виправлення ім'я користувача Головна",
|
|
69
95
|
"zh-cn": "正在接收错误修正名称 专题"
|
|
70
|
-
},
|
|
71
|
-
"1.20.17": {
|
|
72
|
-
"en": "implement Device details",
|
|
73
|
-
"de": "durchführung Gerätedetails",
|
|
74
|
-
"ru": "осуществлять Детали устройства",
|
|
75
|
-
"pt": "implementar Detalhes do dispositivo",
|
|
76
|
-
"nl": "implementeren Apparaatdetails",
|
|
77
|
-
"fr": "mise en œuvre Détails du périphérique",
|
|
78
|
-
"it": "attuazione Dettagli del dispositivo",
|
|
79
|
-
"es": "aplicación Detalles del dispositivo",
|
|
80
|
-
"pl": "wdrożenie Szczegóły dotyczące urządzenia",
|
|
81
|
-
"uk": "реалізація Деталі пристрою",
|
|
82
|
-
"zh-cn": "执行 设备细节"
|
|
83
|
-
},
|
|
84
|
-
"1.20.16": {
|
|
85
|
-
"en": "add informations to device Manager",
|
|
86
|
-
"de": "informationen zum Gerätemanager hinzufügen",
|
|
87
|
-
"ru": "добавление информации в диспетчер устройств",
|
|
88
|
-
"pt": "adicionar informações ao gerenciador de dispositivos",
|
|
89
|
-
"nl": "informatie toevoegen aan apparaatbeheer",
|
|
90
|
-
"fr": "ajouter des informations au gestionnaire de périphériques",
|
|
91
|
-
"it": "aggiungere informazioni al gestore del dispositivo",
|
|
92
|
-
"es": "añadir información al administrador del dispositivo",
|
|
93
|
-
"pl": "dodać informacje do urządzenia Manager",
|
|
94
|
-
"uk": "додати інформацію в диспетчер пристроїв",
|
|
95
|
-
"zh-cn": "向设备管理器添加信息"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
|
@@ -16,6 +16,7 @@ class LoRaWANDeviceManagement extends DeviceManagement {
|
|
|
16
16
|
this.adapter = adapter;
|
|
17
17
|
this.x = adapter;
|
|
18
18
|
}
|
|
19
|
+
|
|
19
20
|
/**
|
|
20
21
|
* List all LoRaWAN devices
|
|
21
22
|
*/
|
|
@@ -23,36 +24,36 @@ class LoRaWANDeviceManagement extends DeviceManagement {
|
|
|
23
24
|
// @ts-expect-error
|
|
24
25
|
async listDevices() {
|
|
25
26
|
const arrDevices = [];
|
|
26
|
-
for (const [
|
|
27
|
+
for (const [devEUI, deviceValue] of Object.entries(this.adapter.objectStore.devices)) {
|
|
27
28
|
// Check for logging
|
|
28
|
-
this.adapter.log[this.adapter.logtypes.listDevices]?.(`List device started for device: ${
|
|
29
|
+
this.adapter.log[this.adapter.logtypes.listDevices]?.(`List device started for device: ${devEUI}`);
|
|
29
30
|
const res = {
|
|
30
|
-
id:
|
|
31
|
-
name:
|
|
32
|
-
icon: await this.getIcon(
|
|
31
|
+
id: devEUI,
|
|
32
|
+
name: deviceValue.object.common.name,
|
|
33
|
+
icon: await this.getIcon(deviceValue),
|
|
33
34
|
manufacturer: 'LoRaWAN',
|
|
34
|
-
model:
|
|
35
|
-
status: await this.getStatus(
|
|
36
|
-
hasDetails:
|
|
35
|
+
model: deviceValue.informations ? deviceValue.informations.devicetype.state.val : undefined, // - ${value.uplink.remaining.rxInfo[0].rssi.ts}`,
|
|
36
|
+
status: await this.getStatus(deviceValue),
|
|
37
|
+
hasDetails: true,
|
|
37
38
|
actions: [
|
|
38
39
|
{
|
|
39
40
|
id: 'rename',
|
|
40
41
|
icon: 'edit',
|
|
41
42
|
description: this.adapter.i18nTranslation['Rename this device'],
|
|
42
|
-
handler: async (_id, context) => await this.handleRenameDevice(_id, context,
|
|
43
|
+
handler: async (_id, context) => await this.handleRenameDevice(_id, context, deviceValue),
|
|
43
44
|
},
|
|
44
45
|
{
|
|
45
46
|
id: 'config',
|
|
46
47
|
icon: 'settings',
|
|
47
48
|
description: this.adapter.i18nTranslation['Config this device'],
|
|
48
|
-
handler: async (_id, context) => await this.handleConfigDevice(_id, context,
|
|
49
|
+
handler: async (_id, context) => await this.handleConfigDevice(_id, context, deviceValue),
|
|
49
50
|
},
|
|
50
|
-
{
|
|
51
|
+
/* {
|
|
51
52
|
id: 'Info',
|
|
52
53
|
icon: 'lines',
|
|
53
54
|
description: this.adapter.i18nTranslation['Info of this device'],
|
|
54
55
|
handler: async (_id, context) => await this.handleInfo(_id, context),
|
|
55
|
-
},
|
|
56
|
+
}, Outcommented at 28.01.2026 (use Details)*/
|
|
56
57
|
],
|
|
57
58
|
};
|
|
58
59
|
arrDevices.push(res);
|
|
@@ -149,6 +150,8 @@ class LoRaWANDeviceManagement extends DeviceManagement {
|
|
|
149
150
|
return possibleIcons.door;
|
|
150
151
|
} else if (deviceValue.detectedRoles['sensor.window']) {
|
|
151
152
|
return possibleIcons.window;
|
|
153
|
+
} else if (deviceValue.detectedRoles['sensor.contact']) {
|
|
154
|
+
return `/adapter/${this.adapter.name}/icons/sensor.contact.png`;
|
|
152
155
|
} else if (deviceValue.detectedRoles['value.temperature']) {
|
|
153
156
|
if (deviceValue.detectedRoles['value.pressure']) {
|
|
154
157
|
return possibleIcons.weatherCurrent;
|
|
@@ -159,7 +162,7 @@ class LoRaWANDeviceManagement extends DeviceManagement {
|
|
|
159
162
|
return possibleIcons.temperature;
|
|
160
163
|
}
|
|
161
164
|
}
|
|
162
|
-
return
|
|
165
|
+
return possibleIcons.hub5; //`/adapter/${this.adapter.name}/icons/Node.png`; //${value.object.common.icon}`,
|
|
163
166
|
}
|
|
164
167
|
|
|
165
168
|
/**
|
|
@@ -247,8 +250,9 @@ class LoRaWANDeviceManagement extends DeviceManagement {
|
|
|
247
250
|
* @param id ID to rename
|
|
248
251
|
* @param context context sendet from Backend
|
|
249
252
|
*/
|
|
250
|
-
async handleInfo(id, context) {
|
|
253
|
+
/*async handleInfo(id, context) {
|
|
251
254
|
const generalItems = {};
|
|
255
|
+
const data = {};
|
|
252
256
|
const lastUplinkTs = new Date(
|
|
253
257
|
this.adapter.objectStore.devices[id].informations.lastUplink.state.ts,
|
|
254
258
|
).toLocaleString('de-DE', {
|
|
@@ -285,8 +289,6 @@ class LoRaWANDeviceManagement extends DeviceManagement {
|
|
|
285
289
|
size: 16,
|
|
286
290
|
data: lastJoinedLc,
|
|
287
291
|
};
|
|
288
|
-
} else {
|
|
289
|
-
this.adapter.log.warn(JSON.stringify(this.adapter.objectStore.devices[id].join));
|
|
290
292
|
}
|
|
291
293
|
|
|
292
294
|
generalItems['uplinkDecodedHeader'] = {
|
|
@@ -309,13 +311,16 @@ class LoRaWANDeviceManagement extends DeviceManagement {
|
|
|
309
311
|
continue;
|
|
310
312
|
}
|
|
311
313
|
for (const subfolder in value) {
|
|
314
|
+
if (!subfolder.startsWith('uplink') && subfolder !== 'downlink.control') {
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
312
317
|
if (!subfolders[subfolder]) {
|
|
313
318
|
subfolders[subfolder] = {};
|
|
314
319
|
}
|
|
315
|
-
subfolders[subfolder][key] =
|
|
320
|
+
subfolders[subfolder][key] = value[subfolder];
|
|
316
321
|
}
|
|
317
322
|
}
|
|
318
|
-
subfolders =
|
|
323
|
+
subfolders = this.sortObjectDeep(subfolders);
|
|
319
324
|
const roleItems = {};
|
|
320
325
|
for (const subfolder in subfolders) {
|
|
321
326
|
roleItems[subfolder] = {
|
|
@@ -324,17 +329,15 @@ class LoRaWANDeviceManagement extends DeviceManagement {
|
|
|
324
329
|
text: subfolder,
|
|
325
330
|
size: 3,
|
|
326
331
|
};
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
.
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
type: 'staticText',
|
|
335
|
-
text: detectedRoles,
|
|
336
|
-
size: 10,
|
|
332
|
+
const detectedRoles = Object.entries(subfolders[subfolder])
|
|
333
|
+
.map(([key, value]) => `${key}(${value})`)
|
|
334
|
+
.join(' ');
|
|
335
|
+
roleItems[`${subfolder.replace(/\./g, '_')}Roles`] = {
|
|
336
|
+
type: 'text',
|
|
337
|
+
minRows: 2,
|
|
338
|
+
readOnly: true,
|
|
337
339
|
};
|
|
340
|
+
data[`${subfolder.replace(/\./g, '_')}Roles`] = detectedRoles;
|
|
338
341
|
}
|
|
339
342
|
const schema = {
|
|
340
343
|
type: 'tabs',
|
|
@@ -354,18 +357,35 @@ class LoRaWANDeviceManagement extends DeviceManagement {
|
|
|
354
357
|
|
|
355
358
|
let deviceInfo = await this.adapter.getStateAsync('info.deviceinformations');
|
|
356
359
|
deviceInfo = JSON.parse(deviceInfo.val);
|
|
360
|
+
const sortedUplinkDecoded = this.sortObjectDeep(deviceInfo[id].uplink.decoded);
|
|
361
|
+
data.uplinkDecoded = JSON.stringify(sortedUplinkDecoded, null, 2);
|
|
357
362
|
const options = {
|
|
358
|
-
data
|
|
359
|
-
uplinkDecoded: JSON.stringify(
|
|
360
|
-
deviceInfo[id].uplink.decoded,
|
|
361
|
-
Object.keys(deviceInfo[id].uplink.decoded).sort(),
|
|
362
|
-
2,
|
|
363
|
-
),
|
|
364
|
-
},
|
|
363
|
+
data,
|
|
365
364
|
title: this.adapter.i18nTranslation['Info of this device'],
|
|
366
365
|
};
|
|
367
366
|
await context.showForm(schema, options);
|
|
368
367
|
return { refresh: true };
|
|
368
|
+
} Outcommented at 28.01.2026 (use Details)*/
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
*
|
|
372
|
+
* @param object Object to sort
|
|
373
|
+
*/
|
|
374
|
+
sortObjectDeep(object) {
|
|
375
|
+
if (Array.isArray(object)) {
|
|
376
|
+
return object.map(this.sortObjectDeep);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (object !== null && typeof object === 'object') {
|
|
380
|
+
return Object.keys(object)
|
|
381
|
+
.sort((a, b) => a.localeCompare(b))
|
|
382
|
+
.reduce((acc, key) => {
|
|
383
|
+
acc[key] = this.sortObjectDeep(object[key]);
|
|
384
|
+
return acc;
|
|
385
|
+
}, {});
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return object;
|
|
369
389
|
}
|
|
370
390
|
|
|
371
391
|
/**
|
|
@@ -373,7 +393,10 @@ class LoRaWANDeviceManagement extends DeviceManagement {
|
|
|
373
393
|
* @returns {Promise<import('@iobroker/dm-utils').DeviceDetails>} return the right value
|
|
374
394
|
*/
|
|
375
395
|
async getDeviceDetails(id) {
|
|
396
|
+
// eslint-disable-next-line jsdoc/check-tag-names
|
|
397
|
+
/** @type {Record<string, import('@iobroker/dm-utils').ConfigItemAny>} */
|
|
376
398
|
const generalItems = {};
|
|
399
|
+
const data = {};
|
|
377
400
|
const lastUplinkTs = new Date(
|
|
378
401
|
this.adapter.objectStore.devices[id].informations.lastUplink.state.ts,
|
|
379
402
|
).toLocaleString('de-DE', {
|
|
@@ -410,22 +433,20 @@ class LoRaWANDeviceManagement extends DeviceManagement {
|
|
|
410
433
|
size: 16,
|
|
411
434
|
data: lastJoinedLc,
|
|
412
435
|
};
|
|
413
|
-
} else {
|
|
414
|
-
this.adapter.log.warn(JSON.stringify(this.adapter.objectStore.devices[id].join));
|
|
415
436
|
}
|
|
416
437
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
generalItems['
|
|
438
|
+
generalItems['uplinkDecodedHeader'] = {
|
|
439
|
+
newLine: true,
|
|
440
|
+
type: 'header',
|
|
441
|
+
text: 'Uplink Decoded',
|
|
442
|
+
size: 3,
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
generalItems['uplinkDecoded'] = {
|
|
425
446
|
type: 'text',
|
|
426
|
-
defaultSendTo: `BS:sendBack:${data}`,
|
|
427
447
|
readOnly: true,
|
|
428
448
|
minRows: 10,
|
|
449
|
+
maxRows: 40,
|
|
429
450
|
};
|
|
430
451
|
|
|
431
452
|
let subfolders = {};
|
|
@@ -434,13 +455,18 @@ class LoRaWANDeviceManagement extends DeviceManagement {
|
|
|
434
455
|
continue;
|
|
435
456
|
}
|
|
436
457
|
for (const subfolder in value) {
|
|
458
|
+
if (!subfolder.startsWith('uplink') && subfolder !== 'downlink.control') {
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
437
461
|
if (!subfolders[subfolder]) {
|
|
438
462
|
subfolders[subfolder] = {};
|
|
439
463
|
}
|
|
440
|
-
subfolders[subfolder][key] =
|
|
464
|
+
subfolders[subfolder][key] = value[subfolder];
|
|
441
465
|
}
|
|
442
466
|
}
|
|
443
|
-
subfolders =
|
|
467
|
+
subfolders = this.sortObjectDeep(subfolders);
|
|
468
|
+
// eslint-disable-next-line jsdoc/check-tag-names
|
|
469
|
+
/** @type {Record<string, import('@iobroker/dm-utils').ConfigItemAny>} */
|
|
444
470
|
const roleItems = {};
|
|
445
471
|
for (const subfolder in subfolders) {
|
|
446
472
|
roleItems[subfolder] = {
|
|
@@ -448,46 +474,40 @@ class LoRaWANDeviceManagement extends DeviceManagement {
|
|
|
448
474
|
type: 'header',
|
|
449
475
|
text: subfolder,
|
|
450
476
|
size: 3,
|
|
451
|
-
xs: 12,
|
|
452
|
-
sm: 12,
|
|
453
|
-
md: 12,
|
|
454
|
-
lg: 12,
|
|
455
|
-
xl: 12,
|
|
456
477
|
};
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
.
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
type: 'staticText',
|
|
465
|
-
text: detectedRoles,
|
|
466
|
-
size: 10,
|
|
478
|
+
const detectedRoles = Object.entries(subfolders[subfolder])
|
|
479
|
+
.map(([key, value]) => `${key}(${value})`)
|
|
480
|
+
.join(' ');
|
|
481
|
+
roleItems[`${subfolder.replace(/\./g, '_')}Roles`] = {
|
|
482
|
+
type: 'text',
|
|
483
|
+
minRows: 2,
|
|
484
|
+
readOnly: true,
|
|
467
485
|
};
|
|
486
|
+
data[`${subfolder.replace(/\./g, '_')}Roles`] = detectedRoles;
|
|
468
487
|
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
label: 'detectedRoles',
|
|
484
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
485
|
-
// @ts-expect-error
|
|
486
|
-
items: roleItems,
|
|
487
|
-
},
|
|
488
|
+
// eslint-disable-next-line jsdoc/check-tag-names
|
|
489
|
+
/** @type {import('@iobroker/dm-utils').JsonFormSchema} */
|
|
490
|
+
const schema = {
|
|
491
|
+
type: 'tabs',
|
|
492
|
+
items: {
|
|
493
|
+
generalTab: {
|
|
494
|
+
type: 'panel',
|
|
495
|
+
label: 'generalInformations',
|
|
496
|
+
items: generalItems,
|
|
497
|
+
},
|
|
498
|
+
roleTab: {
|
|
499
|
+
type: 'panel',
|
|
500
|
+
label: 'detectedRoles',
|
|
501
|
+
items: roleItems,
|
|
488
502
|
},
|
|
489
503
|
},
|
|
490
504
|
};
|
|
505
|
+
|
|
506
|
+
let deviceInfo = await this.adapter.getStateAsync('info.deviceinformations');
|
|
507
|
+
deviceInfo = JSON.parse(deviceInfo.val);
|
|
508
|
+
const sortedUplinkDecoded = this.sortObjectDeep(deviceInfo[id].uplink.decoded);
|
|
509
|
+
data.uplinkDecoded = JSON.stringify(sortedUplinkDecoded, null, 2);
|
|
510
|
+
return { id, schema, data };
|
|
491
511
|
}
|
|
492
512
|
}
|
|
493
513
|
|