iobroker.lorawan 1.19.34 → 1.20.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
@@ -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.1 (2026-01-25)
27
+ * (BenAhrdt) bugfix device Manager
28
+
29
+ ### 1.20.0 (2026-01-25)
30
+ * (BenAhrdt) add first Steps of device Manager
31
+
26
32
  ### 1.19.34 (2026-01-20)
27
33
  * (BenAhrdt) assign Percent & Liter in assignhandler
28
34
 
@@ -37,6 +37,7 @@
37
37
  "ClosedSignalId": "ID für Endschalter schließen",
38
38
  "ClosedSignalText": "ID für Endschalter schließen",
39
39
  "CommandText": "Befehls-ID",
40
+ "Config this device": "Gerät konfigurieren",
40
41
  "CoverAwning": "Markise",
41
42
  "CoverBlind": "Jalousie",
42
43
  "CoverCloseText": "Befehls-ID schließen",
@@ -93,6 +94,7 @@
93
94
  "HumidifierOnOffText": "Ein / Aus",
94
95
  "HumidifierTargetText": "Zielfeuchtigkeit",
95
96
  "HumidifierTooltip": "Luftbefeuchter / Luftentfeuchter",
97
+ "Info of this device": "Geräteinformationen",
96
98
  "LightBrightness": "Helligkeit",
97
99
  "LightBrightnessText": "Helligkeits-ID",
98
100
  "LightBrightnessTooltip": "Aktivieren, um die Helligkeits-ID festzulegen",
@@ -139,6 +141,7 @@
139
141
  "OriginInformation": "Legen Sie den Ursprung der erwarteten Daten fest",
140
142
  "RefreshDiscoveryCronJob": "Discovery Zyklus",
141
143
  "RefreshDiscoveryCronJobTooltip": "Stellen Sie den Cronjob für das Discovery ein",
144
+ "Rename this device": "Gerät umbenennen",
142
145
  "SSL": "SSL",
143
146
  "SeparateIds": "Getrennte IDs für die Befehle",
144
147
  "Serverinformation": "Legen Sie die wichtigsten Kommunikationseinstellungen für Ihren Server fest",
@@ -273,5 +273,8 @@
273
273
  "CoverWindow": "window",
274
274
  "deviceSuffix": "device Suffix",
275
275
  "CoverSimulatePosition": "simulate position",
276
- "CoverSimulatePositionTooltip": "simulates the position depending on the limit switches (required for some systems)"
276
+ "CoverSimulatePositionTooltip": "simulates the position depending on the limit switches (required for some systems)",
277
+ "Rename this device": "Rename this device",
278
+ "Config this device": "Config this device",
279
+ "Info of this device": "Info of this device"
277
280
  }
@@ -37,6 +37,7 @@
37
37
  "ClosedSignalId": "ID para interruptor de límite de cierre",
38
38
  "ClosedSignalText": "ID para interruptor de límite de cierre",
39
39
  "CommandText": "ID de comando",
40
+ "Config this device": "Configurar este dispositivo",
40
41
  "CoverAwning": "toldo",
41
42
  "CoverBlind": "ciego",
42
43
  "CoverCloseText": "Cerrar ID de comando",
@@ -93,6 +94,7 @@
93
94
  "HumidifierOnOffText": "Encendido/Apagado",
94
95
  "HumidifierTargetText": "Humedad objetivo",
95
96
  "HumidifierTooltip": "humidificador / deshumidificador",
97
+ "Info of this device": "Información de este dispositivo",
96
98
  "LightBrightness": "Brillo",
97
99
  "LightBrightnessText": "Identificación de brillo",
98
100
  "LightBrightnessTooltip": "habilitar para configurar la identificación del brillo",
@@ -139,6 +141,7 @@
139
141
  "OriginInformation": "Establecer el origen de los datos esperados.",
140
142
  "RefreshDiscoveryCronJob": "Descubre el ciclo",
141
143
  "RefreshDiscoveryCronJobTooltip": "inserte el cronjob para actualizar el descubrimiento",
144
+ "Rename this device": "Cambiar el nombre de este dispositivo",
142
145
  "SSL": "SSL",
143
146
  "SeparateIds": "identificadores separados para el comando",
144
147
  "Serverinformation": "Establezca la configuración principal de comunicación para su servidor",
@@ -37,6 +37,7 @@
37
37
  "ClosedSignalId": "identifiant pour fin de course de fermeture",
38
38
  "ClosedSignalText": "identifiant pour fin de course de fermeture",
39
39
  "CommandText": "ID de commande",
40
+ "Config this device": "Configurer cet appareil",
40
41
  "CoverAwning": "store",
41
42
  "CoverBlind": "aveugle",
42
43
  "CoverCloseText": "Fermer l'ID de commande",
@@ -93,6 +94,7 @@
93
94
  "HumidifierOnOffText": "Marche/Arrêt",
94
95
  "HumidifierTargetText": "Humidité cible",
95
96
  "HumidifierTooltip": "humidificateur / déshumidificateur",
97
+ "Info of this device": "Informations sur cet appareil",
96
98
  "LightBrightness": "Luminosité",
97
99
  "LightBrightnessText": "Identifiant de luminosité",
98
100
  "LightBrightnessTooltip": "activer pour définir l'identifiant de luminosité",
@@ -139,6 +141,7 @@
139
141
  "OriginInformation": "Définir l'origine des données attendues",
