mqtt-devices-parser 1.0.12 → 1.0.13
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/Changelog.md +8 -1
- package/models/devices.models.js +21 -0
- package/models/logs_actions.models.js +17 -0
- package/models/logs_device.models.js +62 -0
- package/package.json +1 -1
- package/src/db/data.js +2 -2
- package/src/db/device.js +195 -0
- package/src/device/device.js +156 -51
package/Changelog.md
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.13
|
|
4
|
+
adds 2 new tables to db:
|
|
5
|
+
Adds 5 new columns to devices
|
|
6
|
+
Registers device logs, records device settings..
|
|
7
|
+
fixes: ws affected by a DoS when handling a request with many HTTP headers !breaking change
|
|
8
|
+
Updates npm
|
|
9
|
+
|
|
3
10
|
## 1.0.12
|
|
4
|
-
Adds
|
|
11
|
+
Adds module fota
|
|
5
12
|
|
|
6
13
|
## 1.0.11
|
|
7
14
|
index: MQTT
|
package/models/devices.models.js
CHANGED
|
@@ -43,6 +43,27 @@ module.exports = (sequelize,DataTypes)=>{
|
|
|
43
43
|
type: DataTypes.STRING,
|
|
44
44
|
allowNull: true
|
|
45
45
|
},
|
|
46
|
+
remote_settings: { // device settings
|
|
47
|
+
type: DataTypes.JSON,
|
|
48
|
+
allowNull: true
|
|
49
|
+
},
|
|
50
|
+
local_settings: { // server settings
|
|
51
|
+
type: DataTypes.JSON,
|
|
52
|
+
allowNull: true
|
|
53
|
+
},
|
|
54
|
+
settings_ref: { // settings to be used, can be a uid, deviceId, default..
|
|
55
|
+
type: DataTypes.STRING,
|
|
56
|
+
allowNull: true
|
|
57
|
+
},
|
|
58
|
+
associatedDevice: {
|
|
59
|
+
type: DataTypes.INTEGER,
|
|
60
|
+
allowNull: true
|
|
61
|
+
},
|
|
62
|
+
endpoint: { // info about protocol communication
|
|
63
|
+
type: DataTypes.JSON,
|
|
64
|
+
allowNull: true
|
|
65
|
+
},
|
|
66
|
+
|
|
46
67
|
},
|
|
47
68
|
{
|
|
48
69
|
tableName: 'devices',
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
module.exports = (sequelize,DataTypes)=>{
|
|
3
|
+
return sequelize.define("logs_actions", {
|
|
4
|
+
client_id: {
|
|
5
|
+
type: DataTypes.INTEGER,
|
|
6
|
+
allowNull: false
|
|
7
|
+
},
|
|
8
|
+
action: {
|
|
9
|
+
type: DataTypes.STRING,
|
|
10
|
+
allowNull: true
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
tableName: 'logs_actions',
|
|
15
|
+
freezeTableName: true
|
|
16
|
+
})
|
|
17
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
|
|
2
|
+
module.exports = (sequelize,DataTypes)=>{
|
|
3
|
+
return sequelize.define("logs_devices", {
|
|
4
|
+
device_id: {
|
|
5
|
+
type: DataTypes.INTEGER,
|
|
6
|
+
},
|
|
7
|
+
status: {
|
|
8
|
+
type: DataTypes.STRING,
|
|
9
|
+
allowNull: true
|
|
10
|
+
},
|
|
11
|
+
project_id: {
|
|
12
|
+
type: DataTypes.INTEGER,
|
|
13
|
+
references: {
|
|
14
|
+
model: 'projects',
|
|
15
|
+
key: 'id'
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
model_id: {
|
|
19
|
+
type: DataTypes.INTEGER,
|
|
20
|
+
references: {
|
|
21
|
+
model: 'models',
|
|
22
|
+
key: 'id'
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
version: {
|
|
26
|
+
type: DataTypes.STRING,
|
|
27
|
+
allowNull: true
|
|
28
|
+
},
|
|
29
|
+
app_version: {
|
|
30
|
+
type: DataTypes.STRING,
|
|
31
|
+
allowNull: true
|
|
32
|
+
},
|
|
33
|
+
tech: {
|
|
34
|
+
type: DataTypes.STRING,
|
|
35
|
+
allowNull: true
|
|
36
|
+
},
|
|
37
|
+
associatedDevice: {
|
|
38
|
+
type: DataTypes.INTEGER,
|
|
39
|
+
allowNull: true
|
|
40
|
+
},
|
|
41
|
+
local_settings: { // server settings
|
|
42
|
+
type: DataTypes.JSON,
|
|
43
|
+
allowNull: true
|
|
44
|
+
},
|
|
45
|
+
remote_settings: { // server settings
|
|
46
|
+
type: DataTypes.JSON,
|
|
47
|
+
allowNull: true
|
|
48
|
+
},
|
|
49
|
+
settings_ref: { // settings to be used, can be a uid, deviceId, default..
|
|
50
|
+
type: DataTypes.STRING,
|
|
51
|
+
allowNull: true
|
|
52
|
+
},
|
|
53
|
+
endpoint: { // info about protocol communication
|
|
54
|
+
type: DataTypes.JSON,
|
|
55
|
+
allowNull: true
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
tableName: 'logs_devices',
|
|
60
|
+
freezeTableName: true
|
|
61
|
+
})
|
|
62
|
+
}
|
package/package.json
CHANGED
package/src/db/data.js
CHANGED
|
@@ -278,7 +278,7 @@ var self = module.exports = {
|
|
|
278
278
|
addJsonLog: async (table, deviceId, dataObject) => {
|
|
279
279
|
return new Promise((resolve, reject) => {
|
|
280
280
|
if (!dataObject || typeof dataObject !== 'object')
|
|
281
|
-
return
|
|
281
|
+
return reject("Not an object");
|
|
282
282
|
|
|
283
283
|
let obj = {
|
|
284
284
|
updatedAt: moment().utc().format('YYYY-MM-DD HH:mm:ss'),
|
|
@@ -289,7 +289,7 @@ var self = module.exports = {
|
|
|
289
289
|
// Get columns info
|
|
290
290
|
const db_columns = $.models.get(table);
|
|
291
291
|
if (db_columns == null)
|
|
292
|
-
return
|
|
292
|
+
return reject(`No columns for table: ${table}`);
|
|
293
293
|
|
|
294
294
|
// Prepare data for insertion
|
|
295
295
|
for (let key in dataObject) {
|
package/src/db/device.js
CHANGED
|
@@ -194,4 +194,199 @@ var self = module.exports = {
|
|
|
194
194
|
});
|
|
195
195
|
},
|
|
196
196
|
|
|
197
|
+
|
|
198
|
+
addLog : async(id,column,value)=>{
|
|
199
|
+
return new Promise((resolve,reject) => {
|
|
200
|
+
|
|
201
|
+
const timestamp = moment().utc().format('YYYY-MM-DD HH:mm:ss')
|
|
202
|
+
let obj = {
|
|
203
|
+
createdAt : timestamp,
|
|
204
|
+
updatedAt : timestamp
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
obj['device_id'] = id;
|
|
208
|
+
obj[column] = value;
|
|
209
|
+
|
|
210
|
+
$.db.insert("logs_devices",obj)
|
|
211
|
+
.then (rows => {
|
|
212
|
+
return resolve(rows);
|
|
213
|
+
})
|
|
214
|
+
.catch(error => {
|
|
215
|
+
return reject(error);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
addLogIfChanged : async(id,column,value)=>{
|
|
221
|
+
return new Promise(async (resolve,reject) => {
|
|
222
|
+
|
|
223
|
+
let query = "SELECT ?? FROM ?? where id = ? and ?? is NOT NULL ORDER BY updatedAt DESC LIMIT 1";
|
|
224
|
+
let table = [column,"logs_devices",id,column];
|
|
225
|
+
query = mysql.format(query,table);
|
|
226
|
+
|
|
227
|
+
try{
|
|
228
|
+
let rows = await $.db.queryRow(query)
|
|
229
|
+
|
|
230
|
+
if(rows.length > 0){
|
|
231
|
+
let lastValue = rows[0]?.column
|
|
232
|
+
if(lastValue == value)
|
|
233
|
+
resolve();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const timestamp = moment().utc().format('YYYY-MM-DD HH:mm:ss')
|
|
237
|
+
let obj = {
|
|
238
|
+
createdAt : timestamp,
|
|
239
|
+
updatedAt : timestamp
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
obj['device_id'] = id;
|
|
243
|
+
obj[column] = value;
|
|
244
|
+
|
|
245
|
+
await $.db.insert("logs_devices",obj)
|
|
246
|
+
|
|
247
|
+
resolve();
|
|
248
|
+
|
|
249
|
+
}catch (err) {
|
|
250
|
+
return reject(err);
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
});
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
getLocalSettings : async(deviceId)=>{
|
|
257
|
+
|
|
258
|
+
return new Promise((resolve,reject) => {
|
|
259
|
+
|
|
260
|
+
let query = "SELECT local_settings FROM ?? where id = ?";
|
|
261
|
+
let table = ["devices", deviceId];
|
|
262
|
+
query = mysql.format(query,table);
|
|
263
|
+
|
|
264
|
+
$.db.queryRow(query)
|
|
265
|
+
.then( rows => {
|
|
266
|
+
if(rows?.length > 0)
|
|
267
|
+
return resolve(rows[0]?.local_settings);
|
|
268
|
+
else
|
|
269
|
+
return resolve(null);
|
|
270
|
+
})
|
|
271
|
+
.catch( err => {
|
|
272
|
+
return reject(err);
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
},
|
|
276
|
+
|
|
277
|
+
updateLocalSettings : async(settings, deviceId)=>{
|
|
278
|
+
|
|
279
|
+
return new Promise((resolve,reject) => {
|
|
280
|
+
let obj = {
|
|
281
|
+
local_settings : settings,
|
|
282
|
+
updatedAt : moment().utc().format('YYYY-MM-DD HH:mm:ss')
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
let filter = {
|
|
286
|
+
id : deviceId
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
resolve(null)
|
|
290
|
+
|
|
291
|
+
$.db.update("devices",obj,filter)
|
|
292
|
+
.then (rows => {
|
|
293
|
+
return resolve(rows[0]);
|
|
294
|
+
})
|
|
295
|
+
.catch(error => {
|
|
296
|
+
return reject(error);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
});
|
|
300
|
+
},
|
|
301
|
+
|
|
302
|
+
getRemoteSettings : async(deviceId)=>{
|
|
303
|
+
|
|
304
|
+
return new Promise((resolve,reject) => {
|
|
305
|
+
|
|
306
|
+
let query = "SELECT remote_settings FROM ?? where id = ?";
|
|
307
|
+
let table = ["devices", deviceId];
|
|
308
|
+
query = mysql.format(query,table);
|
|
309
|
+
|
|
310
|
+
$.db.queryRow(query)
|
|
311
|
+
.then( rows => {
|
|
312
|
+
if(rows?.length > 0)
|
|
313
|
+
return resolve(rows[0]?.remote_settings);
|
|
314
|
+
else
|
|
315
|
+
return resolve(null);
|
|
316
|
+
})
|
|
317
|
+
.catch( err => {
|
|
318
|
+
return reject(err);
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
},
|
|
322
|
+
|
|
323
|
+
updateRemoteSettings : async(settings, deviceId)=>{
|
|
324
|
+
|
|
325
|
+
return new Promise((resolve,reject) => {
|
|
326
|
+
let obj = {
|
|
327
|
+
remote_settings : settings,
|
|
328
|
+
updatedAt : moment().utc().format('YYYY-MM-DD HH:mm:ss')
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
let filter = {
|
|
332
|
+
id : deviceId
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
resolve(null)
|
|
336
|
+
|
|
337
|
+
$.db.update("devices",obj,filter)
|
|
338
|
+
.then (rows => {
|
|
339
|
+
return resolve(rows[0]);
|
|
340
|
+
})
|
|
341
|
+
.catch(error => {
|
|
342
|
+
return reject(error);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
});
|
|
346
|
+
},
|
|
347
|
+
|
|
348
|
+
getAssociatedDevice : async (deviceId)=>{
|
|
349
|
+
|
|
350
|
+
return new Promise((resolve,reject) => {
|
|
351
|
+
|
|
352
|
+
let query = "SELECT associatedDevice FROM ?? where id = ?";
|
|
353
|
+
let args = ["devices",deviceId];
|
|
354
|
+
query = mysql.format(query,args);
|
|
355
|
+
|
|
356
|
+
$.db.queryRow(query)
|
|
357
|
+
.then( rows => {
|
|
358
|
+
if(rows.length > 0)
|
|
359
|
+
return resolve(rows[0]?.associatedDevice);
|
|
360
|
+
else
|
|
361
|
+
return resolve(null);
|
|
362
|
+
})
|
|
363
|
+
.catch( err => {
|
|
364
|
+
return reject(err);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
});
|
|
368
|
+
},
|
|
369
|
+
|
|
370
|
+
updateAssociatedDevice : async(deviceId,associatedDeviceId)=>{
|
|
371
|
+
return new Promise((resolve,reject) => {
|
|
372
|
+
let obj = {
|
|
373
|
+
associatedDevice : associatedDeviceId,
|
|
374
|
+
updatedAt : moment().utc().format('YYYY-MM-DD HH:mm:ss')
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
let filter = {
|
|
378
|
+
id : deviceId
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
$.db.update("devices",obj,filter)
|
|
382
|
+
.then (rows => {
|
|
383
|
+
return resolve(rows[0]);
|
|
384
|
+
})
|
|
385
|
+
.catch(error => {
|
|
386
|
+
return reject(error);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
|
|
197
392
|
}
|
package/src/device/device.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const moment = require('moment');
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _project = [];
|
|
4
4
|
const logs_table = "sensor_logs";
|
|
5
5
|
const semver = require('semver');
|
|
6
6
|
|
|
@@ -14,11 +14,11 @@ var self = module.exports = {
|
|
|
14
14
|
|
|
15
15
|
projects.map( async (name,counter)=>{
|
|
16
16
|
console.log("project:",name)
|
|
17
|
-
|
|
17
|
+
_project[name] = {
|
|
18
18
|
module : null
|
|
19
19
|
};
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
_project[name].module = require(`${BASE_DIR}/projects/${name}/${name}.js`)
|
|
21
|
+
_project[name].module?.init();
|
|
22
22
|
let row = await $.db_project.getByName(name);
|
|
23
23
|
if(row == null)
|
|
24
24
|
$.db_project.insert(name,name,"logs_"+name);
|
|
@@ -78,33 +78,42 @@ var self = module.exports = {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
// update project id if needed
|
|
81
|
-
if(project_id != null && project_id != device?.project_id)
|
|
81
|
+
if(project_id != null && project_id != device?.project_id){
|
|
82
82
|
$.db_device.update(device.id,"project_id",project_id);
|
|
83
|
+
$.db_device.addLog(device.id,"project_id",project_id);
|
|
84
|
+
}
|
|
83
85
|
|
|
84
86
|
switch (topic) {
|
|
85
87
|
case "status":
|
|
86
88
|
if (payload === "online" || payload === "offline") {
|
|
87
89
|
await $.db_device.update(device.id, "status", payload);
|
|
90
|
+
$.db_device.addLog(device.id,"status",payload);
|
|
88
91
|
}
|
|
89
92
|
break;
|
|
90
93
|
case "model":
|
|
91
94
|
let res = await $.db_model.getByName(payload);
|
|
92
95
|
let model_id = res?.id;
|
|
93
|
-
if (model_id != null) {
|
|
96
|
+
if (model_id != null && device?.tech != payload) {
|
|
94
97
|
await $.db_device.update(device.id, "model_id", model_id);
|
|
98
|
+
$.db_device.addLog(device.id,"model_id",model_id);
|
|
95
99
|
}
|
|
96
100
|
break;
|
|
97
101
|
case "tech":
|
|
98
|
-
|
|
102
|
+
if (device?.tech && payload != device.tech) {
|
|
103
|
+
await $.db_device.update(device.id, "tech", payload);
|
|
104
|
+
$.db_device.addLog(device.id,"tech",payload);
|
|
105
|
+
}
|
|
99
106
|
break;
|
|
100
107
|
case "version":
|
|
101
108
|
if (device?.version && payload != device.version) {
|
|
109
|
+
$.db_device.addLog(device.id,"version",payload);
|
|
102
110
|
await $.db_device.update(device.id, "version", payload);
|
|
103
111
|
await self.handleFotaSuccess(device.id);
|
|
104
112
|
}
|
|
105
113
|
break;
|
|
106
114
|
case "app_version":
|
|
107
115
|
if (device?.app_version && payload != device.app_version) {
|
|
116
|
+
$.db_device.addLog(device.id,"app_version",payload);
|
|
108
117
|
await $.db_device.update(device.id, "app_version", payload);
|
|
109
118
|
await self.handleFotaSuccess(device.id);
|
|
110
119
|
}
|
|
@@ -118,8 +127,38 @@ var self = module.exports = {
|
|
|
118
127
|
break;
|
|
119
128
|
}
|
|
120
129
|
|
|
121
|
-
if(topic.startsWith("
|
|
122
|
-
|
|
130
|
+
if(topic.startsWith("settings/") && topic.endsWith("/set") && payload != "" ){
|
|
131
|
+
// update local settings
|
|
132
|
+
let index = topic.indexOf("settings/");
|
|
133
|
+
topic = topic.substring(index+9);
|
|
134
|
+
self.updateLocalSettings(device,topic,payload);
|
|
135
|
+
}else if(topic.startsWith("settings/") && !topic.endsWith("/set") && payload != "" ){
|
|
136
|
+
// store remote device settings
|
|
137
|
+
let index = topic.indexOf("settings/");
|
|
138
|
+
topic = topic.substring(index+9);
|
|
139
|
+
self.updateRemoteSettings(device,topic,payload);
|
|
140
|
+
}else if(topic == "fw"){
|
|
141
|
+
try{
|
|
142
|
+
payload = JSON.parse(payload);
|
|
143
|
+
}catch(error){}
|
|
144
|
+
if(typeof payload === 'object' && payload !== null){
|
|
145
|
+
try{
|
|
146
|
+
$.db_data.updateJson("fw",device.id,payload);
|
|
147
|
+
$.db_data.addJsonLog("logs_fw",device.id,payload);
|
|
148
|
+
}catch(error){
|
|
149
|
+
console.error(error)
|
|
150
|
+
}
|
|
151
|
+
}else if(typeof payload !== 'object' && payload !== null){
|
|
152
|
+
// change it to topic.startsWith("fw")
|
|
153
|
+
try{
|
|
154
|
+
const column = getWordAfterLastSlash(topic);
|
|
155
|
+
$.db_data.update("fw",device.id,column,payload);
|
|
156
|
+
$.db_data.addLog("logs_fw",device.id,column,payload);
|
|
157
|
+
}catch(error){
|
|
158
|
+
console.error(error)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}else if(topic.startsWith("sensor/")){
|
|
123
162
|
updateSensor(device,topic,paylaod)
|
|
124
163
|
index = topic.indexOf("/");
|
|
125
164
|
if(index == -1)
|
|
@@ -132,13 +171,8 @@ var self = module.exports = {
|
|
|
132
171
|
}
|
|
133
172
|
}
|
|
134
173
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
self.updateSettings(project_name,device,topic,payload);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if(project[project_name]){
|
|
141
|
-
project[project_name].module.parseMessage(client,project_name,device,topic,payload,retain,()=>{});
|
|
174
|
+
if(_project[project_name]){
|
|
175
|
+
_project[project_name]?.module?.parseMessage(client,project_name,device,topic,payload,retain,()=>{});
|
|
142
176
|
}
|
|
143
177
|
}
|
|
144
178
|
|
|
@@ -162,49 +196,115 @@ var self = module.exports = {
|
|
|
162
196
|
}
|
|
163
197
|
},
|
|
164
198
|
|
|
165
|
-
|
|
199
|
+
updateLocalSettings: async (device, topic, payload) => {
|
|
200
|
+
|
|
201
|
+
$.db_device.addLog(device.id,"local_settings",JSON.stringify(payload));
|
|
202
|
+
|
|
166
203
|
let route = topic.split("/");
|
|
167
204
|
|
|
168
|
-
if(route == null){
|
|
169
|
-
console.
|
|
205
|
+
if (route == null || route.length == 0) {
|
|
206
|
+
console.warn("updateLocalSettings: topic invalid:", topic);
|
|
170
207
|
return;
|
|
171
208
|
}
|
|
172
|
-
// get settings
|
|
173
|
-
let settings = await $.db_project.getSettings(project_name,device.id);
|
|
174
|
-
let obj = settings;
|
|
175
209
|
|
|
176
|
-
|
|
177
|
-
|
|
210
|
+
// Retrieve existing settings
|
|
211
|
+
let settings = await $.db_device.getLocalSettings(device.id);
|
|
212
|
+
|
|
213
|
+
if (!settings || typeof settings !== 'object') {
|
|
214
|
+
settings = {};
|
|
178
215
|
}
|
|
179
|
-
|
|
216
|
+
|
|
217
|
+
let obj = settings;
|
|
218
|
+
|
|
219
|
+
// Traverse route parts to reach the target object
|
|
180
220
|
route.slice(0, -1).forEach(property => {
|
|
181
|
-
if (
|
|
182
|
-
|
|
183
|
-
|
|
221
|
+
if (
|
|
222
|
+
!Object.prototype.hasOwnProperty.call(obj, property) ||
|
|
223
|
+
(obj.hasOwnProperty(property) && typeof obj[property] !== 'object') ||
|
|
224
|
+
obj[property] === null
|
|
225
|
+
) {
|
|
226
|
+
obj[property] = {}; // Create nested object if missing or not an object
|
|
227
|
+
}
|
|
228
|
+
obj = obj[property];
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// Parse the payload JSON
|
|
232
|
+
let data = {};
|
|
233
|
+
try {
|
|
234
|
+
data = JSON.parse(payload);
|
|
235
|
+
} catch (error) {
|
|
236
|
+
console.error("Failed to parse payload JSON:", error);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Check if the data is a plain object, then merge
|
|
241
|
+
if (data && typeof data === 'object' && !Array.isArray(data)) {
|
|
242
|
+
Object.assign(obj, data);
|
|
243
|
+
} else {
|
|
244
|
+
console.warn("Payload is not a valid object:", payload);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
// Update the settings in the database
|
|
250
|
+
await $.db_device.updateLocalSettings(JSON.stringify(settings), device.id);
|
|
251
|
+
} catch (err) {
|
|
252
|
+
console.error("Failed to update local settings:", err);
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
updateRemoteSettings : async (device,topic,payload)=>{
|
|
257
|
+
|
|
258
|
+
$.db_device.addLog(device.id,"remote_settings",JSON.stringify(payload));
|
|
259
|
+
|
|
260
|
+
let route = topic.split("/");
|
|
261
|
+
|
|
262
|
+
if(route == null){
|
|
263
|
+
console.warn("updateRemoteSettings: topic invalid:",topic);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
// Parse existing settings
|
|
267
|
+
let settings = await $.db_device.getRemoteSettings(device.id);
|
|
268
|
+
|
|
269
|
+
if (!settings || typeof settings !== 'object') {
|
|
270
|
+
settings = {};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
let obj = settings;
|
|
274
|
+
|
|
275
|
+
// Traverse route parts
|
|
276
|
+
route.slice(0, route.length).forEach(property => {
|
|
277
|
+
if (
|
|
278
|
+
!Object.prototype.hasOwnProperty.call(obj, property) ||
|
|
279
|
+
(obj.hasOwnProperty(property) && typeof obj[property] !== 'object') ||
|
|
280
|
+
obj[property] === null
|
|
281
|
+
) {
|
|
184
282
|
obj[property] = {}; // create nested object if missing or not an object
|
|
185
283
|
}
|
|
186
|
-
obj = obj[property];
|
|
187
|
-
})
|
|
188
|
-
|
|
284
|
+
obj = obj[property];
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Merge payload into nested object
|
|
189
288
|
let data = {};
|
|
190
|
-
try{
|
|
191
|
-
data = JSON.parse(payload)
|
|
192
|
-
}catch(error){
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
289
|
+
try {
|
|
290
|
+
data = JSON.parse(payload);
|
|
291
|
+
} catch(error) {
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (data && typeof data === 'object' && !Array.isArray(data)) {
|
|
295
|
+
// Merge data properties
|
|
196
296
|
for (const [key, value] of Object.entries(data)) {
|
|
197
|
-
obj[key] = value;
|
|
198
|
-
}
|
|
199
|
-
}else{
|
|
200
|
-
|
|
297
|
+
obj[key] = value;
|
|
298
|
+
}
|
|
299
|
+
} else {
|
|
300
|
+
// payload isn't an object, replace the nested object
|
|
301
|
+
obj = payload;
|
|
201
302
|
}
|
|
202
303
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
console.log(error);
|
|
304
|
+
try {
|
|
305
|
+
await $.db_device.updateRemoteSettings(JSON.stringify(settings), device.id);
|
|
306
|
+
} catch (err) {
|
|
307
|
+
console.error("Failed to update local settings:", err);
|
|
208
308
|
}
|
|
209
309
|
},
|
|
210
310
|
|
|
@@ -261,18 +361,17 @@ var self = module.exports = {
|
|
|
261
361
|
if(res == null)
|
|
262
362
|
$.db_fota.update(device.id,obj);
|
|
263
363
|
}catch(error){
|
|
264
|
-
console.
|
|
364
|
+
console.error(error)
|
|
265
365
|
}
|
|
266
366
|
}
|
|
267
367
|
}
|
|
268
368
|
}catch(error){
|
|
269
|
-
console.
|
|
369
|
+
console.error(error);
|
|
270
370
|
continue;
|
|
271
371
|
}
|
|
272
372
|
}
|
|
273
373
|
},
|
|
274
374
|
|
|
275
|
-
|
|
276
375
|
triggerFota : async (release = "dev")=>{
|
|
277
376
|
|
|
278
377
|
const devices = await $.db_fota.getUpdatable(release);
|
|
@@ -290,14 +389,20 @@ var self = module.exports = {
|
|
|
290
389
|
const model_name = model?.name;
|
|
291
390
|
let topic = "";
|
|
292
391
|
if(model_name == "sniffer"){
|
|
392
|
+
resolve();
|
|
393
|
+
// !! This cannot be handled on this way
|
|
394
|
+
|
|
293
395
|
// get sniffer info associated to device
|
|
294
|
-
const sniffer = await $.db_data.
|
|
396
|
+
const sniffer = await $.db_data.getAssociatedToDevice("sniffer",device.id);
|
|
295
397
|
if(sniffer == null) return;
|
|
296
398
|
// get device_uid from devices table
|
|
297
399
|
const gw = await $.db_device.getById(sniffer?.id)
|
|
298
400
|
if(gw == null) return;
|
|
299
401
|
let mqtt_prefix = `${project_name}/${gw.uid}`;
|
|
300
|
-
|
|
402
|
+
if (semver.gt(sniffer.version, "2.0.1"))
|
|
403
|
+
topic = mqtt_prefix+`/app/sniffer/${sniffer.uid}/fota/update/set`;
|
|
404
|
+
else
|
|
405
|
+
topic = mqtt_prefix+`/app/sniffer/fota/update/set`;
|
|
301
406
|
}
|
|
302
407
|
else{
|
|
303
408
|
let mqtt_prefix = `${project_name}/${device.uid}`;
|