iobroker.lorawan 0.3.6 → 0.3.8

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
@@ -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.8 (2024-02-23)
26
+ * (BenAhrdt) write def into state in case of type changes
27
+
28
+ ### 0.3.7 (2024-02-22)
29
+ * (BenAhrdt) improove forbidden chars and implements join raw
30
+
25
31
  ### 0.3.6 (2024-02-21)
26
32
  * (BenAhrdt) set attributs if undefined
27
33
 
@@ -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 true;}",
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.6",
4
+ "version": "0.3.8",
5
5
  "news": {
6
+ "0.3.8": {
7
+ "en": "write def into state in case of type changes",
8
+ "de": "schreiben def in zustand bei typänderungen",
9
+ "ru": "написать деф в состояние в случае изменения типа",
10
+ "pt": "escrever def em estado em caso de alterações de tipo",
11
+ "nl": "def in status schrijven in geval van typewijzigingen",
12
+ "fr": "écrire def dans l'état en cas de changement de type",
13
+ "it": "scrivere def in stato in caso di variazioni di tipo",
14
+ "es": "escribir def en estado en caso de cambios de tipo",
15
+ "pl": "zapis def do stanu w przypadku zmian typu",
16
+ "uk": "писати деф в стан у разі зміни типу",
17
+ "zh-cn": "在类型变化时将 def 写入状态"
18
+ },
19
+ "0.3.7": {
20
+ "en": "improove forbidden chars and implements join raw",
21
+ "de": "unproove verbotene wagen und geräte roh beitreten",
22
+ "ru": "импровизировать запрещенные шары и реализаций присоединяются к сырому",
23
+ "pt": "improove proibido chars e implementos se juntar cru",
24
+ "nl": "improove verboden tekens en werktuigen samen rauw",
25
+ "fr": "improove prohibed chars and implements joignent brut",
26
+ "it": "improove vietati carboni e strumenti si uniscono crudo",
27
+ "es": "improove chars prohibidos e implementos se unen a crudo",
28
+ "pl": "improove zakazane znaki i narzędzia dołączyć surowe",
29
+ "uk": "неприпустимий заборонений діаграма і реалізує приєднатися до сировини",
30
+ "zh-cn": "将禁用字符和工具合并为原始字符"
31
+ },
6
32
  "0.3.6": {
7
33
  "en": "set attributs if undefined",
8
34
  "de": "wenn nicht definiert",
@@ -67,32 +93,6 @@
67
93
  "pl": "sformułowanie otrzymane = > otrzymywane w procesie messaging",
68
94
  "uk": "javascript licenses api веб-сайт go1.13.8 отримувати повідомлення",
69
95
  "zh-cn": "重述的语句 发送信件时收到"
70
- },
71
- "0.3.1": {
72
- "en": "rebuild with better messageing",
73
- "de": "neuaufbau mit besserer botschaft",
74
- "ru": "перестроить с лучшим сообщением",
75
- "pt": "reconstruir com melhor mensagem",
76
- "nl": "herbouwen met betere berichtgeving",
77
- "fr": "reconstruire avec un meilleur message",
78
- "it": "ricostruire con messaggi migliori",
79
- "es": "reconstruir con mejor mensaje",
80
- "pl": "odbudowa dzięki lepszemu rozwiązywaniu problemów",
81
- "uk": "перебудувати краще повідомлення",
82
- "zh-cn": "以更好的信息重建"
83
- },
84
- "0.3.0": {
85
- "en": "define user friendly Blockly Blocks with result",
86
- "de": "benutzerfreundlich definieren Blockly Blocks mit Ergebnis",
87
- "ru": "определение пользователя Блоки с результатом",
88
- "pt": "definir amigável Blocos com resultado",
89
- "nl": "gebruikersvriendelijk definiëren Blokkeren met resultaat",
90
- "fr": "définir une utilisation conviviale Blocs avec résultat",
91
- "it": "definire l'utente amichevole Blocchi Blockly con risultato",
92
- "es": "definir fácil de usar Bloqueo bloques con resultado",
93
- "pl": "zdefiniować przyjazny dla użytkownika Blokady z wynikiem",
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 standard downlink config
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
- // override standard with userconfig
93
- config[downlinkConfig.deviceType] = structuredClone(downlinkConfig);
94
- config[downlinkConfig.deviceType].downlinkState = {};
95
- // generate downlinkstates for internal use
96
- for(const downlinkParameter of Object.values(config[downlinkConfig.deviceType].downlinkParameter)){
97
- // check name for forbidden chars
98
- downlinkParameter.name = downlinkParameter.name.replace(this.adapter.FORBIDDEN_CHARS,"_");
99
- // check the downlinkparameters for all needed attributes and generate them if undefined
100
- for(const attribute in this.downlinkParameterAttributs){
101
- if(downlinkConfig.deviceType !== this.internalDevices.baseDevice && downlinkParameter[attribute] === undefined){
102
- this.adapter.log.debug(`attribute ${attribute} in parameter ${downlinkParameter.name} at devicetype ${downlinkConfig.deviceType} generated`);
103
- downlinkParameter[attribute] = this.downlinkParameterAttributs[attribute];
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){
@@ -63,7 +63,7 @@ class messagehandlerClass {
63
63
  await this.directoryhandler.generateRekursivObjects(this.directoryhandler.directories.application.devices.deviceEUI.deviceId.downlink.lastSend,`${startDirectory}.${this.directoryhandler.reachableSubfolders.downlinkLastSend}`,"","");
64
64
  }
65
65
 
66
- async fillWithDownlinkConfig(deviceStartdirectory){
66
+ async fillWithDownlinkConfig(deviceStartdirectory,options){
67
67
  const activeFunction = "fillWithDownlinkConfig";
68
68
  try{
69
69
  const changeInfo = await this.adapter.getChangeInfo(`${deviceStartdirectory}.fillDownlinkFolder`);
@@ -122,24 +122,35 @@ class messagehandlerClass {
122
122
  stateCommonMax = 1000000;
123
123
  }
124
124
  }
125
- await this.adapter.extendObjectAsync(`${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.downlinkControl}.${downlinkParameter.name}`,{
125
+ // common set into variable to read later (for options)
126
+ const common = {
127
+ name: "",
128
+ type: stateCommonType,
129
+ role: stateCommonRole,
130
+ read: stateCommonRole !== "button",
131
+ write: true,
132
+ unit: downlinkParameter.unit? downlinkParameter.unit:"",
133
+ min: stateCommonMin,
134
+ max: stateCommonMax,
135
+ def: stateCommonType === "boolean"? false : stateCommonType === "number"? stateCommonDef: "",
136
+ };
137
+ const stateId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.downlinkControl}.${downlinkParameter.name}`;
138
+ await this.adapter.extendObjectAsync(stateId,{
126
139
  type: "state",
127
- common: {
128
- name: "",
129
- type: stateCommonType,
130
- role: stateCommonRole,
131
- read: stateCommonRole !== "button",
132
- write: true,
133
- unit: downlinkParameter.unit? downlinkParameter.unit:"",
134
- min: stateCommonMin,
135
- max: stateCommonMax,
136
- def: stateCommonType === "boolean"? false : stateCommonType === "number"? stateCommonDef: "",
137
- },
140
+ common: common,
138
141
  native: {},
139
142
  });
140
143
  if(downlinkDevice !=="all" && downlinkDevice !== this.adapter.downlinkConfighandler.internalDevices.baseDevice){
141
144
  foundLength[downlinkParameter.name] = downlinkDevice.length;
142
145
  }
146
+ //check for right type of data (after a possible change)
147
+ if(!options || !options.inMessage){
148
+ const state = await this.adapter.getStateAsync(stateId);
149
+ if(typeof state.val !== typeof common.def){
150
+ this.adapter.log.silly(`the defaultvale for state ${stateId} will set to ${common.def}`);
151
+ await this.adapter.setStateAsync(stateId,common.def,true);
152
+ }
153
+ }
143
154
  }
144
155
  }
145
156
  }
@@ -185,7 +196,7 @@ class messagehandlerClass {
185
196
  * ****************** Check device startdirectory ********************
186
197
  * ******************************************************************/
187
198
 
188
- if(messageType !== "up" && !await this.adapter.objectExists(`${deviceStartdirectory}`)){
199
+ if(messageType !== "up" && messageType !== "join" && !await this.adapter.objectExists(`${deviceStartdirectory}`)){
189
200
  this.adapter.log.debug(`There was a message with the topic ${topic}, but the object ${deviceStartdirectory} does not exists yet.`);
190
201
  return;
191
202
  }
@@ -199,7 +210,7 @@ class messagehandlerClass {
199
210
  * ******************************************************************/
200
211
 
201
212
  // check for uplink message
202
- if(messageType === "up"){//if(message.uplink_message){
213
+ if(messageType === "up"){
203
214
  /*********************************************************************
204
215
  * ************************ Main directories *************************
205
216
  * ******************************************************************/
@@ -211,9 +222,9 @@ class messagehandlerClass {
211
222
  * ******************************************************************/
212
223
 
213
224
  this.adapter.log.silly(`write rawdata`);
214
- let startDirectory = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.uplinkRaw}`;
225
+ let startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.uplinkRaw}`;
215
226
  // write json
216
- await this.adapter.setObjectNotExistsAsync(`${startDirectory}.json`,{
227
+ await this.adapter.setObjectNotExistsAsync(`${startId}.json`,{
217
228
  type: "state",
218
229
  common: {
219
230
  name: "last recieved message",
@@ -224,7 +235,7 @@ class messagehandlerClass {
224
235
  },
225
236
  native: {},
226
237
  });
227
- await this.adapter.setStateAsync(`${startDirectory}.json`,JSON.stringify(message),true);
238
+ await this.adapter.setStateAsync(`${startId}.json`,JSON.stringify(message),true);
228
239
 
229
240
  /*********************************************************************
230
241
  * ********************** Rawdata (Base64) ***************************
@@ -233,7 +244,7 @@ class messagehandlerClass {
233
244
  if(message.uplink_message.frm_payload){
234
245
  // wite base64 data
235
246
  this.adapter.log.silly(`write base64`);
236
- await this.adapter.setObjectNotExistsAsync(`${startDirectory}.base64`,{
247
+ await this.adapter.setObjectNotExistsAsync(`${startId}.base64`,{
237
248
  type: "state",
238
249
  common: {
239
250
  name: "last recieved data as base64",
@@ -245,11 +256,11 @@ class messagehandlerClass {
245
256
  native: {},
246
257
  });
247
258
  const writedata = message.uplink_message.frm_payload;
248
- await this.adapter.setStateAsync(`${startDirectory}.base64`,writedata,true);
259
+ await this.adapter.setStateAsync(`${startId}.base64`,writedata,true);
249
260
 
250
261
  // write base64 data in hex data
251
262
  this.adapter.log.silly(`write hex`);
252
- await this.adapter.setObjectNotExistsAsync(`${startDirectory}.hex`,{
263
+ await this.adapter.setObjectNotExistsAsync(`${startId}.hex`,{
253
264
  type: "state",
254
265
  common: {
255
266
  name: "last recieved data as hex",
@@ -261,11 +272,11 @@ class messagehandlerClass {
261
272
  native: {},
262
273
  });
263
274
  const hexdata = Buffer.from(message.uplink_message.frm_payload, "base64").toString("hex").toUpperCase();
264
- await this.adapter.setStateAsync(`${startDirectory}.hex`,hexdata,true);
275
+ await this.adapter.setStateAsync(`${startId}.hex`,hexdata,true);
265
276
 
266
277
  // write base64 data in string data
267
278
  this.adapter.log.silly(`write string`);
268
- await this.adapter.setObjectNotExistsAsync(`${startDirectory}.string`,{
279
+ await this.adapter.setObjectNotExistsAsync(`${startId}.string`,{
269
280
  type: "state",
270
281
  common: {
271
282
  name: "last recieved data as string",
@@ -277,25 +288,25 @@ class messagehandlerClass {
277
288
  native: {},
278
289
  });
279
290
  const stringdata = Buffer.from(message.uplink_message.frm_payload, "base64").toString();
280
- await this.adapter.setStateAsync(`${startDirectory}.string`,stringdata,true);
291
+ await this.adapter.setStateAsync(`${startId}.string`,stringdata,true);
281
292
  }
282
293
 
283
294
  /*********************************************************************
284
295
  * ********************** decoded payload ****************************
285
296
  * ******************************************************************/
286
297
 
287
- startDirectory = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.uplinkDecoded}`;
298
+ startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.uplinkDecoded}`;
288
299
  this.adapter.log.silly(`write decoded payload`);
289
- await this.directoryhandler.generateRekursivObjects(message.uplink_message.decoded_payload,startDirectory,topic,message);
300
+ await this.directoryhandler.generateRekursivObjects(message.uplink_message.decoded_payload,startId,topic,message);
290
301
 
291
302
  /*********************************************************************
292
303
  * ************************* remaining *******************************
293
304
  * ******************************************************************/
294
305
 
295
- startDirectory = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.uplinkRemaining}`;
306
+ startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.uplinkRemaining}`;
296
307
  this.adapter.log.silly(`write remaining uplink data`);
297
308
 
298
- await this.directoryhandler.generateRekursivObjects(message.uplink_message,startDirectory,topic,message,{ignoredElementNames:{decoded_payload:{},frm_payload:{}}});
309
+ await this.directoryhandler.generateRekursivObjects(message.uplink_message,startId,topic,message,{ignoredElementNames:{decoded_payload:{},frm_payload:{}}});
299
310
 
300
311
  /*********************************************************************
301
312
  * ******************* Check downlink at uplink **********************
@@ -309,17 +320,17 @@ class messagehandlerClass {
309
320
  * ******************************************************************/
310
321
 
311
322
  // check for uplink message
312
- else if(messageType === "queued" || messageType === "sent"){ //if(message.downlink_queued || message.downlink_sent)//if(message.downlink_queued || message.downlink_sent){
323
+ else if(messageType === "queued" || messageType === "sent"){
313
324
  // Check wich downlink was recieved
314
325
  const downlinkType = `downlink_${messageType}`;
315
326
  /*********************************************************************
316
327
  * ************************ Rawdata json *****************************
317
328
  * ******************************************************************/
318
329
 
319
- let startDirectory = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.downlinkRaw}`;
330
+ let startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.downlinkRaw}`;
320
331
  // write json
321
332
  this.adapter.log.silly(`write rawdata`);
322
- await this.adapter.setObjectNotExistsAsync(`${startDirectory}.json`,{
333
+ await this.adapter.setObjectNotExistsAsync(`${startId}.json`,{
323
334
  type: "state",
324
335
  common: {
325
336
  name: "last recieved message",
@@ -330,7 +341,7 @@ class messagehandlerClass {
330
341
  },
331
342
  native: {},
332
343
  });
333
- await this.adapter.setStateAsync(`${startDirectory}.json`,JSON.stringify(message),true);
344
+ await this.adapter.setStateAsync(`${startId}.json`,JSON.stringify(message),true);
334
345
 
335
346
  /*********************************************************************
336
347
  * ********************** Rawdata (Base64) ***************************
@@ -340,7 +351,7 @@ class messagehandlerClass {
340
351
  this.adapter.log.silly(`write base64`);
341
352
  if(message[downlinkType].frm_payload){
342
353
  // wite base64 data
343
- await this.adapter.setObjectNotExistsAsync(`${startDirectory}.base64`,{
354
+ await this.adapter.setObjectNotExistsAsync(`${startId}.base64`,{
344
355
  type: "state",
345
356
  common: {
346
357
  name: "last recieved data as base64",
@@ -352,11 +363,11 @@ class messagehandlerClass {
352
363
  native: {},
353
364
  });
354
365
  const writedata = message[downlinkType].frm_payload;
355
- await this.adapter.setStateAsync(`${startDirectory}.base64`,writedata,true);
366
+ await this.adapter.setStateAsync(`${startId}.base64`,writedata,true);
356
367
 
357
368
  // write base64 data in hex data
358
369
  this.adapter.log.silly(`write hex`);
359
- await this.adapter.setObjectNotExistsAsync(`${startDirectory}.hex`,{
370
+ await this.adapter.setObjectNotExistsAsync(`${startId}.hex`,{
360
371
  type: "state",
361
372
  common: {
362
373
  name: "last recieved data as hex",
@@ -368,11 +379,11 @@ class messagehandlerClass {
368
379
  native: {},
369
380
  });
370
381
  const hexdata = Buffer.from(message[downlinkType].frm_payload,"base64").toString("hex").toUpperCase();
371
- await this.adapter.setStateAsync(`${startDirectory}.hex`,hexdata,true);
382
+ await this.adapter.setStateAsync(`${startId}.hex`,hexdata,true);
372
383
 
373
384
  // write base64 data in string data
374
385
  this.adapter.log.silly(`write string`);
375
- await this.adapter.setObjectNotExistsAsync(`${startDirectory}.string`,{
386
+ await this.adapter.setObjectNotExistsAsync(`${startId}.string`,{
376
387
  type: "state",
377
388
  common: {
378
389
  name: "last recieved data as string",
@@ -384,23 +395,59 @@ class messagehandlerClass {
384
395
  native: {},
385
396
  });
386
397
  const stringdata = Buffer.from(message[downlinkType].frm_payload,"base64").toString();
387
- await this.adapter.setStateAsync(`${startDirectory}.string`,stringdata,true);
398
+ await this.adapter.setStateAsync(`${startId}.string`,stringdata,true);
388
399
  }
389
400
 
390
401
  /*********************************************************************
391
402
  * ************************* remaining *******************************
392
403
  * ******************************************************************/
393
404
 
394
- startDirectory = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.downlinkRemaining}`;
405
+ startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.downlinkRemaining}`;
395
406
  this.adapter.log.silly(`write remaining downlink data`);
396
- await this.directoryhandler.generateRekursivObjects(message[downlinkType],startDirectory,topic,message,{ignoredElementNames:{frm_payload:{}}});
407
+ await this.directoryhandler.generateRekursivObjects(message[downlinkType],startId,topic,message,{ignoredElementNames:{frm_payload:{}}});
408
+ }
409
+
410
+ // check for join message
411
+ else if(messageType === "join"){
412
+
413
+ /*********************************************************************
414
+ * ************************ Main directories *************************
415
+ * ******************************************************************/
416
+
417
+ await this.directoryhandler.generateRekursivObjects(this.directoryhandler.directories,"",topic,message);
418
+
419
+ /*********************************************************************
420
+ * ************************ Rawdata json *****************************
421
+ * ******************************************************************/
422
+
423
+ this.adapter.log.silly(`write rawdata`);
424
+ const startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.joinRaw}`;
425
+ // write json
426
+ await this.adapter.setObjectNotExistsAsync(`${startId}.json`,{
427
+ type: "state",
428
+ common: {
429
+ name: "last recieved message",
430
+ type: "json",
431
+ role: "value",
432
+ read: true,
433
+ write: false
434
+ },
435
+ native: {},
436
+ });
437
+ await this.adapter.setStateAsync(`${startId}.json`,JSON.stringify(message),true);
438
+ const changeInfo = await this.adapter.getChangeInfo(startId);
439
+ this.adapter.log.info(`the device ${changeInfo.deviceEUI} joined network`);
440
+ }
441
+ // Other messagetypes
442
+ else{
443
+ this.adapter.log.debug(`the messagetype: ${messageType}, is not implemented yet`);
397
444
  }
398
445
 
399
446
  /*********************************************************************
400
447
  * ********************** downlinkConfigs ****************************
401
448
  * ******************************************************************/
402
449
  this.adapter.log.silly(`check configed downlinks`);
403
- await this.fillWithDownlinkConfig(deviceStartdirectory);
450
+ await this.fillWithDownlinkConfig(deviceStartdirectory,{inMessage: true});
404
451
  }
405
452
  catch(error){
406
453
  this.adapter.log.error(`error at ${activeFunction}: ${error} - - - Message: ${JSON.stringify(message)}`);
@@ -434,7 +481,7 @@ class messagehandlerClass {
434
481
  * ****************** Check device startdirectory ********************
435
482
  * ******************************************************************/
436
483
 
437
- if(messageType !== "up" && !await this.adapter.objectExists(`${deviceStartdirectory}`)){
484
+ if(messageType !== "up" && messageType !== "join" && !await this.adapter.objectExists(`${deviceStartdirectory}`)){
438
485
  this.adapter.log.debug(`There was a message with the topic ${topic}, but the object ${deviceStartdirectory} does not exists yet.`);
439
486
  return;
440
487
  }
@@ -448,7 +495,7 @@ class messagehandlerClass {
448
495
  * ******************************************************************/
449
496
 
450
497
  // check for uplink message
451
- if(messageType === "up"){//if(message.uplink_message){
498
+ if(messageType === "up"){
452
499
 
453
500
  /*********************************************************************
454
501
  * ************************ Main directories *************************
@@ -460,10 +507,10 @@ class messagehandlerClass {
460
507
  * ************************ Rawdata json *****************************
461
508
  * ******************************************************************/
462
509
 
463
- let startDirectory = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.uplinkRaw}`;
510
+ let startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.uplinkRaw}`;
464
511
  // write json
465
512
  this.adapter.log.silly(`write rawdata`);
466
- await this.adapter.setObjectNotExistsAsync(`${startDirectory}.json`,{
513
+ await this.adapter.setObjectNotExistsAsync(`${startId}.json`,{
467
514
  type: "state",
468
515
  common: {
469
516
  name: "last recieved message",
@@ -474,7 +521,7 @@ class messagehandlerClass {
474
521
  },
475
522
  native: {},
476
523
  });
477
- await this.adapter.setStateAsync(`${startDirectory}.json`,JSON.stringify(message),true);
524
+ await this.adapter.setStateAsync(`${startId}.json`,JSON.stringify(message),true);
478
525
 
479
526
  /*********************************************************************
480
527
  * ********************** Rawdata (Base64) ***************************
@@ -483,7 +530,7 @@ class messagehandlerClass {
483
530
  if(message.data){
484
531
  // wite base64 data
485
532
  this.adapter.log.silly(`write base64`);
486
- await this.adapter.setObjectNotExistsAsync(`${startDirectory}.base64`,{
533
+ await this.adapter.setObjectNotExistsAsync(`${startId}.base64`,{
487
534
  type: "state",
488
535
  common: {
489
536
  name: "last recieved data as base64",
@@ -495,11 +542,11 @@ class messagehandlerClass {
495
542
  native: {},
496
543
  });
497
544
  const writedata = message.data;
498
- await this.adapter.setStateAsync(`${startDirectory}.base64`,writedata,true);
545
+ await this.adapter.setStateAsync(`${startId}.base64`,writedata,true);
499
546
 
500
547
  // write base64 data in hex data
501
548
  this.adapter.log.silly(`write hex`);
502
- await this.adapter.setObjectNotExistsAsync(`${startDirectory}.hex`,{
549
+ await this.adapter.setObjectNotExistsAsync(`${startId}.hex`,{
503
550
  type: "state",
504
551
  common: {
505
552
  name: "last recieved data as hex",
@@ -511,11 +558,11 @@ class messagehandlerClass {
511
558
  native: {},
512
559
  });
513
560
  const hexdata = Buffer.from(message.data, "base64").toString("hex").toUpperCase();
514
- await this.adapter.setStateAsync(`${startDirectory}.hex`,hexdata,true);
561
+ await this.adapter.setStateAsync(`${startId}.hex`,hexdata,true);
515
562
 
516
563
  // write base64 data in string data
517
564
  this.adapter.log.silly(`write string`);
518
- await this.adapter.setObjectNotExistsAsync(`${startDirectory}.string`,{
565
+ await this.adapter.setObjectNotExistsAsync(`${startId}.string`,{
519
566
  type: "state",
520
567
  common: {
521
568
  name: "last recieved data as string",
@@ -527,23 +574,23 @@ class messagehandlerClass {
527
574
  native: {},
528
575
  });
529
576
  const stringdata = Buffer.from(message.data, "base64").toString();
530
- await this.adapter.setStateAsync(`${startDirectory}.string`,stringdata,true);
577
+ await this.adapter.setStateAsync(`${startId}.string`,stringdata,true);
531
578
  }
532
579
 
533
580
  /*********************************************************************
534
581
  * ****************** decoded payload (Object) ***********************
535
582
  * ******************************************************************/
536
- startDirectory = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.uplinkDecoded}`;
583
+ startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.uplinkDecoded}`;
537
584
  this.adapter.log.silly(`write decoded payload (Object)`);
538
- await this.directoryhandler.generateRekursivObjects(message.object,startDirectory,topic,message);
585
+ await this.directoryhandler.generateRekursivObjects(message.object,startId,topic,message);
539
586
 
540
587
  /*********************************************************************
541
588
  * ************************* remaining *******************************
542
589
  * ******************************************************************/
543
590
 
544
- startDirectory = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.uplinkRemaining}`;
591
+ startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.uplinkRemaining}`;
545
592
  this.adapter.log.silly(`write remaining uplink data`);
546
- await this.directoryhandler.generateRekursivObjects(message,startDirectory,topic,message,{ignoredElementNames:{deduplicationId:{},deviceInfo:{},data:{},object:{}}});
593
+ await this.directoryhandler.generateRekursivObjects(message,startId,topic,message,{ignoredElementNames:{deduplicationId:{},deviceInfo:{},data:{},object:{}}});
547
594
 
548
595
  /*********************************************************************
549
596
  * ******************* Check downlink at uplink **********************
@@ -557,16 +604,16 @@ class messagehandlerClass {
557
604
  * ******************************************************************/
558
605
 
559
606
  // check for uplink message
560
- else if(messageType === "down"){ //if(message.downlink_queued || message.downlink_sent)//if(message.downlink_queued || message.downlink_sent){
607
+ else if(messageType === "down"){
561
608
 
562
609
  /*********************************************************************
563
610
  * ************************ Rawdata json *****************************
564
611
  * ******************************************************************/
565
612
 
566
- const startDirectory = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.downlinkRaw}`;
613
+ const startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.downlinkRaw}`;
567
614
  // write json
568
615
  this.adapter.log.silly(`write rawdata`);
569
- await this.adapter.setObjectNotExistsAsync(`${startDirectory}.json`,{
616
+ await this.adapter.setObjectNotExistsAsync(`${startId}.json`,{
570
617
  type: "state",
571
618
  common: {
572
619
  name: "last recieved message",
@@ -577,7 +624,7 @@ class messagehandlerClass {
577
624
  },
578
625
  native: {},
579
626
  });
580
- await this.adapter.setStateAsync(`${startDirectory}.json`,JSON.stringify(message),true);
627
+ await this.adapter.setStateAsync(`${startId}.json`,JSON.stringify(message),true);
581
628
 
582
629
  /*********************************************************************
583
630
  * ********************** Rawdata (Base64) ***************************
@@ -587,7 +634,7 @@ class messagehandlerClass {
587
634
  if(message.data){
588
635
  // wite base64 data
589
636
  this.adapter.log.silly(`write base64`);
590
- await this.adapter.setObjectNotExistsAsync(`${startDirectory}.base64`,{
637
+ await this.adapter.setObjectNotExistsAsync(`${startId}.base64`,{
591
638
  type: "state",
592
639
  common: {
593
640
  name: "last recieved data as base64",
@@ -599,11 +646,11 @@ class messagehandlerClass {
599
646
  native: {},
600
647
  });
601
648
  const writedata = message.data;
602
- await this.adapter.setStateAsync(`${startDirectory}.base64`,writedata,true);
649
+ await this.adapter.setStateAsync(`${startId}.base64`,writedata,true);
603
650
 
604
651
  // write base64 data in hex data
605
652
  this.adapter.log.silly(`write hex`);
606
- await this.adapter.setObjectNotExistsAsync(`${startDirectory}.hex`,{
653
+ await this.adapter.setObjectNotExistsAsync(`${startId}.hex`,{
607
654
  type: "state",
608
655
  common: {
609
656
  name: "last recieved data as hex",
@@ -615,11 +662,11 @@ class messagehandlerClass {
615
662
  native: {},
616
663
  });
617
664
  const hexdata = Buffer.from(message.data,"base64").toString("hex").toUpperCase();
618
- await this.adapter.setStateAsync(`${startDirectory}.hex`,hexdata,true);
665
+ await this.adapter.setStateAsync(`${startId}.hex`,hexdata,true);
619
666
 
620
667
  // write base64 data in string data
621
668
  this.adapter.log.silly(`write string`);
622
- await this.adapter.setObjectNotExistsAsync(`${startDirectory}.string`,{
669
+ await this.adapter.setObjectNotExistsAsync(`${startId}.string`,{
623
670
  type: "state",
624
671
  common: {
625
672
  name: "last recieved data as string",
@@ -631,7 +678,7 @@ class messagehandlerClass {
631
678
  native: {},
632
679
  });
633
680
  const stringdata = Buffer.from(message.data,"base64").toString();
634
- await this.adapter.setStateAsync(`${startDirectory}.string`,stringdata,true);
681
+ await this.adapter.setStateAsync(`${startId}.string`,stringdata,true);
635
682
  }
636
683
 
637
684
  /*********************************************************************
@@ -639,11 +686,47 @@ class messagehandlerClass {
639
686
  * ******************************************************************/
640
687
 
641
688
  }
689
+
690
+ // check for uplink message
691
+ else if(messageType === "join"){
692
+ /*********************************************************************
693
+ * ************************ Main directories *************************
694
+ * ******************************************************************/
695
+
696
+ await this.directoryhandler.generateRekursivObjects(this.directoryhandler.directories,"",topic,message);
697
+
698
+ /*********************************************************************
699
+ * ************************ Rawdata json *****************************
700
+ * ******************************************************************/
701
+
702
+ const startId = `${deviceStartdirectory}.${this.directoryhandler.reachableSubfolders.joinRaw}`;
703
+ // write json
704
+ this.adapter.log.silly(`write rawdata`);
705
+ await this.adapter.setObjectNotExistsAsync(`${startId}.json`,{
706
+ type: "state",
707
+ common: {
708
+ name: "last recieved message",
709
+ type: "json",
710
+ role: "value",
711
+ read: true,
712
+ write: false
713
+ },
714
+ native: {},
715
+ });
716
+ await this.adapter.setStateAsync(`${startId}.json`,JSON.stringify(message),true);
717
+ const changeInfo = await this.adapter.getChangeInfo(startId);
718
+ this.adapter.log.info(`the device ${changeInfo.deviceEUI} joined network`);
719
+ }
720
+ // Other messagetypes
721
+ else{
722
+ this.adapter.log.debug(`the messagetype: ${messageType}, is not implemented yet`);
723
+ }
724
+
642
725
  /*********************************************************************
643
726
  * ********************** downlinkConfigs ****************************
644
727
  * ******************************************************************/
645
728
  this.adapter.log.silly(`check configed downlinks`);
646
- await this.fillWithDownlinkConfig(deviceStartdirectory);
729
+ await this.fillWithDownlinkConfig(deviceStartdirectory,{inMessage: true});
647
730
 
648
731
  }
649
732
  catch(error){
@@ -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/+/up","v3/+/devices/+/down/#"];
57
+ return ["v3/+/devices/+/+","v3/+/devices/+/down/+"];
58
58
  case this.adapter.origin.chirpstack:
59
- return ["application/+/device/+/event/up","application/+/device/+/command/down"];
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
- //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"};
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";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.lorawan",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "description": "converts the desired lora gateway data to a ioBroker structure",
5
5
  "author": {
6
6
  "name": "BenAhrdt",