mqtt-devices-parser 1.0.12 → 1.0.14
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 +11 -1
- package/Release.md +3 -0
- package/models/devices.models.js +21 -0
- package/models/fota.models.js +3 -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/db/fota.js +17 -17
- package/src/device/device.js +176 -59
package/Changelog.md
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.14
|
|
4
|
+
Fixes check FOTA mechanism and response
|
|
5
|
+
|
|
6
|
+
## 1.0.13
|
|
7
|
+
adds 2 new tables to db:
|
|
8
|
+
Adds 5 new columns to devices
|
|
9
|
+
Registers device logs, records device settings..
|
|
10
|
+
fixes: ws affected by a DoS when handling a request with many HTTP headers !breaking change
|
|
11
|
+
Updates npm
|
|
12
|
+
|
|
3
13
|
## 1.0.12
|
|
4
|
-
Adds
|
|
14
|
+
Adds module fota
|
|
5
15
|
|
|
6
16
|
## 1.0.11
|
|
7
17
|
index: MQTT
|
package/Release.md
CHANGED
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',
|
package/models/fota.models.js
CHANGED
|
@@ -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/db/fota.js
CHANGED
|
@@ -7,7 +7,7 @@ var self = module.exports = {
|
|
|
7
7
|
|
|
8
8
|
return new Promise((resolve,reject) => {
|
|
9
9
|
|
|
10
|
-
let query = `SELECT
|
|
10
|
+
let query = `SELECT * FROM ?? where
|
|
11
11
|
device_id = ? and
|
|
12
12
|
target_version = ? and
|
|
13
13
|
target_app_version = ? and
|
|
@@ -91,13 +91,13 @@ var self = module.exports = {
|
|
|
91
91
|
obj['createdAt'] = moment().utc().format('YYYY-MM-DD HH:mm:ss');
|
|
92
92
|
obj['device_id'] = deviceId;
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
94
|
+
$.db.insert("fota",obj)
|
|
95
|
+
.then (rows => {
|
|
96
|
+
return resolve(rows[0]);
|
|
97
|
+
})
|
|
98
|
+
.catch(error => {
|
|
99
|
+
return reject(error);
|
|
100
|
+
});
|
|
101
101
|
|
|
102
102
|
}else{
|
|
103
103
|
|
|
@@ -106,18 +106,18 @@ var self = module.exports = {
|
|
|
106
106
|
};
|
|
107
107
|
|
|
108
108
|
$.db.update("fota",obj,filter)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
109
|
+
.then (rows => {
|
|
110
|
+
return resolve(rows[0]);
|
|
111
|
+
})
|
|
112
|
+
.catch(error => {
|
|
113
|
+
return reject(error);
|
|
114
|
+
});
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
});
|
|
118
118
|
},
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
getFotaLastLog : async(deviceId)=>{
|
|
121
121
|
|
|
122
122
|
return new Promise((resolve,reject) => {
|
|
123
123
|
|
|
@@ -127,7 +127,7 @@ var self = module.exports = {
|
|
|
127
127
|
LIMIT 1`;
|
|
128
128
|
|
|
129
129
|
let table = [
|
|
130
|
-
"
|
|
130
|
+
"logs_fota",
|
|
131
131
|
deviceId,
|
|
132
132
|
];
|
|
133
133
|
query = mysql.format(query,table);
|
|
@@ -195,7 +195,7 @@ var self = module.exports = {
|
|
|
195
195
|
|
|
196
196
|
return new Promise(async (resolve,reject) => {
|
|
197
197
|
|
|
198
|
-
const log = await
|
|
198
|
+
const log = await self.getFotaLastLog(deviceId);
|
|
199
199
|
|
|
200
200
|
if(log?.createdAt != log?.updatedAt)
|
|
201
201
|
|
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
|
|
|
@@ -214,12 +314,15 @@ var self = module.exports = {
|
|
|
214
314
|
|
|
215
315
|
for (const model of models) {
|
|
216
316
|
|
|
317
|
+
console.log("model:",model?.name);
|
|
217
318
|
if(!model?.id)
|
|
218
319
|
continue;
|
|
219
320
|
|
|
220
321
|
try{
|
|
221
322
|
const latestVersion = await $.db_firmware.getLatestVersion(model.id,release);
|
|
222
323
|
const latestAppVersion = await $.db_firmware.getLatestAppVersion(model.id,release);
|
|
324
|
+
console.log("latestVersion:",latestVersion?.version);
|
|
325
|
+
console.log("latestAppVersion:",latestAppVersion?.app_version);
|
|
223
326
|
|
|
224
327
|
const devices = await $.db_device.listByModel(model.id);
|
|
225
328
|
|
|
@@ -256,23 +359,31 @@ var self = module.exports = {
|
|
|
256
359
|
};
|
|
257
360
|
}
|
|
258
361
|
if(obj != null){
|
|
259
|
-
try{
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
362
|
+
try {
|
|
363
|
+
|
|
364
|
+
let res = await $.db_fota.getEntry(device.id, obj);
|
|
365
|
+
|
|
366
|
+
if (res == null) {
|
|
367
|
+
try {
|
|
368
|
+
console.log("add fota entry for device:", device.uid);
|
|
369
|
+
await $.db_fota.update(device.id, obj);
|
|
370
|
+
} catch (err) {
|
|
371
|
+
console.error("Error updating FOTA entry:", err);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
} catch (error) {
|
|
376
|
+
console.error("Error getting or processing FOTA entry:", error);
|
|
265
377
|
}
|
|
266
378
|
}
|
|
267
379
|
}
|
|
268
380
|
}catch(error){
|
|
269
|
-
console.
|
|
381
|
+
console.error(error);
|
|
270
382
|
continue;
|
|
271
383
|
}
|
|
272
384
|
}
|
|
273
385
|
},
|
|
274
386
|
|
|
275
|
-
|
|
276
387
|
triggerFota : async (release = "dev")=>{
|
|
277
388
|
|
|
278
389
|
const devices = await $.db_fota.getUpdatable(release);
|
|
@@ -290,21 +401,27 @@ var self = module.exports = {
|
|
|
290
401
|
const model_name = model?.name;
|
|
291
402
|
let topic = "";
|
|
292
403
|
if(model_name == "sniffer"){
|
|
404
|
+
resolve();
|
|
405
|
+
// !! This cannot be handled on this way
|
|
406
|
+
|
|
293
407
|
// get sniffer info associated to device
|
|
294
|
-
const sniffer = await $.db_data.
|
|
408
|
+
const sniffer = await $.db_data.getAssociatedToDevice("sniffer",device.id);
|
|
295
409
|
if(sniffer == null) return;
|
|
296
410
|
// get device_uid from devices table
|
|
297
411
|
const gw = await $.db_device.getById(sniffer?.id)
|
|
298
412
|
if(gw == null) return;
|
|
299
413
|
let mqtt_prefix = `${project_name}/${gw.uid}`;
|
|
300
|
-
|
|
414
|
+
if (semver.gt(sniffer.version, "2.0.1"))
|
|
415
|
+
topic = mqtt_prefix+`/app/sniffer/${sniffer.uid}/fota/update/set`;
|
|
416
|
+
else
|
|
417
|
+
topic = mqtt_prefix+`/app/sniffer/fota/update/set`;
|
|
301
418
|
}
|
|
302
419
|
else{
|
|
303
420
|
let mqtt_prefix = `${project_name}/${device.uid}`;
|
|
304
421
|
topic = mqtt_prefix+"/fw/fota/update/set";
|
|
305
422
|
}
|
|
306
423
|
let link = `${$.config.web.protocol}${$.config.web.domain}${$.config.web.fw_path}${firmware?.filename}/download?token=${firmware?.token}`;
|
|
307
|
-
console.log(`Requesting firmware update
|
|
424
|
+
console.log(`Requesting firmware update for ${device.uid} to ${firmware?.filename}`);
|
|
308
425
|
$.mqtt_client.publish(topic,`{"url":"${link}"}`,{qos:1,retain:false});
|
|
309
426
|
|
|
310
427
|
let obj = {
|
|
@@ -343,14 +460,14 @@ var self = module.exports = {
|
|
|
343
460
|
object = {
|
|
344
461
|
success : 1,
|
|
345
462
|
}
|
|
346
|
-
await $.db_fota.updateLog(deviceId,
|
|
463
|
+
await $.db_fota.updateLog(deviceId,object);
|
|
347
464
|
},
|
|
348
465
|
|
|
349
466
|
handleFotaError : async (deviceId, error) => {
|
|
350
467
|
let object = {
|
|
351
468
|
error : error,
|
|
352
469
|
}
|
|
353
|
-
await $.db_fota.updateLog(deviceId,
|
|
470
|
+
await $.db_fota.updateLog(deviceId,object);
|
|
354
471
|
}
|
|
355
472
|
}
|
|
356
473
|
|