mqtt-devices-parser 1.0.9 → 1.0.11

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 CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.11
4
+ index: MQTT
5
+ - makes mqtt client global,
6
+ - adds periodically call for FOTA update
7
+ models/devices.models: adds version fields to devices table
8
+ models/firmwares.models: adds new fields for firmware management
9
+ src/db/device: optimizes calls to manage devices table
10
+ src/device/device: Fota changes, db calls updated to match previous changes
11
+ Adds method to check FOTA updates. Doing 10 at time at each minute for now. Non configurable
12
+
13
+ ## 1.0.10
14
+ src/db/data: handles json data
15
+ - Adds updateJson call
16
+ - Adds addJsonLog
17
+ src/db/project: deals with settings
18
+ src/device/device: fixes fota fw link, stores settings on project table (twin model)
19
+
3
20
  ## 1.0.9
4
21
  - Adds method to delete logs older than 1 week
5
22
 
package/index.js CHANGED
@@ -14,6 +14,7 @@ $.db_device = require('./src/db/device');
14
14
  $.db_model = require('./src/db/model');
15
15
  $.db_firmware = require('./src/db/firmware');
16
16
  $.db_sensor = require('./src/db/sensor');
17
+ $.mqtt_client = null;
17
18
 
18
19
  const packageJson = require(__dirname+'/package.json');
19
20
  const packageVersion = packageJson.version;
@@ -44,7 +45,6 @@ var self = module.exports = {
44
45
  setInterval(async ()=>{
45
46
  await $.device.deleteLogs();
46
47
  },60*60*1000);
47
-
48
48
 
49
49
  return resolve();
50
50
  })
