mqtt-devices-parser 1.0.10 → 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,15 @@
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
+
3
13
  ## 1.0.10
4
14
  src/db/data: handles json data
5
15
  - Adds updateJson call
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.10",
3
+ "version": "1.0.11",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
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
  }
@@ -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,65 +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
-
134
- if(new_app != null && semver.lt(app_version, new_app.app_version)) {
135
- console.log(new_app)
136
- console.log(`updating firmware of ${uid} to minor version ${new_app.app_version}`);
137
- let link = `${$.config.web.protocol}${$.config.web.domain}${$.config.web.fw_path}${new_app.filename}/download?token=${new_app.token}`;
138
- client.publish(mqtt_prefix+"/fw/fota/update/set",`{"url":"${link}"}`,{qos:2,retain:false});
139
- await $.db_data.update(project_name,device.id,"fota_tries",++fota_tries);
140
- }else{
141
- if(new_firmware != null && semver.lt(fw_version, new_firmware.fw_version)) {
142
- console.log(`updating firmware of ${uid} to major version ${new_firmware.fw_version}`);
143
- let link = `${$.config.web.protocol}${$.config.web.domain}${$.config.web.fw_path}${new_firmware.filename}/download?token=${new_firmware.token}`;
144
- client.publish(mqtt_prefix+"/fw/fota/update/set",`{"url":"${link}"}`,{qos:2,retain:false});
145
- await $.db_data.update(project_name,device.id,"fota_tries",++fota_tries);
146
- }
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..
147
172
  }
148
-
149
173
  }
150
174
 
151
175
  if(device.project_id != null && device.model_id != null){