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 +17 -0
- package/index.js +25 -16
- package/models/devices.models.js +16 -4
- package/models/firmwares.models.js +10 -2
- package/package.json +1 -1
- package/src/db/data.js +221 -98
- package/src/db/device.js +80 -102
- package/src/db/project.js +48 -6
- package/src/device/device.js +123 -48
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
|
-
|
|
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
|
-
|
|
136
|
+
$.mqtt_client.on("connect", () => {
|
|
136
137
|
|
|
137
|
-
|
|
138
|
-
|
|
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
|
-
|
|
142
|
+
$.mqtt_client.subscribe(project+"/#", (err) => {});
|
|
142
143
|
|
|
143
144
|
for(let project in $.config.projects){
|
|
144
145
|
if($.config.projects[project])
|
|
145
|
-
|
|
146
|
+
$.mqtt_client.publish(mqtt_prefix+"/"+project,"active",{qos:2,retain:true});
|
|
146
147
|
else
|
|
147
|
-
|
|
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
|
-
|
|
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
|
-
|
|
163
|
+
$.mqtt_client.on("message", (topic, payload, packet) => {
|
|
158
164
|
// payload is Buffer
|
|
159
|
-
$.device.parseMessage(
|
|
165
|
+
$.device.parseMessage($.mqtt_client,topic.toString(),payload.toString(),packet.retain);
|
|
160
166
|
});
|
|
161
167
|
|
|
162
|
-
|
|
168
|
+
$.mqtt_client.on("reconnect",()=>{
|
|
163
169
|
console.log("reconnect")
|
|
164
170
|
});
|
|
165
171
|
|
|
166
|
-
|
|
172
|
+
$.mqtt_client.on("close",()=>{
|
|
167
173
|
console.log("close")
|
|
174
|
+
checkFota = null;
|
|
168
175
|
});
|
|
169
176
|
|
|
170
|
-
|
|
177
|
+
$.mqtt_client.on("offline",()=>{
|
|
171
178
|
console.log("offline")
|
|
179
|
+
checkFota = null;
|
|
172
180
|
});
|
|
173
181
|
|
|
174
|
-
|
|
182
|
+
$.mqtt_client.on("disconnect",(packet)=>{
|
|
175
183
|
console.log(packet)
|
|
184
|
+
checkFota = null;
|
|
176
185
|
})
|
|
177
186
|
|
|
178
|
-
|
|
187
|
+
$.mqtt_client.on("error",(error)=>{
|
|
179
188
|
console.log(error)
|
|
180
189
|
})
|
|
181
190
|
}
|
package/models/devices.models.js
CHANGED
|
@@ -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
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
209
|
+
let obj = {
|
|
210
|
+
updatedAt : moment().utc().format('YYYY-MM-DD HH:mm:ss')
|
|
211
|
+
}
|
|
152
212
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
213
|
+
let db_columns = $.models.get(table);
|
|
214
|
+
if(db_columns == null)
|
|
215
|
+
return resolve();
|
|
156
216
|
|
|
157
|
-
|
|
217
|
+
let index = topic.indexOf("/");
|
|
158
218
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
|
|
181
|
-
|
|
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
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
88
|
+
update : async(id,column,value)=>{
|
|
47
89
|
return new Promise((resolve,reject) => {
|
|
48
90
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
69
|
-
return new Promise((resolve,reject) => {
|
|
95
|
+
obj[column] = value;
|
|
70
96
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|
package/src/device/device.js
CHANGED
|
@@ -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.
|
|
148
|
+
$.db_device.update(device.id,"project_id",project_id);
|
|
91
149
|
|
|
92
|
-
if(topic
|
|
150
|
+
if(topic === "status"){
|
|
93
151
|
if(payload == "online" || payload == "offline")
|
|
94
|
-
await $.db_device.
|
|
95
|
-
|
|
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.
|
|
158
|
+
let res = await $.db_device.update(device.id,"model_id",model_id);
|
|
102
159
|
}
|
|
103
|
-
}else if(topic
|
|
104
|
-
await $.db_device.
|
|
105
|
-
}else if(topic
|
|
106
|
-
|
|
107
|
-
if(
|
|
108
|
-
await $.
|
|
109
|
-
|
|
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
|
-
|
|
122
|
-
if(
|
|
123
|
-
|
|
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
|
}
|