iobroker.lorawan 0.1.0 → 0.1.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
@@ -19,6 +19,9 @@ Adapter was created in collaboration with Joerg Froehner LoraWan@hafenmeister.co
19
19
  Placeholder for the next version (at the beginning of the line):
20
20
  ### **WORK IN PROGRESS**
21
21
  -->
22
+ ### 0.1.1 (2024-01-30)
23
+ * (BenAhrdt) reduceing calling changeInfo > create expersettings to send downlinks with uplink
24
+
22
25
  ### 0.1.0 (2024-01-26)
23
26
  * (BenAhrdt) removing downlink/configuration path and first tests of send downlink with uplink
24
27
 
@@ -8,7 +8,7 @@
8
8
  "port": "Port",
9
9
  "portTooltip": "Geben Sie den Port für die Verbindung ein",
10
10
  "SSL": "SSL",
11
- "sslTooltip": "Wenn Ihre Verbindung SSL verwendet, aktivieren Sie bitte diese checkbox (anstelle von http wird hppts verwendet).",
11
+ "sslTooltip": "Wenn Ihre Verbindung SSL verwendet, aktivieren Sie bitte dieses Kontrollkästchen (anstelle von mqtt wird mqtts verwendet).",
12
12
  "AuthenticationHeader": "Authentifizierungseinstellungen",
13
13
  "AuthenticationInformation": "Legen Sie die Authentifizierung für Ihren Server fest (falls erforderlich)",
14
14
  "username": "Benutzername",
@@ -17,10 +17,11 @@
17
17
  "passwordTooltip": "Geben Sie Ihr Passwort ein",
18
18
  "OriginHeader": "Ursprungseinstellungen",
19
19
  "OriginInformation": "Legen Sie den Ursprung der erwarteten Daten fest",
20
- "origin": "Herkunft",
21
- "originTooltip": "Wählen Sie die Herkunft Ihrer Daten aus",
20
+ "origin": "Ursprung",
21
+ "originTooltip": "Wählen Sie die Ursprung Ihrer Daten aus",
22
22
  "downlinkConfig": "Donwlink-Konfiguration",
23
23
  "name": "Name",
24
+ "nameTooltip": "Geben Sie für diesen Downlink den Namen des States ein",
24
25
  "portDownlink": "Port",
25
26
  "portDownlinkTooltip": "Geben Sie den Port ein, den Sie im Downlink senden möchten",
26
27
  "priority": "Priorität",
@@ -30,22 +31,25 @@
30
31
  "confirmed": "bestätigt",
31
32
  "confirmedTooltip": "Wenn Sie den Download mit einer bestätigten Nachricht senden möchten, aktivieren Sie diese Option",
32
33
  "front": "Führend (hex)",
33
- "frontTooltip": "Geben Sie den vor Ihrem Wert führenden Hex-Code ein, der heruntergeladen werden soll",
34
+ "frontTooltip": "Geben Sie den Frontwert im Hex-Format ein, der heruntergeladen werden soll",
34
35
  "end": "Folgend (hex)",
35
- "endTooltip": "Geben Sie den nach Ihrem Wert folgenden Hex-Code ein, der heruntergeladen werden soll",
36
+ "endTooltip": "Geben Sie den Endwert im Hex-Format ein, der heruntergeladen werden soll",
36
37
  "length": "Gesamtlänge",
37
- "lengthTooltip": "Geben Sie den Wert des gesamten Downlink-Payloads ein",
38
+ "lengthTooltip": "Geben Sie den Wert der gesamten Downlink-Nutzlast ein",
38
39
  "on": "An",
39
40
  "onTooltip": "Geben Sie den Wert ein, den Sie senden möchten, wenn Sie den Status auf „true“ setzen",
40
- "off": "Aus",
41
+ "off": "aus",
41
42
  "offTooltip": "Geben Sie den Wert ein, den Sie senden möchten, wenn Sie den Status auf „false“ setzen",
42
- "onClick": "Klick",
43
- "onClickTooltip": "Geben Sie den Wert ein, den Sie senden möchten, wenn Sie den Status auf „True“ setzen (Klicken des Buttons).",
43
+ "onClick": "bei Klick",
44
+ "onClickTooltip": "Geben Sie den Wert ein, den Sie senden möchten, wenn Sie den Status auf „True“ setzen (Klick auf die Schaltfläche).",
44
45
  "multiplyfaktor": "Multiplikationsfaktor",
45
- "multiplyfaktorTooltip": "Geben Sie den Faktor ein, mit dem Sie Ihre Daten multiplizieren möchten (z.B. 60 für Eingabe 1(min) => 60s)",
46
+ "multiplyfaktorTooltip": "Geben Sie den Faktor ein, mit dem Sie Ihre Daten multiplizieren möchten (z. B. 60 für Eingabe 1(min) => 60s)",
46
47
  "unit": "Einheit",
47
48
  "unitTooltip": "Geben Sie die Einheit für Ihren Wert ein",
48
49
  "deviceType": "Gerätetyp",
49
- "deviceTypeTooltip": "Geben Sie den Namen des Gerätetyps ein, für welchen diese Konfiguration gültig ist. (z. B. 'Dragino XY' passt auch zu 'Dragino')",
50
- "nameTooltip": "Geben Sie für den Datenpunkt dieses Downlinks ein"
50
+ "expertSettings": "Experten-Einstellungen",
51
+ "enabled & collect": "aktiviert & sammeln",
52
+ "deviceTypeTooltip": "Geben Sie den Namen des Gerätetyps ein. Diese Konfiguration ist gültig. (z. B. Dragino XY passt auch zu Dragino)",
53
+ "sendWithUplink": "mit Uplink senden",
54
+ "sendWithUplinkTooltip": "Wählen Sie Ihren Sendemodus für Konfigurationen mit dem gewünschten Gerätetyp"
51
55
  }
@@ -47,5 +47,9 @@
47
47
  "unit": "unit",
48
48
  "unitTooltip": "insert the unit for your value",
49
49
  "deviceType": "device-type",
50
- "deviceTypeTooltip": "insert the name of the device type, this config is valid. (eg. Dragino XY also matches Dragino)"
50
+ "expertSettings": "Expert-Settings",
51
+ "enabled & collect": "enabled & collect",
52
+ "deviceTypeTooltip": "insert the name of the device type, this config is valid. (eg. Dragino XY also matches Dragino)",
53
+ "sendWithUplink": "send with uplink",
54
+ "sendWithUplinkTooltip": "choose your send mode for configs with the desired devicetype"
51
55
  }
@@ -17,10 +17,8 @@
17
17
  "passwordTooltip": "ingresa tu contraseña",
18
18
  "OriginHeader": "Configuración de origen",
19
19
  "OriginInformation": "Establecer el origen de los datos esperados.",
20
- "ttn": "TTN (La red Thinks)",
21
- "ttnTooltip": "habilitar el uso de TTN",
22
- "chirpstack": "Pila de chirridos",
23
- "chirpstackTooltip": "habilitar el uso de chirpstackTooltip",
20
+ "origin": "origen",
21
+ "originTooltip": "selecciona el origen de tus datos",
24
22
  "downlinkConfig": "Configuración de enlace donwlink",
25
23
  "name": "nombre",
26
24
  "nameTooltip": "inserte el nombre del estado, para este enlace descendente",
@@ -49,7 +47,9 @@
49
47
  "unit": "unidad",
50
48
  "unitTooltip": "inserte la unidad para su valor",
51
49
  "deviceType": "tipo de dispositivo",
50
+ "expertSettings": "Configuración de expertos",
51
+ "enabled & collect": "habilitado y recolectar",
52
52
  "deviceTypeTooltip": "inserte el nombre del tipo de dispositivo, esta configuración es válida. (por ejemplo, Dragino XY también coincide con Dragino)",
53
- "origin": "origen",
54
- "originTooltip": "selecciona el origen de tus datos"
53
+ "sendWithUplink": "enviar con enlace ascendente",
54
+ "sendWithUplinkTooltip": "elija su modo de envío para configuraciones con el tipo de dispositivo deseado"
55
55
  }
@@ -17,10 +17,8 @@
17
17
  "passwordTooltip": "saisissez votre mot de passe",
18
18
  "OriginHeader": "Paramètres d'origine",
19
19
  "OriginInformation": "Définir l'origine des données attendues",
20
- "ttn": "TTN (Le réseau Thinks)",
21
- "ttnTooltip": "permettre d'utiliser TTN",
22
- "chirpstack": "Pile gazouillante",
23
- "chirpstackTooltip": "activer l'utilisation de chirpstackTooltip",
20
+ "origin": "origine",
21
+ "originTooltip": "sélectionnez l'origine de vos données",
24
22
  "downlinkConfig": "Configuration du lien de téléchargement",