140
142
  "RefreshDiscoveryCronJob": "Découvrir le cycle",
141
143
  "RefreshDiscoveryCronJobTooltip": "insérez le cronjob pour rafraîchir la découverte",
144
+ "Rename this device": "Renommer cet appareil",
142
145
  "SSL": "SSL",
143
146
  "SeparateIds": "identifiants séparés pour la commande",
144
147
  "Serverinformation": "Définissez les principaux paramètres de communication sur votre serveur",
@@ -37,6 +37,7 @@
37
37
  "ClosedSignalId": "ID per finecorsa di chiusura",
38
38
  "ClosedSignalText": "ID per finecorsa di chiusura",
39
39
  "CommandText": "Identificativo del comando",
40
+ "Config this device": "Configura questo dispositivo",
40
41
  "CoverAwning": "tenda da sole",
41
42
  "CoverBlind": "cieco",
42
43
  "CoverCloseText": "Chiudi ID comando",
@@ -93,6 +94,7 @@
93
94
  "HumidifierOnOffText": "Acceso/Spento",
94
95
  "HumidifierTargetText": "Umidità target",
95
96
  "HumidifierTooltip": "umidificatore/deumidificatore",
97
+ "Info of this device": "Informazioni su questo dispositivo",
96
98
  "LightBrightness": "Luminosità",
97
99
  "LightBrightnessText": "ID luminosità",
98
100
  "LightBrightnessTooltip": "abilitare per impostare l'ID luminosità",
@@ -139,6 +141,7 @@
139
141
  "OriginInformation": "Imposta l'origine dei dati attesi",
140
142
  "RefreshDiscoveryCronJob": "Scopri Ciclo",
141
143
  "RefreshDiscoveryCronJobTooltip": "inserire il cronjob per aggiornare la scoperta",
144
+ "Rename this device": "Rinomina questo dispositivo",
142
145
  "SSL": "SSL",
143
146
  "SeparateIds": "ID separati per il comando",
144
147
  "Serverinformation": "Configura le principali impostazioni di comunicazione sul tuo server",
@@ -37,6 +37,7 @@
37
37
  "ClosedSignalId": "ID voor eindschakelaar sluiten",
38
38
  "ClosedSignalText": "ID voor eindschakelaar sluiten",
39
39
  "CommandText": "Commando-ID",
40
+ "Config this device": "Configureer dit apparaat",
40
41
  "CoverAwning": "luifel",
41
42
  "CoverBlind": "blind",
42
43
  "CoverCloseText": "Sluit opdracht-ID",
@@ -93,6 +94,7 @@
93
94
  "HumidifierOnOffText": "Aan / Uit",
94
95
  "HumidifierTargetText": "Doelvochtigheid",
95
96
  "HumidifierTooltip": "luchtbevochtiger/ontvochtiger",
97
+ "Info of this device": "Informatie over dit apparaat",
96
98
  "LightBrightness": "Helderheid",
97
99
  "LightBrightnessText": "Helderheid ID",
98
100
  "LightBrightnessTooltip": "inschakelen om helderheids-id in te stellen",
@@ -139,6 +141,7 @@
139
141
  "OriginInformation": "Stel de oorsprong van de verwachte gegevens in",
140
142
  "RefreshDiscoveryCronJob": "Ontdek Cyclus",
141
143
  "RefreshDiscoveryCronJobTooltip": "plaats de cronjob om de ontdekking te vernieuwen",
144
+ "Rename this device": "Hernoem dit apparaat",
142
145
  "SSL": "SSL",
143
146
  "SeparateIds": "gescheiden id's voor commando",
144
147
  "Serverinformation": "Stel de belangrijkste communicatie-instellingen in op uw server",
@@ -37,6 +37,7 @@
37
37
  "ClosedSignalId": "identyfikator wyłącznika krańcowego zamknięcia",
38
38
  "ClosedSignalText": "identyfikator wyłącznika krańcowego zamknięcia",
39
39
  "CommandText": "Identyfikator polecenia",
40
+ "Config this device": "Skonfiguruj to urządzenie",
40
41
  "CoverAwning": "markiza",
41
42
  "CoverBlind": "ślepy",
42
43
  "CoverCloseText": "Zamknij identyfikator polecenia",
@@ -93,6 +94,7 @@
93
94
  "HumidifierOnOffText": "Wł./Wył",
94
95
  "HumidifierTargetText": "Docelowa wilgotność",
95
96
  "HumidifierTooltip": "nawilżacz / osuszacz",
97
+ "Info of this device": "Informacje o tym urządzeniu",
96
98
  "LightBrightness": "Jasność",
97
99
  "LightBrightnessText": "Identyfikator jasności",
98
100
  "LightBrightnessTooltip": "włącz ustawienie identyfikatora jasności",
@@ -139,6 +141,7 @@
139
141
  "OriginInformation": "Ustaw pochodzenie oczekiwanych danych",
140
142
  "RefreshDiscoveryCronJob": "Odkryj cykl",
141
143
  "RefreshDiscoveryCronJobTooltip": "wstaw cronjob, aby odświeżyć odkrycie",
144
+ "Rename this device": "Zmień nazwę tego urządzenia",
142
145
  "SSL": "SSL",
143
146
  "SeparateIds": "oddzielone identyfikatory poleceń",
144
147
  "Serverinformation": "Skonfiguruj główne ustawienia komunikacji z serwerem",
