mqtt-devices-parser 1.0.11 → 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 +10 -0
- package/index.js +24 -3
- package/models/devices.models.js +20 -3
- package/models/firmwares.models.js +2 -10
- package/models/fota.models.js +32 -0
- package/models/logs_actions.models.js +17 -0
- package/models/logs_device.models.js +62 -0
- package/models/logs_fota.models.js +41 -0
- package/models/{sensor_logs.models.js → logs_sensor.models.js} +2 -2
- package/models/modelPermissions.models.js +23 -0
- package/models/models.js +238 -211
- package/models/projects.models.js +8 -0
- package/package.json +1 -1
- package/src/db/data.js +91 -87
- package/src/db/db.js +24 -0
- package/src/db/device.js +288 -7
- package/src/db/firmware.js +30 -5
- package/src/db/fota.js +219 -0
- package/src/device/Readme.md +39 -4
- package/src/device/device.js +374 -152
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);
|
|
@@ -32,6 +32,152 @@ var self = module.exports = {
|
|
|
32
32
|
|
|
33
33
|
},
|
|
34
34
|
|
|
35
|
+
parseMessage : async (client,topic,payload,retain)=>{
|
|
36
|
+
|
|
37
|
+
let topic_bck = topic;
|
|
38
|
+
|
|
39
|
+
//let index = topic.indexOf(MACRO_UID_PREFIX);
|
|
40
|
+
// --- project ---
|
|
41
|
+
let index = topic.indexOf("/");
|
|
42
|
+
if(index == -1)
|
|
43
|
+
return;
|
|
44
|
+
|
|
45
|
+
let project_name = topic.substring(0,index);
|
|
46
|
+
let project = await $.db_project.getByName(project_name);
|
|
47
|
+
|
|
48
|
+
if(project == null)
|
|
49
|
+
return;
|
|
50
|
+
|
|
51
|
+
let project_id = project?.id;
|
|
52
|
+
|
|
53
|
+
// --- uid ---
|
|
54
|
+
topic = topic.substring(index+1);
|
|
55
|
+
index = topic.indexOf("/");
|
|
56
|
+
if(index == -1)
|
|
57
|
+
return;
|
|
58
|
+
|
|
59
|
+
let uid = topic.substring(0,index);
|
|
60
|
+
topic = topic.substring(index+1);
|
|
61
|
+
|
|
62
|
+
// check if topic corresponds to a device
|
|
63
|
+
if(uid.startsWith(project.uidPrefix) && uid.length == project?.uidLength){
|
|
64
|
+
|
|
65
|
+
let device = await $.db_device.get(uid);
|
|
66
|
+
|
|
67
|
+
// Insert device if not exists on db
|
|
68
|
+
if(device == null){
|
|
69
|
+
let obj = {
|
|
70
|
+
uid : uid,
|
|
71
|
+
accept_release : "prod",
|
|
72
|
+
}
|
|
73
|
+
$.db_device.insert(obj)
|
|
74
|
+
.then(async()=>{
|
|
75
|
+
device = await $.db_device.get(uid);
|
|
76
|
+
})
|
|
77
|
+
.catch( (err) => {});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// update project id if needed
|
|
81
|
+
if(project_id != null && project_id != device?.project_id){
|
|
82
|
+
$.db_device.update(device.id,"project_id",project_id);
|
|
83
|
+
$.db_device.addLog(device.id,"project_id",project_id);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
switch (topic) {
|
|
87
|
+
case "status":
|
|
88
|
+
if (payload === "online" || payload === "offline") {
|
|
89
|
+
await $.db_device.update(device.id, "status", payload);
|
|
90
|
+
$.db_device.addLog(device.id,"status",payload);
|
|
91
|
+
}
|
|
92
|
+
break;
|
|
93
|
+
case "model":
|
|
94
|
+
let res = await $.db_model.getByName(payload);
|
|
95
|
+
let model_id = res?.id;
|
|
96
|
+
if (model_id != null && device?.tech != payload) {
|
|
97
|
+
await $.db_device.update(device.id, "model_id", model_id);
|
|
98
|
+
$.db_device.addLog(device.id,"model_id",model_id);
|
|
99
|
+
}
|
|
100
|
+
break;
|
|
101
|
+
case "tech":
|
|
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
|
+
}
|
|
106
|
+
break;
|
|
107
|
+
case "version":
|
|
108
|
+
if (device?.version && payload != device.version) {
|
|
109
|
+
$.db_device.addLog(device.id,"version",payload);
|
|
110
|
+
await $.db_device.update(device.id, "version", payload);
|
|
111
|
+
await self.handleFotaSuccess(device.id);
|
|
112
|
+
}
|
|
113
|
+
break;
|
|
114
|
+
case "app_version":
|
|
115
|
+
if (device?.app_version && payload != device.app_version) {
|
|
116
|
+
$.db_device.addLog(device.id,"app_version",payload);
|
|
117
|
+
await $.db_device.update(device.id, "app_version", payload);
|
|
118
|
+
await self.handleFotaSuccess(device.id);
|
|
119
|
+
}
|
|
120
|
+
break;
|
|
121
|
+
case "fw/fota/update/status":
|
|
122
|
+
await self.handleFotaError(device.id, payload);
|
|
123
|
+
break;
|
|
124
|
+
// Optional: default case if needed
|
|
125
|
+
default:
|
|
126
|
+
// handle other topics or do nothing
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
|
|
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/")){
|
|
162
|
+
updateSensor(device,topic,paylaod)
|
|
163
|
+
index = topic.indexOf("/");
|
|
164
|
+
if(index == -1)
|
|
165
|
+
return;
|
|
166
|
+
|
|
167
|
+
const name = topic.substring(index+1);
|
|
168
|
+
let res = await $.db_sensor.getByRef(topic)
|
|
169
|
+
if(res != null){
|
|
170
|
+
await $.db_sensor.insert(logs_table,device.id,res.id,payload);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if(_project[project_name]){
|
|
175
|
+
_project[project_name]?.module?.parseMessage(client,project_name,device,topic,payload,retain,()=>{});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
},
|
|
180
|
+
|
|
35
181
|
deleteLogs : async()=>{
|
|
36
182
|
|
|
37
183
|
let tables = await $.db.getTables();
|
|
@@ -48,193 +194,269 @@ var self = module.exports = {
|
|
|
48
194
|
console.log(`Logs of table ${tableName} deleted in ${time}s`);
|
|
49
195
|
}
|
|
50
196
|
}
|
|
51
|
-
|
|
52
197
|
},
|
|
53
198
|
|
|
54
|
-
|
|
199
|
+
updateLocalSettings: async (device, topic, payload) => {
|
|
55
200
|
|
|
56
|
-
|
|
201
|
+
$.db_device.addLog(device.id,"local_settings",JSON.stringify(payload));
|
|
57
202
|
|
|
58
|
-
|
|
59
|
-
for (let i = 0; i < devices.length; i += batchSize) {
|
|
60
|
-
const batch = devices.slice(i, i + batchSize);
|
|
61
|
-
await Promise.all(batch.map(async (device) => {
|
|
203
|
+
let route = topic.split("/");
|
|
62
204
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
205
|
+
if (route == null || route.length == 0) {
|
|
206
|
+
console.warn("updateLocalSettings: topic invalid:", topic);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
68
209
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
210
|
+
// Retrieve existing settings
|
|
211
|
+
let settings = await $.db_device.getLocalSettings(device.id);
|
|
73
212
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return;
|
|
78
|
-
|
|
79
|
-
let project_name = "";
|
|
80
|
-
let res = await $.db_project.getById(device.project_id);
|
|
81
|
-
if(res != null)
|
|
82
|
-
project_name = res.name;
|
|
83
|
-
else
|
|
84
|
-
return;
|
|
85
|
-
|
|
86
|
-
let mqtt_prefix = `${project_name}/${device.uid}`;
|
|
87
|
-
if(new_app != null && semver.lt(device.app_version, new_app.app_version))
|
|
88
|
-
{
|
|
89
|
-
console.log(`updating firmware of ${device.uid} to minor version ${new_app.app_version}`);
|
|
90
|
-
let link = `${$.config.web.protocol}${$.config.web.domain}${$.config.web.fw_path}${new_app.filename}/download?token=${new_app.token}`;
|
|
91
|
-
client.publish(mqtt_prefix+"/fw/fota/update/set",`{"url":"${link}"}`,{qos:2,retain:false});
|
|
92
|
-
await $.db_data.update(project_name,device.id,"fota_tries",++device.fota_tries);
|
|
93
|
-
}else{
|
|
94
|
-
if(new_firmware != null && semver.lt(device.version, new_firmware.fw_version))
|
|
95
|
-
{
|
|
96
|
-
console.log(`updating firmware of ${device.uid} to major version ${new_firmware.fw_version}`);
|
|
97
|
-
let link = `${$.config.web.protocol}${$.config.web.domain}${$.config.web.fw_path}${new_firmware.filename}/download?token=${new_firmware.token}`;
|
|
98
|
-
$.mqtt_client.publish(mqtt_prefix+"/fw/fota/update/set",`{"url":"${link}"}`,{qos:2,retain:false});
|
|
99
|
-
await $.db_data.update(project_name,device.id,"fota_tries",++device.fota_tries);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}));
|
|
213
|
+
if (!settings || typeof settings !== 'object') {
|
|
214
|
+
settings = {};
|
|
215
|
+
}
|
|
103
216
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
217
|
+
let obj = settings;
|
|
218
|
+
|
|
219
|
+
// Traverse route parts to reach the target object
|
|
220
|
+
route.slice(0, -1).forEach(property => {
|
|
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
|
|
107
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;
|
|
108
246
|
}
|
|
109
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
|
+
}
|
|
110
254
|
},
|
|
111
255
|
|
|
112
|
-
|
|
256
|
+
updateRemoteSettings : async (device,topic,payload)=>{
|
|
113
257
|
|
|
114
|
-
|
|
258
|
+
$.db_device.addLog(device.id,"remote_settings",JSON.stringify(payload));
|
|
115
259
|
|
|
116
|
-
|
|
117
|
-
// --- project ---
|
|
118
|
-
let index = topic.indexOf("/");
|
|
119
|
-
if(index == -1)
|
|
120
|
-
return;
|
|
121
|
-
let project_name = topic.substring(0,index);
|
|
260
|
+
let route = topic.split("/");
|
|
122
261
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
let
|
|
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);
|
|
129
268
|
|
|
130
|
-
|
|
269
|
+
if (!settings || typeof settings !== 'object') {
|
|
270
|
+
settings = {};
|
|
271
|
+
}
|
|
131
272
|
|
|
132
|
-
|
|
133
|
-
if(uid.startsWith(MACRO_UID_PREFIX)){
|
|
134
|
-
let device = await $.db_device.get(uid);
|
|
273
|
+
let obj = settings;
|
|
135
274
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
+
) {
|
|
282
|
+
obj[property] = {}; // create nested object if missing or not an object
|
|
142
283
|
}
|
|
284
|
+
obj = obj[property];
|
|
285
|
+
});
|
|
143
286
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
287
|
+
// Merge payload into nested object
|
|
288
|
+
let data = {};
|
|
289
|
+
try {
|
|
290
|
+
data = JSON.parse(payload);
|
|
291
|
+
} catch(error) {
|
|
292
|
+
}
|
|
149
293
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
let res = await $.db_model.getByName(payload);
|
|
155
|
-
let model_id = res?.id;
|
|
156
|
-
|
|
157
|
-
if(model_id != null){
|
|
158
|
-
let res = await $.db_device.update(device.id,"model_id",model_id);
|
|
159
|
-
}
|
|
160
|
-
}else if(topic === "tech"){
|
|
161
|
-
await $.db_device.update(device.id,"tech",payload);
|
|
162
|
-
}else if(topic === "version"){
|
|
163
|
-
// Update version and app_version on device table..
|
|
164
|
-
if(payload != device.version){
|
|
165
|
-
await $.db_device.update(device.id,"version",payload);
|
|
166
|
-
await $.db_device.update(device.id,"fota_tries",1); // ! value 0 doesn't work..
|
|
167
|
-
}
|
|
168
|
-
}else if(topic === "app_version"){
|
|
169
|
-
if(payload != device.app_version){
|
|
170
|
-
await $.db_device.update(device.id,"app_version",payload);
|
|
171
|
-
await $.db_device.update(device.id,"fota_tries",1); // ! value 0 doesn't work..
|
|
172
|
-
}
|
|
294
|
+
if (data && typeof data === 'object' && !Array.isArray(data)) {
|
|
295
|
+
// Merge data properties
|
|
296
|
+
for (const [key, value] of Object.entries(data)) {
|
|
297
|
+
obj[key] = value;
|
|
173
298
|
}
|
|
299
|
+
} else {
|
|
300
|
+
// payload isn't an object, replace the nested object
|
|
301
|
+
obj = payload;
|
|
302
|
+
}
|
|
174
303
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
304
|
+
try {
|
|
305
|
+
await $.db_device.updateRemoteSettings(JSON.stringify(settings), device.id);
|
|
306
|
+
} catch (err) {
|
|
307
|
+
console.error("Failed to update local settings:", err);
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
|
|
311
|
+
checkFota : async (release = "dev")=>{
|
|
312
|
+
|
|
313
|
+
const models = await $.db_model.getAll();
|
|
314
|
+
|
|
315
|
+
for (const model of models) {
|
|
316
|
+
|
|
317
|
+
if(!model?.id)
|
|
318
|
+
continue;
|
|
319
|
+
|
|
320
|
+
try{
|
|
321
|
+
const latestVersion = await $.db_firmware.getLatestVersion(model.id,release);
|
|
322
|
+
const latestAppVersion = await $.db_firmware.getLatestAppVersion(model.id,release);
|
|
323
|
+
|
|
324
|
+
const devices = await $.db_device.listByModel(model.id);
|
|
325
|
+
|
|
326
|
+
if(devices == null)
|
|
327
|
+
continue;
|
|
328
|
+
|
|
329
|
+
for (const device of devices) {
|
|
330
|
+
|
|
331
|
+
if(device?.accept_release != release){
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
let obj = null;
|
|
336
|
+
// insert filename on fota table for this device or update.
|
|
337
|
+
if(device?.app_version != latestAppVersion.app_version){
|
|
338
|
+
obj = {
|
|
339
|
+
model_id : device.model_id,
|
|
340
|
+
target_version : latestVersion.version,
|
|
341
|
+
target_app_version : latestAppVersion.app_version,
|
|
342
|
+
target_release : device.accept_release,
|
|
343
|
+
firmware_id : latestAppVersion.id,
|
|
344
|
+
nAttempts : 0,
|
|
345
|
+
fUpdate : true,
|
|
346
|
+
};
|
|
347
|
+
}else if(latestVersion?.version && (device?.version != latestVersion.version)){
|
|
348
|
+
obj = {
|
|
349
|
+
model_id : device.model_id,
|
|
350
|
+
target_version : latestVersion.version,
|
|
351
|
+
target_app_version : latestAppVersion.app_version,
|
|
352
|
+
target_release : device.accept_release,
|
|
353
|
+
firmware_id : latestVersion.id,
|
|
354
|
+
nAttempts : 0,
|
|
355
|
+
fUpdate : true,
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
if(obj != null){
|
|
359
|
+
try{
|
|
360
|
+
let res = await $.db_fota.getEntry(device.id,obj);
|
|
361
|
+
if(res == null)
|
|
362
|
+
$.db_fota.update(device.id,obj);
|
|
363
|
+
}catch(error){
|
|
364
|
+
console.error(error)
|
|
365
|
+
}
|
|
366
|
+
}
|
|
179
367
|
}
|
|
368
|
+
}catch(error){
|
|
369
|
+
console.error(error);
|
|
370
|
+
continue;
|
|
180
371
|
}
|
|
372
|
+
}
|
|
373
|
+
},
|
|
181
374
|
|
|
182
|
-
|
|
183
|
-
if(topic.endsWith("/set") && payload != "" ){
|
|
375
|
+
triggerFota : async (release = "dev")=>{
|
|
184
376
|
|
|
185
|
-
|
|
377
|
+
const devices = await $.db_fota.getUpdatable(release);
|
|
186
378
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
// get settings
|
|
192
|
-
let settings = await $.db_project.getSettings(project_name,device.id);
|
|
193
|
-
let obj = settings;
|
|
379
|
+
const batchSize = 10;
|
|
380
|
+
for (let i = 0; i < devices.length; i += batchSize) {
|
|
381
|
+
const batch = devices.slice(i, i + batchSize);
|
|
382
|
+
await Promise.all(batch.map(async (device) => {
|
|
194
383
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
384
|
+
const firmware = await $.db_firmware.getById(device?.firmware_id)
|
|
385
|
+
if(firmware != null){
|
|
386
|
+
const project = await $.db_project.getById(device.project_id);
|
|
387
|
+
const project_name = project?.name;
|
|
388
|
+
const model = await $.db_model.getById(firmware.model_id);
|
|
389
|
+
const model_name = model?.name;
|
|
390
|
+
let topic = "";
|
|
391
|
+
if(model_name == "sniffer"){
|
|
392
|
+
resolve();
|
|
393
|
+
// !! This cannot be handled on this way
|
|
394
|
+
|
|
395
|
+
// get sniffer info associated to device
|
|
396
|
+
const sniffer = await $.db_data.getAssociatedToDevice("sniffer",device.id);
|
|
397
|
+
if(sniffer == null) return;
|
|
398
|
+
// get device_uid from devices table
|
|
399
|
+
const gw = await $.db_device.getById(sniffer?.id)
|
|
400
|
+
if(gw == null) return;
|
|
401
|
+
let mqtt_prefix = `${project_name}/${gw.uid}`;
|
|
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`;
|
|
205
406
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
if (true || (data && typeof payload === 'object' && !Array.isArray(payload) ) ) {
|
|
215
|
-
// Assuming payload is an object with properties to process
|
|
216
|
-
for (const [key, value] of Object.entries(data)) {
|
|
217
|
-
obj[key] = value; // go deeper
|
|
218
|
-
};
|
|
219
|
-
}else{
|
|
220
|
-
obj = payload
|
|
221
|
-
}
|
|
407
|
+
else{
|
|
408
|
+
let mqtt_prefix = `${project_name}/${device.uid}`;
|
|
409
|
+
topic = mqtt_prefix+"/fw/fota/update/set";
|
|
410
|
+
}
|
|
411
|
+
let link = `${$.config.web.protocol}${$.config.web.domain}${$.config.web.fw_path}${firmware?.filename}/download?token=${firmware?.token}`;
|
|
412
|
+
console.log(`Requesting firmware update of ${device.uid} to ${firmware?.filename}`);
|
|
413
|
+
$.mqtt_client.publish(topic,`{"url":"${link}"}`,{qos:1,retain:false});
|
|
222
414
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
415
|
+
let obj = {
|
|
416
|
+
nAttempts : ++device.nAttempts
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
await $.db_fota.update(device.id,obj);
|
|
420
|
+
|
|
421
|
+
obj = {
|
|
422
|
+
device_id : device.id,
|
|
423
|
+
local_version : device.version,
|
|
424
|
+
local_app_version : device.app_version,
|
|
425
|
+
target_version : firmware.version,
|
|
426
|
+
target_app_version : firmware.app_version,
|
|
427
|
+
target_file : firmware.filename,
|
|
428
|
+
nAttempt : device.nAttempts
|
|
429
|
+
}
|
|
430
|
+
await $.db_fota.newLog(device.id,obj);
|
|
228
431
|
}
|
|
229
|
-
|
|
432
|
+
|
|
433
|
+
}));
|
|
230
434
|
|
|
231
|
-
|
|
232
|
-
|
|
435
|
+
// Wait for 1 minute after processing each batch
|
|
436
|
+
if (i + batchSize < devices.length) {
|
|
437
|
+
await new Promise(resolve => setTimeout(resolve, 60000));
|
|
233
438
|
}
|
|
234
439
|
}
|
|
440
|
+
},
|
|
235
441
|
|
|
442
|
+
handleFotaSuccess : async (deviceId) => {
|
|
443
|
+
let object = {
|
|
444
|
+
"nAttempts" : 0,
|
|
445
|
+
"fUpdate" : 0,
|
|
446
|
+
}
|
|
447
|
+
await $.db_fota.update(deviceId,object);
|
|
448
|
+
object = {
|
|
449
|
+
success : 1,
|
|
450
|
+
}
|
|
451
|
+
await $.db_fota.updateLog(deviceId,obj);
|
|
236
452
|
},
|
|
237
453
|
|
|
454
|
+
handleFotaError : async (deviceId, error) => {
|
|
455
|
+
let object = {
|
|
456
|
+
error : error,
|
|
457
|
+
}
|
|
458
|
+
await $.db_fota.updateLog(deviceId,obj);
|
|
459
|
+
}
|
|
238
460
|
}
|
|
239
461
|
|
|
240
462
|
|