25
23
  "name": "nom",
26
24
  "nameTooltip": "insérez le nom de l'état, pour ce lien descendant",
@@ -49,7 +47,9 @@
49
47
  "unit": "unité",
50
48
  "unitTooltip": "insérez l'unité pour votre valeur",
51
49
  "deviceType": "type d'appareil",
50
+ "expertSettings": "Paramètres experts",
51
+ "enabled & collect": "activé et collecté",
52
52
  "deviceTypeTooltip": "insérez le nom du type d'appareil, cette configuration est valide. (par exemple, Dragino XY correspond également à Dragino)",
53
- "origin": "origine",
54
- "originTooltip": "sélectionnez l'origine de vos données"
53
+ "sendWithUplink": "envoyer avec liaison montante",
54
+ "sendWithUplinkTooltip": "choisissez votre mode d'envoi pour les configurations avec le type d'appareil souhaité"
55
55
  }
@@ -17,10 +17,8 @@
17
17
  "passwordTooltip": "inserisci la tua password",
18
18
  "OriginHeader": "Impostazioni dell'origine",
19
19
  "OriginInformation": "Imposta l'origine dei dati attesi",
20
- "ttn": "TTN (La rete dei pensieri)",
21
- "ttnTooltip": "abilitare l'uso del TTN",
22
- "chirpstack": "Chirpstack",
23
- "chirpstackTooltip": "abilitare l'uso di chirpstackTooltip",
20
+ "origin": "origine",
21
+ "originTooltip": "seleziona l'origine dei tuoi dati",
24
22
  "downlinkConfig": "Configurazione downloadlink",
25
23
  "name": "nome",
26
24
  "nameTooltip": "inserire il nome dello stato, per questo downlink",
@@ -49,7 +47,9 @@
49
47
  "unit": "unità",
50
48
  "unitTooltip": "inserisci l'unità per il tuo valore",
51
49
  "deviceType": "tipo di dispositivo",
50
+ "expertSettings": "Impostazioni avanzate",
51
+ "enabled & collect": "abilitato e raccogli",
52
52
  "deviceTypeTooltip": "inserire il nome del tipo di dispositivo, questa configurazione è valida. (es. Dragino XY corrisponde anche a Dragino)",
53
- "origin": "origine",
54
- "originTooltip": "seleziona l'origine dei tuoi dati"
53
+ "sendWithUplink": "inviare con uplink",
54
+ "sendWithUplinkTooltip": "scegli la modalità di invio per le configurazioni con il tipo di dispositivo desiderato"
55
55
  }
@@ -17,10 +17,8 @@
17
17
  "passwordTooltip": "voer uw wachtwoord in",
18
18
  "OriginHeader": "Oorspronkelijke instellingen",
19
19
  "OriginInformation": "Stel de oorsprong van de verwachte gegevens in",
20
- "ttn": "TTN (het Thinks-netwerk)",
21
- "ttnTooltip": "inschakelen om TTN te gebruiken",
22
- "chirpstack": "Tjilpstapel",
23
- "chirpstackTooltip": "schakel het gebruik van chirpstackTooltip in",
20
+ "origin": "oorsprong",
21
+ "originTooltip": "selecteer de herkomst van uw gegevens",
24
22
  "downlinkConfig": "Donwlink-configuratie",
25
23
  "name": "naam",
26
24
  "nameTooltip": "voer de naam van de staat in voor deze downlink",
@@ -49,7 +47,9 @@
49
47
  "unit": "eenheid",
50
48
  "unitTooltip": "voer de eenheid voor uw waarde in",
51
49
  "deviceType": "soort apparaat",
50
+ "expertSettings": "Expert-instellingen",
51
+ "enabled & collect": "ingeschakeld en verzamelen",
52
52
  "deviceTypeTooltip": "voer de naam van het apparaattype in, deze configuratie is geldig. (bijv. Dragino XY komt ook overeen met Dragino)",
53
- "origin": "oorsprong",
54
- "originTooltip": "selecteer de herkomst van uw gegevens"
53
+ "sendWithUplink": "verzenden met uplink",
54
+ "sendWithUplinkTooltip": "kies uw verzendmodus voor configuraties met het gewenste apparaattype"
55
55
  }
@@ -17,10 +17,8 @@
17
17
  "passwordTooltip": "wprowadź hasło",
18
18
  "OriginHeader": "Ustawienia oryginalności",
19
19
  "OriginInformation": "Ustaw pochodzenie oczekiwanych danych",
20
- "ttn": "TTN (Sieć Myśli)",
21
- "ttnTooltip": "umożliwić korzystanie z TTN",
22
- "chirpstack": "Chirpstack",
23
- "chirpstackTooltip": "włącz użycie chirpstackTooltip",
20
+ "origin": "pochodzenie",
21
+ "originTooltip": "wybierz pochodzenie swoich danych",
24
22
  "downlinkConfig": "Konfiguracja Donwlink",
25
23
  "name": "nazwa",
26
24
  "nameTooltip": "wstaw nazwę stanu dla tego łącza pobierania",
@@ -49,7 +47,9 @@
49
47
  "unit": "jednostka",
50
48
  "unitTooltip": "wstaw jednostkę swojej wartości",
51
49
  "deviceType": "rodzaj urządzenia",
50
+ "expertSettings": "Ustawienia eksperckie",
51
+ "enabled & collect": "włączone i zbierane",
52
52
  "deviceTypeTooltip": "wstaw nazwę typu urządzenia, ta konfiguracja jest prawidłowa. (np. Dragino XY pasuje również do Dragino)",
53
- "origin": "pochodzenie",
54
- "originTooltip": "wybierz pochodzenie swoich danych"
53
+ "sendWithUplink": "wyślij za pomocą łącza zwrotnego",
54
+ "sendWithUplinkTooltip": "wybierz tryb wysyłania konfiguracji z żądanym typem urządzenia"
55
55
  }
@@ -17,10 +17,8 @@
17
17
  "passwordTooltip": "insira sua senha",
18
18
  "OriginHeader": "Configurações de origem",
19
19
  "OriginInformation": "Defina a origem dos dados esperados",
20
- "ttn": "TTN (A Rede Pensa)",
21
- "ttnTooltip": "habilitar o uso de TTN",
22
- "chirpstack": "Pilha de chirp",
23
- "chirpstackTooltip": "habilitar o uso do chirpstackTooltip",
20
+ "origin": "origem",
21
+ "originTooltip": "selecione a origem dos seus dados",
24
22
  "downlinkConfig": "Configuração Donwlink",
25
23
  "name": "nome",
26
24
  "nameTooltip": "insira o nome do estado, para este downlink",
@@ -49,7 +47,9 @@
49
47
  "unit": "unidade",
50
48
  "unitTooltip": "insira a unidade para seu valor",
51
49
  "deviceType": "tipo de dispositivo",
50
+ "expertSettings": "Configurações de especialistas",
51
+ "enabled & collect": "ativado e coletado",
52
52
  "deviceTypeTooltip": "insira o nome do tipo de dispositivo, esta configuração é válida. (por exemplo, Dragino XY também corresponde a Dragino)",
53
- "origin": "origem",
54
- "originTooltip": "selecione a origem dos seus dados"
53
+ "sendWithUplink": "enviar com uplink",
54
+ "sendWithUplinkTooltip": "escolha seu modo de envio para configurações com o tipo de dispositivo desejado"
55
55
  }
@@ -17,10 +17,8 @@
17
17
  "passwordTooltip": "введите свой пароль",
18
18
  "OriginHeader": "Оригинальные настройки",
19
19
  "OriginInformation": "Установите источник ожидаемых данных",
20
- "ttn": "ТТН (Сеть мыслителей)",
21
- "ttnTooltip": "включить использование ТТН",
22
- "chirpstack": "Чирпстек",
23
- "chirpstackTooltip": "включить использование chirpstackTooltip",
20
+ "origin": "источник",
21
+ "originTooltip": "выберите источник ваших данных",
24
22
  "downlinkConfig": "Donwlink-конфигурация",
25
23
  "name": "имя",
26
24
  "nameTooltip": "вставьте название штата для этого даулинка",
@@ -49,7 +47,9 @@
49
47
  "unit": "единица",
50
48
  "unitTooltip": "вставьте единицу измерения вашего значения",
51
49
  "deviceType": "тип устройства",
50
+ "expertSettings": "Эксперт-Настройки",
51
+ "enabled & collect": "включить и собирать",
52
52
  "deviceTypeTooltip": "вставьте название типа устройства, этот конфиг действителен. (например, Dragino XY также соответствует Dragino)",