@@ -37,6 +37,7 @@
37
37
  "ClosedSignalId": "id para interruptor de limite fechado",
38
38
  "ClosedSignalText": "id para interruptor de limite fechado",
39
39
  "CommandText": "ID do comando",
40
+ "Config this device": "Configurar este dispositivo",
40
41
  "CoverAwning": "toldo",
41
42
  "CoverBlind": "cego",
42
43
  "CoverCloseText": "Fechar ID do comando",
@@ -93,6 +94,7 @@
93
94
  "HumidifierOnOffText": "Ligado/Desligado",
94
95
  "HumidifierTargetText": "Umidade alvo",
95
96
  "HumidifierTooltip": "umidificador / desumidificador",
97
+ "Info of this device": "Informações deste dispositivo",
96
98
  "LightBrightness": "Brilho",
97
99
  "LightBrightnessText": "ID de brilho",
98
100
  "LightBrightnessTooltip": "ativar para definir o ID de brilho",
@@ -139,6 +141,7 @@
139
141
  "OriginInformation": "Defina a origem dos dados esperados",
140
142
  "RefreshDiscoveryCronJob": "Descubra o Ciclo",
141
143
  "RefreshDiscoveryCronJobTooltip": "insira o cronjob para atualizar a descoberta",
144
+ "Rename this device": "Renomear este dispositivo",
142
145
  "SSL": "SSL",
143
146
  "SeparateIds": "ids separados para comando",
144
147
  "Serverinformation": "Defina as principais configurações de comunicação para o seu servidor",
@@ -37,6 +37,7 @@
37
37
  "ClosedSignalId": "идентификатор концевого выключателя закрытия",
38
38
  "ClosedSignalText": "идентификатор концевого выключателя закрытия",
39
39
  "CommandText": "Идентификатор команды",
40
+ "Config this device": "Настроить это устройство",
40
41
  "CoverAwning": "тент",
41
42
  "CoverBlind": "слепой",
42
43
  "CoverCloseText": "Идентификатор команды закрытия",
@@ -93,6 +94,7 @@
93
94
  "HumidifierOnOffText": "Вкл/Выкл",
94
95
  "HumidifierTargetText": "Целевая влажность",
95
96
  "HumidifierTooltip": "увлажнитель / осушитель",
97
+ "Info of this device": "Информация об этом устройстве",
96
98
  "LightBrightness": "Яркость",
97
99
  "LightBrightnessText": "Идентификатор яркости",
98
100
  "LightBrightnessTooltip": "включить установку идентификатора яркости",
@@ -139,6 +141,7 @@
139
141
  "OriginInformation": "Установите источник ожидаемых данных",
140
142
  "RefreshDiscoveryCronJob": "Откройте для себя цикл",
141
143
  "RefreshDiscoveryCronJobTooltip": "вставьте cronjob для обновления открытия",
144
+ "Rename this device": "Переименуйте это устройство",
142
145
  "SSL": "SSL",
143
146
  "SeparateIds": "отдельные идентификаторы для команды",
144
147
  "Serverinformation": "Установите основные настройки связи на ваш сервер",
@@ -37,6 +37,7 @@
37
37
  "ClosedSignalId": "ідентифікатор для кінцевого вимикача",
38
38
  "ClosedSignalText": "ідентифікатор для кінцевого вимикача",
39
39
  "CommandText": "ID команди",
40
+ "Config this device": "Налаштуйте цей пристрій",
40
41
  "CoverAwning": "тент",
41
42
  "CoverBlind": "сліпий",
42
43
  "CoverCloseText": "Закрити ID команди",
@@ -93,6 +94,7 @@
93
94
  "HumidifierOnOffText": "Увімк. / Вимк",
94
95
  "HumidifierTargetText": "Цільова вологість",
95
96
  "HumidifierTooltip": "зволожувач / осушувач повітря",
97
+ "Info of this device": "Інформація про цей пристрій",
96
98
  "LightBrightness": "Яскравість",
97
99
  "LightBrightnessText": "Ідентифікатор яскравості",
98
100
  "LightBrightnessTooltip": "дозволити встановити ідентифікатор яскравості",
@@ -139,6 +141,7 @@
139
141
  "OriginInformation": "Встановіть джерело очікуваних даних",
140
142
  "RefreshDiscoveryCronJob": "Цикл відкриття",
141
143
  "RefreshDiscoveryCronJobTooltip": "вставте cronjob для оновлення відкриття",
144
+ "Rename this device": "Перейменуйте цей пристрій",
142
145
  "SSL": "SSL",
143
146
  "SeparateIds": "розділені ідентифікатори для команди",
144
147
  "Serverinformation": "Встановіть основні параметри зв'язку на вашому сервері",
@@ -37,6 +37,7 @@
37
37
  "ClosedSignalId": "接近限位开关的 id",
38
38
  "ClosedSignalText": "接近限位开关的 id",
39
39
  "CommandText": "命令ID",
40
+ "Config this device": "配置该设备",
40
41
  "CoverAwning": "棚",
41
42
  "CoverBlind": "瞎的",
42
43
  "CoverCloseText": "关闭命令ID",
@@ -93,6 +94,7 @@
93
94
  "HumidifierOnOffText": "开/关",
94
95
  "HumidifierTargetText": "目标湿度",
95
96
  "HumidifierTooltip": "加湿器/除湿器",
97
+ "Info of this device": "该设备的信息",
96
98
  "LightBrightness": "亮度",
