iobroker.lorawan 0.0.8 → 0.0.9
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 +11 -1
- package/admin/lorawan.png +0 -0
- package/io-package.json +14 -14
- package/lib/modules/directorieshandler.js +92 -45
- package/lib/modules/downlinkConfighandler.js +23 -15
- package/lib/modules/downlinks/downlinks.js +24 -22
- package/lib/modules/messagehandler.js +61 -49
- package/lib/modules/mqttclient.js +14 -2
- package/main.js +5 -107
- package/package.json +1 -1
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.0.9 (2024-01-19)
|
|
23
|
+
* (BenAhrdt) first version for beta
|
|
24
|
+
|
|
22
25
|
### 0.0.8 (2024-01-18)
|
|
23
26
|
* (BenAhrdt) first implementation of chirpstack
|
|
24
27
|
|
|
@@ -44,6 +47,7 @@ Adapter was created in collaboration with Joerg Froehner LoraWan@hafenmeister.co
|
|
|
44
47
|
MIT License
|
|
45
48
|
|
|
46
49
|
Copyright (c) 2024 BenAhrdt <bsahrdt@gmail.com>
|
|
50
|
+
Copyright (c) 2024 Joerg Froehner <LoraWan@hafenmeister.com>
|
|
47
51
|
|
|
48
52
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
49
53
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -61,4 +65,10 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
61
65
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
62
66
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
63
67
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
64
|
-
SOFTWARE.
|
|
68
|
+
SOFTWARE.
|
|
69
|
+
|
|
70
|
+
## DISCLAIMER
|
|
71
|
+
The rights of the trademarks and company names,
|
|
72
|
+
remain with their owners and have no relation to this adapter.
|
|
73
|
+
The fairuse policy must continue to be adhered to by the operator of the adapter.
|
|
74
|
+
If this repository is forked, it must be cited as the source.
|
package/admin/lorawan.png
CHANGED
|
Binary file
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "lorawan",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.9",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.0.9": {
|
|
7
|
+
"en": "first version for beta",
|
|
8
|
+
"de": "erste version für beta",
|
|
9
|
+
"ru": "первая версия для бета",
|
|
10
|
+
"pt": "primeira versão para beta",
|
|
11
|
+
"nl": "eerste versie voor beta",
|
|
12
|
+
"fr": "première version pour bêta",
|
|
13
|
+
"it": "prima versione per beta",
|
|
14
|
+
"es": "primera versión para beta",
|
|
15
|
+
"pl": "pierwsza wersja dla beta",
|
|
16
|
+
"uk": "перша версія для бета",
|
|
17
|
+
"zh-cn": "β的第一个版本"
|
|
18
|
+
},
|
|
6
19
|
"0.0.8": {
|
|
7
20
|
"en": "first implementation of chirpstack",
|
|
8
21
|
"de": "erste implementierung von chirpstack",
|
|
@@ -80,19 +93,6 @@
|
|
|
80
93
|
"pl": "pierwszy config dla downlinks nieznany",
|
|
81
94
|
"uk": "перший конфігурація для вхідних посилань",
|
|
82
95
|
"zh-cn": "输入下行链路的第一个配置"
|
|
83
|
-
},
|
|
84
|
-
"0.0.2": {
|
|
85
|
-
"en": "initial release",
|
|
86
|
-
"de": "erstausstrahlung",
|
|
87
|
-
"ru": "первоначальный выпуск",
|
|
88
|
-
"pt": "lançamento inicial",
|
|
89
|
-
"nl": "eerste release",
|
|
90
|
-
"fr": "libération initiale",
|
|
91
|
-
"it": "rilascio iniziale",
|
|
92
|
-
"es": "liberación inicial",
|
|
93
|
-
"pl": "początkowe zwolnienie",
|
|
94
|
-
"uk": "початковий реліз",
|
|
95
|
-
"zh-cn": "初步释放"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"title": "LoRaWAN",
|
|
@@ -29,19 +29,19 @@ class messagehandlerClass {
|
|
|
29
29
|
// declare the directory structre
|
|
30
30
|
this.directories = {
|
|
31
31
|
application:{
|
|
32
|
-
objectStateName : (message) =>{
|
|
33
|
-
return this.getAttributValue(message,this.searchableAttributeNames.apllicationId);
|
|
32
|
+
objectStateName : (topic,message) =>{
|
|
33
|
+
return this.getAttributValue(topic,message,this.searchableAttributeNames.apllicationId);
|
|
34
34
|
},
|
|
35
35
|
objectCommonName: "application",
|
|
36
36
|
devices:{
|
|
37
37
|
deviceUid:{
|
|
38
|
-
objectStateName : (message) =>{
|
|
39
|
-
return this.getAttributValue(message,this.searchableAttributeNames.deviceUid);
|
|
38
|
+
objectStateName : (topic,message) =>{
|
|
39
|
+
return this.getAttributValue(topic,message,this.searchableAttributeNames.deviceUid);
|
|
40
40
|
},
|
|
41
41
|
objectCommonName: "device UID",
|
|
42
42
|
deviceId:{
|
|
43
|
-
objectStateName : (message) =>{
|
|
44
|
-
return this.getAttributValue(message,this.searchableAttributeNames.deviceId);
|
|
43
|
+
objectStateName : (topic,message) =>{
|
|
44
|
+
return this.getAttributValue(topic,message,this.searchableAttributeNames.deviceId);
|
|
45
45
|
},
|
|
46
46
|
objectCommonName: "device ID",
|
|
47
47
|
objectType:"channel",
|
|
@@ -105,7 +105,7 @@ class messagehandlerClass {
|
|
|
105
105
|
* ************************ Objectstring *****************************
|
|
106
106
|
* ******************************************************************/
|
|
107
107
|
|
|
108
|
-
async generateRekursivObjects(obj,startDirectory,message,options = undefined){
|
|
108
|
+
async generateRekursivObjects(obj,startDirectory,topic,message,options = undefined){
|
|
109
109
|
// just proceed with ojects
|
|
110
110
|
if(typeof obj === "object"){
|
|
111
111
|
// go to every element in the object
|
|
@@ -119,7 +119,7 @@ class messagehandlerClass {
|
|
|
119
119
|
let objectId = `${startDirectory}.${elementName}`;
|
|
120
120
|
let internalObjectId = elementName;
|
|
121
121
|
if(obj[elementName].objectStateName){
|
|
122
|
-
internalObjectId = `${obj[elementName].objectStateName(message)}`;
|
|
122
|
+
internalObjectId = `${obj[elementName].objectStateName(topic,message)}`;
|
|
123
123
|
objectId = `${startDirectory}.${internalObjectId}`;
|
|
124
124
|
}
|
|
125
125
|
if(objectId.indexOf(".") === 0){
|
|
@@ -129,10 +129,10 @@ class messagehandlerClass {
|
|
|
129
129
|
if(!this.reachableDirectories){
|
|
130
130
|
this.reachableDirectories = {};
|
|
131
131
|
}
|
|
132
|
-
if(!this.reachableDirectories[this.getObjectDirectory(message,this.searchableAttributeNames.deviceId)]){
|
|
133
|
-
this.reachableDirectories[this.getObjectDirectory(message,this.searchableAttributeNames.deviceId)] = {};
|
|
132
|
+
if(!this.reachableDirectories[this.getObjectDirectory(topic,message,this.searchableAttributeNames.deviceId)]){
|
|
133
|
+
this.reachableDirectories[this.getObjectDirectory(topic,message,this.searchableAttributeNames.deviceId)] = {};
|
|
134
134
|
}
|
|
135
|
-
this.reachableDirectories[this.getObjectDirectory(message,this.searchableAttributeNames.deviceId)][obj[elementName].safeDirectory] = objectId;
|
|
135
|
+
this.reachableDirectories[this.getObjectDirectory(topic,message,this.searchableAttributeNames.deviceId)][obj[elementName].safeDirectory] = objectId;
|
|
136
136
|
}
|
|
137
137
|
await this.adapter.setObjectNotExistsAsync(objectId,{
|
|
138
138
|
// @ts-ignore
|
|
@@ -142,7 +142,7 @@ class messagehandlerClass {
|
|
|
142
142
|
},
|
|
143
143
|
native : {},
|
|
144
144
|
});
|
|
145
|
-
await this.generateRekursivObjects(obj[elementName],objectId,message);
|
|
145
|
+
await this.generateRekursivObjects(obj[elementName],objectId,topic,message);
|
|
146
146
|
}
|
|
147
147
|
else{
|
|
148
148
|
let stateCommonType = typeof obj[elementName];
|
|
@@ -158,7 +158,7 @@ class messagehandlerClass {
|
|
|
158
158
|
let objectId = `${startDirectory}.${elementName}`;
|
|
159
159
|
let internalObjectId = elementName;
|
|
160
160
|
if(obj[elementName].objectStateName){
|
|
161
|
-
internalObjectId = `${obj[elementName].objectStateName(message)}`;
|
|
161
|
+
internalObjectId = `${obj[elementName].objectStateName(topic,message)}`;
|
|
162
162
|
objectId = `${startDirectory}.${internalObjectId}`;
|
|
163
163
|
}
|
|
164
164
|
if(objectId.indexOf(".") === 0){
|
|
@@ -196,13 +196,13 @@ class messagehandlerClass {
|
|
|
196
196
|
* ************************** Attribute ******************************
|
|
197
197
|
* ******************************************************************/
|
|
198
198
|
|
|
199
|
-
getAttributValue(message,resolvetype){
|
|
199
|
+
getAttributValue(topic,message,resolvetype){
|
|
200
200
|
// Select search in case of origin
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
201
|
+
switch(this.adapter.config.origin){
|
|
202
|
+
case "ttn":
|
|
203
|
+
return this.getTtnAttributValue(topic,message,resolvetype);
|
|
204
|
+
case "chirpstack":
|
|
205
|
+
return this.getChirpstackAttributValue(topic,message,resolvetype);
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
|
|
@@ -210,18 +210,34 @@ class messagehandlerClass {
|
|
|
210
210
|
* ************************ Object Directory *************************
|
|
211
211
|
* ******************************************************************/
|
|
212
212
|
|
|
213
|
-
getObjectDirectory(message,resolvetype){
|
|
213
|
+
getObjectDirectory(topic,message,resolvetype){
|
|
214
214
|
// Select search in case of origin
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
215
|
+
switch(this.adapter.config.origin){
|
|
216
|
+
case "ttn":
|
|
217
|
+
return this.getTtnObjectDirectory(topic,message,resolvetype);
|
|
218
|
+
case "chirpstack":
|
|
219
|
+
return this.getChirpstackObjectDirectory(topic,message,resolvetype);
|
|
220
220
|
}
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
-
|
|
224
|
-
|
|
223
|
+
/*********************************************************************
|
|
224
|
+
* *********************** Topic resolved ****************************
|
|
225
|
+
* ******************************************************************/
|
|
226
|
+
getTopicResoled(topic){
|
|
227
|
+
this.adapter.log.debug(`topic ${topic} is requested for resolveing`);
|
|
228
|
+
const topicElements = topic.split("/");
|
|
229
|
+
const topicResolved = {
|
|
230
|
+
applicationId: topicElements[1],
|
|
231
|
+
deviceId: topicElements[3],
|
|
232
|
+
messageType: topicElements[topicElements.length - 1]
|
|
233
|
+
};
|
|
234
|
+
// clean up application id
|
|
235
|
+
const indexOfOrigin = topicResolved.applicationId.indexOf("@");
|
|
236
|
+
if(indexOfOrigin !== -1){
|
|
237
|
+
topicResolved.applicationId = topicResolved.applicationId.substring(0,indexOfOrigin);
|
|
238
|
+
}
|
|
239
|
+
return topicResolved;
|
|
240
|
+
}
|
|
225
241
|
|
|
226
242
|
/*********************************************************************
|
|
227
243
|
* **************************** TTN *********************************
|
|
@@ -231,16 +247,18 @@ class messagehandlerClass {
|
|
|
231
247
|
* ************************** Attribute ******************************
|
|
232
248
|
* ******************************************************************/
|
|
233
249
|
|
|
234
|
-
getTtnAttributValue(message,resolvetype){
|
|
250
|
+
getTtnAttributValue(topic,message,resolvetype){
|
|
251
|
+
this.adapter.log.debug(`attribute ${resolvetype} is requested for ttn`);
|
|
252
|
+
const topicResolved = this.getTopicResoled(topic);
|
|
235
253
|
switch(resolvetype){
|
|
236
254
|
case this.searchableAttributeNames.apllicationId:
|
|
237
|
-
return
|
|
255
|
+
return topicResolved.applicationId;
|
|
238
256
|
|
|
239
257
|
case this.searchableAttributeNames.deviceUid:
|
|
240
258
|
return message.end_device_ids.dev_eui;
|
|
241
259
|
|
|
242
260
|
case this.searchableAttributeNames.deviceId:
|
|
243
|
-
return
|
|
261
|
+
return topicResolved.deviceId;
|
|
244
262
|
|
|
245
263
|
default:
|
|
246
264
|
this.adapter.log.warn(`No attribute with the name ${resolvetype} found.`);
|
|
@@ -252,11 +270,13 @@ class messagehandlerClass {
|
|
|
252
270
|
* ************************ Object Directory *************************
|
|
253
271
|
* ******************************************************************/
|
|
254
272
|
|
|
255
|
-
getTtnObjectDirectory(message,resolvetype){
|
|
273
|
+
getTtnObjectDirectory(topic,message,resolvetype){
|
|
274
|
+
this.adapter.log.debug(`directory ${resolvetype} is requested for ttn`);
|
|
275
|
+
const topicResolved = this.getTopicResoled(topic);
|
|
256
276
|
if(typeof message !== "string"){
|
|
257
277
|
switch(resolvetype){
|
|
258
278
|
case this.searchableAttributeNames.deviceId:
|
|
259
|
-
return `${
|
|
279
|
+
return `${topicResolved.applicationId}.devices.${message.end_device_ids.dev_eui}.${topicResolved.deviceId}`;
|
|
260
280
|
|
|
261
281
|
default:
|
|
262
282
|
return message;
|
|
@@ -271,6 +291,7 @@ class messagehandlerClass {
|
|
|
271
291
|
|
|
272
292
|
|
|
273
293
|
|
|
294
|
+
|
|
274
295
|
/*********************************************************************
|
|
275
296
|
* ************************ Chirpstack ******************************
|
|
276
297
|
* ******************************************************************/
|
|
@@ -280,16 +301,26 @@ class messagehandlerClass {
|
|
|
280
301
|
* ******************************************************************/
|
|
281
302
|
|
|
282
303
|
|
|
283
|
-
getChirpstackAttributValue(message,resolvetype){
|
|
304
|
+
getChirpstackAttributValue(topic,message,resolvetype){
|
|
305
|
+
this.adapter.log.debug(`attribute ${resolvetype} is requested for chirpstack`);
|
|
306
|
+
const topicResolved = this.getTopicResoled(topic);
|
|
307
|
+
let devUid = undefined;
|
|
284
308
|
switch(resolvetype){
|
|
285
309
|
case this.searchableAttributeNames.apllicationId:
|
|
286
|
-
return
|
|
310
|
+
return topicResolved.applicationId;
|
|
287
311
|
|
|
288
312
|
case this.searchableAttributeNames.deviceUid:
|
|
289
|
-
|
|
313
|
+
if(topicResolved.messageType === "up"){
|
|
314
|
+
devUid = message.deviceInfo.devEui;
|
|
315
|
+
}
|
|
316
|
+
else if(topicResolved.messageType === "down")
|
|
317
|
+
{
|
|
318
|
+
devUid = message.devEui;
|
|
319
|
+
}
|
|
320
|
+
return devUid;
|
|
290
321
|
|
|
291
322
|
case this.searchableAttributeNames.deviceId:
|
|
292
|
-
return
|
|
323
|
+
return topicResolved.deviceId;
|
|
293
324
|
|
|
294
325
|
default:
|
|
295
326
|
this.adapter.log.warn(`No attribute with the name ${resolvetype} found.`);
|
|
@@ -301,18 +332,34 @@ class messagehandlerClass {
|
|
|
301
332
|
* ************************ Object Directory *************************
|
|
302
333
|
* ******************************************************************/
|
|
303
334
|
|
|
304
|
-
getChirpstackObjectDirectory(message,resolvetype){
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
335
|
+
getChirpstackObjectDirectory(topic,message,resolvetype){
|
|
336
|
+
this.adapter.log.debug(`directory ${resolvetype} is requested for chirpstack`);
|
|
337
|
+
const topicResolved = this.getTopicResoled(topic);
|
|
338
|
+
let devUid = undefined;
|
|
339
|
+
if(topicResolved.messageType === "up"){
|
|
340
|
+
devUid = message.deviceInfo.devEui;
|
|
341
|
+
}
|
|
342
|
+
else if(topicResolved.messageType === "down")
|
|
343
|
+
{
|
|
344
|
+
devUid = message.devEui;
|
|
345
|
+
}
|
|
346
|
+
if(devUid !== undefined){
|
|
347
|
+
if(typeof message !== "string"){
|
|
348
|
+
switch(resolvetype){
|
|
349
|
+
case this.searchableAttributeNames.deviceId:
|
|
350
|
+
return `${topicResolved.applicationId}.devices.${devUid}.${topicResolved.deviceId}`;
|
|
351
|
+
|
|
352
|
+
default:
|
|
353
|
+
return message;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
else{
|
|
357
|
+
return message;
|
|
312
358
|
}
|
|
313
359
|
}
|
|
314
360
|
else{
|
|
315
|
-
|
|
361
|
+
this.adapter.log.warn(`no devEui found in message`);
|
|
362
|
+
this.adapter.log.warn(`message: ${message}`);
|
|
316
363
|
}
|
|
317
364
|
}
|
|
318
365
|
}
|
|
@@ -15,6 +15,7 @@ class downlinkConfighandlerClass {
|
|
|
15
15
|
* ******************************************************************/
|
|
16
16
|
|
|
17
17
|
addAndMergeDownlinkConfigs(){
|
|
18
|
+
this.adapter.log.debug(`the standard and configed downlinks will be merged`);
|
|
18
19
|
// @ts-ignore
|
|
19
20
|
for(const downlinkConfig of Object.values(this.downlinks.internalDownlinks)){
|
|
20
21
|
this.addDownlinkConfigByType(downlinkConfig);
|
|
@@ -35,6 +36,7 @@ class downlinkConfighandlerClass {
|
|
|
35
36
|
|
|
36
37
|
getDownlinkConfig(changeInfo,options){
|
|
37
38
|
const activeFunction = "getDownlinkConfig";
|
|
39
|
+
this.adapter.log.debug(`the downlinkconfig is requested for the following changeinfo: ${JSON.stringify(changeInfo)}`);
|
|
38
40
|
try{
|
|
39
41
|
let downlinkConfig = undefined;
|
|
40
42
|
for(const deviceType in this.activeDownlinkConfigs){
|
|
@@ -69,12 +71,13 @@ class downlinkConfighandlerClass {
|
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
getDownlink(downlinkConfig,state,changeInfo){
|
|
72
|
-
// Select
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
// Select downlink in case of origin
|
|
75
|
+
this.adapter.log.debug(`the downlink for the changeinfo ${JSON.stringify(changeInfo)} is requested`);
|
|
76
|
+
switch(this.adapter.config.origin){
|
|
77
|
+
case "ttn":
|
|
78
|
+
return this.getTtnDownlink(downlinkConfig,state);
|
|
79
|
+
case "chirpstack":
|
|
80
|
+
return this.getChirpstackDownlink(downlinkConfig,state,changeInfo);
|
|
78
81
|
}
|
|
79
82
|
}
|
|
80
83
|
|
|
@@ -84,6 +87,7 @@ class downlinkConfighandlerClass {
|
|
|
84
87
|
|
|
85
88
|
calculatePayload(downlinkConfig,state){
|
|
86
89
|
// declare pyaload variable
|
|
90
|
+
this.adapter.log.debug(`the payload will be calculated`);
|
|
87
91
|
let payloadInHex = "";
|
|
88
92
|
let multipliedVal = 0;
|
|
89
93
|
//Check type
|
|
@@ -129,13 +133,13 @@ class downlinkConfighandlerClass {
|
|
|
129
133
|
* *********************** Downlinktopic *****************************
|
|
130
134
|
* ******************************************************************/
|
|
131
135
|
|
|
132
|
-
getDownlinkTopic(
|
|
133
|
-
// Select
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
getDownlinkTopic(changeInfo,suffix){
|
|
137
|
+
// Select downlinktopic in case of origin
|
|
138
|
+
switch(this.adapter.config.origin){
|
|
139
|
+
case "ttn":
|
|
140
|
+
return this.getTtnDownlinkTopicFromDirektory(changeInfo,suffix);
|
|
141
|
+
case "chirpstack":
|
|
142
|
+
return this.getChirpstackDownlinkTopicFromDirektory(changeInfo,suffix);
|
|
139
143
|
}
|
|
140
144
|
}
|
|
141
145
|
|
|
@@ -148,6 +152,7 @@ class downlinkConfighandlerClass {
|
|
|
148
152
|
* ******************************************************************/
|
|
149
153
|
|
|
150
154
|
getTtnDownlinkTopicFromDirektory(changeInfo,suffix){
|
|
155
|
+
this.adapter.log.debug(`the downlinktopic for ttn is requested`);
|
|
151
156
|
const topicElements = {
|
|
152
157
|
Version : "v3",
|
|
153
158
|
applicationId : `/${changeInfo.applicationId}`,
|
|
@@ -168,6 +173,7 @@ class downlinkConfighandlerClass {
|
|
|
168
173
|
* ******************************************************************/
|
|
169
174
|
|
|
170
175
|
getTtnDownlink(downlinkConfig,state){
|
|
176
|
+
this.adapter.log.debug(`the downlink for ttn is requested`);
|
|
171
177
|
const payloadInBase64 = this.calculatePayload(downlinkConfig,state);
|
|
172
178
|
// retun the whole downlink
|
|
173
179
|
return {downlinks:[{f_port:downlinkConfig.port,frm_payload:payloadInBase64,priority:downlinkConfig.priority,confirmed:downlinkConfig.confirmed}]};
|
|
@@ -185,11 +191,12 @@ class downlinkConfighandlerClass {
|
|
|
185
191
|
* ******************************************************************/
|
|
186
192
|
|
|
187
193
|
getChirpstackDownlinkTopicFromDirektory(changeInfo,suffix){
|
|
194
|
+
this.adapter.log.debug(`the downlinktopic for chirpstack is requested`);
|
|
188
195
|
const topicElements = {
|
|
189
196
|
Version : "application",
|
|
190
197
|
applicationId : `/${changeInfo.applicationId}`,
|
|
191
|
-
|
|
192
|
-
|
|
198
|
+
device : `/device`,
|
|
199
|
+
device_uid : `/${changeInfo.dev_uid}`,
|
|
193
200
|
command: `/command`,
|
|
194
201
|
suffix : suffix
|
|
195
202
|
};
|
|
@@ -205,6 +212,7 @@ class downlinkConfighandlerClass {
|
|
|
205
212
|
* ******************************************************************/
|
|
206
213
|
|
|
207
214
|
getChirpstackDownlink(downlinkConfig,state,changeInfo){
|
|
215
|
+
this.adapter.log.debug(`the downlink for chirpstack is requested`);
|
|
208
216
|
const payloadInBase64 = this.calculatePayload(downlinkConfig,state);
|
|
209
217
|
// retun the whole downlink
|
|
210
218
|
return {devEui:changeInfo.dev_uid,confirmed:downlinkConfig.confirmed,fPort:downlinkConfig.port,data:payloadInBase64};
|
|
@@ -19,28 +19,30 @@ class downlinksClass {
|
|
|
19
19
|
isConfiguration: true
|
|
20
20
|
}
|
|
21
21
|
];
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
22
|
+
// Select downlink in case of origin
|
|
23
|
+
switch(adapter.config.origin){
|
|
24
|
+
case "ttn":
|
|
25
|
+
this.internalDownlinks.unshift(
|
|
26
|
+
// @ts-ignore
|
|
27
|
+
{
|
|
28
|
+
name: "push",
|
|
29
|
+
type: "json",
|
|
30
|
+
deviceType: "all"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "replace",
|
|
34
|
+
type: "json",
|
|
35
|
+
deviceType: "all"
|
|
36
|
+
});
|
|
37
|
+
break;
|
|
38
|
+
case "chirpstack":
|
|
39
|
+
this.internalDownlinks.unshift(
|
|
40
|
+
// @ts-ignore
|
|
41
|
+
{
|
|
42
|
+
name: "push",
|
|
43
|
+
type: "json",
|
|
44
|
+
deviceType: "all"
|
|
45
|
+
});
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
48
|
|
|
@@ -13,11 +13,12 @@ class messagehandlerClass {
|
|
|
13
13
|
|
|
14
14
|
async handleMessage(topic,message){
|
|
15
15
|
// Select datahandling in case of origin
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
switch(this.adapter.config.origin){
|
|
17
|
+
case "ttn":
|
|
18
|
+
await this.handleTtnMessage(topic,message);
|
|
19
|
+
break;
|
|
20
|
+
case "chirpstack":
|
|
21
|
+
await this.handleChirpstackMessage(topic,message);
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
|
|
@@ -46,6 +47,7 @@ class messagehandlerClass {
|
|
|
46
47
|
async fillWithDownlinkConfig(deviceStartdirectory){
|
|
47
48
|
for(const downlinkDevices of Object.values(this.adapter.downlinkConfighandler.activeDownlinkConfigs)){
|
|
48
49
|
for(const downlinkConfig of Object.values(downlinkDevices)){
|
|
50
|
+
this.adapter.log.debug(`the downlinkconfig ${JSON.stringify(downlinkConfig)}, will checked.`);
|
|
49
51
|
let startDirectory = "";
|
|
50
52
|
if(!downlinkConfig.isConfiguration){
|
|
51
53
|
startDirectory = `${deviceStartdirectory}.downlink.control`;
|
|
@@ -100,14 +102,15 @@ class messagehandlerClass {
|
|
|
100
102
|
|
|
101
103
|
try{
|
|
102
104
|
const messageType = topic.substring(topic.lastIndexOf("/") + 1 ,topic.length);
|
|
103
|
-
|
|
105
|
+
this.adapter.log.debug(`the messagetype ${messageType} was determined`);
|
|
104
106
|
// generate startdirectory of device
|
|
105
|
-
const deviceStartdirectory = this.directoryhandler.getObjectDirectory(message,this.directoryhandler.searchableAttributeNames.deviceId);
|
|
107
|
+
const deviceStartdirectory = this.directoryhandler.getObjectDirectory(topic,message,this.directoryhandler.searchableAttributeNames.deviceId);
|
|
108
|
+
this.adapter.log.debug(`the startdirectory ${deviceStartdirectory} was determined`);
|
|
109
|
+
|
|
106
110
|
/*********************************************************************
|
|
107
111
|
* ************************ Main directories *************************
|
|
108
112
|
* ******************************************************************/
|
|
109
113
|
|
|
110
|
-
await this.directoryhandler.generateRekursivObjects(this.directoryhandler.directories,"",message);
|
|
111
114
|
/*********************************************************************
|
|
112
115
|
* ************************* Infodata ********************************
|
|
113
116
|
* ******************************************************************/
|
|
@@ -119,11 +122,16 @@ class messagehandlerClass {
|
|
|
119
122
|
// check for uplink message
|
|
120
123
|
if(messageType === "up"){//if(message.uplink_message){
|
|
121
124
|
|
|
125
|
+
// Generate new directories only with uplink
|
|
126
|
+
|
|
127
|
+
await this.directoryhandler.generateRekursivObjects(this.directoryhandler.directories,"",topic,message);
|
|
128
|
+
|
|
122
129
|
/*********************************************************************
|
|
123
130
|
* ************************ Rawdata json *****************************
|
|
124
131
|
* ******************************************************************/
|
|
125
132
|
|
|
126
133
|
if(this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.uplinkRaw]){
|
|
134
|
+
this.adapter.log.debug(`write rawdata`);
|
|
127
135
|
const startDirectory = this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.uplinkRaw];
|
|
128
136
|
// write json
|
|
129
137
|
await this.adapter.setObjectNotExistsAsync(`${startDirectory}.json`,{
|
|
@@ -146,6 +154,7 @@ class messagehandlerClass {
|
|
|
146
154
|
// check for frm payload
|
|
147
155
|
if(message.uplink_message.frm_payload){
|
|
148
156
|
// wite base64 data
|
|
157
|
+
this.adapter.log.debug(`write base64`);
|
|
149
158
|
await this.adapter.setObjectNotExistsAsync(`${startDirectory}.base64`,{
|
|
150
159
|
type: "state",
|
|
151
160
|
common: {
|
|
@@ -161,6 +170,7 @@ class messagehandlerClass {
|
|
|
161
170
|
await this.adapter.setStateAsync(`${startDirectory}.base64`,writedata,true);
|
|
162
171
|
|
|
163
172
|
// write base64 data in hex data
|
|
173
|
+
this.adapter.log.debug(`write hex`);
|
|
164
174
|
await this.adapter.setObjectNotExistsAsync(`${startDirectory}.hex`,{
|
|
165
175
|
type: "state",
|
|
166
176
|
common: {
|
|
@@ -176,6 +186,7 @@ class messagehandlerClass {
|
|
|
176
186
|
await this.adapter.setStateAsync(`${startDirectory}.hex`,hexdata,true);
|
|
177
187
|
|
|
178
188
|
// write base64 data in string data
|
|
189
|
+
this.adapter.log.debug(`write string`);
|
|
179
190
|
await this.adapter.setObjectNotExistsAsync(`${startDirectory}.string`,{
|
|
180
191
|
type: "state",
|
|
181
192
|
common: {
|
|
@@ -198,7 +209,8 @@ class messagehandlerClass {
|
|
|
198
209
|
|
|
199
210
|
if(this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.uplinkDecoded]){
|
|
200
211
|
const startDirectory = this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.uplinkDecoded];
|
|
201
|
-
|
|
212
|
+
this.adapter.log.debug(`write decoded payload`);
|
|
213
|
+
await this.directoryhandler.generateRekursivObjects(message.uplink_message.decoded_payload,startDirectory,topic,message);
|
|
202
214
|
}
|
|
203
215
|
|
|
204
216
|
/*********************************************************************
|
|
@@ -207,8 +219,9 @@ class messagehandlerClass {
|
|
|
207
219
|
|
|
208
220
|
if(this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.uplinkRemaining]){
|
|
209
221
|
const startDirectory = this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.uplinkRemaining];
|
|
222
|
+
this.adapter.log.debug(`write remaining uplink data`);
|
|
210
223
|
// @ts-ignore
|
|
211
|
-
await this.directoryhandler.generateRekursivObjects(message.uplink_message,startDirectory,message,{ignoredElementNames:{decoded_payload:{},frm_payload:{}}});
|
|
224
|
+
await this.directoryhandler.generateRekursivObjects(message.uplink_message,startDirectory,topic,message,{ignoredElementNames:{decoded_payload:{},frm_payload:{}}});
|
|
212
225
|
}
|
|
213
226
|
}
|
|
214
227
|
|
|
@@ -219,10 +232,7 @@ class messagehandlerClass {
|
|
|
219
232
|
// check for uplink message
|
|
220
233
|
else if(messageType === "queued" || messageType === "sent"){ //if(message.downlink_queued || message.downlink_sent)//if(message.downlink_queued || message.downlink_sent){
|
|
221
234
|
// Check wich downlink was recieved
|
|
222
|
-
|
|
223
|
-
if(message.downlink_sent){
|
|
224
|
-
downlinkType = "downlink_sent";
|
|
225
|
-
}
|
|
235
|
+
const downlinkType = `downlink_${messageType}`;
|
|
226
236
|
/*********************************************************************
|
|
227
237
|
* ************************ Rawdata json *****************************
|
|
228
238
|
* ******************************************************************/
|
|
@@ -230,6 +240,7 @@ class messagehandlerClass {
|
|
|
230
240
|
if(this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.downlinkRaw]){
|
|
231
241
|
const startDirectory = this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.downlinkRaw];
|
|
232
242
|
// write json
|
|
243
|
+
this.adapter.log.debug(`write rawdata`);
|
|
233
244
|
await this.adapter.setObjectNotExistsAsync(`${startDirectory}.json`,{
|
|
234
245
|
type: "state",
|
|
235
246
|
common: {
|
|
@@ -248,6 +259,7 @@ class messagehandlerClass {
|
|
|
248
259
|
* ******************************************************************/
|
|
249
260
|
|
|
250
261
|
// check for frm payload
|
|
262
|
+
this.adapter.log.debug(`write base64`);
|
|
251
263
|
if(message[downlinkType].frm_payload){
|
|
252
264
|
// wite base64 data
|
|
253
265
|
await this.adapter.setObjectNotExistsAsync(`${startDirectory}.base64`,{
|
|
@@ -265,6 +277,7 @@ class messagehandlerClass {
|
|
|
265
277
|
await this.adapter.setStateAsync(`${startDirectory}.base64`,writedata,true);
|
|
266
278
|
|
|
267
279
|
// write base64 data in hex data
|
|
280
|
+
this.adapter.log.debug(`write hex`);
|
|
268
281
|
await this.adapter.setObjectNotExistsAsync(`${startDirectory}.hex`,{
|
|
269
282
|
type: "state",
|
|
270
283
|
common: {
|
|
@@ -280,6 +293,7 @@ class messagehandlerClass {
|
|
|
280
293
|
await this.adapter.setStateAsync(`${startDirectory}.hex`,hexdata,true);
|
|
281
294
|
|
|
282
295
|
// write base64 data in string data
|
|
296
|
+
this.adapter.log.debug(`write string`);
|
|
283
297
|
await this.adapter.setObjectNotExistsAsync(`${startDirectory}.string`,{
|
|
284
298
|
type: "state",
|
|
285
299
|
common: {
|
|
@@ -302,20 +316,21 @@ class messagehandlerClass {
|
|
|
302
316
|
|
|
303
317
|
if(this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.downlinkRemaining]){
|
|
304
318
|
const startDirectory = this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.downlinkRemaining];
|
|
319
|
+
this.adapter.log.debug(`write remaining downlink data`);
|
|
305
320
|
// @ts-ignore
|
|
306
|
-
await this.directoryhandler.generateRekursivObjects(message[downlinkType],startDirectory,message,{ignoredElementNames:{frm_payload:{}}});
|
|
321
|
+
await this.directoryhandler.generateRekursivObjects(message[downlinkType],startDirectory,topic,message,{ignoredElementNames:{frm_payload:{}}});
|
|
307
322
|
}
|
|
308
323
|
}
|
|
309
324
|
|
|
310
325
|
/*********************************************************************
|
|
311
326
|
* ********************** downlinkConfigs ****************************
|
|
312
327
|
* ******************************************************************/
|
|
313
|
-
|
|
328
|
+
this.adapter.log.debug(`check configed downlinks`);
|
|
314
329
|
await this.fillWithDownlinkConfig(deviceStartdirectory);
|
|
315
330
|
}
|
|
316
331
|
catch(error){
|
|
317
|
-
this.adapter.log.warn("Message: " + JSON.stringify(message));
|
|
318
332
|
this.adapter.log.error(`error at ${activeFunction}: ` + error);
|
|
333
|
+
this.adapter.log.warn("Message: " + JSON.stringify(message));
|
|
319
334
|
}
|
|
320
335
|
}
|
|
321
336
|
|
|
@@ -337,14 +352,15 @@ class messagehandlerClass {
|
|
|
337
352
|
|
|
338
353
|
try{
|
|
339
354
|
const messageType = topic.substring(topic.lastIndexOf("/") + 1 ,topic.length);
|
|
340
|
-
|
|
355
|
+
this.adapter.log.debug(`the messagetype ${messageType} was determined`);
|
|
341
356
|
// generate startdirectory of device
|
|
342
|
-
const deviceStartdirectory = this.directoryhandler.getObjectDirectory(message,this.directoryhandler.searchableAttributeNames.deviceId);
|
|
357
|
+
const deviceStartdirectory = this.directoryhandler.getObjectDirectory(topic,message,this.directoryhandler.searchableAttributeNames.deviceId);
|
|
358
|
+
this.adapter.log.debug(`the startdirectory ${deviceStartdirectory} was determined`);
|
|
359
|
+
|
|
343
360
|
/*********************************************************************
|
|
344
361
|
* ************************ Main directories *************************
|
|
345
362
|
* ******************************************************************/
|
|
346
363
|
|
|
347
|
-
await this.directoryhandler.generateRekursivObjects(this.directoryhandler.directories,"",message);
|
|
348
364
|
/*********************************************************************
|
|
349
365
|
* ************************* Infodata ********************************
|
|
350
366
|
* ******************************************************************/
|
|
@@ -356,6 +372,9 @@ class messagehandlerClass {
|
|
|
356
372
|
// check for uplink message
|
|
357
373
|
if(messageType === "up"){//if(message.uplink_message){
|
|
358
374
|
|
|
375
|
+
// generate new directories only with uplink
|
|
376
|
+
await this.directoryhandler.generateRekursivObjects(this.directoryhandler.directories,"",topic,message);
|
|
377
|
+
|
|
359
378
|
/*********************************************************************
|
|
360
379
|
* ************************ Rawdata json *****************************
|
|
361
380
|
* ******************************************************************/
|
|
@@ -363,6 +382,7 @@ class messagehandlerClass {
|
|
|
363
382
|
if(this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.uplinkRaw]){
|
|
364
383
|
const startDirectory = this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.uplinkRaw];
|
|
365
384
|
// write json
|
|
385
|
+
this.adapter.log.debug(`write rawdata`);
|
|
366
386
|
await this.adapter.setObjectNotExistsAsync(`${startDirectory}.json`,{
|
|
367
387
|
type: "state",
|
|
368
388
|
common: {
|
|
@@ -383,6 +403,7 @@ class messagehandlerClass {
|
|
|
383
403
|
// check for data
|
|
384
404
|
if(message.data){
|
|
385
405
|
// wite base64 data
|
|
406
|
+
this.adapter.log.debug(`write base64`);
|
|
386
407
|
await this.adapter.setObjectNotExistsAsync(`${startDirectory}.base64`,{
|
|
387
408
|
type: "state",
|
|
388
409
|
common: {
|
|
@@ -398,6 +419,7 @@ class messagehandlerClass {
|
|
|
398
419
|
await this.adapter.setStateAsync(`${startDirectory}.base64`,writedata,true);
|
|
399
420
|
|
|
400
421
|
// write base64 data in hex data
|
|
422
|
+
this.adapter.log.debug(`write hex`);
|
|
401
423
|
await this.adapter.setObjectNotExistsAsync(`${startDirectory}.hex`,{
|
|
402
424
|
type: "state",
|
|
403
425
|
common: {
|
|
@@ -413,6 +435,7 @@ class messagehandlerClass {
|
|
|
413
435
|
await this.adapter.setStateAsync(`${startDirectory}.hex`,hexdata,true);
|
|
414
436
|
|
|
415
437
|
// write base64 data in string data
|
|
438
|
+
this.adapter.log.debug(`write string`);
|
|
416
439
|
await this.adapter.setObjectNotExistsAsync(`${startDirectory}.string`,{
|
|
417
440
|
type: "state",
|
|
418
441
|
common: {
|
|
@@ -430,12 +453,13 @@ class messagehandlerClass {
|
|
|
430
453
|
}
|
|
431
454
|
|
|
432
455
|
/*********************************************************************
|
|
433
|
-
*
|
|
456
|
+
* ****************** decoded payload (Object) ***********************
|
|
434
457
|
* ******************************************************************/
|
|
435
458
|
|
|
436
459
|
if(this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.uplinkDecoded]){
|
|
437
460
|
const startDirectory = this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.uplinkDecoded];
|
|
438
|
-
|
|
461
|
+
this.adapter.log.debug(`write decoded payload (Object)`);
|
|
462
|
+
await this.directoryhandler.generateRekursivObjects(message.object,startDirectory,topic,message);
|
|
439
463
|
}
|
|
440
464
|
|
|
441
465
|
/*********************************************************************
|
|
@@ -444,8 +468,9 @@ class messagehandlerClass {
|
|
|
444
468
|
|
|
445
469
|
if(this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.uplinkRemaining]){
|
|
446
470
|
const startDirectory = this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.uplinkRemaining];
|
|
471
|
+
this.adapter.log.debug(`write remaining uplink data`);
|
|
447
472
|
// @ts-ignore
|
|
448
|
-
await this.directoryhandler.generateRekursivObjects(message,startDirectory,message,{ignoredElementNames:{deduplicationId:{},deviceInfo:{},data:{},object:{}}});
|
|
473
|
+
await this.directoryhandler.generateRekursivObjects(message,startDirectory,topic,message,{ignoredElementNames:{deduplicationId:{},deviceInfo:{},data:{},object:{}}});
|
|
449
474
|
}
|
|
450
475
|
}
|
|
451
476
|
|
|
@@ -454,12 +479,8 @@ class messagehandlerClass {
|
|
|
454
479
|
* ******************************************************************/
|
|
455
480
|
|
|
456
481
|
// check for uplink message
|
|
457
|
-
else if(messageType === "
|
|
458
|
-
|
|
459
|
-
let downlinkType = "downlink_queued";
|
|
460
|
-
if(message.downlink_sent){
|
|
461
|
-
downlinkType = "downlink_sent";
|
|
462
|
-
}
|
|
482
|
+
else if(messageType === "down"){ //if(message.downlink_queued || message.downlink_sent)//if(message.downlink_queued || message.downlink_sent){
|
|
483
|
+
|
|
463
484
|
/*********************************************************************
|
|
464
485
|
* ************************ Rawdata json *****************************
|
|
465
486
|
* ******************************************************************/
|
|
@@ -467,6 +488,7 @@ class messagehandlerClass {
|
|
|
467
488
|
if(this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.downlinkRaw]){
|
|
468
489
|
const startDirectory = this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.downlinkRaw];
|
|
469
490
|
// write json
|
|
491
|
+
this.adapter.log.debug(`write rawdata`);
|
|
470
492
|
await this.adapter.setObjectNotExistsAsync(`${startDirectory}.json`,{
|
|
471
493
|
type: "state",
|
|
472
494
|
common: {
|
|
@@ -480,21 +502,14 @@ class messagehandlerClass {
|
|
|
480
502
|
});
|
|
481
503
|
await this.adapter.setStateAsync(`${startDirectory}.json`,JSON.stringify(message),true);
|
|
482
504
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
// Ab hier muss mal geschautr werden, was kommt
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
505
|
/*********************************************************************
|
|
492
506
|
* ********************** Rawdata (Base64) ***************************
|
|
493
507
|
* ******************************************************************/
|
|
494
508
|
|
|
495
|
-
// check for
|
|
496
|
-
if(message
|
|
509
|
+
// check for data
|
|
510
|
+
if(message.data){
|
|
497
511
|
// wite base64 data
|
|
512
|
+
this.adapter.log.debug(`write base64`);
|
|
498
513
|
await this.adapter.setObjectNotExistsAsync(`${startDirectory}.base64`,{
|
|
499
514
|
type: "state",
|
|
500
515
|
common: {
|
|
@@ -506,10 +521,11 @@ class messagehandlerClass {
|
|
|
506
521
|
},
|
|
507
522
|
native: {},
|
|
508
523
|
});
|
|
509
|
-
const writedata = message
|
|
524
|
+
const writedata = message.data;
|
|
510
525
|
await this.adapter.setStateAsync(`${startDirectory}.base64`,writedata,true);
|
|
511
526
|
|
|
512
527
|
// write base64 data in hex data
|
|
528
|
+
this.adapter.log.debug(`write hex`);
|
|
513
529
|
await this.adapter.setObjectNotExistsAsync(`${startDirectory}.hex`,{
|
|
514
530
|
type: "state",
|
|
515
531
|
common: {
|
|
@@ -521,10 +537,11 @@ class messagehandlerClass {
|
|
|
521
537
|
},
|
|
522
538
|
native: {},
|
|
523
539
|
});
|
|
524
|
-
const hexdata = Buffer.from(message
|
|
540
|
+
const hexdata = Buffer.from(message.data,"base64").toString("hex").toUpperCase();
|
|
525
541
|
await this.adapter.setStateAsync(`${startDirectory}.hex`,hexdata,true);
|
|
526
542
|
|
|
527
543
|
// write base64 data in string data
|
|
544
|
+
this.adapter.log.debug(`write string`);
|
|
528
545
|
await this.adapter.setObjectNotExistsAsync(`${startDirectory}.string`,{
|
|
529
546
|
type: "state",
|
|
530
547
|
common: {
|
|
@@ -536,7 +553,7 @@ class messagehandlerClass {
|
|
|
536
553
|
},
|
|
537
554
|
native: {},
|
|
538
555
|
});
|
|
539
|
-
const stringdata = Buffer.from(message
|
|
556
|
+
const stringdata = Buffer.from(message.data,"base64").toString();
|
|
540
557
|
await this.adapter.setStateAsync(`${startDirectory}.string`,stringdata,true);
|
|
541
558
|
}
|
|
542
559
|
}
|
|
@@ -545,22 +562,17 @@ class messagehandlerClass {
|
|
|
545
562
|
* ************************* remaining *******************************
|
|
546
563
|
* ******************************************************************/
|
|
547
564
|
|
|
548
|
-
if(this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.downlinkRemaining]){
|
|
549
|
-
const startDirectory = this.directoryhandler.reachableDirectories[deviceStartdirectory][this.directoryhandler.safeableDirectories.downlinkRemaining];
|
|
550
|
-
// @ts-ignore
|
|
551
|
-
await this.directoryhandler.generateRekursivObjects(message[downlinkType],startDirectory,message,{ignoredElementNames:{frm_payload:{}}});
|
|
552
|
-
}
|
|
553
565
|
}
|
|
554
566
|
|
|
555
567
|
/*********************************************************************
|
|
556
568
|
* ********************** downlinkConfigs ****************************
|
|
557
569
|
* ******************************************************************/
|
|
558
|
-
|
|
570
|
+
this.adapter.log.debug(`check configed downlinks`);
|
|
559
571
|
await this.fillWithDownlinkConfig(deviceStartdirectory);
|
|
560
572
|
}
|
|
561
573
|
catch(error){
|
|
562
|
-
this.adapter.log.warn("Message: " + JSON.stringify(message));
|
|
563
574
|
this.adapter.log.error(`error at ${activeFunction}: ` + error);
|
|
575
|
+
this.adapter.log.warn("Message: " + JSON.stringify(message));
|
|
564
576
|
}
|
|
565
577
|
}
|
|
566
578
|
|
|
@@ -13,7 +13,8 @@ class mqttClientClass {
|
|
|
13
13
|
this.client.on("connect", () => {
|
|
14
14
|
this.adapter.log.info(`Connection is active.`);
|
|
15
15
|
this.adapter.setState("info.connection", true, true);
|
|
16
|
-
|
|
16
|
+
// @ts-ignore
|
|
17
|
+
this.client.subscribe(this.getSubscribtionArray(), (err) => {
|
|
17
18
|
if (err) {
|
|
18
19
|
this.adapter.log.error(`On subscribe: ${err}`);
|
|
19
20
|
}
|
|
@@ -21,7 +22,7 @@ class mqttClientClass {
|
|
|
21
22
|
});
|
|
22
23
|
this.client.on("disconnect", () => {
|
|
23
24
|
this.adapter.setState("info.connection", false, true);
|
|
24
|
-
this.adapter.log.
|
|
25
|
+
this.adapter.log.info(`disconnected`);
|
|
25
26
|
});
|
|
26
27
|
this.client.on("error", (err) => {
|
|
27
28
|
this.adapter.log.error(`${err}`);
|
|
@@ -33,6 +34,8 @@ class mqttClientClass {
|
|
|
33
34
|
});
|
|
34
35
|
|
|
35
36
|
this.client.on("message", async (topic, message) => {
|
|
37
|
+
this.adapter.log.debug(`incomming topic: ${topic}`);
|
|
38
|
+
this.adapter.log.debug(`incomming message: ${message}`);
|
|
36
39
|
// @ts-ignore
|
|
37
40
|
message = JSON.parse(message);
|
|
38
41
|
|
|
@@ -47,6 +50,15 @@ class mqttClientClass {
|
|
|
47
50
|
destroy(){
|
|
48
51
|
this.client.end();
|
|
49
52
|
}
|
|
53
|
+
|
|
54
|
+
getSubscribtionArray(){
|
|
55
|
+
switch(this.adapter.config.origin){
|
|
56
|
+
case "ttn":
|
|
57
|
+
return ["v3/+/devices/+/up","v3/+/devices/+/down/#"];
|
|
58
|
+
case "chirpstack":
|
|
59
|
+
return ["application/+/device/+/event/up","application/+/device/+/command/down"];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
50
62
|
}
|
|
51
63
|
|
|
52
64
|
module.exports = mqttClientClass;
|
package/main.js
CHANGED
|
@@ -33,37 +33,6 @@ class Lorawan extends utils.Adapter {
|
|
|
33
33
|
async onReady() {
|
|
34
34
|
const activeFunction = "onReady";
|
|
35
35
|
try{
|
|
36
|
-
/*
|
|
37
|
-
Definitionen der Umrechnungen:
|
|
38
|
-
dec to hex:
|
|
39
|
-
const decdata = 33;
|
|
40
|
-
const decdatastring = decdata.toString(16);
|
|
41
|
-
|
|
42
|
-
base64 to hex:
|
|
43
|
-
return(Buffer.from(base_64, 'base64').toString("hex"));
|
|
44
|
-
|
|
45
|
-
ascii to hex:
|
|
46
|
-
return (Buffer.from(ascii).toString('hex'));
|
|
47
|
-
|
|
48
|
-
ascii to base64:
|
|
49
|
-
return (Buffer.from(ascii).toString('base64'));
|
|
50
|
-
|
|
51
|
-
base64 to string:
|
|
52
|
-
return(Buffer.from(base_64, 'base64').toString());
|
|
53
|
-
|
|
54
|
-
hex 2 base64:
|
|
55
|
-
return Buffer.from(hex, 'hex').toString('base64')
|
|
56
|
-
|
|
57
|
-
hex 2 number:
|
|
58
|
-
parseInt(hexdata,16);
|
|
59
|
-
|
|
60
|
-
return Math.abs(dec).toString(16);
|
|
61
|
-
// force 4 Digits
|
|
62
|
-
//return ('0000' + dec.toString(16).toUpperCase()).slice(-4);
|
|
63
|
-
// force 2 Digits
|
|
64
|
-
// return ('00' + dec.toString(16).toUpperCase()).slice(-2);
|
|
65
|
-
|
|
66
|
-
*/
|
|
67
36
|
// create downlinkConfigs
|
|
68
37
|
this.downlinkConfighandler = new downlinkConfighandlerClass(this);
|
|
69
38
|
|
|
@@ -82,81 +51,7 @@ class Lorawan extends utils.Adapter {
|
|
|
82
51
|
//Subscribe all configuration and control states
|
|
83
52
|
this.subscribeStatesAsync("*.configuration.*");
|
|
84
53
|
this.subscribeStatesAsync("*downlink.control.*");
|
|
85
|
-
|
|
86
|
-
this.fakeMessage = {
|
|
87
|
-
"deduplicationId":"655e5d71-a625-4332-833c-2700fcacefc2",
|
|
88
|
-
"time":"2024-01-17T21:08:41.551292+00:00",
|
|
89
|
-
"deviceInfo":{
|
|
90
|
-
"tenantId":"52f14cd4-c6f1-4fbd-8f87-4025e1d49242",
|
|
91
|
-
"tenantName":"ChirpStack",
|
|
92
|
-
"applicationId":"59bcc5a7-59e2-4481-9615-fc4e58791915",
|
|
93
|
-
"applicationName":"Mclimate_Vicki",
|
|
94
|
-
"deviceProfileId":"3a9bc28f-3664-4bdf-b3be-a20d1eb32dc8",
|
|
95
|
-
"deviceProfileName":"Mclimate_Vicki",
|
|
96
|
-
"deviceName":"MClimate_Vicki_Heizkoerperventil_001",
|
|
97
|
-
"devEui":"70b3d52dd300ed31",
|
|
98
|
-
"deviceClassEnabled":"CLASS_A",
|
|
99
|
-
"tags":{
|
|
100
|
-
}
|
|
101
|
-
},
|
|
102
|
-
"devAddr":"01343968",
|
|
103
|
-
"adr":true,
|
|
104
|
-
"dr":5,
|
|
105
|
-
"fCnt":8702,
|
|
106
|
-
"fPort":2,
|
|
107
|
-
"confirmed":false,
|
|
108
|
-
"data":"GAGBDItw9vYR0DA=",
|
|
109
|
-
"object":{
|
|
110
|
-
"attachedBackplate":true,
|
|
111
|
-
"batteryVoltage":3.3,
|
|
112
|
-
"relativeHumidity":43.75,
|
|
113
|
-
"childLock":false,
|
|
114
|
-
"brokenSensor":false,
|
|
115
|
-
"calibrationFailed":false,
|
|
116
|
-
"sensorTemperature":19.53,
|
|
117
|
-
"motorPosition":502.0,
|
|
118
|
-
"highMotorConsumption":false,
|
|
119
|
-
"reason":81.0,
|
|
120
|
-
"perceiveAsOnline":true,
|
|
121
|
-
"targetTemperature":12.0,
|
|
122
|
-
"lowMotorConsumption":false,
|
|
123
|
-
"operationalMode":1.0,
|
|
124
|
-
"openWindow":false,
|
|
125
|
-
"motorRange":502.0
|
|
126
|
-
},
|
|
127
|
-
"rxInfo":[
|
|
128
|
-
{
|
|
129
|
-
"gatewayId":"50313953530a4750",
|
|
130
|
-
"uplinkId":56321,
|
|
131
|
-
"gwTime":"2024-01-17T21:08:41.551292+00:00",
|
|
132
|
-
"nsTime":"2024-01-17T21:08:41.570017809+00:00",
|
|
133
|
-
"rssi":-74,
|
|
134
|
-
"snr":11.0,
|
|
135
|
-
"channel":4,
|
|
136
|
-
"location":{
|
|
137
|
-
"latitude":53.55485739669679,
|
|
138
|
-
"longitude":9.921609163284304
|
|
139
|
-
},
|
|
140
|
-
"context":"albPhA==",
|
|
141
|
-
"metadata":{
|
|
142
|
-
"region_config_id":"eu868",
|
|
143
|
-
"region_common_name":"EU868"
|
|
144
|
-
},
|
|
145
|
-
"crcStatus":"CRC_OK"
|
|
146
|
-
}
|
|
147
|
-
],
|
|
148
|
-
"txInfo":{
|
|
149
|
-
"frequency":867300000,
|
|
150
|
-
"modulation":{
|
|
151
|
-
"lora":{
|
|
152
|
-
"bandwidth":125000,
|
|
153
|
-
"spreadingFactor":7,
|
|
154
|
-
"codeRate":"CR_4_5"
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
//await this.messagehandler.handleMessage("a/up", this.fakeMessage);
|
|
54
|
+
this.log.debug(`the adapter start with the config: ${JSON.stringify(this.config)}.`);
|
|
160
55
|
}
|
|
161
56
|
catch(error){
|
|
162
57
|
this.log.error(`error at ${activeFunction}: ` + error.stack);
|
|
@@ -207,8 +102,8 @@ class Lorawan extends utils.Adapter {
|
|
|
207
102
|
if(!state.ack){
|
|
208
103
|
// Check for downlink in id
|
|
209
104
|
if(id.indexOf("downlink") !== -1){
|
|
105
|
+
this.log.debug(`the state ${id} has changed to ${state.val}.`);
|
|
210
106
|
// get information of the changing state
|
|
211
|
-
// @ts-ignore
|
|
212
107
|
const changeInfo = await this.getChangeInfo(id);
|
|
213
108
|
if(this.config.origin === "ttn"){
|
|
214
109
|
let appending = "push";
|
|
@@ -276,6 +171,7 @@ class Lorawan extends utils.Adapter {
|
|
|
276
171
|
async getChangeInfo(id){
|
|
277
172
|
const activeFunction = "getChangeInfo";
|
|
278
173
|
try{
|
|
174
|
+
this.log.debug(`changeinfo of id ${id}, will be generated.`);
|
|
279
175
|
id = this.removeNamespace(id);
|
|
280
176
|
const idElements = id.split(".");
|
|
281
177
|
const changeInfo = {
|
|
@@ -292,6 +188,7 @@ class Lorawan extends utils.Adapter {
|
|
|
292
188
|
// @ts-ignore
|
|
293
189
|
changeInfo.deviceType = deviceTypeIdState.val;
|
|
294
190
|
}
|
|
191
|
+
this.log.debug(`changeinfo is ${JSON.stringify(changeInfo)}.`);
|
|
295
192
|
return changeInfo;
|
|
296
193
|
}
|
|
297
194
|
catch(error){
|
|
@@ -301,6 +198,7 @@ class Lorawan extends utils.Adapter {
|
|
|
301
198
|
|
|
302
199
|
removeNamespace(id){
|
|
303
200
|
if(id.indexOf(this.namespace) !== -1){
|
|
201
|
+
this.log.debug(`namespace will be removed from id ${id}.`);
|
|
304
202
|
id = id.substring(this.namespace.length + 1,id.length);
|
|
305
203
|
}
|
|
306
204
|
return id;
|