53
- "origin": "источник",
54
- "originTooltip": "выберите источник ваших данных"
53
+ "sendWithUplink": "отправить по восходящей линии связи",
54
+ "sendWithUplinkTooltip": "выберите режим отправки для конфигов с нужным типом устройства"
55
55
  }
@@ -17,10 +17,8 @@
17
17
  "passwordTooltip": "введіть свій пароль",
18
18
  "OriginHeader": "Налаштування походження",
19
19
  "OriginInformation": "Встановіть джерело очікуваних даних",
20
- "ttn": "TTN (The Thinks Network)",
21
- "ttnTooltip": "дозволити використовувати ТТН",
22
- "chirpstack": "Chirpstack",
23
- "chirpstackTooltip": "увімкнути використання chirpstackTooltip",
20
+ "origin": "походження",
21
+ "originTooltip": "виберіть джерело даних",
24
22
  "downlinkConfig": "Конфігурація Donwlink",
25
23
  "name": "назва",
26
24
  "nameTooltip": "вставте назву штату для цього посилання",
@@ -49,7 +47,9 @@
49
47
  "unit": "одиниця",
50
48
  "unitTooltip": "вставте одиницю для вашого значення",
51
49
  "deviceType": "тип пристрою",
50
+ "expertSettings": "Експерт-Налаштування",
51
+ "enabled & collect": "увімкнено та збирайте",
52
52
  "deviceTypeTooltip": "вставте назву типу пристрою, ця конфігурація дійсна. (наприклад, Dragino XY також відповідає Dragino)",
53
- "origin": "походження",
54
- "originTooltip": "виберіть джерело даних"
53
+ "sendWithUplink": "надіслати за допомогою висхідної лінії",
54
+ "sendWithUplinkTooltip": "виберіть режим надсилання конфігурацій із потрібним типом пристрою"
55
55
  }
@@ -17,10 +17,8 @@
17
17
  "passwordTooltip": "输入您的密码",
18
18
  "OriginHeader": "原始设置",
19
19
  "OriginInformation": "设置预期数据的来源",
20
- "ttn": "TTN(思考网络)",
21
- "ttnTooltip": "启用 TTN",
22
- "chirpstack": "调频堆栈",
23
- "chirpstackTooltip": "启用使用 chirpstackTooltip",
20
+ "origin": "起源",
21
+ "originTooltip": "选择您的数据来源",
24
22
  "downlinkConfig": "下行链路配置",
25
23
  "name": "姓名",
26
24
  "nameTooltip": "为此下行链接插入州名称",
@@ -49,7 +47,9 @@
49
47
  "unit": "单元",
50
48
  "unitTooltip": "插入您的值的单位",
51
49
  "deviceType": "设备类型",
50
+ "expertSettings": "专家设置",
51
+ "enabled & collect": "启用并收集",
52
52
  "deviceTypeTooltip": "插入设备类型的名称,此配置有效。 (例如,Dragino XY 也匹配 Dragino)",
53
- "origin": "起源",
54
- "originTooltip": "选择您的数据来源"
53
+ "sendWithUplink": "通过上行链路发送",
54
+ "sendWithUplinkTooltip": "选择具有所需设备类型的配置的发送模式"
55
55
  }
@@ -239,6 +239,69 @@
239
239
  ]
240
240
  }
241
241
  }
242
+ },
243
+ "ExpertsettingsTab":{
244
+ "type": "panel",
245
+ "label": "expertSettings",
246
+ "items": {
247
+ "ExpertsettingsAccordion":{
248
+ "type":"accordion",
249
+ "titleAttr": "deviceType",
250
+ "clone": true,
251
+ "sm":12,
252
+ "items":[
253
+ {
254
+ "type": "autocomplete",
255
+ "attr": "deviceType",
256
+ "label": "deviceType",
257
+ "tooltip": "deviceTypeTooltip",
258
+ "options": [
259
+ {"label":"all","value":"all"}
260
+ ],
261
+ "default": "all",
262
+ "freeSolo": true,
263
+ "sm":2
264
+ },
265
+ {
266
+ "type": "number",
267
+ "attr": "port",
268
+ "label": "portDownlink",
269
+ "tooltip": "portDownlinkTooltip",
270
+ "default": 2,
271
+ "sm":2
272
+ },
273
+ {
274
+ "type": "text",
275
+ "attr": "priority",
276
+ "label": "priority",
277
+ "tooltip": "priorityTooltip",
278
+ "default": "NORMAL",
279
+ "sm":2
280
+ },
281
+ {
282
+ "type": "checkbox",
283
+ "attr": "confirmed",
284
+ "label": "confirmed",
285
+ "tooltip": "confirmedTooltip",
286
+ "default": false,
287
+ "sm":2
288
+ },
289
+ {
290
+ "type": "select",
291
+ "attr": "sendWithUplink",
292
+ "label": "sendWithUplink",
293
+ "tooltip": "sendWithUplinkTooltip",
294
+ "options": [
295
+ {"label":"disabled","value":"disabled"},
296
+ {"label":"enabled","value":"enabled"},
297
+ {"label":"enabled & collect","value":"enabled & collect"}
298
+ ],
299
+ "default": "disabled",
300
+ "sm":2
301
+ }
302
+ ]
303
+ }
304
+ }
242
305
  }
243
306
  }
244
307
  }
package/io-package.json CHANGED
@@ -1,8 +1,21 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "lorawan",
4
- "version": "0.1.0",
4
+ "version": "0.1.1",
5
5
  "news": {
6
+ "0.1.1": {
7
+ "en": "reduceing calling changeInfo > create expersettings to send downlinks with uplink",
8
+ "de": "reduzierung der Anrufänderung Info > erstellen Exkursionen, um Downlinks mit Uplink zu senden",
9
+ "ru": "уменьшение изменения вызовов Инфо > создать отрывки для отправки обратных ссылок с помощью uplink",
10
+ "pt": "redução da mudança de chamada Info > criar expersettings para enviar downlinks com uplink",
11
+ "nl": "verminderen van aanroepverandering Info > maakt expersettings om downlinks met uplink te versturen",
12
+ "fr": "réduire le changement d'appel Info > créer des expersettings pour envoyer des liens vers le bas avec uplink",
13
+ "it": "ridurre il cambiamento di chiamata Info > creare expersettings per inviare downlink con uplink",
14
+ "es": "reducción del cambio de llamada Info > crear explotaciones para enviar enlaces descendentes con uplink",
15
+ "pl": "redukcja zmiany wywołania Info > tworzenie expersettings do wysyłania linków w dół za pomocą łącza",
16
+ "uk": "зменшення зміни виклику Інформація > створити налаштування для відправки посилань з посиланням",
17
+ "zh-cn": "减少调用更改 Info > 创建带上行链路的下行链路"
18
+ },
6
19
  "0.1.0": {
7
20
  "en": "removing downlink/configuration path and first tests of send downlink with uplink",
8
21
  "de": "entfernen von downlink/konfigurationspfad und ersten tests von downlink mit uplink",
@@ -80,19 +93,6 @@
80
93
  "pl": "katalog chirpstock bugfix",
81
94
  "uk": "javascript licenses api веб-сайт",
82
95
  "zh-cn": "bugfix 奇普斯塔克目录"
83
- },
84
- "0.0.13": {
85
- "en": "change device id selecting in chirpstack out of directory (for downlink queued)",
86
- "de": "id auswahl in chirpstack aus verzeichnis (für downlink queued)",
87
- "ru": "переменное устройство id выбора в кирпштак из каталога (для очерченной очертания обратной ссылки)",
88
- "pt": "mudar o dispositivo id selecionando no chirpstack fora do diretório (para downlink queued)",
89
- "nl": "apparaat-id wijzigen in chirpstack uit de map (voor downlink wachtrij)",
90
- "fr": "modifier l'id de l'appareil en sélectionnant dans chirpstack hors du répertoire (pour la file d'attente en bas)",
91
- "it": "cambiamento dispositivo id selezionando in chirpstack fuori directory (per downlink coda)",
92
- "es": "cambiar dispositivo id seleccionando en chirpstack fuera del directorio (para downlink queued)",
93
- "pl": "zmienić id urządzenia wybierając w chirpstock z katalogu (dla downlink kolejka)",
94
- "uk": "змінити пристрій id виберіть в chirpstack з каталогу (для кривих посилань)",
95
- "zh-cn": "更改设备 id 从目录中选择 chirpstack (用于下链条队列)"
96
96
  }
97
97
  },
98
98
  "title": "LoRaWAN",
@@ -169,7 +169,8 @@
169
169
  "password": "",
170
170
  "ssl": true,
171
171
  "origin": "ttn",