97
99
  "LightBrightnessText": "亮度 ID",
98
100
  "LightBrightnessTooltip": "启用设置亮度ID",
@@ -139,6 +141,7 @@
139
141
  "OriginInformation": "设置预期数据的来源",
140
142
  "RefreshDiscoveryCronJob": "发现周期",
141
143
  "RefreshDiscoveryCronJobTooltip": "插入 cronjob 以刷新发现",
144
+ "Rename this device": "重命名该设备",
142
145
  "SSL": "SSL协议",
143
146
  "SeparateIds": "命令的分隔 ID",
144
147
  "Serverinformation": "设置服务器的主要通信设置",
Binary file
@@ -5,6 +5,31 @@
5
5
  "width": "calc(100% - 100px)"
6
6
  },
7
7
  "items":{
8
+ "_deviceManager": {
9
+ "type": "panel",
10
+ "label": "Device manager",
11
+ "items": {
12
+ "_dm": {
13
+ "type": "deviceManager",
14
+ "sm": 12,
15
+ "style": {
16
+ "width": "100%",
17
+ "height": "100%",
18
+ "overflow": "hidden"
19
+ }
20
+ }
21
+ },
22
+ "style": {
23
+ "width": "100%",
24
+ "height": "100%",
25
+ "overflow": "hidden"
26
+ },
27
+ "innerStyle": {
28
+ "width": "100%",
29
+ "height": "100%",
30
+ "overflow": "hidden"
31
+ }
32
+ },
8
33
  "mainTab":{
9
34
  "type": "panel",
10
35
  "label": "mainSettings",
@@ -5,6 +5,31 @@
5
5
  "width": "calc(100% - 100px)"
6
6
  },
7
7
  "items":{
8
+ "_deviceManager": {
9
+ "type": "panel",
10
+ "label": "Device manager",
11
+ "items": {
12
+ "_dm": {
13
+ "type": "deviceManager",
14
+ "sm": 12,
15
+ "style": {
16
+ "width": "100%",
17
+ "height": "100%",
18
+ "overflow": "hidden"
19
+ }
20
+ }
21
+ },
22
+ "style": {
23
+ "width": "100%",
24
+ "height": "100%",
25
+ "overflow": "hidden"
26
+ },
27
+ "innerStyle": {
28
+ "width": "100%",
29
+ "height": "100%",
30
+ "overflow": "hidden"
31
+ }
32
+ },
8
33
  "_DiscoveredIds":{
9
34
  "type": "panel",
10
35
  "label": "_DiscoveredIds",
package/io-package.json CHANGED
@@ -1,8 +1,34 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "lorawan",
4
- "version": "1.19.34",
4
+ "version": "1.20.1",
5
5
  "news": {
6
+ "1.20.1": {
7
+ "en": "bugfix device Manager",
8
+ "de": "bugfix Gerät Manager",
9
+ "ru": "bugfix устройство диспетчер",
10
+ "pt": "gerenciador de dispositivos de correção de erros",
11
+ "nl": "bugfix apparaatbeheer",
12
+ "fr": "gestionnaire de périphériques bugfix",
13
+ "it": "bugfix dispositivo Manager",
14
+ "es": "bugfix device Manager",
15
+ "pl": "menedżer urządzeń bugfix",
16
+ "uk": "диспетчер пристроїв",
17
+ "zh-cn": "错误修正设备管理器"
18
+ },
19
+ "1.20.0": {
20
+ "en": "add first Steps of device Manager",
21
+ "de": "erste Schritte des Gerätemanagers hinzufügen",
22
+ "ru": "добавить первые шаги диспетчера устройств",
23
+ "pt": "adicionar os primeiros Passos do Gestor de Dispositivos",
24
+ "nl": "eerste stappen van apparaatbeheer toevoegen",
25
+ "fr": "ajouter les premières étapes du gestionnaire de périphérique",
26
+ "it": "aggiungere i primi passi di Gestione dispositivi",
27
+ "es": "añadir los primeros pasos del administrador del dispositivo",
28
+ "pl": "dodaj pierwsze kroki menedżera urządzeń",
29
+ "uk": "додати перші кроки диспетчера пристроїв",
30
+ "zh-cn": "添加设备管理器的第一个步骤"
31
+ },
6
32
  "1.19.34": {
7
33
  "en": "assign Percent & Liter in assignhandler",
8
34
  "de": "percent & Liter in assignhandler zuweisen",
@@ -67,32 +93,6 @@
67
93
  "pl": "dodać symulację pozycji dla pokrycia",
68
94
  "uk": "додати моделювання позиції для покриття",
69
95
  "zh-cn": "添加覆盖位置模拟"
70
- },
71
- "1.19.29": {
72
- "en": "bugfix tilt min & max",
73
- "de": "bugfix neigung min & max",
74
- "ru": "багфикс tilt min & max",
75
- "pt": "min & max da inclinação do erro de correção",
76
- "nl": "bugfix tilt min & max",
77
- "fr": "bugfix inclinaison min & max",
78
- "it": "bugfix tilt min & max",
79
- "es": "bugfix tilt min < max",
80
- "pl": "przechył bugfix min & max",
81
- "uk": "виправлення tilt min & макс",
82
- "zh-cn": "最大时长( u)"
83
- },
84
- "1.19.28": {
85
- "en": "add logging possibility info, debug, warn, error to internal logging",
86
- "de": "hinzufügen von logging-möglichkeiten info, debug, warnen, fehler in der internen protokollierung",
87
- "ru": "добавьте информацию о возможности регистрации, отладку, предупреждение, ошибку к внутренней регистрации",
88
- "pt": "adicionar informações de possibilidade de registro, depurar, alertar, erro ao registro interno",
89
- "nl": "log mogelijkheid info toevoegen, debug, waarschuwen, fout bij interne logging",
90
- "fr": "ajouter des informations de possibilité de log, debug, avertissement, erreur à la log interne",
91
- "it": "aggiungere informazioni possibilità di registrazione, debug, avvertire, errore di registrazione interna",
92
- "es": "añadir información de la posibilidad de registro, depuración, aviso, error al registro interno",
93
- "pl": "dodaj informacje o możliwości logowania, debugowanie, ostrzeganie, błąd logowania wewnętrznego",
94
- "uk": "додайте інформацію про можливість входу, відхилити, попереджати, похибка до внутрішнього входу",
95
- "zh-cn": "将记录可能性信息、调试、警告、错误添加到内部记录"
96
96
  }
97
97
  },
98
98
  "titleLang": {
@@ -145,6 +145,9 @@
145
145
  "messagebox": true,
146
146
  "dataSource": "push",
147
147
  "blockly": true,
148
+ "supportedMessages": {
149
+ "deviceManager": true
150
+ },
148
151
  "adminUI": {
149
152
  "config": "json",
150
153
  "tab": "json"
@@ -181,7 +181,7 @@ class assignhandlerClass {
181
181
  'uplink.decoded': {
182
182
  assignfunction: this.commonAssign,
183
183
  common: {
184
- role: 'level.humidity',
184
+ role: 'value.humidity',
185
185
  unit: '%',
186
186
  },
187
187
  },
@@ -566,7 +566,7 @@ class assignhandlerClass {
566
566
  'uplink.decoded': {
567
567
  assignfunction: this.commonAssign,
568
568
  common: {
569
- role: 'level.temperature',
569
+ role: 'value.temperature',
570
570
  unit: '°C',
571
571
  },
572
572
  },
@@ -577,7 +577,7 @@ class assignhandlerClass {
577
577
  'uplink.decoded': {
578
578
  assignfunction: this.commonAssign,
579
579
  common: {
580
- role: 'level.temperature',
580
+ role: 'value.temperature',
581
581
  unit: '°C',
582
582
  },
583
583
  },
@@ -0,0 +1,162 @@
1
+ 'use strict';
2
+
3
+ const { DeviceManagement } = require('@iobroker/dm-utils');
4
+
5
+ /**
6
+ * Devicemanager Class
7
+ */
8
+ class LoRaWANDeviceManagement extends DeviceManagement {
9
+ /**
10
+ * Initalize Class with Adapter
11
+ *
12
+ * @param adapter Adapter Reference
13
+ */
14
+ constructor(adapter) {
15
+ super(adapter);
16
+ this.adapter = adapter;
17
+ }
18
+ /**
19
+ * List all LoRaWAN devices
20
+ */
21
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
22
+ // @ts-expect-error
23
+ async listDevices() {
24
+ const arrDevices = [];
25
+ for (const [key, value] of Object.entries(this.adapter.objectStore.devices)) {
26
+ const res = {
27
+ id: key,
28
+ name: value.object.common.name,
29
+ icon: await this.getIcon(value),
30
+ manufacturer: value.checks.lastUplink
31
+ ? new Date(value.checks.lastUplink.state.ts).toLocaleString('de-DE', {
32
+ weekday: 'short', // Mo
33
+ year: 'numeric', // 2026
34
+ month: '2-digit', // 01
35
+ day: '2-digit', // 24
36
+ hour: '2-digit', // 14
37
+ minute: '2-digit', // 32
38
+ second: '2-digit', // 10
39
+ })
40
+ : undefined,
41
+ model: value.checks.devicetype.state.val, // - ${value.uplink.remaining.rxInfo[0].rssi.ts}`,
42
+ status: await this.getStatus(value),
43
+ hasDetails: undefined,
44
+ actions: [
45
+ {
46
+ id: 'rename',
47
+ icon: 'fa-solid fa-pen',
48
+ description: this.adapter.i18nTranslation['Rename this device'],
49
+ handler: undefined, //async (_id, context) => await this.handleRenameDevice(_id, context),
50
+ },
51
+ ],
52
+ };
53
+ if (res.status.connection === 'connected') {
54
+ res.actions.push({
55
+ id: 'config',
56
+ icon: 'settings',
57
+ description: this.adapter.i18nTranslation['Config this device'],
58
+ handler: undefined, //async (_id, context) => await this.handleRenameDevice(_id, context),
59
+ });
60
+ res.actions.push({
61
+ id: 'Info',
62
+ icon: 'lines',
63
+ description: this.adapter.i18nTranslation['Info of this device'],
64
+ handler: undefined, //async (_id, context) => await this.handleRenameDevice(_id, context),
65
+ });
66
+ }
67
+ arrDevices.push(res);
68
+ }
69
+ return arrDevices;
70
+ }
71
+
72
+ /**
73
+ *
74
+ * @param devicevalue values of device
75
+ */
76
+ async getStatus(devicevalue) {
77
+ const status = {};
78
+ if (devicevalue.object.common.icon.includes('offline')) {
79
+ status.connection = 'disconnected';
80
+ } else {
81
+ status.connection = 'connected';
82
+ if (devicevalue.checks.rssi) {
83
+ status.rssi = devicevalue.checks.rssi.state.val;
84
+ }
85
+ if (devicevalue.checks.batteryPercent) {
86
+ status.battery = devicevalue.checks.batteryPercent.state.val ?? undefined;
87
+ }
88
+ }
89
+ return status;
90
+ }
91
+
92
+ /**
93
+ *
94
+ * @param devicevalue values of device
95
+ */
96
+ async getIcon(devicevalue) {
97
+ if (devicevalue.checks) {
98
+ if (devicevalue.checks.isThermostat) {
99
+ return 'thermostat';
100
+ } else if (devicevalue.checks.isWindow) {
101
+ return 'window';
102
+ } else if (devicevalue.checks.isDoor) {
103
+ return 'door';
104
+ }
105
+ }
106
+ return `/adapter/${this.adapter.name}/icons/Node.png`; //${value.object.common.icon}`,
107
+ }
108
+
109
+ /**
110
+ *
111
+ * @param id id to rename
112
+ * @param context context sendet from Backend
113
+ */
114
+ async handleRenameDevice(id, context) {
115
+ const result = await context.showForm(
116
+ {
117
+ type: 'panel',
118
+ items: {
119
+ newName: {
120
+ type: 'text',
121
+ trim: false,
122
+ placeholder: '',
123
+ },
124
+ },
125
+ },
126
+ {
127
+ data: {
128
+ newName: '',
129
+ },
130
+ title: {
131
+ en: 'Enter new name',
132
+ de: 'Neuen Namen eingeben',
133
+ ru: 'Введите новое имя',
134
+ pt: 'Digite um novo nome',
135
+ nl: 'Voer een nieuwe naam in',
136
+ fr: 'Entrez un nouveau nom',
137
+ it: 'Inserisci un nuovo nome',
138
+ es: 'Ingrese un nuevo nombre',
139
+ pl: 'Wpisz nowe imię',
140
+ 'zh-cn': '输入新名称',
141
+ uk: "Введіть нове ім'я",
142
+ },
143
+ },
144
+ );
145
+ if (result?.newName === undefined || result?.newName === '') {
146
+ return { refresh: false };
147
+ }
148
+ const obj = {
149
+ common: {
150
+ name: result.newName,
151
+ },
152
+ };
153
+ const res = await this.adapter.extendObjectAsync(id, obj);
154
+ if (res === null) {
155
+ this.adapter.log.warn(`Can not rename device ${id}: ${JSON.stringify(res)}`);
156
+ return { refresh: false };
157
+ }
158
+ return { refresh: true };
159
+ }
160
+ }
161
+
162
+ module.exports = LoRaWANDeviceManagement;
@@ -0,0 +1,205 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Objectstore Class
5
+ */
6
+ class objectStoreClass {
7
+ /**
8
+ * Initalize Class with Adapter
9
+ *
10
+ * @param adapter Adapter Reference
11
+ */
12
+ constructor(adapter) {
13
+ this.adapter = adapter;
14
+
15
+ // Objects
16
+ this.devices = {};
17
+ this.applications = {};
18
+ this.currentIds = {};
19
+
20
+ this.rolesToCheck = {
21
+ 'value.battery': {
22
+ checkIndicator: 'isBatteryDevice',
23
+ assignToDevice: { name: 'batteryPercent', subfolder: '.uplink.decoded' },
24
+ },
25
+ 'level.temperature': {
26
+ checkIndicator: { name: 'isThermostat', subfolder: '.downlink.control' },
27
+ },
28
+ 'sensor.window': {
29
+ checkIndicator: { name: 'isWindow', subfolder: '.uplink.decoded' },
30
+ },
31
+ 'sensor.door': {
32
+ checkIndicator: { name: 'isDoor', subfolder: '.uplink.decoded' },
33
+ },
34
+ };
35
+ this.assignToDevice = {
36
+ rssi: true,
37
+ devicetype: { name: 'devicetype', subfolder: '.configuration' },
38
+ json: { name: 'lastUplink', subfolder: '.uplink.raw' },
39
+ };
40
+ }
41
+
42
+ /**
43
+ * Funktion to get Devicestructure
44
+ *
45
+ */
46
+ async generateDeviceObjects() {
47
+ const activeFunction = 'objectStore.js - generateDeviceObjects';
48
+ this.adapter.log.silly(`Function ${activeFunction} started.`);
49
+ try {
50
+ // Get the States
51
+ const adapterObjects = await this.adapter.getAdapterObjectsAsync();
52
+ for (const adapterObject of Object.values(adapterObjects)) {
53
+ if (
54
+ !adapterObject._id.startsWith(`${this.adapter.namespace}.info`) &&
55
+ !adapterObject._id.startsWith(`${this.adapter.namespace}.bridge`)
56
+ ) {
57
+ await this.generateObjectStructureFromId(adapterObject._id, { payload: { object: adapterObject } });
58
+ }
59
+ }
60
+ } catch (error) {
61
+ this.adapter.log.error(`error at ${activeFunction}: ${error}`);
62
+ }
63
+ }
64
+
65
+ /**
66
+ * @param id id, for wich the structure is to build
67
+ * @param options eg. payload wich is set to last element in id
68
+ */
69
+ async generateObjectStructureFromId(id, options = {}) {
70
+ const activeFunction = 'objectStore.js - generateObjectStructureFromId';
71
+ this.adapter.log.silly(`Function ${activeFunction} started.`);
72
+ try {
73
+ let { strip = 2, payload } = options;
74
+
75
+ // Get global values
76
+ const applicationObject = this.applications;
77
+ const deviceObject = this.devices;
78
+ const idObject = this.currentIds;
79
+
80
+ const parts = id.split('.').slice(strip);
81
+ let node = applicationObject;
82
+ const deviceId = parts[2];
83
+ const idWithoutLast = id.substring(0, id.length - parts[parts.length - 1].length - 1);
84
+ for (let i = 0; i < parts.length; i++) {
85
+ const key = parts[i];
86
+ const isLast = i === parts.length - 1;
87
+
88
+ if (isLast) {
89
+ if (payload !== undefined) {
90
+ if (!node[key]) {
91
+ node[key] = {};
92
+ if (!idObject[id]) {
93
+ idObject[id] = node[key];
94
+ }
95
+ }
96
+ for (const [name, value] of Object.entries(payload)) {
97
+ node[key][name] = value;
98
+ }
99
+ // Assign deviceObject
100
+ if (deviceId === key) {
101
+ if (!deviceObject[deviceId]) {
102
+ deviceObject[deviceId] = node[key];
103
+ }
104
+ }
105
+ let assign = undefined;
106
+ if (payload.object) {
107
+ if (Object.hasOwn(this.rolesToCheck, payload.object.common.role)) {
108
+ if (!deviceObject[deviceId].checks) {
109
+ deviceObject[deviceId].checks = {};
110
+ }
111
+ if (this.rolesToCheck[payload.object.common.role].checkIndicator) {
112
+ if (
113
+ typeof this.rolesToCheck[payload.object.common.role].checkIndicator === 'string'
114
+ ) {
115
+ deviceObject[deviceId].checks[
116
+ this.rolesToCheck[payload.object.common.role].checkIndicator
117
+ ] = true;
118
+ } else if (
119
+ typeof this.rolesToCheck[payload.object.common.role].checkIndicator === 'object'
120
+ ) {
121
+ let name = key;
122
+ if (
123
+ this.rolesToCheck[payload.object.common.role].checkIndicator.subfolder &&
124
+ !idWithoutLast.endsWith(
125
+ this.rolesToCheck[payload.object.common.role].checkIndicator.subfolder,
126
+ )
127
+ ) {
128
+ continue;
129
+ }
130
+ if (this.rolesToCheck[payload.object.common.role].checkIndicator.name) {
131
+ name = this.rolesToCheck[payload.object.common.role].checkIndicator.name;
132
+ }
133
+ deviceObject[deviceId].checks[name] = true;
134
+ }
135
+ deviceObject[deviceId].checks[
136
+ this.rolesToCheck[payload.object.common.role].checkIndicator
137
+ ] = true;
138
+ }
139
+ if (this.rolesToCheck[payload.object.common.role].assignToDevice) {
140
+ assign = this.rolesToCheck[payload.object.common.role].assignToDevice;
141
+ }
142
+ }
143
+ }
144
+ // Following only type state
145
+ if (node[key].object && node[key].object.type === 'state') {
146
+ // Get state, if not present
147
+ if (!node[key].state) {
148
+ if (node[key].object._id) {
149
+ const state = await this.adapter.getStateAsync(node[key].object._id);
150
+ node[key].state = state;
151
+ }
152
+ }
153
+ // Assign to device
154
+ if (Object.hasOwn(this.assignToDevice, key) || assign) {
155
+ if (!deviceObject[deviceId].checks) {
156
+ deviceObject[deviceId].checks = {};
157
+ }
158
+ let name = key;
159
+ if (assign) {
160
+ if (typeof assign === 'string') {
161
+ name = assign;
162
+ } else if (typeof assign === 'object') {
163
+ if (assign.subfolder && !idWithoutLast.endsWith(assign.subfolder)) {
164
+ continue;
165
+ }
166
+ if (assign.name) {
167
+ name = assign.name;
168
+ }
169
+ }
170
+ } else if (typeof this.assignToDevice[key] === 'string') {
171
+ name = this.assignToDevice[key];
172
+ } else if (typeof this.assignToDevice[key] === 'object') {
173
+ if (
174
+ this.assignToDevice[key].subfolder &&
175
+ !idWithoutLast.endsWith(this.assignToDevice[key].subfolder)
176
+ ) {
177
+ continue;
178
+ }
179
+ if (this.assignToDevice[key].name) {
180
+ name = this.assignToDevice[key].name;
181
+ }
182
+ }
183
+ if (!deviceObject[deviceId].checks[name]) {
184
+ deviceObject[deviceId].checks[name] = node[key];
185
+ }
186
+ }
187
+ }
188
+ } else {
189
+ node[key] ??= {};
190
+ if (!idObject[id]) {
191
+ idObject[id] = node[key];
192
+ }
193
+ }
194
+ } else {
195
+ node[key] ??= {};
196
+ node = node[key];
197
+ }
198
+ }
199
+ } catch (error) {
200
+ this.adapter.log.error(`error at ${activeFunction}: ${error} - id: ${id}`);
201
+ }
202
+ }
203
+ }
204
+
205
+ module.exports = objectStoreClass;
package/main.js CHANGED
@@ -14,6 +14,8 @@ const bridgeClass = require('./lib/modules/bridge');
14
14
  const mqttClientClass = require('./lib/modules/mqttclient');
15
15
  const messagehandlerClass = require('./lib/modules/messagehandler');
16
16
  const downlinkConfighandlerClass = require('./lib/modules/downlinkConfighandler');
17
+ const LoRaWANDeviceManagement = require('./lib/modules/deviceManager');
18
+ const objectStoreClass = require('./lib/modules/objectStore');
17
19
 
18
20
  class Lorawan extends utils.Adapter {
19
21
  /**
@@ -70,6 +72,11 @@ class Lorawan extends utils.Adapter {
70
72
  async onReady() {
71
73
  const activeFunction = 'onReady';
72
74
  try {
75
+ // Generate Objectstore
76
+ this.objectStore = new objectStoreClass(this);
77
+
78
+ await this.objectStore.generateDeviceObjects();
79
+
73
80
  // Get Logtypes
74
81
  this.logtypes = JSON.parse(await this.setDefIfEmptyAndReturnVal('bridge.debug.logtypes'));
75
82
 
@@ -114,9 +121,11 @@ class Lorawan extends utils.Adapter {
114
121
  this.bridge = new bridgeClass(this);
115
122
  }
116
123
 
124
+ this.deviceManagement = new LoRaWANDeviceManagement(this);
125
+
117
126
  //Subscribe all configuration and control states
118
127
  await this.subscribeStatesAsync('*');
119
- //this.subscribeObjectsAsync('*.uplink.decoded.*');
128
+ await this.subscribeObjectsAsync('*');
120
129
  //this.subscribeObjectsAsync('*.downlink.control.*');
121
130
  this.log.debug(`the adapter starts with downlinkconfigs: ${JSON.stringify(this.config.downlinkConfig)}.`);
122
131
  this.log.debug(
@@ -487,33 +496,41 @@ class Lorawan extends utils.Adapter {
487
496
  * @param obj value and ack of the changed object
488
497
  */
489
498
  async onObjectChange(id, obj) {
490
- this.log.debug(`${id} is changed into ${JSON.stringify(obj.common)}`);
499
+ this.log.silly(`${id} is changed into ${JSON.stringify(obj)}`);
491
500
  const activeFunction = 'main.js - onObjectChange';
492
501
  this.log.silly(`Function ${activeFunction} started.`);
493
502
  try {
494
- // Only work, if bridge is activ
495
- if (this.bridge) {
496
- // Erzeugen der HA Bridged für Control
497
- // check for new Entry
498
- const members = obj.common.members;
499
- for (const member of members) {
500
- if (!this.bridge.ForeignBridgeMembers[member]) {
501
- if (!member.startsWith(this.namespace)) {
502
- await this.bridge?.discoverForeignRange(member);
503
- } else {
504
- this.log.warn(
505
- `The bridge enum is set within adapternamespace. please remove form id: ${member}`,
506
- );
503
+ // Internal Objects => Assign to objectStore
504
+ if (id.startsWith(this.namespace)) {
505
+ // Update State in objectStore
506
+ await this.objectStore?.generateObjectStructureFromId(id, { payload: { object: obj } });
507
+
508
+ // External States
509
+ } else {
510
+ // Only work, if bridge is activ
511
+ if (this.bridge) {
512
+ // Erzeugen der HA Bridged für Control
513
+ // check for new Entry
514
+ const members = obj.common.members;
515
+ for (const member of members) {
516
+ if (!this.bridge.ForeignBridgeMembers[member]) {
517
+ if (!member.startsWith(this.namespace)) {
518
+ await this.bridge?.discoverForeignRange(member);
519
+ } else {
520
+ this.log.warn(
521
+ `The bridge enum is set within adapternamespace. please remove form id: ${member}`,
522
+ );
523
+ }
524
+ return;
507
525
  }
508
- return;
509
526
  }
510
- }
511
527
 
512
- // check for Entry removed
513
- for (const member of Object.values(this.bridge.ForeignBridgeMembers)) {
514
- if (!members.includes(member)) {
515
- await this.bridge.discoverForeignRange(member, true);
516
- return;
528
+ // check for Entry removed
529
+ for (const member of Object.values(this.bridge.ForeignBridgeMembers)) {
530
+ if (!members.includes(member)) {
531
+ await this.bridge.discoverForeignRange(member, true);
532
+ return;
533
+ }
517
534
  }
518
535
  }
519
536
  }
@@ -921,6 +938,9 @@ class Lorawan extends utils.Adapter {
921
938
  // Query for Namespace => Just publish foreign States with ack = true
922
939
  if (!id.startsWith(this.namespace)) {
923
940
  await this.bridge?.publishId(id, state.val, {});
941
+ } else {
942
+ // Update State in objectStore
943
+ await this.objectStore?.generateObjectStructureFromId(id, { payload: { state: state } });
924
944
  }
925
945
  }
926
946
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.lorawan",
3
- "version": "1.19.34",
3
+ "version": "1.20.1",
4
4
  "description": "converts the desired lora gateway data to a ioBroker structure",
5
5
  "author": {
6
6
  "name": "BenAhrdt",
@@ -26,6 +26,7 @@
26
26
  },
27
27
  "dependencies": {
28
28
  "@iobroker/adapter-core": "^3.3.2",
29
+ "@iobroker/dm-utils": "^1.0.16",
29
30
  "easy-crc": "^1.1.0",
30
31
  "lodash": "^4.17.21",
31
32
  "mqtt": "^5.14.1",