@@ -117,7 +117,8 @@ var self = module.exports = {
117
117
  function mqtt_connect(){
118
118
 
119
119
  const mqtt_prefix = $.config.mqtt.logs_path+"/"+$.config.mqtt.client;
120
- const client = mqtt.connect({
120
+ let checkFota = null;
121
+ $.mqtt_client = mqtt.connect({
121
122
  host : $.config.mqtt.host,
122
123
  port : $.config.mqtt.port,
123
124
  username : $.config.mqtt.user,
@@ -132,50 +133,58 @@ function mqtt_connect(){
132
133
  }
133
134
  });
134
135
 
135
- client.on("connect", () => {
136
+ $.mqtt_client.on("connect", () => {
136
137
 
137
- client.publish(mqtt_prefix+"/status","online",{qos:2,retain:true});
138
- client.publish(mqtt_prefix+"/version",packageVersion,{qos:2,retain:true});
138
+ $.mqtt_client.publish(mqtt_prefix+"/status","online",{qos:2,retain:true});
139
+ $.mqtt_client.publish(mqtt_prefix+"/version",packageVersion,{qos:2,retain:true});
139
140
 
140
141
  projects.map( (project)=>{
141
- client.subscribe(project+"/#", (err) => {});
142
+ $.mqtt_client.subscribe(project+"/#", (err) => {});
142
143
 
143
144
  for(let project in $.config.projects){
144
145
  if($.config.projects[project])
145
- client.publish(mqtt_prefix+"/"+project,"active",{qos:2,retain:true});
146
+ $.mqtt_client.publish(mqtt_prefix+"/"+project,"active",{qos:2,retain:true});
146
147
  else
147
- client.publish(mqtt_prefix+"/"+project,"deactive",{qos:2,retain:true});
148
+ $.mqtt_client.publish(mqtt_prefix+"/"+project,"deactive",{qos:2,retain:true});
148
149
  };
149
150
  })
150
151
  console.log(`MQTT connected to: ${$.config.mqtt.host}:${$.config.mqtt.port}`);
151
152
  projects.map( project=>{
152
153
  console.log("subscribing project:",project);
153
- client.subscribe(project+"/#")
154
+ $.mqtt_client.subscribe(project+"/#")
154
155
  })
156
+
157
+ checkFota = setInterval(async ()=>{
158
+ await $.device.checkFota();
159
+ },60*1000);
160
+
155
161
  });
156
162
 
157
- client.on("message", (topic, payload, packet) => {
163
+ $.mqtt_client.on("message", (topic, payload, packet) => {
158
164
  // payload is Buffer
159
- $.device.parseMessage(client,topic.toString(),payload.toString(),packet.retain);
165
+ $.device.parseMessage($.mqtt_client,topic.toString(),payload.toString(),packet.retain);
160
166
  });
161
167
 
162
- client.on("reconnect",()=>{
168
+ $.mqtt_client.on("reconnect",()=>{
163
169
  console.log("reconnect")
164
170
  });
165
171
 
166
- client.on("close",()=>{
172
+ $.mqtt_client.on("close",()=>{
167
173
  console.log("close")
174
+ checkFota = null;
168
175
  });
169
176
 
170
- client.on("offline",()=>{
177
+ $.mqtt_client.on("offline",()=>{
171
178
  console.log("offline")
179
+ checkFota = null;
172
180
  });
173
181
 
174
- client.on("disconnect",(packet)=>{
182
+ $.mqtt_client.on("disconnect",(packet)=>{
175
183
  console.log(packet)
184
+ checkFota = null;
176
185
  })
177
186
 
178
- client.on("error",(error)=>{
187
+ $.mqtt_client.on("error",(error)=>{
179
188
  console.log(error)
180
189
  })
181
190
  }
@@ -9,10 +9,6 @@ module.exports = (sequelize,DataTypes)=>{
9
9
  type: DataTypes.STRING,
10
10
  allowNull: true
11
11
  },
12
- project: { // deprecated
13
- type: DataTypes.STRING,
14
- allowNull: true
15
- },
16
12
  status: {
17
13
  type: DataTypes.STRING,
18
14
  allowNull: true
@@ -31,6 +27,22 @@ module.exports = (sequelize,DataTypes)=>{
31
27
  key: 'id'
32
28
  }
33
29
  },
30
+ version: {
31
+ type: DataTypes.STRING,
32
+ allowNull: true
33
+ },
34
+ app_version: {
35
+ type: DataTypes.STRING,
36
+ allowNull: true
37
+ },
38
+ release: {
39
+ type: DataTypes.STRING,
40
+ allowNull: true
41
+ },
42
+ fota_tries: {
43
+ type: DataTypes.STRING,
44
+ allowNull: true
45
+ },
34
46
  tech: {
35
47
  type: DataTypes.STRING,
36
48
  allowNull: true
@@ -10,7 +10,11 @@ module.exports = (sequelize,DataTypes)=>{
10
10
  allowNull: true,
11
11
  unique: true
12
12
  },
13
- fw_version: {
13
+ fw_version: { // deprecated
14
+ type: DataTypes.STRING,
15
+ allowNull: true
16
+ },
17
+ version: {
14
18
  type: DataTypes.STRING,
15
19
  allowNull: true
16
20
  },
@@ -18,7 +22,11 @@ module.exports = (sequelize,DataTypes)=>{
18
22
  type: DataTypes.STRING,
19
23
  allowNull: true
20
24
  },
21
- fw_release: {
25
+ fw_release: { // deprecated
26
+ type: DataTypes.STRING,
27
+ allowNull: true
28
+ },
29
+ release: {
22
30
  type: DataTypes.STRING,
23
31
  allowNull: true
24
32
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mqtt-devices-parser",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/src/db/data.js CHANGED
@@ -5,24 +5,24 @@ var self = module.exports = {
5
5
 
6
6
  checkEntry : async (table,deviceId)=>{
7
7
 
8
- return new Promise((resolve,reject) => {
9
-
10
- let query = "SELECT * FROM ?? where device_id = ?";
11
- let args = [table,deviceId];
12
- query = mysql.format(query,args);
13
-
14
- $.db.queryRow(query)
15
- .then( rows => {
16
- if(rows.length > 0)
17
- return resolve(rows[0]);
18
- else
19
- return resolve(null);
20
- })
21
- .catch( err => {
22
- console.log(err);
23
- return resolve(null);
24
- });
25
- });
8
+ return new Promise((resolve,reject) => {
9
+
10
+ let query = "SELECT * FROM ?? where device_id = ?";
11
+ let args = [table,deviceId];
12
+ query = mysql.format(query,args);
13
+
14
+ $.db.queryRow(query)
15
+ .then( rows => {
16
+ if(rows.length > 0)
17
+ return resolve(rows[0]);
18
+ else
19
+ return resolve(null);
20
+ })
21
+ .catch( err => {
22
+ console.log(err);
23
+ return resolve(null);
24
+ });
25
+ });
26
26
  },
27
27
 
28
28
  update : async (table, deviceId, topic, payload)=>{
@@ -54,41 +54,41 @@ var self = module.exports = {
54
54
  topic = topic.substring(index+1);
55
55
 
56
56
  if(db_columns.hasOwnProperty(key)){ // check if db has a column for this key
57
- // create JSON struct with the remaining topic
58
- // table is the table
59
- // key is the column
60
-
61
- // build object with the remaining topic and respective data
62
- if(typeof data === "object")
63
- obj[key] = JSON.stringify(parser.pathIntoObject(topic,JSON.stringify(data)))
64
- else
65
- obj[key] = JSON.stringify(parser.pathIntoObject(topic,data));
66
-
67
- let exists = await self.checkEntry(table,deviceId);
68
- if(!exists){
69
- obj['device_id'] = deviceId;
70
- obj['createdAt'] = moment().utc().format('YYYY-MM-DD HH:mm:ss');
71
- $.db.insert(table,obj)
72
- .then((rows)=>{
73
- return resolve(rows);
74
- })
75
- .catch((err)=>{
76
- console.log(err);
77
- return resolve();
78
- })
79
- }else{
80
- let filter = {
81
- device_id : deviceId
82
- }
83
- $.db.update(table,obj,filter)
84
- .then((rows)=>{
85
- return resolve(rows);
86
- })
87
- .catch((err)=>{
88
- console.log(err);
89
- return resolve();
90
- })
91
- }
57
+ // create JSON struct with the remaining topic
58
+ // table is the table
59
+ // key is the column
60
+
61
+ // build object with the remaining topic and respective data
62
+ if(typeof data === "object")
63
+ obj[key] = JSON.stringify(parser.pathIntoObject(topic,JSON.stringify(data)))
64
+ else
65
+ obj[key] = JSON.stringify(parser.pathIntoObject(topic,data));
66
+
67
+ let exists = await self.checkEntry(table,deviceId);
68
+ if(!exists){
69
+ obj['device_id'] = deviceId;
70
+ obj['createdAt'] = moment().utc().format('YYYY-MM-DD HH:mm:ss');
71
+ $.db.insert(table,obj)
72
+ .then((rows)=>{
73
+ return resolve(rows);
74
+ })
75
+ .catch((err)=>{
76
+ console.log(err);
77
+ return resolve();
78
+ })
79
+ }else{
80
+ let filter = {
81
+ device_id : deviceId
82
+ }
83
+ $.db.update(table,obj,filter)
84
+ .then((rows)=>{
85
+ return resolve(rows);
86
+ })
87
+ .catch((err)=>{
88
+ console.log(err);
89
+ return resolve();
90
+ })
91
+ }
92
92
 
93
93
  }else return resolve();
94
94
  }else{
@@ -115,7 +115,7 @@ var self = module.exports = {
115
115
  })
116
116
  }else{
117
117
  let filter = {
118
- device_id : deviceId
118
+ device_id : deviceId
119
119
  }
120
120
 
121
121
  $.db.update(table,obj,filter)
@@ -132,67 +132,184 @@ var self = module.exports = {
132
132
  })
133
133
  },
134
134
 
135
+ updateJson : async (table, deviceId, payload)=>{
136
+
137
+ return new Promise( async (resolve, reject) => {
138
+
139
+ if (!payload || typeof payload !== 'object')
140
+ return resolve();
141
+
142
+ let obj = {
143
+ updatedAt: moment().utc().format('YYYY-MM-DD HH:mm:ss'),
144
+ device_id: deviceId,
145
+ };
146
+
147
+ // Get columns info
148
+ const db_columns = $.models.get(table);
149
+ if (db_columns == null)
150
+ return resolve();
151
+
152
+ // Prepare data for insertion
153
+ for (let key in payload) {
154
+ if (db_columns.hasOwnProperty(key)) {
155
+ let value = payload[key];
156
+
157
+ // Convert object to JSON string if needed
158
+ if (typeof value === 'object') {
159
+ value = JSON.stringify(value);
160
+ }
161
+
162
+ obj[key] = value;
163
+ }
164
+ }
165
+
166
+ let exists = await self.checkEntry(table,deviceId);
167
+ if(!exists){
168
+ obj['createdAt'] = moment().utc().format('YYYY-MM-DD HH:mm:ss');
169
+ $.db.insert(table,obj)
170
+ .then((rows)=>{
171
+ return resolve(rows);
172
+ })
173
+ .catch((err)=>{
174
+ console.log(err);
175
+ return resolve();
176
+ })
177
+ }else{
178
+ let filter = {
179
+ device_id : deviceId
180
+ }
181
+ $.db.update(table,obj,filter)
182
+ .then((rows)=>{
183
+ return resolve(rows);
184
+ })
185
+ .catch((err)=>{
186
+ console.log(err);
187
+ return resolve();
188
+ })
189
+ }
190
+
191
+ return resolve();
192
+ });
193
+ },
194
+
135
195
  addLog : async (table, deviceId, topic, payload)=>{
136
196
 
137
197
  return new Promise((resolve,reject) => {
138
198
 
139
199
  if(!payload) return resolve();
140
200
 
141
- let data = null;
142
- // check if data is in JSON format
143
- try{
144
- data = JSON.parse(payload);
145
- }catch(e){
146
- data = payload;
147
- }
201
+ let data = null;
202
+ // check if data is in JSON format
203
+ try{
204
+ data = JSON.parse(payload);
205
+ }catch(e){
206
+ data = payload;
207
+ }
148
208
 
149
- let obj = {
150
- updatedAt : moment().utc().format('YYYY-MM-DD HH:mm:ss')
151
- }
209
+ let obj = {
210
+ updatedAt : moment().utc().format('YYYY-MM-DD HH:mm:ss')
211
+ }
152
212
 
153
- let db_columns = $.models.get(table);
154
- if(db_columns == null)
155
- return resolve();
213
+ let db_columns = $.models.get(table);
214
+ if(db_columns == null)
215
+ return resolve();
156
216
 
157
- let index = topic.indexOf("/");
217
+ let index = topic.indexOf("/");
158
218
 
159
- if(index > -1){ // check if topic has subtopics
160
- let key = topic.substring(0,index);
161
- topic = topic.substring(index+1);
219
+ if(index > -1){ // check if topic has subtopics
220
+ let key = topic.substring(0,index);
221
+ topic = topic.substring(index+1);
162
222
 
163
- if(db_columns.hasOwnProperty(key)){ // check if db has a column for this key
164
- // create JSON struct with the remaining topic
165
- // key is the column
223
+ if(db_columns.hasOwnProperty(key)){ // check if db has a column for this key
224
+ // create JSON struct with the remaining topic
225
+ // key is the column
166
226
 
167
- // build object with the remaining topic and respective data
168
- if(typeof data === "object")
169
- obj[key] = JSON.stringify(parser.pathIntoObject(topic,JSON.stringify(data)))
170
- else
171
- obj[key] = JSON.stringify(parser.pathIntoObject(topic,data));
227
+ // build object with the remaining topic and respective data
228
+ if(typeof data === "object")
229
+ obj[key] = JSON.stringify(parser.pathIntoObject(topic,JSON.stringify(data)))
230
+ else
231
+ obj[key] = JSON.stringify(parser.pathIntoObject(topic,data));
232
+
233
+ obj['device_id'] = deviceId;
234
+ obj['createdAt'] = moment().utc().format('YYYY-MM-DD HH:mm:ss');
235
+ $.db.insert(table,obj)
236
+ .then((rows)=>{
237
+ return resolve(rows);
238
+ })
239
+ .catch((err)=>{
240
+ console.log(err);
241
+ return resolve();
242
+ })
243
+
244
+ }else
245
+ return resolve();
246
+ }else{
172
247
 
173
- obj['device_id'] = deviceId;
174
- obj['createdAt'] = moment().utc().format('YYYY-MM-DD HH:mm:ss');
175
- $.db.insert(table,obj)
248
+ let key = topic;
249
+ if(db_columns.hasOwnProperty(key)){ // check if db has a column for this key
250
+ // build object with respective data
251
+ if(typeof data === "object")
252
+ obj[key] = JSON.stringify(data);
253
+ else
254
+ obj[key] = data;
176
255
 
256
+ obj['device_id'] = deviceId;
257
+ obj['createdAt'] = moment().utc().format('YYYY-MM-DD HH:mm:ss');
258
+ $.db.insert(table,obj)
259
+ .then((rows)=>{
260
+ return resolve(rows);
261
+ })
262
+ .catch((err)=>{
263
+ console.log(err);
264
+ return resolve();
265
+ })
266
+ }else
267
+ return resolve();
177
268
  }
178
- }else{
179
269
 
180
- let key = topic;
181
- if(db_columns.hasOwnProperty(key)){ // check if db has a column for this key
182
- // build object with respective data
183
- if(typeof data === "object")
184
- obj[key] = JSON.stringify(data);
185
- else
186
- obj[key] = data;
270
+ });
271
+ },
187
272
 
188
- obj['device_id'] = deviceId;
189
- obj['createdAt'] = moment().utc().format('YYYY-MM-DD HH:mm:ss');
190
- $.db.insert(table,obj);
273
+ addJsonLog: async (table, deviceId, dataObject) => {
274
+ return new Promise((resolve, reject) => {
275
+ if (!dataObject || typeof dataObject !== 'object')
276
+ return resolve();
277
+
278
+ let obj = {
279
+ updatedAt: moment().utc().format('YYYY-MM-DD HH:mm:ss'),
280
+ device_id: deviceId,
281
+ createdAt: moment().utc().format('YYYY-MM-DD HH:mm:ss')
282
+ };
283
+
284
+ // Get columns info
285
+ const db_columns = $.models.get(table);
286
+ if (db_columns == null)
287
+ return resolve();
288
+
289
+ // Prepare data for insertion
290
+ for (let key in dataObject) {
291
+ if (db_columns.hasOwnProperty(key)) {
292
+ let value = dataObject[key];
293
+
294
+ // Convert object to JSON string if needed
295
+ if (typeof value === 'object') {
296
+ value = JSON.stringify(value);
297
+ }
298
+
299
+ obj[key] = value;
300
+ }
191
301
  }
192
- }
193
302
 
194
- return resolve();
195
- });
303
+ //console.log("updateJSONlog")
304
+ $.db.insert(table, obj)
305
+ .then((rows)=>{
306
+ return resolve(rows);
307
+ })
308
+ .catch((err)=>{
309
+ console.log(err);
310
+ return resolve();
311
+ })
312
+ });
196
313
  },
197
314
 
198
315
  deleteLogs : async (table, deviceId, topic, payload)=>{
@@ -223,7 +340,13 @@ var self = module.exports = {
223
340
  obj['device_id'] = deviceId;
224
341
  obj['createdAt'] = moment().utc().format('YYYY-MM-DD HH:mm:ss');
225
342
  $.db.insert(table,obj)
226
-
343
+ .then((rows)=>{
344
+ return resolve(rows);
345
+ })
346
+ .catch((err)=>{
347
+ console.log(err);
348
+ return resolve();
349
+ })
227
350
  }
228
351
  }else{
229
352
 
@@ -237,7 +360,7 @@ var self = module.exports = {
237
360
 
238
361
  obj['device_id'] = deviceId;
239
362
  obj['createdAt'] = moment().utc().format('YYYY-MM-DD HH:mm:ss');
240
- $.db.insert(table,obj);
363
+ $.db.insert(table,obj)
241
364
  }
242
365
  }
243
366
 
package/src/db/device.js CHANGED
@@ -7,20 +7,62 @@ var self = module.exports = {
7
7
  return new Promise((resolve,reject) => {
8
8
 
9
9
  let query = "SELECT id,uid,project_id,model_id,status FROM ?? where uid = ?";
10
- let table = ["devices",uid];
11
- query = mysql.format(query,table);
12
-
13
- $.db.queryRow(query)
14
- .then( rows => {
15
- if(rows.length > 0)
16
- return resolve(rows[0]);
17
- else
18
- return resolve(null);
19
- })
20
- .catch( err => {
21
- console.log(err);
22
- return resolve(null);
23
- });
10
+ let table = ["devices",uid];
11
+ query = mysql.format(query,table);
12
+
13
+ $.db.queryRow(query)
14
+ .then( rows => {
15
+ if(rows.length > 0)
16
+ return resolve(rows[0]);
17
+ else
18
+ return resolve(null);
19
+ })
20
+ .catch( err => {
21
+ console.log(err);
22
+ return resolve(null);
23
+ });
24
+ });
25
+ },
26
+
27
+ listOnline : async ()=>{
28
+ return new Promise((resolve,reject) => {
29
+
30
+ let query = "SELECT * FROM ?? where status = ?";
31
+ let table = ["devices","online"];
32
+ query = mysql.format(query,table);
33
+
34
+ $.db.queryRow(query)
35
+ .then( rows => {
36
+ if(rows.length > 0)
37
+ return resolve(rows);
38
+ else
39
+ return resolve(null);
40
+ })
41
+ .catch( err => {
42
+ console.log(err);
43
+ return resolve(null);
44
+ });
45
+ });
46
+ },
47
+
48
+ getField : async (id,column)=>{
49
+ return new Promise((resolve,reject) => {
50
+
51
+ let query = "SELECT ?? FROM devices where id = ?";
52
+ let table = [column,id];
53
+ query = mysql.format(query,table);
54
+
55
+ $.db.queryRow(query)
56
+ .then( rows => {
57
+ if(rows.length > 0)
58
+ return resolve(rows[0]);
59
+ else
60
+ return resolve(null);
61
+ })
62
+ .catch( err => {
63
+ console.log(err);
64
+ return resolve(null);
65
+ });
24
66
  });
25
67
  },
26
68
 
@@ -33,101 +75,37 @@ var self = module.exports = {
33
75
  updatedAt : moment().utc().format('YYYY-MM-DD HH:mm:ss')
34
76
  }
35
77
 
36
- $.db.insert("devices",obj)
37
- .then (rows => {
38
- return resolve(rows[0]);
39
- })
40
- .catch(error => {
41
- return reject(error);
42
- });
78
+ $.db.insert("devices",obj)
79
+ .then (rows => {
80
+ return resolve(rows[0]);
81
+ })
82
+ .catch(error => {
83
+ return reject(error);
84
+ });
43
85
  });
44
- },
86
+ },
45
87
 
46
- updateStatus : async(uid,status)=>{
88
+ update : async(id,column,value)=>{
47
89
  return new Promise((resolve,reject) => {
48
90
 
49
- let obj = {
50
- status : status,
51
- updatedAt : moment().utc().format('YYYY-MM-DD HH:mm:ss')
52
- };
53
-
54
- let filter = {
55
- uid : uid,
56
- };
57
-
58
- $.db.update("devices",obj,filter)
59
- .then (rows => {
60
- return resolve(rows);
61
- })
62
- .catch(error => {
63
- return reject(error);
64
- });
65
- });
66
- },
91
+ let obj = {
92
+ updatedAt : moment().utc().format('YYYY-MM-DD HH:mm:ss')
93
+ };
67
94
 
68
- updateTech : async(uid,tech)=>{
69
- return new Promise((resolve,reject) => {
95
+ obj[column] = value;
70
96
 
71
- let obj = {
72
- tech : tech,
73
- updatedAt : moment().utc().format('YYYY-MM-DD HH:mm:ss')
74
- };
75
-
76
- let filter = {
77
- uid : uid,
78
- };
79
-
80
- $.db.update("devices",obj,filter)
81
- .then (rows => {
82
- return resolve(rows);
83
- })
84
- .catch(error => {
85
- return reject(error);
86
- });
87
- });
88
- },
97
+ let filter = {
98
+ id : id,
99
+ };
89
100
 
90
- updateProject : async(uid,project_id)=>{
91
- return new Promise((resolve,reject) => {
92
-
93
- let obj = {
94
- project_id : project_id,
95
- updatedAt : moment().utc().format('YYYY-MM-DD HH:mm:ss')
96
- };
97
-
98
- let filter = {
99
- uid : uid,
100
- };
101
-
102
- $.db.update("devices",obj,filter)
103
- .then (rows => {
104
- return resolve(rows);
105
- })
106
- .catch(error => {
107
- return reject(error);
101
+ $.db.update("devices",obj,filter)
102
+ .then (rows => {
103
+ return resolve(rows);
104
+ })
105
+ .catch(error => {
106
+ return reject(error);
108
107
  });
109
- });
110
- },
111
-
112
- updateModel : async(uid,model_id)=>{
113
- return new Promise((resolve,reject) => {
108
+ });
109
+ },
114
110
 
115
- let obj = {
116
- model_id : model_id,
117
- updatedAt : moment().utc().format('YYYY-MM-DD HH:mm:ss')
118
- };
119
-
120
- let filter = {
121
- uid : uid,
122
- };
123
-
124
- $.db.update("devices",obj,filter)
125
- .then (rows => {
126
- return resolve(rows);
127
- })
128
- .catch(error => {
129
- return reject(error);
130
- });
131
- });
132
- },
133
111
  }
package/src/db/project.js CHANGED
@@ -20,8 +20,7 @@ var self = module.exports = {
20
20
  return resolve(null);
21
21
  })
22
22
  .catch( err => {
23
- console.log(err);
24
- return resolve(null);
23
+ return reject(err);
25
24
  });
26
25
  });
27
26
  },
@@ -42,8 +41,7 @@ var self = module.exports = {
42
41
  return resolve(null);
43
42
  })
44
43
  .catch( err => {
45
- console.log(err);
46
- return resolve(null);
44
+ return reject(err);
47
45
  });
48
46
  });
49
47
  },
@@ -61,8 +59,7 @@ var self = module.exports = {
61
59
  return resolve(rows);
62
60
  })
63
61
  .catch( err => {
64
- console.log(err);
65
- return resolve(null);
62
+ return reject(null);
66
63
  });
67
64
  });
68
65
  },
@@ -88,4 +85,49 @@ var self = module.exports = {
88
85
  });
89
86
  },
90
87
 
88
+ getSettings : async(project,deviceId)=>{
89
+
90
+ return new Promise((resolve,reject) => {
91
+
92
+ let query = "SELECT settings FROM ?? where device_id = ?";
93
+ let table = [project, deviceId];
94
+ query = mysql.format(query,table);
95
+
96
+ $.db.queryRow(query)
97
+ .then( rows => {
98
+ if(rows?.length > 0)
99
+ return resolve(rows[0].settings);
100
+ else
101
+ return resolve(null);
102
+ })
103
+ .catch( err => {
104
+ return reject(err);
105
+ });
106
+ });
107
+ },
108
+
109
+ updateSettings : async(project, settings, deviceId)=>{
110
+
111
+ return new Promise((resolve,reject) => {
112
+ let obj = {
113
+ settings : settings,
114
+ updatedAt : moment().utc().format('YYYY-MM-DD HH:mm:ss')
115
+ }
116
+
117
+ let filter = {
118
+ device_id : deviceId
119
+ };
120
+
121
+ resolve(null)
122
+
123
+ $.db.update(project,obj,filter)
124
+ .then (rows => {
125
+ return resolve(rows[0]);
126
+ })
127
+ .catch(error => {
128
+ return reject(error);
129
+ });
130
+
131
+ });
132
+ },
91
133
  }
@@ -51,6 +51,64 @@ var self = module.exports = {
51
51
 
52
52
  },
53
53
 
54
+ checkFota : async ()=>{
55
+
56
+ const devices = await $.db_device.listOnline();
57
+
58
+ const batchSize = 10;
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) => {
62
+
63
+ if (device.release == null || device.release === "critical")
64
+ {
65
+ // don't update
66
+ return;
67
+ }
68
+
69
+ if (device.fota_tries > 3)
70
+ {
71
+ return;
72
+ }
73
+
74
+ let new_firmware = await $.db_firmware.getLatestFWVersion(device.model_id,device.release);
75
+ let new_app = await $.db_firmware.getLatestAppVersion(device.model_id,device.release);
76
+ if(new_firmware == null || new_app == null)
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
+ }));
103
+
104
+ // Wait for 1 minute after processing each batch
105
+ if (i + batchSize < devices.length) {
106
+ await new Promise(resolve => setTimeout(resolve, 60000));
107
+ }
108
+ }
109
+
110
+ },
111
+
54
112
  parseMessage : async (client,topic,payload,retain)=>{
55
113
 
56
114
  let topic_bck = topic;
@@ -87,63 +145,31 @@ var self = module.exports = {
87
145
  let res = await $.db_project.getByName(project_name);
88
146
  let project_id = res?.id;
89
147
  if(project_id != null && project_id != device?.project_id)
90
- $.db_device.updateProject(uid,project_id);
148
+ $.db_device.update(device.id,"project_id",project_id);
91
149
 
92
- if(topic.endsWith("status")){
150
+ if(topic === "status"){
93
151
  if(payload == "online" || payload == "offline")
94
- await $.db_device.updateStatus(uid,payload);
95
- console.log(project_name,uid,payload)
96
- }else if(topic.endsWith("model")){
152
+ await $.db_device.update(device.id,"status",payload);
153
+ }else if(topic === "model"){
97
154
  let res = await $.db_model.getByName(payload);
98
155
  let model_id = res?.id;
99
156
 
100
157
  if(model_id != null){
101
- let res = await $.db_device.updateModel(uid,model_id);
158
+ let res = await $.db_device.update(device.id,"model_id",model_id);
102
159
  }
103
- }else if(topic.endsWith("tech")){
104
- await $.db_device.updateTech(uid,payload);
105
- }else if(topic.endsWith("fw_version")){
106
- let fw_version = await $.db.getFieldFromDeviceId(project_name,device.id,"fw_version");
107
- if(fw_version != payload)
108
- await $.db_data.update(project_name,device.id,"fota_tries",1); // ! 0 is not working..
109
- }else if(topic.endsWith("app_version")){
110
- let app_version = await $.db.getFieldFromDeviceId(project_name,device.id,"app_version");
111
- if(app_version != payload)
112
- await $.db_data.update(project_name,device.id,"fota_tries",1); // ! 0 is not working..
113
- }else if(topic.endsWith("uptime")){ // !! maybe this topic should be change for something ending in fota
114
- // check fw version
115
- // get current fw and app version
116
- let release = await $.db.getFieldFromDeviceId(project_name,device.id,"fw_release");
117
- if(release == null || release == "critical"){
118
- // don't update
119
- return;
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..
120
167
  }
121
- let fota_tries = await $.db.getFieldFromDeviceId(project_name,device.id,"fota_tries");
122
- if(fota_tries > 3)
123
- return;
124
-
125
- let fw_version = await $.db.getFieldFromDeviceId(project_name,device.id,"fw_version");
126
- let app_version = await $.db.getFieldFromDeviceId(project_name,device.id,"app_version");
127
- let new_firmware = await $.db_firmware.getLatestFWVersion(device.model_id,release);
128
- let new_app = await $.db_firmware.getLatestAppVersion(device.model_id,release);
129
- if(new_firmware == null || new_app == null)
130
- return;
131
-
132
- let mqtt_prefix = `${project_name}/${uid}`;
133
- let link = `${$.config.web.protocol}${$.config.web.domain}${$.config.web.fw_path}${new_firmware.filename}/download?token=${new_firmware.token}`;
134
-
135
- if(new_firmware != null && semver.lt(fw_version, new_firmware.fw_version)) {
136
- console.log(`updating firmware of ${uid} to ${new_firmware.fw_version}`);
137
- client.publish(mqtt_prefix+"/fw/fota/update/set",`{"url":"${link}"}`,{qos:2,retain:false});
138
- await $.db_data.update(project_name,device.id,"fota_tries",++fota_tries);
139
- }else{
140
- if(new_app != null && semver.lt(app_version, new_app.app_version)) {
141
- console.log(`updating firmware of ${uid} to ${new_app.app_version}`);
142
- client.publish(mqtt_prefix+"/fw/fota/update/set",`{"url":"${link}"}`,{qos:2,retain:false});
143
- await $.db_data.update(project_name,device.id,"fota_tries",++fota_tries);
144
- }
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..
145
172
  }
146
-
147
173
  }
148
174
 
149
175
  if(device.project_id != null && device.model_id != null){
@@ -153,6 +179,55 @@ var self = module.exports = {
153
179
  }
154
180
  }
155
181
 
182
+ // store remote device settings on project table - twin model
183
+ if(topic.endsWith("/set") && payload != "" ){
184
+
185
+ let route = topic.split("/");
186
+
187
+ if(route == null){
188
+ console.log("topic invalid:",topic);
189
+ return;
190
+ }
191
+ // get settings
192
+ let settings = await $.db_project.getSettings(project_name,device.id);
193
+ let obj = settings;
194
+
195
+ if(obj == null){
196
+ console.log("no settings available for deviceId:",device.id)
197
+ obj = {};
198
+ }
199
+ // Traverse through all route parts except the last one
200
+ route.slice(0, -1).forEach(property => {
201
+ if (!obj.hasOwnProperty(property) ||
202
+ ( obj.hasOwnProperty(property) && typeof obj[property] !== 'object'))
203
+ {
204
+ obj[property] = {}; // create nested object if missing or not an object
205
+ }
206
+ obj = obj[property]; // go deeper
207
+ })
208
+
209
+ let data = {};
210
+ try{
211
+ data = JSON.parse(payload)
212
+ }catch(error){}
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
+ }
222
+
223
+ // update on device fw settings
224
+ try{
225
+ await $.db_project.updateSettings(project_name,JSON.stringify(settings),device.id);
226
+ }catch(error){
227
+ console.log(error);
228
+ }
229
+ }
230
+
156
231
  if(project[project_name]){
157
232
  project[project_name].module.parseMessage(client,project_name,device,topic,payload,retain,()=>{});
158
233
  }