172
- "downlinkConfigAccordion": {}
172
+ "downlinkConfigAccordion": {},
173
+ "ExpertsettingsAccordion": {}
173
174
  },
174
175
  "objects": [],
175
176
  "instanceObjects": [
@@ -193,6 +194,19 @@
193
194
  "def": false
194
195
  },
195
196
  "native": {}
197
+ },
198
+ {
199
+ "_id": "info.logAvailableConfignames",
200
+ "type": "state",
201
+ "common": {
202
+ "role": "button",
203
+ "name": "logs the names of available device configurations",
204
+ "type": "boolean",
205
+ "read": true,
206
+ "write": true,
207
+ "def": false
208
+ },
209
+ "native": {}
196
210
  }
197
211
  ]
198
212
  }
@@ -132,11 +132,11 @@ class directorieshandlerClass {
132
132
  // Check the the elementname is not in ignored object
133
133
  if(!this.ignoredElementNames[elementName] && !options?.ignoredElementNames[elementName]){
134
134
  // Check if the element is an object
135
- if(typeof obj[elementName] === "object" && !(obj[elementName] && obj[elementName].isState)){
135
+ if(typeof obj[elementName] === "object" && obj[elementName] && !obj[elementName].isState){
136
136
  // if there is an declared ObjectStateName (must be a function)=> take it
137
137
  let objectId = `${startDirectory}.${elementName}`;
138
138
  let internalObjectId = elementName;
139
- if(obj[elementName] && obj[elementName].objectStateName){
139
+ if(obj[elementName].objectStateName){
140
140
  internalObjectId = `${await obj[elementName].objectStateName(topic,message)}`;
141
141
  objectId = `${startDirectory}.${internalObjectId}`;
142
142
  }
@@ -144,9 +144,9 @@ class directorieshandlerClass {
144
144
  objectId = objectId.substring(1,objectId.length);
145
145
  }
146
146
  await this.adapter.setObjectNotExistsAsync(objectId,{
147
- type: obj[elementName]? obj[elementName].objectType? obj[elementName].objectType : "folder" : "folder",
147
+ type: obj[elementName].objectType? obj[elementName].objectType : "folder",
148
148
  common: {
149
- name: obj[elementName]? obj[elementName].objectCommonName? obj[elementName].objectCommonName : "" : ""
149
+ name: obj[elementName].objectCommonName? obj[elementName].objectCommonName : ""
150
150
  },
151
151
  native : {},
152
152
  });
@@ -177,12 +177,12 @@ class directorieshandlerClass {
177
177
  await this.adapter.setObjectNotExistsAsync(objectId,{
178
178
  type: "state",
179
179
  common: {
180
- type: stateCommonType!== "object"? stateCommonType: "mixed",
180
+ type: stateCommonType !== undefined? stateCommonType!== "object"? stateCommonType: "mixed": "mixed",
181
181
  name: stateCommonName,
182
182
  role: "value",
183
183
  read: true,
184
- unit: obj[elementName].CommonStateUnit? obj[elementName].CommonStateUnit : this.units[internalObjectId]? this.units[internalObjectId] : "",
185
- def: obj[elementName].stateCommonDef? obj[elementName].stateCommonDef: stateCommonType === "boolean"? false : stateCommonType === "number"? 0: "",
184
+ unit: obj[elementName]? obj[elementName].CommonStateUnit? obj[elementName].CommonStateUnit : this.units[internalObjectId]? this.units[internalObjectId] : "" : "",
185
+ def: obj[elementName]? obj[elementName].stateCommonDef? obj[elementName].stateCommonDef: stateCommonType === "boolean"? false : stateCommonType === "number"? 0: "": stateCommonType === "number"? 0: "",
186
186
  write: stateCommonWrite
187
187
  },
188
188
  native: {},
@@ -199,8 +199,7 @@ class directorieshandlerClass {
199
199
  }
200
200
  }
201
201
  catch(error){
202
- this.adapter.log.error(`error at ${activeFunction}: ` + error);
203
- this.adapter.log.warn("Message: " + JSON.stringify(message));
202
+ this.adapter.log.error(`error at ${activeFunction}: ${error} - - - Message: ${JSON.stringify(message)}`);
204
203
  }
205
204
  }
206
205
 
@@ -220,8 +219,7 @@ class directorieshandlerClass {
220
219
  }
221
220
  }
222
221
  catch(error){
223
- this.adapter.log.error(`error at ${activeFunction}: ` + error);
224
- this.adapter.log.warn("Message: " + JSON.stringify(message));
222
+ this.adapter.log.error(`error at ${activeFunction}: ${error} - - - Message: ${JSON.stringify(message)}`);
225
223
  }
226
224
  }
227
225
 
@@ -241,8 +239,7 @@ class directorieshandlerClass {
241
239
  }
242
240
  }
243
241
  catch(error){
244
- this.adapter.log.error(`error at ${activeFunction}: ` + error);
245
- this.adapter.log.warn("Message: " + JSON.stringify(message));
242
+ this.adapter.log.error(`error at ${activeFunction}: ${error} - - - Message: ${JSON.stringify(message)}`);
246
243
  }
247
244
  }
248
245
 
@@ -262,8 +259,7 @@ class directorieshandlerClass {
262
259
  }
263
260
  }
264
261
  catch(error){
265
- this.adapter.log.error(`error at ${activeFunction}: ` + error);
266
- this.adapter.log.warn("Topic: " + JSON.stringify(topic));
262
+ this.adapter.log.error(`error at ${activeFunction}: ${error} - - - Topic: ${JSON.stringify(topic)}`);
267
263
  }
268
264
  }
269
265
 
@@ -296,8 +292,7 @@ class directorieshandlerClass {
296
292
  }
297
293
  }
298
294
  catch(error){
299
- this.adapter.log.error(`error at ${activeFunction}: ` + error);
300
- this.adapter.log.warn("Message: " + JSON.stringify(message));
295
+ this.adapter.log.error(`error at ${activeFunction}: ${error} - - - Topic: ${JSON.stringify(topic)}`);
301
296
  }
302
297
  }
303
298
 
@@ -324,8 +319,7 @@ class directorieshandlerClass {
324
319
  }
325
320
  }
326
321
  catch(error){
327
- this.adapter.log.error(`error at ${activeFunction}: ` + error);
328
- this.adapter.log.warn("Message: " + JSON.stringify(message));
322
+ this.adapter.log.error(`error at ${activeFunction}: ${error} - - - Message: ${JSON.stringify(message)}`);
329
323
  }
330
324
  }
331
325
 
@@ -350,8 +344,7 @@ class directorieshandlerClass {
350
344
  return topicResolved;
351
345
  }
352
346
  catch(error){
353
- this.adapter.log.error(`error at ${activeFunction}: ` + error);
354
- this.adapter.log.warn("Topic: " + JSON.stringify(topic));
347
+ this.adapter.log.error(`error at ${activeFunction}: ${error} - - - Topic: ${JSON.stringify(topic)}`);
355
348
  }
356
349
  }
357
350
 
@@ -405,8 +398,7 @@ class directorieshandlerClass {
405
398
  }
406
399
  }
407
400
  catch(error){
408
- this.adapter.log.error(`error at ${activeFunction}: ` + error);
409
- this.adapter.log.warn("Message: " + JSON.stringify(message));
401
+ this.adapter.log.error(`error at ${activeFunction}: ${error} - - - Message: ${JSON.stringify(message)}`);
410
402
  }
411
403
  }
412
404
 
@@ -447,8 +439,7 @@ class directorieshandlerClass {
447
439
  }
448
440
  }
449
441
  catch(error){
450
- this.adapter.log.error(`error at ${activeFunction}: ` + error);
451
- this.adapter.log.warn("Message: " + JSON.stringify(message));
442
+ this.adapter.log.error(`error at ${activeFunction}: ${error} - - - Message: ${JSON.stringify(message)}`);
452
443
  }
453
444
  }
454
445
 
@@ -473,8 +464,7 @@ class directorieshandlerClass {
473
464
  return topicResolved;
474
465
  }
475
466
  catch(error){
476
- this.adapter.log.error(`error at ${activeFunction}: ` + error);
477
- this.adapter.log.warn("Topic: " + JSON.stringify(topic));
467
+ this.adapter.log.error(`error at ${activeFunction}: ${error} - - - Topic: ${JSON.stringify(topic)}`);
478
468
  }
479
469
  }
480
470
  }
