iobroker.lorawan 0.3.5 → 0.3.7
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/jsonConfig.json +7 -1
- package/io-package.json +27 -27
- package/lib/modules/directorieshandler.js +7 -1
- package/lib/modules/downlinkConfighandler.js +22 -19
- package/lib/modules/messagehandler.js +124 -52
- package/lib/modules/mqttclient.js +2 -2
- package/main.js +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,6 +22,12 @@ For now there is documentation in English here: http://www.hafenmeister.com/Lora
|
|
|
22
22
|
Placeholder for the next version (at the beginning of the line):
|
|
23
23
|
### **WORK IN PROGRESS**
|
|
24
24
|
-->
|
|
25
|
+
### 0.3.7 (2024-02-22)
|
|
26
|
+
* (BenAhrdt) improove forbidden chars and implements join raw
|
|
27
|
+
|
|
28
|
+
### 0.3.6 (2024-02-21)
|
|
29
|
+
* (BenAhrdt) set attributs if undefined
|
|
30
|
+
|
|
25
31
|
### 0.3.5 (2024-02-21)
|
|
26
32
|
* (BenAhrdt) set tier to 2 and improove standard devices
|
|
27
33
|
|
package/admin/jsonConfig.json
CHANGED
|
@@ -180,7 +180,8 @@
|
|
|
180
180
|
"label": "name",
|
|
181
181
|
"tooltip": "nameTooltip",
|
|
182
182
|
"default": "",
|
|
183
|
-
"validator": "if(data.name === '' || data.name === null){return false;}else{return
|
|
183
|
+
"validator": "if(data.name === '' || data.name === null){return false;}else{const myRegEx = /^([0-9a-z])*$/i; return myRegEx.test(data.name);}",
|
|
184
|
+
"validatorNoSaveOnError": true,
|
|
184
185
|
"sm":2
|
|
185
186
|
},
|
|
186
187
|
{
|
|
@@ -246,6 +247,7 @@
|
|
|
246
247
|
"tooltip": "frontTooltip",
|
|
247
248
|
"default": "03",
|
|
248
249
|
"validator": "if(data.type !== 'string'){const myRegEx = /^([0-9a-f]{2})*$/i; return myRegEx.test(data.front)}else{return true}",
|
|
250
|
+
"validatorNoSaveOnError": true,
|
|
249
251
|
"hidden": "data.type === 'boolean' || data.type === 'button'",
|
|
250
252
|
"sm":2
|
|
251
253
|
},
|
|
@@ -256,6 +258,7 @@
|
|
|
256
258
|
"tooltip": "endTooltip",
|
|
257
259
|
"default": "11",
|
|
258
260
|
"validator": "if(data.type !== 'string'){const myRegEx = /^([0-9a-f]{2})*$/i; return myRegEx.test(data.front)}else{return true}",
|
|
261
|
+
"validatorNoSaveOnError": true,
|
|
259
262
|
"hidden": "data.type === 'boolean' || data.type === 'button'",
|
|
260
263
|
"sm":2
|
|
261
264
|
},
|
|
@@ -278,6 +281,7 @@
|
|
|
278
281
|
"tooltip": "onTooltip",
|
|
279
282
|
"default": "01",
|
|
280
283
|
"validator": "const myRegEx = /^([0-9a-f]{2})*$/i; return myRegEx.test(data.on);",
|
|
284
|
+
"validatorNoSaveOnError": true,
|
|
281
285
|
"hidden": "data.type !== 'boolean'",
|
|
282
286
|
"sm":2
|
|
283
287
|
},
|
|
@@ -288,6 +292,7 @@
|
|
|
288
292
|
"tooltip": "offTooltip",
|
|
289
293
|
"default": "11",
|
|
290
294
|
"validator": "const myRegEx = /^([0-9a-f]{2})*$/i; return myRegEx.test(data.off);",
|
|
295
|
+
"validatorNoSaveOnError": true,
|
|
291
296
|
"hidden": "data.type !== 'boolean'",
|
|
292
297
|
"sm":2
|
|
293
298
|
},
|
|
@@ -299,6 +304,7 @@
|
|
|
299
304
|
"tooltip": "onClickTooltip",
|
|
300
305
|
"default": "030111",
|
|
301
306
|
"validator": "const myRegEx = /^([0-9a-f]{2})*$/i; return myRegEx.test(data.onClick);",
|
|
307
|
+
"validatorNoSaveOnError": true,
|
|
302
308
|
"hidden": "data.type !== 'button'",
|
|
303
309
|
"sm":2
|
|
304
310
|
},
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "lorawan",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.7",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.3.7": {
|
|
7
|
+
"en": "improove forbidden chars and implements join raw",
|
|
8
|
+
"de": "unproove verbotene wagen und geräte roh beitreten",
|
|
9
|
+
"ru": "импровизировать запрещенные шары и реализаций присоединяются к сырому",
|
|
10
|
+
"pt": "improove proibido chars e implementos se juntar cru",
|
|
11
|
+
"nl": "improove verboden tekens en werktuigen samen rauw",
|
|
12
|
+
"fr": "improove prohibed chars and implements joignent brut",
|
|
13
|
+
"it": "improove vietati carboni e strumenti si uniscono crudo",
|
|
14
|
+
"es": "improove chars prohibidos e implementos se unen a crudo",
|
|
15
|
+
"pl": "improove zakazane znaki i narzędzia dołączyć surowe",
|
|
16
|
+
"uk": "неприпустимий заборонений діаграма і реалізує приєднатися до сировини",
|
|
17
|
+
"zh-cn": "将禁用字符和工具合并为原始字符"
|
|
18
|
+
},
|
|
19
|
+
"0.3.6": {
|
|
20
|
+
"en": "set attributs if undefined",
|
|
21
|
+
"de": "wenn nicht definiert",
|
|
22
|
+
"ru": "набор атрибутов, если не определено",
|
|
23
|
+
"pt": "definir atributos se indefinido",
|
|
24
|
+
"nl": "attributes instellen indien niet gedefinieerd",
|
|
25
|
+
"fr": "définir les attributs si non définis",
|
|
26
|
+
"it": "attributi impostati se non definiti",
|
|
27
|
+
"es": "conjunto atributos si no definido",
|
|
28
|
+
"pl": "set attributs if undefined",
|
|
29
|
+
"uk": "встановити attributs if undefined",
|
|
30
|
+
"zh-cn": "如果未定义, 设置附件"
|
|
31
|
+
},
|
|
6
32
|
"0.3.5": {
|
|
7
33
|
"en": "set tier to 2 and improove standard devices",
|
|
8
34
|
"de": "tier auf 2 und improovierte standardgeräte",
|
|
@@ -67,32 +93,6 @@
|
|
|
67
93
|
"pl": "odbudowa dzięki lepszemu rozwiązywaniu problemów",
|
|
68
94
|
"uk": "перебудувати краще повідомлення",
|
|
69
95
|
"zh-cn": "以更好的信息重建"
|
|
70
|
-
},
|
|
71
|
-
"0.3.0": {
|
|
72
|
-
"en": "define user friendly Blockly Blocks with result",
|
|
73
|
-
"de": "benutzerfreundlich definieren Blockly Blocks mit Ergebnis",
|
|
74
|
-
"ru": "определение пользователя Блоки с результатом",
|
|
75
|
-
"pt": "definir amigável Blocos com resultado",
|
|
76
|
-
"nl": "gebruikersvriendelijk definiëren Blokkeren met resultaat",
|
|
77
|
-
"fr": "définir une utilisation conviviale Blocs avec résultat",
|
|
78
|
-
"it": "definire l'utente amichevole Blocchi Blockly con risultato",
|
|
79
|
-
"es": "definir fácil de usar Bloqueo bloques con resultado",
|
|
80
|
-
"pl": "zdefiniować przyjazny dla użytkownika Blokady z wynikiem",
|
|
81
|
-
"uk": "визначення дружності користувача Блокнотні блоки з результатом",
|
|
82
|
-
"zh-cn": "定义用户友好 块状块及结果"
|
|
83
|
-
},
|
|
84
|
-
"0.2.1": {
|
|
85
|
-
"en": "check types of messaging values and implements more blockly blocks",
|
|
86
|
-
"de": "überprüfen sie die arten der messaging-werte und implementiert mehr blockweise blöcke",
|
|
87
|
-
"ru": "проверить типы значений обмена сообщениями и реализовать более блоков",
|
|
88
|
-
"pt": "verificar os tipos de valores de mensagens e implementa blocos mais bloqueados",
|
|
89
|
-
"nl": "controleer soorten messaging waarden en implementeert meer blokken",
|
|
90
|
-
"fr": "vérifier les types de valeurs de messagerie et implémente des blocs plus bloc",
|
|
91
|
-
"it": "controllare i tipi di valori di messaggistica e implementa più blocchi bloccati",
|
|
92
|
-
"es": "comprobar tipos de valores de mensajería e implementar bloques más bloque",
|
|
93
|
-
"pl": "sprawdzają typy wartości wiadomości i wdrażają blokowane bloki",
|
|
94
|
-
"uk": "перевіряти типи значень обміну повідомленнями та реалізовувати більше блоків",
|
|
95
|
-
"zh-cn": "检查消息值的类型, 执行更多块"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"title": "LoRaWAN",
|
|
@@ -24,7 +24,9 @@ class directorieshandlerClass {
|
|
|
24
24
|
downlinkControl: "downlink.control",
|
|
25
25
|
downlinkRemaining: "downlink.remaining",
|
|
26
26
|
downlinkNextSend: "downlink.nextSend",
|
|
27
|
-
downlinkLastSend: "downlink.lastSend"
|
|
27
|
+
downlinkLastSend: "downlink.lastSend",
|
|
28
|
+
join: "join",
|
|
29
|
+
joinRaw: "join.raw"
|
|
28
30
|
};
|
|
29
31
|
|
|
30
32
|
//define path for uplink roles
|
|
@@ -96,6 +98,10 @@ class directorieshandlerClass {
|
|
|
96
98
|
remaining:{
|
|
97
99
|
}
|
|
98
100
|
},
|
|
101
|
+
join:{
|
|
102
|
+
raw:{
|
|
103
|
+
}
|
|
104
|
+
}
|
|
99
105
|
}
|
|
100
106
|
}
|
|
101
107
|
}
|
|
@@ -44,17 +44,17 @@ class downlinkConfighandlerClass {
|
|
|
44
44
|
const activeFunction = "addAndMergeDownlinkConfigs";
|
|
45
45
|
this.adapter.log.silly(`the standard and configed downlinks will be merged`);
|
|
46
46
|
try{
|
|
47
|
-
// Add
|
|
47
|
+
// Add user downlink config first
|
|
48
|
+
for(const downlinkConfig of Object.values(this.adapter.config.downlinkConfig)){
|
|
49
|
+
this.addDownlinkConfigByType(downlinkConfig,this.activeDownlinkConfigs);
|
|
50
|
+
}
|
|
51
|
+
// Add standard downlink config if devices not present
|
|
48
52
|
const internalDownlinks = this.getJsonArrayFromDirectoryfiles(`${this.adapter.adapterDir}${this.deviceProfilesPath}`);
|
|
49
53
|
if(Array.isArray(internalDownlinks)){
|
|
50
54
|
for(const downlinkConfig of Object.values(internalDownlinks)){
|
|
51
55
|
this.addDownlinkConfigByType(downlinkConfig,this.activeDownlinkConfigs);
|
|
52
56
|
}
|
|
53
57
|
}
|
|
54
|
-
// Add user downlink config
|
|
55
|
-
for(const downlinkConfig of Object.values(this.adapter.config.downlinkConfig)){
|
|
56
|
-
this.addDownlinkConfigByType(downlinkConfig,this.activeDownlinkConfigs);
|
|
57
|
-
}
|
|
58
58
|
// Check active userconfig
|
|
59
59
|
const adapterId = `system.adapter.${this.adapter.namespace}`;
|
|
60
60
|
const obj = await this.adapter.getForeignObjectAsync(adapterId);
|
|
@@ -89,22 +89,25 @@ class downlinkConfighandlerClass {
|
|
|
89
89
|
addDownlinkConfigByType(downlinkConfig,config){
|
|
90
90
|
const activeFunction = "addDownlinkConfigByType";
|
|
91
91
|
try{
|
|
92
|
-
//
|
|
93
|
-
config[downlinkConfig.deviceType]
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
//
|
|
98
|
-
downlinkParameter
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
92
|
+
// Check for device not present
|
|
93
|
+
if(!config[downlinkConfig.deviceType]){
|
|
94
|
+
// override standard with userconfig
|
|
95
|
+
config[downlinkConfig.deviceType] = structuredClone(downlinkConfig);
|
|
96
|
+
config[downlinkConfig.deviceType].downlinkState = {};
|
|
97
|
+
// generate downlinkstates for internal use
|
|
98
|
+
for(const downlinkParameter of Object.values(config[downlinkConfig.deviceType].downlinkParameter)){
|
|
99
|
+
// check name for forbidden chars
|
|
100
|
+
downlinkParameter.name = downlinkParameter.name.replace(this.adapter.FORBIDDEN_CHARS,"_");
|
|
101
|
+
// check the downlinkparameters for all needed attributes and generate them if undefined
|
|
102
|
+
for(const attribute in this.downlinkParameterAttributs){
|
|
103
|
+
if(downlinkConfig.deviceType !== this.internalDevices.baseDevice && downlinkParameter[attribute] === undefined){
|
|
104
|
+
this.adapter.log.debug(`attribute ${attribute} in parameter ${downlinkParameter.name} at devicetype ${downlinkConfig.deviceType} generated`);
|
|
105
|
+
downlinkParameter[attribute] = this.downlinkParameterAttributs[attribute];
|
|
106
|
+
}
|
|
104
107
|
}
|
|
108
|
+
// assign downlinkparamter to internal structure
|
|
109
|
+
config[downlinkConfig.deviceType].downlinkState[downlinkParameter.name] = downlinkParameter;
|
|
105
110
|
}
|
|
106
|
-
// assign downlinkparamter to internal structure
|
|
107
|
-
config[downlinkConfig.deviceType].downlinkState[downlinkParameter.name] = downlinkParameter;
|
|
108
111
|
}
|
|
109
112
|
}
|
|
110
113
|
catch(error){
|
|
@@ -185,7 +185,7 @@ class messagehandlerClass {
|
|
|
185
185
|
* ****************** Check device startdirectory ********************
|
|
186
186
|
* ******************************************************************/
|
|
187
187
|
|
|
188
|
-
if(messageType !== "up" && !await this.adapter.objectExists(`${deviceStartdirectory}`)){
|
|
188
|
+
if(messageType !== "up" && messageType !== "join" && !await this.adapter.objectExists(`${deviceStartdirectory}`)){
|
|
189
189
|
this.adapter.log.debug(`There was a message with the topic ${topic}, but the object ${deviceStartdirectory} does not exists yet.`);
|
|
190
190
|
return;
|
|
191
191
|
}
|
|
@@ -199,7 +199,7 @@ class messagehandlerClass {
|
|
|
199
199
|
* ******************************************************************/
|
|
200
200
|
|
|
201
201
|
// check for uplink message
|
|
202
|
-
if(messageType === "up"){
|
|
202
|
+
if(messageType === "up"){
|
|
203
203
|
/*********************************************************************
|
|
204
204
|
* ************************ Main directories *************************
|
|
205
205
|
* ******************************************************************/
|
|
@@ -211,9 +211,9 @@ class messagehandlerClass {
|
|
|
211
211
|
* ******************************************************************/
|
|
212
212
|
|
|
213
213
|
this.adapter.log.silly(`write rawdata`);
|
|
214
|
-
let
|
|
214
|
+
let startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.uplinkRaw}`;
|
|
215
215
|
// write json
|
|
216
|
-
await this.adapter.setObjectNotExistsAsync(`${
|
|
216
|
+
await this.adapter.setObjectNotExistsAsync(`${startId}.json`,{
|
|
217
217
|
type: "state",
|
|
218
218
|
common: {
|
|
219
219
|
name: "last recieved message",
|
|
@@ -224,7 +224,7 @@ class messagehandlerClass {
|
|
|
224
224
|
},
|
|
225
225
|
native: {},
|
|
226
226
|
});
|
|
227
|
-
await this.adapter.setStateAsync(`${
|
|
227
|
+
await this.adapter.setStateAsync(`${startId}.json`,JSON.stringify(message),true);
|
|
228
228
|
|
|
229
229
|
/*********************************************************************
|
|
230
230
|
* ********************** Rawdata (Base64) ***************************
|
|
@@ -233,7 +233,7 @@ class messagehandlerClass {
|
|
|
233
233
|
if(message.uplink_message.frm_payload){
|
|
234
234
|
// wite base64 data
|
|
235
235
|
this.adapter.log.silly(`write base64`);
|
|
236
|
-
await this.adapter.setObjectNotExistsAsync(`${
|
|
236
|
+
await this.adapter.setObjectNotExistsAsync(`${startId}.base64`,{
|
|
237
237
|
type: "state",
|
|
238
238
|
common: {
|
|
239
239
|
name: "last recieved data as base64",
|
|
@@ -245,11 +245,11 @@ class messagehandlerClass {
|
|
|
245
245
|
native: {},
|
|
246
246
|
});
|
|
247
247
|
const writedata = message.uplink_message.frm_payload;
|
|
248
|
-
await this.adapter.setStateAsync(`${
|
|
248
|
+
await this.adapter.setStateAsync(`${startId}.base64`,writedata,true);
|
|
249
249
|
|
|
250
250
|
// write base64 data in hex data
|
|
251
251
|
this.adapter.log.silly(`write hex`);
|
|
252
|
-
await this.adapter.setObjectNotExistsAsync(`${
|
|
252
|
+
await this.adapter.setObjectNotExistsAsync(`${startId}.hex`,{
|
|
253
253
|
type: "state",
|
|
254
254
|
common: {
|
|
255
255
|
name: "last recieved data as hex",
|
|
@@ -261,11 +261,11 @@ class messagehandlerClass {
|
|
|
261
261
|
native: {},
|
|
262
262
|
});
|
|
263
263
|
const hexdata = Buffer.from(message.uplink_message.frm_payload, "base64").toString("hex").toUpperCase();
|
|
264
|
-
await this.adapter.setStateAsync(`${
|
|
264
|
+
await this.adapter.setStateAsync(`${startId}.hex`,hexdata,true);
|
|
265
265
|
|
|
266
266
|
// write base64 data in string data
|
|
267
267
|
this.adapter.log.silly(`write string`);
|
|
268
|
-
await this.adapter.setObjectNotExistsAsync(`${
|
|
268
|
+
await this.adapter.setObjectNotExistsAsync(`${startId}.string`,{
|
|
269
269
|
type: "state",
|
|
270
270
|
common: {
|
|
271
271
|
name: "last recieved data as string",
|
|
@@ -277,25 +277,25 @@ class messagehandlerClass {
|
|
|
277
277
|
native: {},
|
|
278
278
|
});
|
|
279
279
|
const stringdata = Buffer.from(message.uplink_message.frm_payload, "base64").toString();
|
|
280
|
-
await this.adapter.setStateAsync(`${
|
|
280
|
+
await this.adapter.setStateAsync(`${startId}.string`,stringdata,true);
|
|
281
281
|
}
|
|
282
282
|
|
|
283
283
|
/*********************************************************************
|
|
284
284
|
* ********************** decoded payload ****************************
|
|
285
285
|
* ******************************************************************/
|
|
286
286
|
|
|
287
|
-
|
|
287
|
+
startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.uplinkDecoded}`;
|
|
288
288
|
this.adapter.log.silly(`write decoded payload`);
|
|
289
|
-
await this.directoryhandler.generateRekursivObjects(message.uplink_message.decoded_payload,
|
|
289
|
+
await this.directoryhandler.generateRekursivObjects(message.uplink_message.decoded_payload,startId,topic,message);
|
|
290
290
|
|
|
291
291
|
/*********************************************************************
|
|
292
292
|
* ************************* remaining *******************************
|
|
293
293
|
* ******************************************************************/
|
|
294
294
|
|
|
295
|
-
|
|
295
|
+
startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.uplinkRemaining}`;
|
|
296
296
|
this.adapter.log.silly(`write remaining uplink data`);
|
|
297
297
|
|
|
298
|
-
await this.directoryhandler.generateRekursivObjects(message.uplink_message,
|
|
298
|
+
await this.directoryhandler.generateRekursivObjects(message.uplink_message,startId,topic,message,{ignoredElementNames:{decoded_payload:{},frm_payload:{}}});
|
|
299
299
|
|
|
300
300
|
/*********************************************************************
|
|
301
301
|
* ******************* Check downlink at uplink **********************
|
|
@@ -309,17 +309,17 @@ class messagehandlerClass {
|
|
|
309
309
|
* ******************************************************************/
|
|
310
310
|
|
|
311
311
|
// check for uplink message
|
|
312
|
-
else if(messageType === "queued" || messageType === "sent"){
|
|
312
|
+
else if(messageType === "queued" || messageType === "sent"){
|
|
313
313
|
// Check wich downlink was recieved
|
|
314
314
|
const downlinkType = `downlink_${messageType}`;
|
|
315
315
|
/*********************************************************************
|
|
316
316
|
* ************************ Rawdata json *****************************
|
|
317
317
|
* ******************************************************************/
|
|
318
318
|
|
|
319
|
-
let
|
|
319
|
+
let startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.downlinkRaw}`;
|
|
320
320
|
// write json
|
|
321
321
|
this.adapter.log.silly(`write rawdata`);
|
|
322
|
-
await this.adapter.setObjectNotExistsAsync(`${
|
|
322
|
+
await this.adapter.setObjectNotExistsAsync(`${startId}.json`,{
|
|
323
323
|
type: "state",
|
|
324
324
|
common: {
|
|
325
325
|
name: "last recieved message",
|
|
@@ -330,7 +330,7 @@ class messagehandlerClass {
|
|
|
330
330
|
},
|
|
331
331
|
native: {},
|
|
332
332
|
});
|
|
333
|
-
await this.adapter.setStateAsync(`${
|
|
333
|
+
await this.adapter.setStateAsync(`${startId}.json`,JSON.stringify(message),true);
|
|
334
334
|
|
|
335
335
|
/*********************************************************************
|
|
336
336
|
* ********************** Rawdata (Base64) ***************************
|
|
@@ -340,7 +340,7 @@ class messagehandlerClass {
|
|
|
340
340
|
this.adapter.log.silly(`write base64`);
|
|
341
341
|
if(message[downlinkType].frm_payload){
|
|
342
342
|
// wite base64 data
|
|
343
|
-
await this.adapter.setObjectNotExistsAsync(`${
|
|
343
|
+
await this.adapter.setObjectNotExistsAsync(`${startId}.base64`,{
|
|
344
344
|
type: "state",
|
|
345
345
|
common: {
|
|
346
346
|
name: "last recieved data as base64",
|
|
@@ -352,11 +352,11 @@ class messagehandlerClass {
|
|
|
352
352
|
native: {},
|
|
353
353
|
});
|
|
354
354
|
const writedata = message[downlinkType].frm_payload;
|
|
355
|
-
await this.adapter.setStateAsync(`${
|
|
355
|
+
await this.adapter.setStateAsync(`${startId}.base64`,writedata,true);
|
|
356
356
|
|
|
357
357
|
// write base64 data in hex data
|
|
358
358
|
this.adapter.log.silly(`write hex`);
|
|
359
|
-
await this.adapter.setObjectNotExistsAsync(`${
|
|
359
|
+
await this.adapter.setObjectNotExistsAsync(`${startId}.hex`,{
|
|
360
360
|
type: "state",
|
|
361
361
|
common: {
|
|
362
362
|
name: "last recieved data as hex",
|
|
@@ -368,11 +368,11 @@ class messagehandlerClass {
|
|
|
368
368
|
native: {},
|
|
369
369
|
});
|
|
370
370
|
const hexdata = Buffer.from(message[downlinkType].frm_payload,"base64").toString("hex").toUpperCase();
|
|
371
|
-
await this.adapter.setStateAsync(`${
|
|
371
|
+
await this.adapter.setStateAsync(`${startId}.hex`,hexdata,true);
|
|
372
372
|
|
|
373
373
|
// write base64 data in string data
|
|
374
374
|
this.adapter.log.silly(`write string`);
|
|
375
|
-
await this.adapter.setObjectNotExistsAsync(`${
|
|
375
|
+
await this.adapter.setObjectNotExistsAsync(`${startId}.string`,{
|
|
376
376
|
type: "state",
|
|
377
377
|
common: {
|
|
378
378
|
name: "last recieved data as string",
|
|
@@ -384,16 +384,52 @@ class messagehandlerClass {
|
|
|
384
384
|
native: {},
|
|
385
385
|
});
|
|
386
386
|
const stringdata = Buffer.from(message[downlinkType].frm_payload,"base64").toString();
|
|
387
|
-
await this.adapter.setStateAsync(`${
|
|
387
|
+
await this.adapter.setStateAsync(`${startId}.string`,stringdata,true);
|
|
388
388
|
}
|
|
389
389
|
|
|
390
390
|
/*********************************************************************
|
|
391
391
|
* ************************* remaining *******************************
|
|
392
392
|
* ******************************************************************/
|
|
393
393
|
|
|
394
|
-
|
|
394
|
+
startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.downlinkRemaining}`;
|
|
395
395
|
this.adapter.log.silly(`write remaining downlink data`);
|
|
396
|
-
await this.directoryhandler.generateRekursivObjects(message[downlinkType],
|
|
396
|
+
await this.directoryhandler.generateRekursivObjects(message[downlinkType],startId,topic,message,{ignoredElementNames:{frm_payload:{}}});
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// check for join message
|
|
400
|
+
else if(messageType === "join"){
|
|
401
|
+
|
|
402
|
+
/*********************************************************************
|
|
403
|
+
* ************************ Main directories *************************
|
|
404
|
+
* ******************************************************************/
|
|
405
|
+
|
|
406
|
+
await this.directoryhandler.generateRekursivObjects(this.directoryhandler.directories,"",topic,message);
|
|
407
|
+
|
|
408
|
+
/*********************************************************************
|
|
409
|
+
* ************************ Rawdata json *****************************
|
|
410
|
+
* ******************************************************************/
|
|
411
|
+
|
|
412
|
+
this.adapter.log.silly(`write rawdata`);
|
|
413
|
+
const startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.joinRaw}`;
|
|
414
|
+
// write json
|
|
415
|
+
await this.adapter.setObjectNotExistsAsync(`${startId}.json`,{
|
|
416
|
+
type: "state",
|
|
417
|
+
common: {
|
|
418
|
+
name: "last recieved message",
|
|
419
|
+
type: "json",
|
|
420
|
+
role: "value",
|
|
421
|
+
read: true,
|
|
422
|
+
write: false
|
|
423
|
+
},
|
|
424
|
+
native: {},
|
|
425
|
+
});
|
|
426
|
+
await this.adapter.setStateAsync(`${startId}.json`,JSON.stringify(message),true);
|
|
427
|
+
const changeInfo = await this.adapter.getChangeInfo(startId);
|
|
428
|
+
this.adapter.log.info(`the device ${changeInfo.deviceEUI} joined network`);
|
|
429
|
+
}
|
|
430
|
+
// Other messagetypes
|
|
431
|
+
else{
|
|
432
|
+
this.adapter.log.debug(`the messagetype: ${messageType}, is not implemented yet`);
|
|
397
433
|
}
|
|
398
434
|
|
|
399
435
|
/*********************************************************************
|
|
@@ -434,7 +470,7 @@ class messagehandlerClass {
|
|
|
434
470
|
* ****************** Check device startdirectory ********************
|
|
435
471
|
* ******************************************************************/
|
|
436
472
|
|
|
437
|
-
if(messageType !== "up" && !await this.adapter.objectExists(`${deviceStartdirectory}`)){
|
|
473
|
+
if(messageType !== "up" && messageType !== "join" && !await this.adapter.objectExists(`${deviceStartdirectory}`)){
|
|
438
474
|
this.adapter.log.debug(`There was a message with the topic ${topic}, but the object ${deviceStartdirectory} does not exists yet.`);
|
|
439
475
|
return;
|
|
440
476
|
}
|
|
@@ -448,7 +484,7 @@ class messagehandlerClass {
|
|
|
448
484
|
* ******************************************************************/
|
|
449
485
|
|
|
450
486
|
// check for uplink message
|
|
451
|
-
if(messageType === "up"){
|
|
487
|
+
if(messageType === "up"){
|
|
452
488
|
|
|
453
489
|
/*********************************************************************
|
|
454
490
|
* ************************ Main directories *************************
|
|
@@ -460,10 +496,10 @@ class messagehandlerClass {
|
|
|
460
496
|
* ************************ Rawdata json *****************************
|
|
461
497
|
* ******************************************************************/
|
|
462
498
|
|
|
463
|
-
let
|
|
499
|
+
let startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.uplinkRaw}`;
|
|
464
500
|
// write json
|
|
465
501
|
this.adapter.log.silly(`write rawdata`);
|
|
466
|
-
await this.adapter.setObjectNotExistsAsync(`${
|
|
502
|
+
await this.adapter.setObjectNotExistsAsync(`${startId}.json`,{
|
|
467
503
|
type: "state",
|
|
468
504
|
common: {
|
|
469
505
|
name: "last recieved message",
|
|
@@ -474,7 +510,7 @@ class messagehandlerClass {
|
|
|
474
510
|
},
|
|
475
511
|
native: {},
|
|
476
512
|
});
|
|
477
|
-
await this.adapter.setStateAsync(`${
|
|
513
|
+
await this.adapter.setStateAsync(`${startId}.json`,JSON.stringify(message),true);
|
|
478
514
|
|
|
479
515
|
/*********************************************************************
|
|
480
516
|
* ********************** Rawdata (Base64) ***************************
|
|
@@ -483,7 +519,7 @@ class messagehandlerClass {
|
|
|
483
519
|
if(message.data){
|
|
484
520
|
// wite base64 data
|
|
485
521
|
this.adapter.log.silly(`write base64`);
|
|
486
|
-
await this.adapter.setObjectNotExistsAsync(`${
|
|
522
|
+
await this.adapter.setObjectNotExistsAsync(`${startId}.base64`,{
|
|
487
523
|
type: "state",
|
|
488
524
|
common: {
|
|
489
525
|
name: "last recieved data as base64",
|
|
@@ -495,11 +531,11 @@ class messagehandlerClass {
|
|
|
495
531
|
native: {},
|
|
496
532
|
});
|
|
497
533
|
const writedata = message.data;
|
|
498
|
-
await this.adapter.setStateAsync(`${
|
|
534
|
+
await this.adapter.setStateAsync(`${startId}.base64`,writedata,true);
|
|
499
535
|
|
|
500
536
|
// write base64 data in hex data
|
|
501
537
|
this.adapter.log.silly(`write hex`);
|
|
502
|
-
await this.adapter.setObjectNotExistsAsync(`${
|
|
538
|
+
await this.adapter.setObjectNotExistsAsync(`${startId}.hex`,{
|
|
503
539
|
type: "state",
|
|
504
540
|
common: {
|
|
505
541
|
name: "last recieved data as hex",
|
|
@@ -511,11 +547,11 @@ class messagehandlerClass {
|
|
|
511
547
|
native: {},
|
|
512
548
|
});
|
|
513
549
|
const hexdata = Buffer.from(message.data, "base64").toString("hex").toUpperCase();
|
|
514
|
-
await this.adapter.setStateAsync(`${
|
|
550
|
+
await this.adapter.setStateAsync(`${startId}.hex`,hexdata,true);
|
|
515
551
|
|
|
516
552
|
// write base64 data in string data
|
|
517
553
|
this.adapter.log.silly(`write string`);
|
|
518
|
-
await this.adapter.setObjectNotExistsAsync(`${
|
|
554
|
+
await this.adapter.setObjectNotExistsAsync(`${startId}.string`,{
|
|
519
555
|
type: "state",
|
|
520
556
|
common: {
|
|
521
557
|
name: "last recieved data as string",
|
|
@@ -527,23 +563,23 @@ class messagehandlerClass {
|
|
|
527
563
|
native: {},
|
|
528
564
|
});
|
|
529
565
|
const stringdata = Buffer.from(message.data, "base64").toString();
|
|
530
|
-
await this.adapter.setStateAsync(`${
|
|
566
|
+
await this.adapter.setStateAsync(`${startId}.string`,stringdata,true);
|
|
531
567
|
}
|
|
532
568
|
|
|
533
569
|
/*********************************************************************
|
|
534
570
|
* ****************** decoded payload (Object) ***********************
|
|
535
571
|
* ******************************************************************/
|
|
536
|
-
|
|
572
|
+
startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.uplinkDecoded}`;
|
|
537
573
|
this.adapter.log.silly(`write decoded payload (Object)`);
|
|
538
|
-
await this.directoryhandler.generateRekursivObjects(message.object,
|
|
574
|
+
await this.directoryhandler.generateRekursivObjects(message.object,startId,topic,message);
|
|
539
575
|
|
|
540
576
|
/*********************************************************************
|
|
541
577
|
* ************************* remaining *******************************
|
|
542
578
|
* ******************************************************************/
|
|
543
579
|
|
|
544
|
-
|
|
580
|
+
startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.uplinkRemaining}`;
|
|
545
581
|
this.adapter.log.silly(`write remaining uplink data`);
|
|
546
|
-
await this.directoryhandler.generateRekursivObjects(message,
|
|
582
|
+
await this.directoryhandler.generateRekursivObjects(message,startId,topic,message,{ignoredElementNames:{deduplicationId:{},deviceInfo:{},data:{},object:{}}});
|
|
547
583
|
|
|
548
584
|
/*********************************************************************
|
|
549
585
|
* ******************* Check downlink at uplink **********************
|
|
@@ -557,16 +593,16 @@ class messagehandlerClass {
|
|
|
557
593
|
* ******************************************************************/
|
|
558
594
|
|
|
559
595
|
// check for uplink message
|
|
560
|
-
else if(messageType === "down"){
|
|
596
|
+
else if(messageType === "down"){
|
|
561
597
|
|
|
562
598
|
/*********************************************************************
|
|
563
599
|
* ************************ Rawdata json *****************************
|
|
564
600
|
* ******************************************************************/
|
|
565
601
|
|
|
566
|
-
const
|
|
602
|
+
const startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.downlinkRaw}`;
|
|
567
603
|
// write json
|
|
568
604
|
this.adapter.log.silly(`write rawdata`);
|
|
569
|
-
await this.adapter.setObjectNotExistsAsync(`${
|
|
605
|
+
await this.adapter.setObjectNotExistsAsync(`${startId}.json`,{
|
|
570
606
|
type: "state",
|
|
571
607
|
common: {
|
|
572
608
|
name: "last recieved message",
|
|
@@ -577,7 +613,7 @@ class messagehandlerClass {
|
|
|
577
613
|
},
|
|
578
614
|
native: {},
|
|
579
615
|
});
|
|
580
|
-
await this.adapter.setStateAsync(`${
|
|
616
|
+
await this.adapter.setStateAsync(`${startId}.json`,JSON.stringify(message),true);
|
|
581
617
|
|
|
582
618
|
/*********************************************************************
|
|
583
619
|
* ********************** Rawdata (Base64) ***************************
|
|
@@ -587,7 +623,7 @@ class messagehandlerClass {
|
|
|
587
623
|
if(message.data){
|
|
588
624
|
// wite base64 data
|
|
589
625
|
this.adapter.log.silly(`write base64`);
|
|
590
|
-
await this.adapter.setObjectNotExistsAsync(`${
|
|
626
|
+
await this.adapter.setObjectNotExistsAsync(`${startId}.base64`,{
|
|
591
627
|
type: "state",
|
|
592
628
|
common: {
|
|
593
629
|
name: "last recieved data as base64",
|
|
@@ -599,11 +635,11 @@ class messagehandlerClass {
|
|
|
599
635
|
native: {},
|
|
600
636
|
});
|
|
601
637
|
const writedata = message.data;
|
|
602
|
-
await this.adapter.setStateAsync(`${
|
|
638
|
+
await this.adapter.setStateAsync(`${startId}.base64`,writedata,true);
|
|
603
639
|
|
|
604
640
|
// write base64 data in hex data
|
|
605
641
|
this.adapter.log.silly(`write hex`);
|
|
606
|
-
await this.adapter.setObjectNotExistsAsync(`${
|
|
642
|
+
await this.adapter.setObjectNotExistsAsync(`${startId}.hex`,{
|
|
607
643
|
type: "state",
|
|
608
644
|
common: {
|
|
609
645
|
name: "last recieved data as hex",
|
|
@@ -615,11 +651,11 @@ class messagehandlerClass {
|
|
|
615
651
|
native: {},
|
|
616
652
|
});
|
|
617
653
|
const hexdata = Buffer.from(message.data,"base64").toString("hex").toUpperCase();
|
|
618
|
-
await this.adapter.setStateAsync(`${
|
|
654
|
+
await this.adapter.setStateAsync(`${startId}.hex`,hexdata,true);
|
|
619
655
|
|
|
620
656
|
// write base64 data in string data
|
|
621
657
|
this.adapter.log.silly(`write string`);
|
|
622
|
-
await this.adapter.setObjectNotExistsAsync(`${
|
|
658
|
+
await this.adapter.setObjectNotExistsAsync(`${startId}.string`,{
|
|
623
659
|
type: "state",
|
|
624
660
|
common: {
|
|
625
661
|
name: "last recieved data as string",
|
|
@@ -631,7 +667,7 @@ class messagehandlerClass {
|
|
|
631
667
|
native: {},
|
|
632
668
|
});
|
|
633
669
|
const stringdata = Buffer.from(message.data,"base64").toString();
|
|
634
|
-
await this.adapter.setStateAsync(`${
|
|
670
|
+
await this.adapter.setStateAsync(`${startId}.string`,stringdata,true);
|
|
635
671
|
}
|
|
636
672
|
|
|
637
673
|
/*********************************************************************
|
|
@@ -639,6 +675,42 @@ class messagehandlerClass {
|
|
|
639
675
|
* ******************************************************************/
|
|
640
676
|
|
|
641
677
|
}
|
|
678
|
+
|
|
679
|
+
// check for uplink message
|
|
680
|
+
else if(messageType === "join"){
|
|
681
|
+
/*********************************************************************
|
|
682
|
+
* ************************ Main directories *************************
|
|
683
|
+
* ******************************************************************/
|
|
684
|
+
|
|
685
|
+
await this.directoryhandler.generateRekursivObjects(this.directoryhandler.directories,"",topic,message);
|
|
686
|
+
|
|
687
|
+
/*********************************************************************
|
|
688
|
+
* ************************ Rawdata json *****************************
|
|
689
|
+
* ******************************************************************/
|
|
690
|
+
|
|
691
|
+
const startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.joinRaw}`;
|
|
692
|
+
// write json
|
|
693
|
+
this.adapter.log.silly(`write rawdata`);
|
|
694
|
+
await this.adapter.setObjectNotExistsAsync(`${startId}.json`,{
|
|
695
|
+
type: "state",
|
|
696
|
+
common: {
|
|
697
|
+
name: "last recieved message",
|
|
698
|
+
type: "json",
|
|
699
|
+
role: "value",
|
|
700
|
+
read: true,
|
|
701
|
+
write: false
|
|
702
|
+
},
|
|
703
|
+
native: {},
|
|
704
|
+
});
|
|
705
|
+
await this.adapter.setStateAsync(`${startId}.json`,JSON.stringify(message),true);
|
|
706
|
+
const changeInfo = await this.adapter.getChangeInfo(startId);
|
|
707
|
+
this.adapter.log.info(`the device ${changeInfo.deviceEUI} joined network`);
|
|
708
|
+
}
|
|
709
|
+
// Other messagetypes
|
|
710
|
+
else{
|
|
711
|
+
this.adapter.log.debug(`the messagetype: ${messageType}, is not implemented yet`);
|
|
712
|
+
}
|
|
713
|
+
|
|
642
714
|
/*********************************************************************
|
|
643
715
|
* ********************** downlinkConfigs ****************************
|
|
644
716
|
* ******************************************************************/
|
|
@@ -54,9 +54,9 @@ class mqttClientClass {
|
|
|
54
54
|
getSubscribtionArray(){
|
|
55
55
|
switch(this.adapter.config.origin){
|
|
56
56
|
case this.adapter.origin.ttn:
|
|
57
|
-
return ["v3/+/devices
|
|
57
|
+
return ["v3/+/devices/+/+","v3/+/devices/+/down/+"];
|
|
58
58
|
case this.adapter.origin.chirpstack:
|
|
59
|
-
return ["application/+/device/+/event
|
|
59
|
+
return ["application/+/device/+/event/+","application/+/device/+/command/down"];
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
}
|
package/main.js
CHANGED
|
@@ -82,8 +82,8 @@ class Lorawan extends utils.Adapter {
|
|
|
82
82
|
//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"}}};
|
|
83
83
|
|
|
84
84
|
// ACK
|
|
85
|
-
const topic = "v3/hafi-ttn-lorawan@ttn/devices/eui-a84041162183f8fb/down/ack";
|
|
86
|
-
const message = {"end_device_ids":{"device_id":"eui-a84041162183f8fb","application_ids":{"application_id":"hafi-ttn-lorawan"},"dev_eui":"A84041162183F8FB","join_eui":"A840410000000101","dev_addr":"260B141A"},"correlation_ids":["as:downlink:01HP6D18MQXJN90J5B07DC11HY","gs:uplink:01HP6D1A9X4WAA3SFMXH4ESSMV"],"received_at":"2024-02-09T07:41:41.776887672Z","downlink_ack":{"session_key_id":"AY2MUrmnuovS8DCZAfYmsA==","f_port":1,"f_cnt":21,"frm_payload":"AQAAeA==","confirmed":true,"priority":"NORMAL","correlation_ids":["as:downlink:01HP6D18MQXJN90J5B07DC11HY"],"confirmed_retry":{"attempt":1}}};
|
|
85
|
+
//const topic = "v3/hafi-ttn-lorawan@ttn/devices/eui-a84041162183f8fb/down/ack";
|
|
86
|
+
//const message = {"end_device_ids":{"device_id":"eui-a84041162183f8fb","application_ids":{"application_id":"hafi-ttn-lorawan"},"dev_eui":"A84041162183F8FB","join_eui":"A840410000000101","dev_addr":"260B141A"},"correlation_ids":["as:downlink:01HP6D18MQXJN90J5B07DC11HY","gs:uplink:01HP6D1A9X4WAA3SFMXH4ESSMV"],"received_at":"2024-02-09T07:41:41.776887672Z","downlink_ack":{"session_key_id":"AY2MUrmnuovS8DCZAfYmsA==","f_port":1,"f_cnt":21,"frm_payload":"AQAAeA==","confirmed":true,"priority":"NORMAL","correlation_ids":["as:downlink:01HP6D18MQXJN90J5B07DC11HY"],"confirmed_retry":{"attempt":1}}};
|
|
87
87
|
|
|
88
88
|
// Chipstack
|
|
89
89
|
//const topic = "application/d63c10b6-9263-4ab3-9299-4308fa19a2ad/device/a84041f621857cd2/event/up";
|
|
@@ -118,8 +118,8 @@ class Lorawan extends utils.Adapter {
|
|
|
118
118
|
//const message = {"time":"2024-01-27T10:29:58.221817559+00:00","deviceInfo":{"tenantId":"52f14cd4-c6f1-4fbd-8f87-4025e1d49242","tenantName":"ChirpStack","applicationId":"59bcc5a7-59e2-4481-9615-fc4e58791915","applicationName":"Mclimate_Vicki","deviceProfileId":"3a9bc28f-3664-4bdf-b3be-a20d1eb32dc8","deviceProfileName":"Mclimate_Vicki","deviceName":"MClimate_Vicki_Heizkoerperventil_001","devEui":"70b3d52dd300ed31","deviceClassEnabled":"CLASS_A","tags":{}},"level":"ERROR","code":"UPLINK_CODEC","description":"Exception generated by quickjs","context":{"deduplication_id":"c44e7e25-09ce-4c95-b96f-5a298c5c6440"}};
|
|
119
119
|
|
|
120
120
|
// JOIN
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
const topic = "application/59bcc5a7-59e2-4481-9615-fc4e58791915/device/70b3d52dd300ed31/event/join";
|
|
122
|
+
const message = {"deduplicationId":"44cef56d-1b8d-45fc-a762-03b98b620db2","time":"2023-12-12T03:13:21.551178+00:00","deviceInfo":{"tenantId":"52f14cd4-c6f1-4fbd-8f87-4025e1d49242","tenantName":"ChirpStack","applicationId":"59bcc5a7-59e2-4481-9615-fc4e58791915","applicationName":"Mclimate_Vicki","deviceProfileId":"3a9bc28f-3664-4bdf-b3be-a20d1eb32dc8","deviceProfileName":"Mclimate_Vicki","deviceName":"MClimate_Vicki_Heizkoerperventil_001","devEui":"70b3d52dd300ed31","deviceClassEnabled":"CLASS_A","tags":{}},"devAddr":"01009400"};
|
|
123
123
|
|
|
124
124
|
// DOWN
|
|
125
125
|
//const topic = "application/59bcc5a7-59e2-4481-9615-fc4e58791915/device/70b3d52dd300ed31/command/down";
|