@@ -4,6 +4,7 @@ class downlinkConfighandlerClass {
4
4
  constructor(adapter) {
5
5
  this.adapter = adapter;
6
6
  this.activeDownlinkConfigs = {};
7
+ this.activeExpertConfigs = {};
7
8
  }
8
9
 
9
10
  /*********************************************************************
@@ -14,14 +15,20 @@ class downlinkConfighandlerClass {
14
15
  const activeFunction = "addAndMergeDownlinkConfigs";
15
16
  this.adapter.log.silly(`the standard and configed downlinks will be merged`);
16
17
  try{
18
+ // Add standard downlink config
17
19
  const internalDownlinks = this.getJsonArrayFromDirectoryfiles(`${this.adapter.adapterDir}/lib/modules/downlinks`);
18
20
  if(Array.isArray(internalDownlinks)){
19
21
  for(const downlinkConfig of Object.values(internalDownlinks)){
20
- this.addDownlinkConfigByType(downlinkConfig);
22
+ this.addDownlinkConfigByType(downlinkConfig,this.activeDownlinkConfigs);
21
23
  }
22
24
  }
25
+ // Add user downlink config
23
26
  for(const downlinkConfig of Object.values(this.adapter.config.downlinkConfigAccordion)){
24
- this.addDownlinkConfigByType(downlinkConfig);
27
+ this.addDownlinkConfigByType(downlinkConfig,this.activeDownlinkConfigs);
28
+ }
29
+ // add expert configs
30
+ for(const expertConfig of Object.values(this.adapter.config.ExpertsettingsAccordion)){
31
+ this.addDownlinkConfigByType(expertConfig,this.activeExpertConfigs,{isExpertconfig:true});
25
32
  }
26
33
  }
27
34
  catch(error){
@@ -30,14 +37,19 @@ class downlinkConfighandlerClass {
30
37
  }
31
38
  }
32
39
 
33
- addDownlinkConfigByType(downlinkConfig){
40
+ addDownlinkConfigByType(downlinkConfig,config,options){
34
41
  const activeFunction = "addDownlinkConfigByType";
35
42
  try{
36
- if(!this.activeDownlinkConfigs[downlinkConfig.deviceType]){
37
- this.activeDownlinkConfigs[downlinkConfig.deviceType] = {};
43
+ if(!config[downlinkConfig.deviceType]){
44
+ config[downlinkConfig.deviceType] = {};
38
45
  }
39
- if(!this.activeDownlinkConfigs[downlinkConfig.deviceType][downlinkConfig.name]){
40
- this.activeDownlinkConfigs[downlinkConfig.deviceType][downlinkConfig.name] = downlinkConfig;
46
+ if(!options || !options.isExpertconfig){
47
+ if(!config[downlinkConfig.deviceType][downlinkConfig.name]){
48
+ config[downlinkConfig.deviceType][downlinkConfig.name] = downlinkConfig;
49
+ }
50
+ }
51
+ else{
52
+ config[downlinkConfig.deviceType] = downlinkConfig;
41
53
  }
42
54
  }
43
55
  catch(error){
@@ -64,6 +76,32 @@ class downlinkConfighandlerClass {
64
76
  }
65
77
  }
66
78
 
79
+ getBestMatchForExpertConfig(changeInfo){
80
+ const activeFunction = "checkBestMerge";
81
+ try{
82
+ let foundMatch = "";
83
+ let foundLength = 0;
84
+ for(const deviceType in this.activeExpertConfigs){
85
+ if((deviceType === "all" || changeInfo.deviceType.indexOf(deviceType) === 0) && deviceType.length > foundLength){
86
+ foundMatch = deviceType;
87
+ if(deviceType !== "all"){
88
+ foundLength = deviceType.length;
89
+ }
90
+ }
91
+ }
92
+
93
+ if(foundMatch !== ""){
94
+ return foundMatch;
95
+ }
96
+ else{
97
+ return undefined;
98
+ }
99
+ }
100
+ catch(error){
101
+ this.adapter.log.error(`error at ${activeFunction}: ` + error);
102
+ }
103
+ }
104
+
67
105
  getDownlinkConfig(changeInfo,options){
68
106
  const activeFunction = "getDownlinkConfig";
69
107
  this.adapter.log.silly(`the downlinkconfig is requested for the following changeinfo: ${JSON.stringify(changeInfo)}`);
@@ -23,14 +23,13 @@ class messagehandlerClass {
23
23
  }
24
24
 
25
25
  // Startup
26
- async generateDownlinkstatesAtStatup(){
26
+ async generateDownlinksAndRemoveStatesAtStatup(){
27
27
  const activeFunction = "generateDownlinkstatesAtStatup";
28
28
  try{
29
29
  const adapterObjectsAtStart = await this.adapter.getAdapterObjectsAsync();
30
30
  for(const adapterObject of Object.values(adapterObjectsAtStart)){
31
31
  if(adapterObject.type === "channel" && adapterObject.common.name !== "Information"){
32
- const stateId = this.adapter.removeNamespace(adapterObject._id);
33
- await this.fillWithDownlinkConfig(stateId);
32
+ await this.fillWithDownlinkConfig(adapterObject._id);
34
33
  //await this.addDirectoriesToPresentDirectory(`${stateId}`); Not used yet (Maybe for thefuture with more folders)
35
34
  }
36
35
  }
@@ -60,44 +59,50 @@ class messagehandlerClass {
60
59
  async fillWithDownlinkConfig(deviceStartdirectory){
61
60
  const activeFunction = "fillWithDownlinkConfig";
62
61
  try{
62
+ const changeInfo = await this.adapter.getChangeInfo(`${deviceStartdirectory}.fillDownlinkFolder`);
63
63
  const foundLength = {};
64
- for(const downlinkDevices of Object.values(this.adapter.downlinkConfighandler.activeDownlinkConfigs)){
65
- for(const downlinkConfig of Object.values(downlinkDevices)){
66
- this.adapter.log.silly(`the downlinkconfig ${JSON.stringify(downlinkConfig)}, will checked.`);
67
- const startDirectory = `${deviceStartdirectory}.downlink.control`;
68
- const changeInfo = await this.adapter.getChangeInfo(`${startDirectory}.${downlinkConfig.name}`);
69
- // check for forbidden states
70
- if(this.stateForbidden(changeInfo.changedState)){
71
- continue;
72
- }
73
- if(!foundLength[changeInfo.changedState]){
74
- foundLength[changeInfo.changedState] = 0;
75
- }
76
- if((downlinkConfig.deviceType === "all" || changeInfo.deviceType.indexOf(downlinkConfig.deviceType) === 0) && downlinkConfig.deviceType.length > foundLength[changeInfo.changedState]){
77
- let commonStateRole = "value";
78
- let commonStateType = downlinkConfig.type;
79
- if(commonStateType === "button"){
80
- commonStateType = "boolean";
81
- commonStateRole = "button";
64
+ //iterate downlinkDevice
65
+ for(const downlinkDevice in this.adapter.downlinkConfighandler.activeDownlinkConfigs){
66
+ // query for match deviceType
67
+ if((downlinkDevice === "all" || changeInfo.deviceType.indexOf(downlinkDevice) === 0)){
68
+ // iterate downlinkConfig
69
+ for(const downlinkConfig of Object.values(this.adapter.downlinkConfighandler.activeDownlinkConfigs[downlinkDevice])){
70
+ this.adapter.log.silly(`the downlinkconfig ${JSON.stringify(downlinkConfig)}, will checked.`);
71
+ // check for forbidden states
72
+ if(this.stateForbidden(changeInfo.changedState)){
73
+ continue;
82
74
  }
83
- else if(commonStateType === "ascii"){
84
- commonStateType = "string";
75
+ // Create found length if not defined
76
+ if(!foundLength[downlinkConfig.name]){
77
+ foundLength[downlinkConfig.name] = 0;
85
78
  }
86
- await this.adapter.setObjectAsync(`${startDirectory}.${downlinkConfig.name}`,{
87
- type: "state",
88
- common: {
89
- name: "",
90
- type: commonStateType,
91
- role: commonStateRole,
92
- read: true,
93
- write: true,
94
- unit: downlinkConfig.unit? downlinkConfig.unit:"",
95
- def: commonStateType === "boolean"? false : commonStateType === "number"? 0: "",
96
- },
97
- native: {},
98
- });
99
- if(downlinkDevices !=="all"){
100
- foundLength[changeInfo.changedState] = downlinkConfig.deviceType.length;
79
+ // check found length
80
+ if(downlinkDevice.length > foundLength[downlinkConfig.name]){
81
+ let commonStateRole = "value";
82
+ let commonStateType = downlinkConfig.type;
83
+ if(commonStateType === "button"){
84
+ commonStateType = "boolean";
85
+ commonStateRole = "button";
86
+ }
87
+ else if(commonStateType === "ascii"){
88
+ commonStateType = "string";
89
+ }
90
+ await this.adapter.setObjectAsync(`${deviceStartdirectory}.downlink.control.${downlinkConfig.name}`,{
91
+ type: "state",
92
+ common: {
93
+ name: "",
94
+ type: commonStateType,
95
+ role: commonStateRole,
96
+ read: true,
97
+ write: true,
98
+ unit: downlinkConfig.unit? downlinkConfig.unit:"",
99
+ def: commonStateType === "boolean"? false : commonStateType === "number"? 0: "",
100
+ },
101
+ native: {},
102
+ });
103
+ if(downlinkDevice !=="all"){
104
+ foundLength[downlinkConfig.name] = downlinkDevice.length;
105
+ }
101
106
  }
102
107
  }
103
108
  }
@@ -249,7 +254,7 @@ class messagehandlerClass {
249
254
  * ******************* Check downlink at uplink **********************
250
255
  * ******************************************************************/
251
256
 
252
- await this.adapter.checkSendDownlinkWithUplink(`${deviceStartdirectory}.downlink.control.Intervall`);
257
+ await this.adapter.checkSendDownlinkWithUplink(`${deviceStartdirectory}.downlink.control.push`);
253
258
  }
254
259
 
255
260
  /*********************************************************************
@@ -351,8 +356,7 @@ class messagehandlerClass {
351
356
  await this.fillWithDownlinkConfig(deviceStartdirectory);
352
357
  }
353
358
  catch(error){
354
- this.adapter.log.error(`error at ${activeFunction}: ` + error);
355
- this.adapter.log.warn("Message: " + JSON.stringify(message));
359
+ this.adapter.log.error(`error at ${activeFunction}: ${error} - - - Message: ${JSON.stringify(message)}`);
356
360
  }
357
361
  }
358
362
 
@@ -489,7 +493,7 @@ class messagehandlerClass {
489
493
  * ******************* Check downlink at uplink **********************
490
494
  * ******************************************************************/
491
495
 
492
- await this.adapter.checkSendDownlinkWithUplink(`${deviceStartdirectory}.downlink.control.Intervall`);
496
+ await this.adapter.checkSendDownlinkWithUplink(`${deviceStartdirectory}.downlink.control.push`);
493
497
  }
494
498
 
495
499
  /*********************************************************************
@@ -587,8 +591,7 @@ class messagehandlerClass {
587
591
 
588
592
  }
589
593
  catch(error){
590
- this.adapter.log.error(`error at ${activeFunction}: ` + error);
591
- this.adapter.log.warn("Message: " + JSON.stringify(message));
594
+ this.adapter.log.error(`error at ${activeFunction}: ${error} - - - Message: ${JSON.stringify(message)}`);
592
595
  }
593
596
  }
594
597
 
package/main.js CHANGED
@@ -47,17 +47,24 @@ class Lorawan extends utils.Adapter {
47
47
  this.downlinkConfighandler.addAndMergeDownlinkConfigs();
48
48
 
49
49
  // generate new configed downlinkstates on allready existing devices at adapter startup
50
- await this.messagehandler.generateDownlinkstatesAtStatup();
50
+ await this.messagehandler.generateDownlinksAndRemoveStatesAtStatup();
51
51
 
52
52
  //Subscribe all configuration and control states
53
53
  this.subscribeStatesAsync("*.configuration.*");
54
54
  this.subscribeStatesAsync("*downlink.control.*");
55
+ this.subscribeStatesAsync("*.logAvailableConfignames");
55
56
  this.log.debug(`the adapter start with the config: ${JSON.stringify(this.config)}.`);
56
57
  this.log.silly(`the whole reacable downlinkconfigs are: ${JSON.stringify(this.downlinkConfighandler.activeDownlinkConfigs)}`);
57
58
 
58
59
  /*setTimeout(async () => {
59
60
  await this.startSimulation();
60
61
  }, 5000);*/
62
+ /*setTimeout(async () => {
63
+ const topic = "application/d63c10b6-9263-4ab3-9299-4308fa19a2ad/device/f1c0ae0e-b4a2-4547-b360-7cfa15e85734/command/down";
64
+ const message = {devEui:"f1c0ae0e-b4a2-4547-b360-7cfa15e85734",confirmed:false,fPort:1,data:"AAA"};
65
+ await this.mqttClient?.publish(topic,JSON.stringify(message));
66
+ }, 5000);*/
67
+
61
68
  }
62
69
  catch(error){
63
70
  this.log.error(`error at ${activeFunction}: ` + error);
@@ -66,18 +73,19 @@ class Lorawan extends utils.Adapter {
66
73
 
67
74
  async startSimulation(){
68
75
 
69
- // const topic ="v3/hafi-ttn-lorawan@ttn/devices/eui-lobaro-modbus/up";
70
- // const message = {"end_device_ids":{"device_id":"eui-lobaro-modbus","application_ids":{"application_id":"hafi-ttn-lorawan"},"dev_eui":"70B3D5E050013950","join_eui":"D55B58C0DDC074DE","dev_addr":"260B5972"},"correlation_ids":["gs:uplink:01HMQZVSCX4D7JRDNFA7GJ9D4W"],"received_at":"2024-01-22T07:06:25.260676101Z","uplink_message":{"session_key_id":"AY0v/ZirzRkpNW0Cgjdhig==","f_port":20,"f_cnt":2,"frm_payload":"AA5BAf0AxwIAAQ==","decoded_payload":{"airhumidity":50.9,"airtemperature":19.9,"port":20,"relais1":0,"relais2":1,"relais3":null,"relais5":null,"volt":3.649,"zisternenpegel":2},"rx_metadata":[{"gateway_ids":{"gateway_id":"hafenmeister-port2ttn-ng","eui":"50313953530A4750"},"time":"2024-01-22T07:06:25.013878Z","timestamp":995696116,"rssi":-37,"channel_rssi":-37,"snr":8.5,"location":{"latitude":53.5548443059465,"longitude":9.92155426743724,"altitude":10,"source":"SOURCE_REGISTRY"},"uplink_token":"CiYKJAoYaGFmZW5tZWlzdGVyLXBvcnQydHRuLW5nEghQMTlTUwpHUBD0u+TaAxoLCPGnuK0GEM3uvhkgoIL0oP24Sg==","channel_index":5,"received_at":"2024-01-22T07:06:25.032492359Z"}],"settings":{"data_rate":{"lora":{"bandwidth":125000,"spreading_factor":9,"coding_rate":"4/5"}},"frequency":"867500000","timestamp":995696116,"time":"2024-01-22T07:06:25.013878Z"},"received_at":"2024-01-22T07:06:25.054442349Z","consumed_airtime":"0.205824s","network_ids":{"net_id":"000013","ns_id":"EC656E0000000181","tenant_id":"ttn","cluster_id":"eu1","cluster_address":"eu1.cloud.thethings.network"}}};
71
-
76
+ // TTN
77
+ const topic ="v3/hafi-ttn-lorawan@ttn/devices/eui-lobaro-modbus/up";
78
+ const message = {"end_device_ids":{"device_id":"eui-lobaro-modbus","application_ids":{"application_id":"hafi-ttn-lorawan"},"dev_eui":"70B3D5E050013950","join_eui":"D55B58C0DDC074DE","dev_addr":"260B5972"},"correlation_ids":["gs:uplink:01HMQZVSCX4D7JRDNFA7GJ9D4W"],"received_at":"2024-01-22T07:06:25.260676101Z","uplink_message":{"session_key_id":"AY0v/ZirzRkpNW0Cgjdhig==","f_port":20,"f_cnt":2,"frm_payload":"AA5BAf0AxwIAAQ==","decoded_payload":{"airhumidity":50.9,"airtemperature":19.9,"port":20,"relais1":0,"relais2":1,"relais3":null,"relais5":null,"volt":3.649,"zisternenpegel":2},"rx_metadata":[{"gateway_ids":{"gateway_id":"hafenmeister-port2ttn-ng","eui":"50313953530A4750"},"time":"2024-01-22T07:06:25.013878Z","timestamp":995696116,"rssi":-37,"channel_rssi":-37,"snr":8.5,"location":{"latitude":53.5548443059465,"longitude":9.92155426743724,"altitude":10,"source":"SOURCE_REGISTRY"},"uplink_token":"CiYKJAoYaGFmZW5tZWlzdGVyLXBvcnQydHRuLW5nEghQMTlTUwpHUBD0u+TaAxoLCPGnuK0GEM3uvhkgoIL0oP24Sg==","channel_index":5,"received_at":"2024-01-22T07:06:25.032492359Z"}],"settings":{"data_rate":{"lora":{"bandwidth":125000,"spreading_factor":9,"coding_rate":"4/5"}},"frequency":"867500000","timestamp":995696116,"time":"2024-01-22T07:06:25.013878Z"},"received_at":"2024-01-22T07:06:25.054442349Z","consumed_airtime":"0.205824s","network_ids":{"net_id":"000013","ns_id":"EC656E0000000181","tenant_id":"ttn","cluster_id":"eu1","cluster_address":"eu1.cloud.thethings.network"}}};
72
79
 
80
+ // Chipstack
73
81
  //const topic = "application/d63c10b6-9263-4ab3-9299-4308fa19a2ad/device/a84041f621857cd2/event/up";
74
82
  //const message = {"deduplicationId":"96e4a065-ad5e-402d-a997-7b261072a33c","time":"2024-01-21T17:01:36.641008+00:00","deviceInfo":{"tenantId":"52f14cd4-c6f1-4fbd-8f87-4025e1d49242","tenantName":"ChirpStack","applicationId":"d63c10b6-9263-4ab3-9299-4308fa19a2ad","applicationName":"Benjamin Schmidt","deviceProfileId":"0b46400f-37ec-4f17-8005-168b06159347","deviceProfileName":"Dragino Feuchtesenor","deviceName":"Skimmer","devEui":"a84041f621857cd2","deviceClassEnabled":"CLASS_A","tags":{}},"devAddr":"01fd9738","adr":true,"dr":5,"fCnt":2,"fPort":2,"confirmed":false,"data":"DPYBAAD//wAA","object":{"soilconductivity":0.0,"soiltemperature":-0.1,"volt":3.318,"soilmoisture":0.0},"rxInfo":[{"gatewayId":"50303541b0344750","uplinkId":39169,"gwTime":"2024-01-21T17:01:36.641008+00:00","nsTime":"2024-01-21T17:01:37.695656999+00:00","rssi":-89,"snr":6.25,"rfChain":1,"location":{"latitude":50.69344693065449,"longitude":8.476783633232118},"context":"qESemw==","metadata":{"region_config_id":"eu868","region_common_name":"EU868"},"crcStatus":"CRC_OK"}],"txInfo":{"frequency":868100000,"modulation":{"lora":{"bandwidth":125000,"spreadingFactor":7,"codeRate":"CR_4_5"}}}};
75
83
  //const topic = "application/d63c10b6-9263-4ab3-9299-4308fa19a2ad/device/a84041f621857cd2/command/down";
76
84
  //const message = {"devEui":"a84041f621857cd2","confirmed":false,"fPort":1,"data":"AQAqMA=="};
77
85
 
78
86
  // Chirpstack LT222222
79
- const topic = "application/d63c10b6-9263-4ab3-9299-4308fa19a2ad/device/a8404127a188d826/event/up";
80
- const message = {"deduplicationId":"bd3fdb3b-af86-4617-b9f2-da07075d2bc5","time":"2024-01-24T16:47:01.573381+00:00","deviceInfo":{"tenantId":"52f14cd4-c6f1-4fbd-8f87-4025e1d49242","tenantName":"ChirpStack","applicationId":"d63c10b6-9263-4ab3-9299-4308fa19a2ad","applicationName":"Benjamin Schmidt","deviceProfileId":"f1c0ae0e-b4a2-4547-b360-7cfa15e85734","deviceProfileName":"Dragino LT22222","deviceName":"Relaistestgerät","devEui":"a8404127a188d826","deviceClassEnabled":"CLASS_C","tags":{}},"devAddr":"01dfbaf2","adr":true,"dr":5,"fCnt":12,"fPort":2,"confirmed":false,"data":"AAAAAAAAAAA8/0E=","object":{"RO1_status":"OFF","DO2_status":"H","ACI2_mA":0.0,"DO1_status":"H","Hardware_mode":"LT22222","RO2_status":"OFF","AVI2_V":0.0,"ACI1_mA":0.0,"DI1_status":"H","DI2_status":"H","Work_mode":"2ACI+2AVI","AVI1_V":0.0},"rxInfo":[{"gatewayId":"50303541b0344750","uplinkId":57857,"gwTime":"2024-01-24T16:47:01.573381+00:00","nsTime":"2024-01-24T16:47:02.370171527+00:00","rssi":-54,"snr":8.5,"channel":6,"location":{"latitude":50.69344693065449,"longitude":8.476783633232118},"context":"2tr9BA==","metadata":{"region_config_id":"eu868","region_common_name":"EU868"},"crcStatus":"CRC_OK"}],"txInfo":{"frequency":867700000,"modulation":{"lora":{"bandwidth":125000,"spreadingFactor":7,"codeRate":"CR_4_5"}}}};
87
+ //const topic = "application/d63c10b6-9263-4ab3-9299-4308fa19a2ad/device/a8404127a188d826/event/up";
88
+ //const message = {"deduplicationId":"bd3fdb3b-af86-4617-b9f2-da07075d2bc5","time":"2024-01-24T16:47:01.573381+00:00","deviceInfo":{"tenantId":"52f14cd4-c6f1-4fbd-8f87-4025e1d49242","tenantName":"ChirpStack","applicationId":"d63c10b6-9263-4ab3-9299-4308fa19a2ad","applicationName":"Benjamin Schmidt","deviceProfileId":"f1c0ae0e-b4a2-4547-b360-7cfa15e85734","deviceProfileName":"Dragino LT22222","deviceName":"Relaistestgerät","devEui":"a8404127a188d826","deviceClassEnabled":"CLASS_C","tags":{}},"devAddr":"01dfbaf2","adr":true,"dr":5,"fCnt":12,"fPort":2,"confirmed":false,"data":"AAAAAAAAAAA8/0E=","object":{"RO1_status":"OFF","DO2_status":"H","ACI2_mA":0.0,"DO1_status":"H","Hardware_mode":"LT22222","RO2_status":"OFF","AVI2_V":0.0,"ACI1_mA":0.0,"DI1_status":"H","DI2_status":"H","Work_mode":"2ACI+2AVI","AVI1_V":0.0},"rxInfo":[{"gatewayId":"50303541b0344750","uplinkId":57857,"gwTime":"2024-01-24T16:47:01.573381+00:00","nsTime":"2024-01-24T16:47:02.370171527+00:00","rssi":-54,"snr":8.5,"channel":6,"location":{"latitude":50.69344693065449,"longitude":8.476783633232118},"context":"2tr9BA==","metadata":{"region_config_id":"eu868","region_common_name":"EU868"},"crcStatus":"CRC_OK"}],"txInfo":{"frequency":867700000,"modulation":{"lora":{"bandwidth":125000,"spreadingFactor":7,"codeRate":"CR_4_5"}}}};
81
89
  //const topic = "application/d63c10b6-9263-4ab3-9299-4308fa19a2ad/device/a8404127a188d826/command/down";
82
90
  //const message = {"devEui":"a8404127a188d826","confirmed":false,"fPort":1,"data":"AQACWA=="};
83
91
  await this.messagehandler?.handleMessage(topic, message);
@@ -128,7 +136,7 @@ class Lorawan extends utils.Adapter {
128
136
  if(id.indexOf("downlink") !== -1){
129
137
  this.log.silly(`the state ${id} has changed to ${state.val}.`);
130
138
  // get information of the changing state
131
- const changeInfo = await this.getChangeInfo(id);
139
+ const changeInfo = await this.getChangeInfo(id,{withBestMatch:true});
132
140
  if(this.config.origin === "ttn"){
133
141
  let appending = "push";
134
142
  if(changeInfo?.changedState === "push"){
@@ -147,10 +155,12 @@ class Lorawan extends utils.Adapter {
147
155
  const downlinkConfig = this.downlinkConfighandler?.getDownlinkConfig(changeInfo);
148
156
  if(downlinkConfig !== undefined){
149
157
  const payloadInHex = this.downlinkConfighandler?.calculatePayloadInHex(downlinkConfig,state);
150
- await this.writeNextSend(changeInfo?.objectStartDirectory,payloadInHex);
151
- const downlink = this.downlinkConfighandler?.getDownlink(downlinkConfig,payloadInHex,changeInfo);
152
- if(downlink !== undefined){
153
- await this.sendDownlink(downlinkTopic,JSON.stringify(downlink),changeInfo);
158
+ await this.writeNextSend(changeInfo,payloadInHex);
159
+ if(!changeInfo?.bestExpertDownlinkMatch || this.downlinkConfighandler?.activeExpertConfigs[changeInfo.bestExpertDownlinkMatch].sendWithUplink === "disabled"){
160
+ const downlink = this.downlinkConfighandler?.getDownlink(downlinkConfig,payloadInHex,changeInfo);
161
+ if(downlink !== undefined){
162
+ await this.sendDownlink(downlinkTopic,JSON.stringify(downlink),changeInfo);
163
+ }
154
164
  }
155
165
  this.setStateAsync(id,state.val,true);
156
166
  }
@@ -167,10 +177,12 @@ class Lorawan extends utils.Adapter {
167
177
  const downlinkConfig = this.downlinkConfighandler?.getDownlinkConfig(changeInfo);
168
178
  if(downlinkConfig !== undefined){
169
179
  const payloadInHex = this.downlinkConfighandler?.calculatePayloadInHex(downlinkConfig,state);
170
- await this.writeNextSend(changeInfo?.objectStartDirectory,payloadInHex);
171
- const downlink = this.downlinkConfighandler?.getDownlink(downlinkConfig,payloadInHex,changeInfo);
172
- if(downlink !== undefined){
173
- await this.sendDownlink(downlinkTopic,JSON.stringify(downlink),changeInfo);
180
+ await this.writeNextSend(changeInfo,payloadInHex);
181
+ if(!changeInfo?.bestExpertDownlinkMatch || this.downlinkConfighandler?.activeExpertConfigs[changeInfo.bestExpertDownlinkMatch].sendWithUplink === "disabled"){
182
+ const downlink = this.downlinkConfighandler?.getDownlink(downlinkConfig,payloadInHex,changeInfo);
183
+ if(downlink !== undefined){
184
+ await this.sendDownlink(downlinkTopic,JSON.stringify(downlink),changeInfo);
185
+ }
174
186
  }
175
187
  this.setStateAsync(id,state.val,true);
176
188
  }
@@ -178,7 +190,31 @@ class Lorawan extends utils.Adapter {
178
190
  }
179
191
  }
180
192
  // State is from configuration path
181
- else{
193
+ else if(id.indexOf("configuration") !== -1){
194
+ const changeInfo = await this.getChangeInfo(id,{withBestMatch:true});
195
+ this.messagehandler?.fillWithDownlinkConfig(changeInfo?.objectStartDirectory);
196
+
197
+ // remove not configed states
198
+ const adapterObjects = await this.getAdapterObjectsAsync();
199
+ for(const adapterObject of Object.values(adapterObjects)){
200
+ if(adapterObject.type === "state" && (adapterObject._id.indexOf(`${changeInfo?.objectStartDirectory}.downlink.control`) !== -1)){
201
+ const changeInfo = await this.getChangeInfo(adapterObject._id);
202
+ const downlinkConfig = this.downlinkConfighandler?.getDownlinkConfig(changeInfo,{startupCheck:true});
203
+ if(!downlinkConfig){
204
+ await this.delObjectAsync(this.removeNamespace(adapterObject._id));
205
+ }
206
+ }
207
+ }
208
+ this.setStateAsync(id,state.val,true);
209
+ }
210
+ // logging of the actual available configs
211
+ else if(id.indexOf("logAvailableConfignames") !== -1){
212
+ this.log.info(`The following devicenames has an existing downlink-config`);
213
+ let index = 0;
214
+ for(const devicename in this.downlinkConfighandler?.activeDownlinkConfigs){
215
+ index++;
216
+ this.log.info(`Device ${index}: ${devicename}`);
217
+ }
182
218
  this.setStateAsync(id,state.val,true);
183
219
  }
184
220
  }
@@ -196,18 +232,16 @@ class Lorawan extends utils.Adapter {
196
232
  const activeFunction = "checkSendDownlinkWithUplink";
197
233
  try{
198
234
  this.log.silly(`Check for send downlink with uplink.`);
199
- const changeInfo = await this.getChangeInfo(id);
200
- const nextSend = await this.getNextSend(changeInfo?.objectStartDirectory);
201
- if(nextSend?.val !== "0"){
202
- const downlinkTopic = this.downlinkConfighandler?.getDownlinkTopic(changeInfo,`/down/push`);
203
- const downlinkConfig = this.downlinkConfighandler?.getDownlinkConfig(changeInfo);
204
- if(!downlinkConfig){
205
- this.log.warn(`no downlinkconfig found - nextSend: ${nextSend?.val}`);
206
- return;
207
- }
208
- const downlink = this.downlinkConfighandler?.getDownlink(downlinkConfig,nextSend?.val,changeInfo);
209
- if(downlink !== undefined){
210
- await this.sendDownlink(downlinkTopic,JSON.stringify(downlink),changeInfo);
235
+ const changeInfo = await this.getChangeInfo(id,{withBestMatch:true});
236
+ if(changeInfo && changeInfo.bestExpertDownlinkMatch && this.downlinkConfighandler?.activeExpertConfigs[changeInfo.bestExpertDownlinkMatch].sendWithUplink !== "disabled"){
237
+ const nextSend = await this.getNextSend(changeInfo?.objectStartDirectory);
238
+ if(nextSend?.val !== "0"){
239
+ const downlinkTopic = this.downlinkConfighandler?.getDownlinkTopic(changeInfo,`/down/push`);
240
+ const downlinkConfig = this.downlinkConfighandler?.activeExpertConfigs[changeInfo.bestExpertDownlinkMatch];
241
+ const downlink = this.downlinkConfighandler?.getDownlink(downlinkConfig,nextSend?.val,changeInfo);
242
+ if(downlink !== undefined){
243
+ await this.sendDownlink(downlinkTopic,JSON.stringify(downlink),changeInfo);
244
+ }
211
245
  }
212
246
  }
213
247
  }
@@ -221,9 +255,15 @@ class Lorawan extends utils.Adapter {
221
255
  return await this.getStateAsync(`${idFolder}.hex`);
222
256
  }
223
257
 
224
- async writeNextSend(deviceDirectory,payloadInHex){
225
- const idFolder = `${deviceDirectory}.${this.messagehandler?.directoryhandler.reachableSubfolders.downlinkNextSend}`;
226
- await this.setStateAsync(`${idFolder}.hex`,payloadInHex,true);
258
+ async writeNextSend(changeInfo,payloadInHex){
259
+ const idFolderNextSend = `${changeInfo.objectStartDirectory}.${this.messagehandler?.directoryhandler.reachableSubfolders.downlinkNextSend}`;
260
+ if(changeInfo.bestExpertDownlinkMatch && this.downlinkConfighandler?.activeExpertConfigs[changeInfo.bestExpertDownlinkMatch].sendWithUplink === "enabled & collect"){
261
+ const nextSend = await this.getStateAsync(`${idFolderNextSend}.hex`);
262
+ if(nextSend?.val !== "0"){
263
+ payloadInHex = nextSend?.val + payloadInHex;
264
+ }
265
+ }
266
+ await this.setStateAsync(`${idFolderNextSend}.hex`,payloadInHex,true);
227
267
  }
228
268
 
229
269
  async sendDownlink(topic,message,changeInfo){
@@ -280,16 +320,27 @@ class Lorawan extends utils.Adapter {
280
320
  }
281
321
  }
282
322
 
283
- async getChangeInfo(id){
323
+ async getChangeInfo(id,options){
284
324
  const activeFunction = "getChangeInfo";
285
325
  try{
286
326
  this.log.silly(`changeinfo of id ${id}, will be generated.`);
287
327
  const changeInfo = this.getBaseDeviceInfo(id);
288
328
  const myId = `${changeInfo?.applicationId}.devices.${changeInfo?.dev_uid}.${changeInfo?.device_id}.configuration.devicetype`;
329
+ // Get deviceType
289
330
  const deviceTypeIdState = await this.getStateAsync(myId);
290
- if(deviceTypeIdState){
291
- // @ts-ignore
331
+ if(changeInfo && deviceTypeIdState){
292
332
  changeInfo.deviceType = deviceTypeIdState.val;
333
+ if(options && options.withBestMatch){
334
+ // Get best match of expert downlink
335
+ const bestExpertDownlinkMatch = this.downlinkConfighandler?.getBestMatchForExpertConfig(changeInfo);
336
+ if(bestExpertDownlinkMatch){
337
+ changeInfo.bestExpertDownlinkMatch = bestExpertDownlinkMatch;
338
+ this.log.debug(`best match for expertconfig of device: ${changeInfo.deviceType? changeInfo.deviceType: "empty devicetype"} is: ${bestExpertDownlinkMatch}`);
339
+ }
340
+ else{
341
+ this.log.debug(`no match for expert downlinkconfig found: ${changeInfo.deviceType? changeInfo.deviceType: "empty devicetype"}`);
342
+ }
343
+ }
293
344
  }
294
345
  this.log.silly(`changeinfo is ${JSON.stringify(changeInfo)}.`);
295
346
  return changeInfo;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.lorawan",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "converts the desired lora gateway data to a ioBroker structure",
5
5
  "author": {
6
6
  "name": "BenAhrdt",