@ncd-io/node-red-enterprise-sensors 1.4.7 → 1.6.1
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/data/configuration_map.json +5320 -0
- package/data/sensor_configs.json +1 -0
- package/data/sensor_type_map.json +1117 -0
- package/lib/WirelessGateway.js +975 -595
- package/package.json +1 -1
- package/wireless.html +425 -87
- package/wireless.js +1014 -62
package/wireless.js
CHANGED
|
@@ -5,7 +5,10 @@ const Queue = require("promise-queue");
|
|
|
5
5
|
const events = require("events");
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const path = require('path');
|
|
8
|
-
const home_dir = require('os').homedir
|
|
8
|
+
const home_dir = require('os').homedir;
|
|
9
|
+
const { isDeepStrictEqual } = require('util');
|
|
10
|
+
|
|
11
|
+
|
|
9
12
|
module.exports = function(RED) {
|
|
10
13
|
var gateway_pool = {};
|
|
11
14
|
function NcdGatewayConfig(config){
|
|
@@ -21,9 +24,36 @@ module.exports = function(RED) {
|
|
|
21
24
|
this._emitter = new events.EventEmitter();
|
|
22
25
|
this.on = (e,c) => this._emitter.on(e, c);
|
|
23
26
|
|
|
27
|
+
const config_file_location = home_dir()+'/.node-red/node_modules/@ncd-io/node-red-enterprise-sensors/data/sensor_configs.json';
|
|
28
|
+
const configuration_map_location = home_dir()+'/.node-red/node_modules/@ncd-io/node-red-enterprise-sensors/data/configuration_map.json';
|
|
29
|
+
const sensor_type_map_location = home_dir()+'/.node-red/node_modules/@ncd-io/node-red-enterprise-sensors/data/sensor_type_map.json';
|
|
30
|
+
|
|
31
|
+
this.config_node_capable = [114];
|
|
32
|
+
|
|
24
33
|
// comms_timer object var added to clear the time to prevent issues with rapid redeploy
|
|
25
34
|
this.comms_timer;
|
|
26
35
|
|
|
36
|
+
// this.sensor_configs = {};
|
|
37
|
+
try {
|
|
38
|
+
this.sensor_configs = JSON.parse(fs.readFileSync(config_file_location,));
|
|
39
|
+
} catch(err){
|
|
40
|
+
this.sensor_configs = {};
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
this.configuration_map = JSON.parse(fs.readFileSync(configuration_map_location,));
|
|
45
|
+
} catch(err){
|
|
46
|
+
this.configuration_map = {};
|
|
47
|
+
console.log('Error reading configuration list');
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
this.sensor_type_map = JSON.parse(fs.readFileSync(sensor_type_map_location,));
|
|
52
|
+
} catch(err){
|
|
53
|
+
this.sensor_type_map = {};
|
|
54
|
+
console.log('Error reading sensor type map file');
|
|
55
|
+
};
|
|
56
|
+
|
|
27
57
|
if(config.comm_type == 'serial'){
|
|
28
58
|
this.key = config.port;
|
|
29
59
|
}
|
|
@@ -31,6 +61,16 @@ module.exports = function(RED) {
|
|
|
31
61
|
this.key = config.ip_address+":"+config.tcp_port;
|
|
32
62
|
}
|
|
33
63
|
|
|
64
|
+
this.store_sensor_configs = function(sensor_configs){
|
|
65
|
+
fs.writeFile(config_file_location, sensor_configs, function(err){
|
|
66
|
+
if(err){
|
|
67
|
+
return err;
|
|
68
|
+
}else{
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
|
|
34
74
|
var node = this;
|
|
35
75
|
|
|
36
76
|
node.is_config = 3;
|
|
@@ -96,11 +136,113 @@ module.exports = function(RED) {
|
|
|
96
136
|
}
|
|
97
137
|
// Event listener to make sure this only triggers once no matter how many gateway nodes there are
|
|
98
138
|
node.gateway.on('sensor_mode', (d) => {
|
|
99
|
-
if(d.mode == "FLY"){
|
|
100
|
-
if(Object.hasOwn(node.sensor_list, d.mac) && Object.hasOwn(node.sensor_list[d.mac], 'update_request')){
|
|
139
|
+
if(d.mode == "FLY" || d.mode == "OTF"){
|
|
140
|
+
if(Object.hasOwn(node.sensor_list, d.mac) && Object.hasOwn(node.sensor_list[d.mac], 'update_request') && d.mode == "FLY"){
|
|
101
141
|
node.request_manifest(d.mac);
|
|
102
|
-
}
|
|
103
|
-
|
|
142
|
+
}else if(node.config_node_capable.includes(d.type)){
|
|
143
|
+
// API CONFIGURATION NODE
|
|
144
|
+
let values = d.reported_config.machine_values;
|
|
145
|
+
if(Object.hasOwn(values, 'uptime_counter')) delete values.uptime_counter;
|
|
146
|
+
if(Object.hasOwn(values, 'tx_lifetime_counter')) delete values.tx_lifetime_counter;
|
|
147
|
+
if(Object.hasOwn(values, 'reserved')) delete values.reserved;
|
|
148
|
+
|
|
149
|
+
let store_flag = false;
|
|
150
|
+
|
|
151
|
+
if(!Object.hasOwn(node.sensor_configs, d.mac)){
|
|
152
|
+
node.sensor_configs[d.mac] = {};
|
|
153
|
+
store_flag = true;
|
|
154
|
+
}
|
|
155
|
+
// Store hardware_id outside of reported_configs
|
|
156
|
+
if(!Object.hasOwn(node.sensor_configs[d.mac], 'hardware_id') && Object.hasOwn(values, 'hardware_id')){
|
|
157
|
+
node.sensor_configs[d.mac].hardware_id = values.hardware_id;
|
|
158
|
+
store_flag = true;
|
|
159
|
+
}
|
|
160
|
+
if(Object.hasOwn(values, 'hardware_id')) delete values.hardware_id;
|
|
161
|
+
// Loop through and translate and validate values.
|
|
162
|
+
// We want to allow passing in integers instead of byte arrays etc.
|
|
163
|
+
// This the FLY so we don't need to validate.
|
|
164
|
+
values.network_id = config.pan_id;
|
|
165
|
+
if(Object.hasOwn(d, 'nodeId')){
|
|
166
|
+
values.node_id = d.nodeId;
|
|
167
|
+
}
|
|
168
|
+
for(let key in values){
|
|
169
|
+
if(Object.hasOwn(node.sensor_type_map, d.type) && Object.hasOwn(node.sensor_type_map[d.type], 'configs') && Object.hasOwn(node.sensor_type_map[d.type].configs, key)){
|
|
170
|
+
let map_key = node.sensor_type_map[d.type].configs[key];
|
|
171
|
+
if(Object.hasOwn(node.configuration_map, map_key) && Object.hasOwn(node.configuration_map[map_key], 'validator')){
|
|
172
|
+
if(Object.hasOwn(node.configuration_map[map_key].validator, 'type')){
|
|
173
|
+
switch(node.configuration_map[map_key].validator.type){
|
|
174
|
+
// case 'uint8':
|
|
175
|
+
// console.log(key);
|
|
176
|
+
// console.log(values[key]);
|
|
177
|
+
// values[key] = values[key].reduce(msbLsb);
|
|
178
|
+
// break;
|
|
179
|
+
case 'uint16':
|
|
180
|
+
values[key] = values[key].reduce(msbLsb);
|
|
181
|
+
break;
|
|
182
|
+
case 'uint24':
|
|
183
|
+
values[key] = values[key].reduce(msbLsb);
|
|
184
|
+
break;
|
|
185
|
+
case 'uint32':
|
|
186
|
+
values[key] = values[key].reduce(msbLsb);
|
|
187
|
+
break;
|
|
188
|
+
case 'hexString':
|
|
189
|
+
values[key] = values[key].toLowerCase();
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// If object has no reported configs, instantiate them
|
|
197
|
+
if(!Object.hasOwn(node.sensor_configs[d.mac], 'reported_configs')){
|
|
198
|
+
node.sensor_configs[d.mac].reported_configs = {};
|
|
199
|
+
store_flag = true;
|
|
200
|
+
}
|
|
201
|
+
// If object has no desired configs, add them
|
|
202
|
+
if(!Object.hasOwn(node.sensor_configs[d.mac], 'desired_configs')){
|
|
203
|
+
node.sensor_configs[d.mac].desired_configs = values;
|
|
204
|
+
store_flag = true;
|
|
205
|
+
}
|
|
206
|
+
if(!Object.hasOwn(node.sensor_configs[d.mac], 'type')){
|
|
207
|
+
node.sensor_configs[d.mac].type = d.type;
|
|
208
|
+
store_flag = true;
|
|
209
|
+
}else if(node.sensor_configs[d.mac].type != d.type){
|
|
210
|
+
// This code is only called when the type doesn't match what the sensor reports, only foreseeable if user swaps sensor modules OR preloads configs for wrong sensor type
|
|
211
|
+
delete node.sensor_configs[d.mac].desired_configs;
|
|
212
|
+
node.sensor_configs[d.mac].type = d.type;
|
|
213
|
+
node._emitter.emit('config_node_error', {topic: 'sensor_type_error', payload: {'error': "Sensor type used for desired configs does not match sensor type reported by sensor. Deleting desired configs"}, addr: d.mac, time: Date.now()});
|
|
214
|
+
store_flag = true;
|
|
215
|
+
}
|
|
216
|
+
if(!isDeepStrictEqual(node.sensor_configs[d.mac].reported_configs, values)){
|
|
217
|
+
// Values are different, update the stored configs and write to file
|
|
218
|
+
node.sensor_configs[d.mac].reported_configs = values;
|
|
219
|
+
// If reported configs change, but the auto config does not control configs, update automatically
|
|
220
|
+
// Will duplicate setting desired configs on first run, but only once or if user clear desired_configs
|
|
221
|
+
if(!Object.hasOwn(node.sensor_configs[d.mac], 'api_config_override')){
|
|
222
|
+
node.sensor_configs[d.mac].desired_configs = values;
|
|
223
|
+
}
|
|
224
|
+
store_flag = true;
|
|
225
|
+
node._emitter.emit('config_node_msg', {topic: 'sensor_configs_update', payload: node.sensor_configs[d.mac], addr: d.mac, time: Date.now()});
|
|
226
|
+
// node.send({topic: 'sensor_configs_update', payload: node.sensor_configs[d.mac], time: Date.now()});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if(Object.hasOwn(node.sensor_configs[d.mac], 'desired_configs') && d.mode != "OTF"){
|
|
230
|
+
let required_configs = this.get_required_configs(node.sensor_configs[d.mac].desired_configs, node.sensor_configs[d.mac].reported_configs);
|
|
231
|
+
if(Object.keys(required_configs).length !== 0){
|
|
232
|
+
node.sensor_configs[d.mac].temp_required_configs = required_configs;
|
|
233
|
+
store_flag = true;
|
|
234
|
+
var tout = setTimeout(() => {
|
|
235
|
+
this._send_otn_request(d);
|
|
236
|
+
}, 100);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if(store_flag){
|
|
240
|
+
node.store_sensor_configs(JSON.stringify(node.sensor_configs));
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}else if(d.mode == "OTN" && Object.hasOwn(node.sensor_configs, d.mac) && Object.hasOwn(node.sensor_configs[d.mac], 'temp_required_configs')){
|
|
244
|
+
node.configure(d);
|
|
245
|
+
}
|
|
104
246
|
});
|
|
105
247
|
node.gateway.on('manifest_received', (manifest_data) => {
|
|
106
248
|
// read manifest length is 37. Could use the same event for both
|
|
@@ -147,7 +289,6 @@ module.exports = function(RED) {
|
|
|
147
289
|
}else{
|
|
148
290
|
manifest_data.enter_ota_success = false;
|
|
149
291
|
}
|
|
150
|
-
console.log(name);
|
|
151
292
|
} else{
|
|
152
293
|
if(manifest_data.enter_ota_success){
|
|
153
294
|
// enter ota mode
|
|
@@ -185,6 +326,187 @@ module.exports = function(RED) {
|
|
|
185
326
|
});
|
|
186
327
|
}
|
|
187
328
|
};
|
|
329
|
+
|
|
330
|
+
this.get_required_configs = function(desired_configs, reported_configs){
|
|
331
|
+
const mismatched = {};
|
|
332
|
+
for (const key in desired_configs) {
|
|
333
|
+
if (reported_configs.hasOwnProperty(key)) {
|
|
334
|
+
if (!isDeepStrictEqual(desired_configs[key], reported_configs[key])) {
|
|
335
|
+
// if (desired_configs[key] !== reported_configs[key]) {
|
|
336
|
+
mismatched[key] = desired_configs[key];
|
|
337
|
+
};
|
|
338
|
+
};
|
|
339
|
+
};
|
|
340
|
+
return mismatched;
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
// TODO consider adding logic for if only 1 config to go out, skip OTN request
|
|
344
|
+
this.configure = function(sensor){
|
|
345
|
+
return new Promise((top_fulfill, top_reject) => {
|
|
346
|
+
var success = {};
|
|
347
|
+
setTimeout(() => {
|
|
348
|
+
var tout = setTimeout(() => {
|
|
349
|
+
// TODO handle timeout and send emitters
|
|
350
|
+
node._emitter.emit('config_node_msg', {topic: 'Config Results', payload: success, addr: sensor.mac, time: Date.now()});
|
|
351
|
+
// node.status(modes.PGM_ERR);
|
|
352
|
+
// node.send({topic: 'Config Results', payload: success, time: Date.now(), addr: sensor.mac});
|
|
353
|
+
}, 60000);
|
|
354
|
+
// node.status(modes.PGM_NOW);
|
|
355
|
+
var mac = sensor.mac;
|
|
356
|
+
var promises = {};
|
|
357
|
+
var reboot = false;
|
|
358
|
+
|
|
359
|
+
let configs = node.sensor_configs[sensor.mac].temp_required_configs;
|
|
360
|
+
for (const key in configs) {
|
|
361
|
+
let config_obj = node.configuration_map[node.sensor_type_map[sensor.type].configs[key]];
|
|
362
|
+
if(Object.hasOwn(config_obj, 'validator') && Object.hasOwn(config_obj.validator, 'type')){
|
|
363
|
+
if(key == 'node_id' || key == 'delay'){
|
|
364
|
+
// TODO expand this logic in the future for cases where sensor doesn't report delay.
|
|
365
|
+
if(Object.hasOwn(configs, 'node_id') && Object.hasOwn(configs, 'delay') && Object.hasOwn(config_obj, "delay") && Object.hasOwn(config_obj, "node_id")){
|
|
366
|
+
// If the sensor has and should have node id and delay (standard sensor)
|
|
367
|
+
promises['node_id_and_delay'] = node.gateway.config_node_id_and_delay(sensor.mac, parseInt(configs['node_id']), parseInt(configs['delay']));
|
|
368
|
+
}else if(Object.hasOwn(configs, 'node_id') && Object.hasOwn(config_obj, "node_id") && !Object.hasOwn(config_obj, "delay")){
|
|
369
|
+
// If the sensor has and should have node id but should not have delay (special sensor)
|
|
370
|
+
// We will ignore delay setting in this case and set it to 0
|
|
371
|
+
promises['node_id_and_delay'] = node.gateway.config_node_id_and_delay(sensor.mac, parseInt(configs['node_id']), 0);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
switch(config_obj.validator.type){
|
|
375
|
+
case 'hexString':
|
|
376
|
+
console.log('Configuring hexString '+key+' to '+configs[key] + ' eval as '+parseInt(configs[key], 16));
|
|
377
|
+
promises[key] = node.gateway[config_obj.call](sensor.mac, parseInt(configs[key], 16));
|
|
378
|
+
break;
|
|
379
|
+
default:
|
|
380
|
+
promises[key] = node.gateway[config_obj.call](sensor.mac, parseInt(configs[key]));
|
|
381
|
+
break;
|
|
382
|
+
}
|
|
383
|
+
}else{
|
|
384
|
+
promises[key] = node.gateway[config_obj.call](sensor.mac, parseInt(configs[key]));
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// These sensors listed in original_otf_devices use a different OTF code.
|
|
389
|
+
let original_otf_devices = [53, 80, 81, 82, 83, 84, 87, 101, 102, 103, 110, 111, 112, 114, 117, 180, 181, 518, 519, 520, 538];
|
|
390
|
+
// If we changed the network ID reboot the sensor to take effect.
|
|
391
|
+
// TODO if we add the encryption key command to node-red we need to reboot for it as well.
|
|
392
|
+
if(reboot){
|
|
393
|
+
promises.reboot_sensor = node.gateway.config_reboot_sensor(mac);
|
|
394
|
+
} else {
|
|
395
|
+
if(original_otf_devices.includes(sensor.type)){
|
|
396
|
+
promises.exit_otn_mode = node.gateway.config_exit_otn_mode(mac);
|
|
397
|
+
}else{
|
|
398
|
+
promises.config_exit_otn_mode_common = node.gateway.config_exit_otn_mode_common(mac);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
promises.finish = new Promise((fulfill, reject) => {
|
|
402
|
+
node.gateway.queue.add(() => {
|
|
403
|
+
return new Promise((f, r) => {
|
|
404
|
+
clearTimeout(tout);
|
|
405
|
+
// node.status(modes.READY);
|
|
406
|
+
fulfill();
|
|
407
|
+
f();
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
for(var i in promises){
|
|
412
|
+
(function(name){
|
|
413
|
+
promises[name].then((f) => {
|
|
414
|
+
if(name != 'finish'){
|
|
415
|
+
if(Object.hasOwn(f, 'result')){
|
|
416
|
+
switch(f.result){
|
|
417
|
+
case 255:
|
|
418
|
+
success[name] = true;
|
|
419
|
+
delete node.sensor_configs[mac].temp_required_configs[name];
|
|
420
|
+
break;
|
|
421
|
+
default:
|
|
422
|
+
success[name] = {
|
|
423
|
+
res: "Bad Response",
|
|
424
|
+
result: f.result,
|
|
425
|
+
sent: f.sent
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
}else{
|
|
429
|
+
success[name] = {
|
|
430
|
+
res: "no result",
|
|
431
|
+
result: null,
|
|
432
|
+
sent: f.sent
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
} else{
|
|
436
|
+
// #OTF
|
|
437
|
+
// Check if sensor responded with true for each config sent, if so delete from temp_required_configs
|
|
438
|
+
// we could auto reboot sensor, but this could lead to boot cycle for bad configs/cmds
|
|
439
|
+
if(Object.keys(node.sensor_configs[mac].temp_required_configs).length === 0){
|
|
440
|
+
delete node.sensor_configs[mac].temp_required_configs;
|
|
441
|
+
}
|
|
442
|
+
// TODO turn into event emitter.
|
|
443
|
+
node._emitter.emit('config_node_msg', {topic: 'Config Results', payload: success, addr: mac, time: Date.now()});
|
|
444
|
+
// node.send({topic: 'Config Results', payload: success, time: Date.now(), addr: mac});
|
|
445
|
+
top_fulfill(success);
|
|
446
|
+
}
|
|
447
|
+
}).catch((err) => {
|
|
448
|
+
success[name] = err;
|
|
449
|
+
});
|
|
450
|
+
})(i);
|
|
451
|
+
}
|
|
452
|
+
}, 1000);
|
|
453
|
+
});
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
this._send_otn_request = function(sensor){
|
|
457
|
+
return new Promise((top_fulfill, top_reject) => {
|
|
458
|
+
var msg = {};
|
|
459
|
+
setTimeout(() => {
|
|
460
|
+
var tout = setTimeout(() => {
|
|
461
|
+
node.status(modes.PGM_ERR);
|
|
462
|
+
node.send({topic: 'OTN Request Results', payload: msg, time: Date.now()});
|
|
463
|
+
}, 10000);
|
|
464
|
+
|
|
465
|
+
var promises = {};
|
|
466
|
+
// This command is used for OTF on types 53, 80,81,82,83,84, 101, 102, 110, 111, 518, 519
|
|
467
|
+
const original_otf_devices = [53, 80, 81, 82, 83, 84, 87, 101, 102, 103, 110, 111, 112, 114, 117, 180, 181, 518, 519, 520, 538];
|
|
468
|
+
if(original_otf_devices.includes(sensor.type)){
|
|
469
|
+
// This command is used for OTF on types 53, 80, 81, 82, 83, 84, 101, 102, 110, 111, 518, 519
|
|
470
|
+
promises.config_enter_otn_mode = node.gateway.config_enter_otn_mode(sensor.mac);
|
|
471
|
+
}else{
|
|
472
|
+
// This command is used for OTF on types not 53, 80, 81, 82, 83, 84, 101, 102, 110, 111, 518, 519
|
|
473
|
+
promises.config_enter_otn_mode = node.gateway.config_enter_otn_mode_common(sensor.mac);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
promises.finish = new Promise((fulfill, reject) => {
|
|
477
|
+
node.gateway.queue.add(() => {
|
|
478
|
+
return new Promise((f, r) => {
|
|
479
|
+
clearTimeout(tout);
|
|
480
|
+
// TODO emitter to set status on config nodes.
|
|
481
|
+
// node.status(modes.FLY);
|
|
482
|
+
fulfill();
|
|
483
|
+
f();
|
|
484
|
+
});
|
|
485
|
+
});
|
|
486
|
+
});
|
|
487
|
+
for(var i in promises){
|
|
488
|
+
(function(name){
|
|
489
|
+
promises[name].then((f) => {
|
|
490
|
+
if(name != 'finish') msg[name] = true;
|
|
491
|
+
else{
|
|
492
|
+
// #OTF
|
|
493
|
+
node.warn('OTN Request Finished');
|
|
494
|
+
// node.send({topic: 'OTN Request Results', payload: msg, time: Date.now()});
|
|
495
|
+
top_fulfill(msg);
|
|
496
|
+
}
|
|
497
|
+
}).catch((err) => {
|
|
498
|
+
if(Object.hasOwn(node.sensor_configs[sensor.mac], 'temp_required_configs')){
|
|
499
|
+
delete node.sensor_configs[sensor.mac].temp_required_configs;
|
|
500
|
+
}
|
|
501
|
+
node.warn('Error entering OTN mode');
|
|
502
|
+
msg[name] = err;
|
|
503
|
+
});
|
|
504
|
+
})(i);
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
});
|
|
508
|
+
};
|
|
509
|
+
|
|
188
510
|
node.check_mode = function(cb){
|
|
189
511
|
node.gateway.digi.send.at_command("ID").then((res) => {
|
|
190
512
|
var pan_id = (res.data[0] << 8) | res.data[1];
|
|
@@ -581,7 +903,7 @@ module.exports = function(RED) {
|
|
|
581
903
|
this.gateway._emitter.removeAllListeners('link_info');
|
|
582
904
|
this.gateway._emitter.removeAllListeners('converter_response');
|
|
583
905
|
this.gateway._emitter.removeAllListeners('manifest_received');
|
|
584
|
-
console.log(this.gateway._emitter.eventNames());
|
|
906
|
+
// console.log(this.gateway._emitter.eventNames());
|
|
585
907
|
});
|
|
586
908
|
|
|
587
909
|
node.is_config = false;
|
|
@@ -1291,12 +1613,12 @@ module.exports = function(RED) {
|
|
|
1291
1613
|
promises.current_calibration_13 = node.config_gateway.config_set_current_calibration_13(mac, cali);
|
|
1292
1614
|
}
|
|
1293
1615
|
}
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1616
|
+
if(config.current_calibration_13_dep_active){
|
|
1617
|
+
var cali = parseInt(config.current_calibration_13_dep);
|
|
1618
|
+
if(cali != 0){
|
|
1619
|
+
promises.current_calibration_13_dep = node.config_gateway.config_set_current_calibration_13_dep(mac, cali);
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1300
1622
|
if(config.change_detection_t3_active){
|
|
1301
1623
|
promises.change_detection = node.config_gateway.config_set_change_detection(mac, config.change_enabled ? 1 : 0, parseInt(config.change_pr), parseInt(config.change_interval));
|
|
1302
1624
|
}
|
|
@@ -1366,18 +1688,18 @@ module.exports = function(RED) {
|
|
|
1366
1688
|
promises.current_calibration_ch2_19 = node.config_gateway.config_set_current_calibration_ch2_19(mac, cali);
|
|
1367
1689
|
}
|
|
1368
1690
|
}
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1691
|
+
if(config.current_calibration_13_dep_active){
|
|
1692
|
+
var cali = parseInt(config.current_calibration_13_dep);
|
|
1693
|
+
if(cali != 0){
|
|
1694
|
+
promises.current_calibration_13_dep = node.config_gateway.config_set_current_calibration_13_dep(mac, cali);
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
if(config.current_calibration_ch2_19_dep_active){
|
|
1698
|
+
var cali = parseInt(config.current_calibration_ch2_19_dep);
|
|
1699
|
+
if(cali != 0){
|
|
1700
|
+
promises.current_calibration_ch2_19_dep = node.config_gateway.config_set_current_calibration_ch2_19_dep(mac, cali);
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1381
1703
|
if(config.change_detection_t3_active){
|
|
1382
1704
|
promises.change_detection = node.config_gateway.config_set_change_detection(mac, config.change_enabled ? 1 : 0, parseInt(config.change_pr), parseInt(config.change_interval));
|
|
1383
1705
|
}
|
|
@@ -1475,24 +1797,24 @@ module.exports = function(RED) {
|
|
|
1475
1797
|
promises.current_calibration_ch3_28 = node.config_gateway.config_set_current_calibration_ch3_28(mac, cali);
|
|
1476
1798
|
}
|
|
1477
1799
|
}
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1800
|
+
if(config.current_calibration_13_dep_active){
|
|
1801
|
+
var cali = parseInt(config.current_calibration_13_dep);
|
|
1802
|
+
if(cali != 0){
|
|
1803
|
+
promises.current_calibration_13_dep = node.config_gateway.config_set_current_calibration_13_dep(mac, cali);
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
if(config.current_calibration_ch2_19_dep_active){
|
|
1807
|
+
var cali = parseInt(config.current_calibration_ch2_19_dep);
|
|
1808
|
+
if(cali != 0){
|
|
1809
|
+
promises.current_calibration_ch2_19_dep = node.config_gateway.config_set_current_calibration_ch2_19_dep(mac, cali);
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
if(config.current_calibration_ch3_28_dep_active){
|
|
1813
|
+
var cali = parseInt(config.current_calibration_ch3_28_dep);
|
|
1814
|
+
if(cali != 0){
|
|
1815
|
+
promises.current_calibration_ch3_28_dep = node.config_gateway.config_set_current_calibration_ch3_28_dep(mac, cali);
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1496
1818
|
if(config.change_detection_t3_active){
|
|
1497
1819
|
promises.change_detection = node.config_gateway.config_set_change_detection(mac, config.change_enabled ? 1 : 0, parseInt(config.change_pr), parseInt(config.change_interval));
|
|
1498
1820
|
}
|
|
@@ -2269,29 +2591,35 @@ module.exports = function(RED) {
|
|
|
2269
2591
|
// promises.set_rtc_101 = node.config_gateway.config_set_rtc_101(mac);
|
|
2270
2592
|
break;
|
|
2271
2593
|
case 103:
|
|
2272
|
-
if(config.
|
|
2273
|
-
promises.
|
|
2594
|
+
if(config.acc_output_data_rate_103_active){
|
|
2595
|
+
promises.acc_output_data_rate_103 = node.config_gateway.config_set_acc_output_data_rate_103(mac, parseInt(config.acc_output_data_rate_103));
|
|
2274
2596
|
}
|
|
2275
|
-
if(config.
|
|
2276
|
-
promises.
|
|
2597
|
+
if(config.output_data_rate_103_active){
|
|
2598
|
+
promises.gyro_output_data_rate_103 = node.config_gateway.config_set_output_data_rate_101(mac, parseInt(config.output_data_rate_103));
|
|
2277
2599
|
}
|
|
2278
|
-
if(config.
|
|
2279
|
-
promises.
|
|
2600
|
+
if(config.adxl_fsr_103_active){
|
|
2601
|
+
promises.acc_fsr_103 = node.config_gateway.config_set_adxl_fsr_103(mac, parseInt(config.adxl_fsr_103));
|
|
2280
2602
|
}
|
|
2281
|
-
if(config.
|
|
2282
|
-
promises.
|
|
2603
|
+
if(config.sampling_duration_103_active){
|
|
2604
|
+
promises.sampling_duration_103 = node.config_gateway.config_set_sampling_duration_101(mac, parseInt(config.sampling_duration_103));
|
|
2283
2605
|
}
|
|
2284
2606
|
if(config.enable_hp_filter_cutoff_103_active){
|
|
2285
2607
|
promises.enable_hp_filter_cutoff_103 = node.config_gateway.config_set_enable_hp_filter_cutoff_103(mac, parseInt(config.enable_hp_filter_cutoff_103));
|
|
2286
2608
|
}
|
|
2609
|
+
if(config.sampling_interval_101_active){
|
|
2610
|
+
promises.sampling_interval_103 = node.config_gateway.config_set_sampling_interval_101(mac, parseInt(config.sampling_interval_101));
|
|
2611
|
+
}
|
|
2287
2612
|
if(config.gyro_fsr_103_active){
|
|
2288
2613
|
promises.gyro_fsr_103 = node.config_gateway.config_set_gyro_fsr_103(mac, parseInt(config.gyro_fsr_103));
|
|
2289
2614
|
}
|
|
2290
|
-
if(config.
|
|
2291
|
-
promises.
|
|
2615
|
+
if(config.enable_sensor_103_active){
|
|
2616
|
+
promises.enable_sensor_103 = node.config_gateway.config_set_enable_sensor_103(mac, parseInt(config.enable_sensor_103));
|
|
2292
2617
|
}
|
|
2293
|
-
if(config.
|
|
2294
|
-
promises.
|
|
2618
|
+
if(config.acc_threshold_103_active){
|
|
2619
|
+
promises.acc_threshold_103 = node.config_gateway.config_set_acc_threshold_103(mac, parseInt(config.acc_threshold_103));
|
|
2620
|
+
}
|
|
2621
|
+
if(config.max_num_motion_103_active){
|
|
2622
|
+
promises.max_num_motion_103 = node.config_gateway.config_set_max_num_motion_103(mac, parseInt(config.max_num_motion_103));
|
|
2295
2623
|
}
|
|
2296
2624
|
if(config.set_rtc_101){
|
|
2297
2625
|
promises.set_rtc_103 = node.config_gateway.config_set_rtc_101(mac);
|
|
@@ -3581,6 +3909,26 @@ module.exports = function(RED) {
|
|
|
3581
3909
|
promises.max_num_motion_tx_delay_110 = node.config_gateway.config_set_max_num_motion_tx_delay_110(mac, parseInt(config.max_num_motion_tx_delay_110));
|
|
3582
3910
|
}
|
|
3583
3911
|
break;
|
|
3912
|
+
case 545:
|
|
3913
|
+
if(config.temperature_unit_545_active){
|
|
3914
|
+
promises.temperature_unit_545 = node.config_gateway.config_set_temperature_unit_545(mac, parseInt(config.temperature_unit_545));
|
|
3915
|
+
}
|
|
3916
|
+
if(config.flow_unit_545_active){
|
|
3917
|
+
promises.flow_unit_545 = node.config_gateway.config_set_flow_unit_545(mac, parseInt(config.flow_unit_545));
|
|
3918
|
+
}
|
|
3919
|
+
if(config.gas_type_545_active){
|
|
3920
|
+
promises.gas_type_545 = node.config_gateway.config_set_gas_type_545(mac, parseInt(config.gas_type_545));
|
|
3921
|
+
}
|
|
3922
|
+
if(config.number_of_gas_type_545_active){
|
|
3923
|
+
let gas_type_array = [];
|
|
3924
|
+
let percentage_array = [];
|
|
3925
|
+
for(let ind = 0; ind < config.number_of_gas_type_545; ind++){
|
|
3926
|
+
gas_type_array.push(parseInt(config['gas_type_'+ind+'_545']));
|
|
3927
|
+
percentage_array.push(parseInt(config['percentage_value_'+ind+'_545']));
|
|
3928
|
+
}
|
|
3929
|
+
promises.config_set_gas_type_mix_545 = node.config_gateway.config_set_gas_type_mix_545(mac, parseInt(config.number_of_gas_type_545), gas_type_array, percentage_array);
|
|
3930
|
+
}
|
|
3931
|
+
break;
|
|
3584
3932
|
case 1010:
|
|
3585
3933
|
if(config.stay_on_mode_539_active){
|
|
3586
3934
|
promises.stay_on_mode_539 = node.config_gateway.config_set_stay_on_mode_539(mac, parseInt(config.stay_on_mode_539));
|
|
@@ -3770,10 +4118,13 @@ module.exports = function(RED) {
|
|
|
3770
4118
|
// Added timeout to fix issue
|
|
3771
4119
|
if(config.sensor_type == 1010 || config.sensor_type == 1011){
|
|
3772
4120
|
_config(sensor, true);
|
|
3773
|
-
}else{
|
|
4121
|
+
}else if(!Object.hasOwn(node.gateway_node.sensor_configs, sensor.mac) || !Object.hasOwn(node.gateway_node.sensor_configs[sensor.mac], 'api_config_override')){
|
|
4122
|
+
// node.send({topic: "debug", payload: 'WIRELESS DEVICE NODE IS CONFIGURING SENSORS no mac!!!!!'});
|
|
3774
4123
|
var tout = setTimeout(() => {
|
|
3775
4124
|
_send_otn_request(sensor);
|
|
3776
4125
|
}, 100);
|
|
4126
|
+
}else{
|
|
4127
|
+
node.send({topic: 'warning', payload: {'warning': 'Wireless Device Node configurations overridden by API Configuration'}, addr: sensor.mac, time: Date.now()});
|
|
3777
4128
|
}
|
|
3778
4129
|
}else if(config.auto_config && config.on_the_fly_enable && sensor.mode == "OTN"){
|
|
3779
4130
|
if(config.sensor_type == 101 || config.sensor_type == 102 || config.sensor_type == 202){
|
|
@@ -3795,9 +4146,12 @@ module.exports = function(RED) {
|
|
|
3795
4146
|
_config(sensor, true);
|
|
3796
4147
|
}, 3500);
|
|
3797
4148
|
}
|
|
3798
|
-
}else{
|
|
4149
|
+
}else if(!Object.hasOwn(node.gateway_node.sensor_configs, sensor.mac) || !Object.hasOwn(node.gateway_node.sensor_configs[sensor.mac], 'api_config_override')){
|
|
4150
|
+
// node.send({topic: "debug", payload: 'WIRELESS DEVICE NODE IS CONFIGURING SENSORS with mac!!!!!'});
|
|
3799
4151
|
_config(sensor, true);
|
|
3800
|
-
}
|
|
4152
|
+
}else{
|
|
4153
|
+
node.send({topic: 'warning', payload: {'warning': 'Wireless Device Node configurations overridden by API Configuration'}, addr: sensor.mac, time: Date.now()});
|
|
4154
|
+
};
|
|
3801
4155
|
} else if(config.sensor_type == 101 && sensor.mode == "FLY" || config.sensor_type == 102 && sensor.mode == "FLY" || config.sensor_type == 202 && sensor.mode == "FLY"){
|
|
3802
4156
|
if(this.gateway.hasOwnProperty('fly_101_in_progress') && this.gateway.fly_101_in_progress == false || !this.gateway.hasOwnProperty('fly_101_in_progress')){
|
|
3803
4157
|
this.gateway.fly_101_in_progress = true;
|
|
@@ -3880,12 +4234,14 @@ module.exports = function(RED) {
|
|
|
3880
4234
|
// Added timeout to fix issue
|
|
3881
4235
|
if(config.sensor_type == 1010 || config.sensor_type == 1011){
|
|
3882
4236
|
_config(sensor, true);
|
|
3883
|
-
}else{
|
|
4237
|
+
}else if(!Object.hasOwn(node.gateway_node.sensor_configs, sensor.mac) || !Object.hasOwn(node.gateway_node.sensor_configs[sensor.mac], 'api_config_override')){
|
|
4238
|
+
// node.send({topic: "debug", payload: 'WIRELESS DEVICE NODE IS CONFIGURING SENSORS no mac!!!!!'});
|
|
3884
4239
|
var tout = setTimeout(() => {
|
|
3885
4240
|
_send_otn_request(sensor);
|
|
3886
4241
|
}, 100);
|
|
4242
|
+
}else{
|
|
4243
|
+
node.send({topic: 'warning', payload: {'warning': 'Wireless Device Node configurations overridden by API Configuration'}, addr: sensor.mac, time: Date.now()});
|
|
3887
4244
|
}
|
|
3888
|
-
|
|
3889
4245
|
}else if(config.auto_config && config.on_the_fly_enable && sensor.mode == "OTN"){
|
|
3890
4246
|
if(config.sensor_type == 101 || config.sensor_type == 102 || config.sensor_type == 202){
|
|
3891
4247
|
if(this.gateway.hasOwnProperty('fly_101_in_progress') && this.gateway.fly_101_in_progress == false || !this.gateway.hasOwnProperty('fly_101_in_progress')){
|
|
@@ -3905,9 +4261,14 @@ module.exports = function(RED) {
|
|
|
3905
4261
|
_config(sensor, true);
|
|
3906
4262
|
}, 3500);
|
|
3907
4263
|
}
|
|
3908
|
-
}else{
|
|
4264
|
+
} else if(!Object.hasOwn(node.gateway_node.sensor_configs, sensor.mac) || !Object.hasOwn(node.gateway_node.sensor_configs[sensor.mac], 'api_config_override')){
|
|
4265
|
+
// node.send({topic: "debug", payload: 'WIRELESS DEVICE NODE IS CONFIGURING SENSORS with mac!!!!!'});
|
|
3909
4266
|
_config(sensor, true);
|
|
3910
|
-
}
|
|
4267
|
+
}else{
|
|
4268
|
+
// node.warn(!Object.hasOwn(node.gateway_node.sensor_configs, sensor.mac));
|
|
4269
|
+
// node.warn(!Object.hasOwn(node.gateway_node.sensor_configs[sensor.mac], 'desired_configs'));
|
|
4270
|
+
node.send({topic: 'warning', payload: {'warning': 'Wireless Device Node configurations overridden by API Configuration'}, addr: sensor.mac, time: Date.now()});
|
|
4271
|
+
};
|
|
3911
4272
|
|
|
3912
4273
|
}else if(sensor.mode == "FLY" && config.sensor_type == 101 || sensor.mode == "FLY" && config.sensor_type == 102 || sensor.mode == "FLY" && config.sensor_type == 202){
|
|
3913
4274
|
if(this.gateway.hasOwnProperty('fly_101_in_progress') && this.gateway.fly_101_in_progress == false || !this.gateway.hasOwnProperty('fly_101_in_progress')){
|
|
@@ -4045,6 +4406,597 @@ module.exports = function(RED) {
|
|
|
4045
4406
|
res.json({needs_input: false});
|
|
4046
4407
|
}
|
|
4047
4408
|
});
|
|
4409
|
+
|
|
4410
|
+
function NcdAPIConfigurationNode(config){
|
|
4411
|
+
RED.nodes.createNode(this,config);
|
|
4412
|
+
|
|
4413
|
+
this._gateway_node = RED.nodes.getNode(config.connection);
|
|
4414
|
+
|
|
4415
|
+
this._gateway_node.open_comms();
|
|
4416
|
+
this.gateway = this._gateway_node.gateway;
|
|
4417
|
+
|
|
4418
|
+
var node = this;
|
|
4419
|
+
|
|
4420
|
+
node.on('close', function(){
|
|
4421
|
+
this._gateway_node.close_comms();
|
|
4422
|
+
});
|
|
4423
|
+
|
|
4424
|
+
var statuses =[
|
|
4425
|
+
{fill:"green",shape:"dot",text:"Ready"},
|
|
4426
|
+
{fill:"yellow",shape:"ring",text:"Configuring"},
|
|
4427
|
+
{fill:"red",shape:"dot",text:"Failed to Connect"},
|
|
4428
|
+
{fill:"green",shape:"ring",text:"Connecting..."}
|
|
4429
|
+
];
|
|
4430
|
+
|
|
4431
|
+
// node.set_status = function(){
|
|
4432
|
+
// node.status(statuses[node._gateway_node.is_config]);
|
|
4433
|
+
// };
|
|
4434
|
+
|
|
4435
|
+
node.on('input', function(msg, send, done){
|
|
4436
|
+
var response;
|
|
4437
|
+
switch(msg.topic){
|
|
4438
|
+
case 'set_desired_configs':
|
|
4439
|
+
console.log('set_desired_configs triggered');
|
|
4440
|
+
response = this.set_desired_configs(msg.payload);
|
|
4441
|
+
msg.request = msg.payload;
|
|
4442
|
+
if(Object.hasOwn(response, 'error')){
|
|
4443
|
+
msg.payload = response;
|
|
4444
|
+
msg.status = 500;
|
|
4445
|
+
}else{
|
|
4446
|
+
msg.payload = response;
|
|
4447
|
+
msg.status = 200;
|
|
4448
|
+
}
|
|
4449
|
+
msg.time = Date.now();
|
|
4450
|
+
send(msg);
|
|
4451
|
+
break;
|
|
4452
|
+
case 'get_sensor_info':
|
|
4453
|
+
msg.request = msg.payload;
|
|
4454
|
+
if(typeof msg.payload == 'string'){
|
|
4455
|
+
msg.payload = [msg.payload];
|
|
4456
|
+
}
|
|
4457
|
+
response = this.get_sensor_array_info(msg.payload);
|
|
4458
|
+
msg.payload = response.body;
|
|
4459
|
+
msg.status = response.status;
|
|
4460
|
+
msg.time = Date.now();
|
|
4461
|
+
send(msg);
|
|
4462
|
+
break;
|
|
4463
|
+
case 'get_all_sensor_info':
|
|
4464
|
+
response = this.get_all_sensor_info();
|
|
4465
|
+
msg.request = msg.payload;
|
|
4466
|
+
msg.payload = response;
|
|
4467
|
+
msg.status = 200;
|
|
4468
|
+
msg.time = Date.now();
|
|
4469
|
+
send(msg);
|
|
4470
|
+
break;
|
|
4471
|
+
case 'get_sensor_list':
|
|
4472
|
+
node.warn("get_sensor_list not yet implemented");
|
|
4473
|
+
break;
|
|
4474
|
+
case 'reset_sensor_desired_configs':
|
|
4475
|
+
msg.request = msg.payload;
|
|
4476
|
+
if(typeof msg.payload == "string"){
|
|
4477
|
+
msg.payload = [msg.payload];
|
|
4478
|
+
}
|
|
4479
|
+
msg.payload = this.reset_desired_configs(msg.payload);
|
|
4480
|
+
// msg.payload = node._gateway_node.sensor_configs;
|
|
4481
|
+
msg.time = Date.now();
|
|
4482
|
+
msg.status = 200;
|
|
4483
|
+
send(msg);
|
|
4484
|
+
break;
|
|
4485
|
+
case 'sensor_config_options':
|
|
4486
|
+
msg.request = msg.payload;
|
|
4487
|
+
// TODO move logic to function
|
|
4488
|
+
if(typeof msg.payload == 'number' && Object.hasOwn(node._gateway_node.sensor_type_map, msg.payload)){
|
|
4489
|
+
let options = this.get_config_options(msg.payload);
|
|
4490
|
+
msg.payload = options;
|
|
4491
|
+
msg.status = 200;
|
|
4492
|
+
msg.time = Date.now();
|
|
4493
|
+
send(msg);
|
|
4494
|
+
}else{
|
|
4495
|
+
msg.payload = {error: 'get_config_options error: Payload must be a valid sensor type number'};
|
|
4496
|
+
msg.status = 500;
|
|
4497
|
+
msg.time = Date.now();
|
|
4498
|
+
send(msg);
|
|
4499
|
+
}
|
|
4500
|
+
break;
|
|
4501
|
+
default:
|
|
4502
|
+
msg.request = msg.payload;
|
|
4503
|
+
msg.payload = {error: 'Invalid topic. Valid topics are: set_desired_configs, get_sensor_info, get_all_sensor_info, reset_sensor_desired_configs, sensor_config_options'};
|
|
4504
|
+
msg.status = 500;
|
|
4505
|
+
msg.time = Date.now();
|
|
4506
|
+
send(msg);
|
|
4507
|
+
break;
|
|
4508
|
+
};
|
|
4509
|
+
done();
|
|
4510
|
+
});
|
|
4511
|
+
|
|
4512
|
+
this.reset_desired_configs = function(sensor_array){
|
|
4513
|
+
let store_flag = false;
|
|
4514
|
+
const response = {
|
|
4515
|
+
status: 200,
|
|
4516
|
+
body: {}
|
|
4517
|
+
};
|
|
4518
|
+
for (let addr of sensor_array){
|
|
4519
|
+
addr = addr.toLowerCase();
|
|
4520
|
+
response.body[addr] = {};
|
|
4521
|
+
if(Object.hasOwn(node._gateway_node.sensor_configs, addr)){
|
|
4522
|
+
if(Object.hasOwn(node._gateway_node.sensor_configs[addr], 'desired_configs')){
|
|
4523
|
+
node._gateway_node.sensor_configs[addr].desired_configs = node._gateway_node.sensor_configs[addr].reported_configs;
|
|
4524
|
+
response.body[addr].success = true;
|
|
4525
|
+
store_flag = true;
|
|
4526
|
+
}
|
|
4527
|
+
if(Object.hasOwn(node._gateway_node.sensor_configs[addr], 'api_config_override')){
|
|
4528
|
+
delete node._gateway_node.sensor_configs[addr].api_config_override;
|
|
4529
|
+
store_flag = true;
|
|
4530
|
+
}
|
|
4531
|
+
// node._gateway_node.sensor_configs[addr].desired_configs = node._gateway_node.sensor_configs[addr].reported_configs;
|
|
4532
|
+
// delete node._gateway_node.sensor_configs[addr].api_config_override;
|
|
4533
|
+
if(Object.hasOwn(node._gateway_node.sensor_configs[addr], 'temp_required_configs')){
|
|
4534
|
+
delete node._gateway_node.sensor_configs[addr].temp_required_configs;
|
|
4535
|
+
store_flag = true;
|
|
4536
|
+
}
|
|
4537
|
+
if(response.status < 8){
|
|
4538
|
+
response.status +=200;
|
|
4539
|
+
}
|
|
4540
|
+
response.body[addr].data = node._gateway_node.sensor_configs[addr];
|
|
4541
|
+
store_flag = true;
|
|
4542
|
+
}else{
|
|
4543
|
+
if(response.status < 7 || response.status == 200){
|
|
4544
|
+
response.status +=7;
|
|
4545
|
+
}
|
|
4546
|
+
response.body[addr] = {error: "Sensor not found in configuration store"};
|
|
4547
|
+
}
|
|
4548
|
+
};
|
|
4549
|
+
if(response.status == 7){
|
|
4550
|
+
response.status = 500;
|
|
4551
|
+
}
|
|
4552
|
+
if(store_flag) node._gateway_node.store_sensor_configs(JSON.stringify(node._gateway_node.sensor_configs));
|
|
4553
|
+
return response;
|
|
4554
|
+
};
|
|
4555
|
+
|
|
4556
|
+
this.get_config_options = function(sensor_type){
|
|
4557
|
+
if(Object.hasOwn(node._gateway_node.sensor_type_map, sensor_type)){
|
|
4558
|
+
const config_list = node._gateway_node.sensor_type_map[sensor_type].configs;
|
|
4559
|
+
let response = {};
|
|
4560
|
+
for (const key in config_list){
|
|
4561
|
+
const info = node._gateway_node.configuration_map[config_list[key]];
|
|
4562
|
+
// If sensors actually reports and supports the listed config
|
|
4563
|
+
if(Object.hasOwn(info, 'fly_not_reported') && info.fly_not_reported.includes(sensor_type)){
|
|
4564
|
+
continue;
|
|
4565
|
+
}
|
|
4566
|
+
response[key] = {
|
|
4567
|
+
title: info.title,
|
|
4568
|
+
default_value: info.default_value,
|
|
4569
|
+
};
|
|
4570
|
+
if(Object.hasOwn(info, 'main_caption')){
|
|
4571
|
+
response[key].description = info.main_caption;
|
|
4572
|
+
}
|
|
4573
|
+
if(Object.hasOwn(info, 'validator')){
|
|
4574
|
+
if(Object.hasOwn(info.validator, 'generated')){
|
|
4575
|
+
delete info.validator.generated;
|
|
4576
|
+
}
|
|
4577
|
+
response[key] = {...response[key], ...info.validator};
|
|
4578
|
+
}
|
|
4579
|
+
if(Object.hasOwn(info, 'options')){
|
|
4580
|
+
response[key].options = info.options;
|
|
4581
|
+
}
|
|
4582
|
+
|
|
4583
|
+
// if(Object.hasOwn(info, 'validator') && Object.hasOwn(info.validator, 'type')){
|
|
4584
|
+
|
|
4585
|
+
// response[key].value_type = info.validator.type;
|
|
4586
|
+
// }
|
|
4587
|
+
// if(Object.hasOwn(info, 'options')){
|
|
4588
|
+
// response[key].options = info.options;
|
|
4589
|
+
// }else{
|
|
4590
|
+
// if(Object.hasOwn(info, 'validator') && Object.hasOwn(info.validator, 'min')){
|
|
4591
|
+
// response[key].minimum_value = info.validator.min;
|
|
4592
|
+
// }
|
|
4593
|
+
// if(Object.hasOwn(info, 'validator') && Object.hasOwn(info.validator, 'max')){
|
|
4594
|
+
// response[key].maximum_value = info.validator.max;
|
|
4595
|
+
// }
|
|
4596
|
+
// }
|
|
4597
|
+
// node.warn(info);
|
|
4598
|
+
}
|
|
4599
|
+
return response;
|
|
4600
|
+
}else{
|
|
4601
|
+
return 'Invalid sensor type';
|
|
4602
|
+
}
|
|
4603
|
+
};
|
|
4604
|
+
|
|
4605
|
+
this.set_desired_configs = function(desired_configs){
|
|
4606
|
+
var _requires_file_update = false;
|
|
4607
|
+
var response = {};
|
|
4608
|
+
let error_msg = {};
|
|
4609
|
+
let warning_msg = {};
|
|
4610
|
+
if(desired_configs == null || typeof desired_configs == 'undefined'){
|
|
4611
|
+
return {error: 'msg.payload is required. It must be an array of sensor configuration objects. Each object in the array must have addr, type, and configs properties i.e. [{addr: "sensor_mac_address", type: sensor_type_number, configs: {config_name: desired_value}}]'};
|
|
4612
|
+
}else if(!Array.isArray(desired_configs) || desired_configs.length == 0){
|
|
4613
|
+
return {error: 'msg.payload must be an array of sensor configuration objects. Each object in the array must have addr, type, and configs properties i.e. [{addr: "sensor_mac_address", type: sensor_type_number, configs: {config_name: desired_value}}]'};
|
|
4614
|
+
}
|
|
4615
|
+
for (const sensor of desired_configs){
|
|
4616
|
+
// TODO validate sensor object
|
|
4617
|
+
// must have sensor.addr, sensor.type, sensor.configs
|
|
4618
|
+
// sensor.configs is an object with key value pairs of config name and desired value
|
|
4619
|
+
if(!Object.hasOwn(sensor, 'addr')){
|
|
4620
|
+
// throw new Error('Invalid sensor object, must have addr, type, and configs properties');
|
|
4621
|
+
error_msg.syntax_error ||= {};
|
|
4622
|
+
error_msg.syntax_error = {
|
|
4623
|
+
type: 'error',
|
|
4624
|
+
message: 'A Sensor object missing the addr property. Each object in the array must have addr, type, and configs properties i.e. [{addr: "sensor_mac_address", type: sensor_type_number, configs: {config_name: desired_value}}]',
|
|
4625
|
+
detail: {
|
|
4626
|
+
"text": "Missing addr property",
|
|
4627
|
+
"received": sensor,
|
|
4628
|
+
"help": "The following properties are required for each sensor: addr, type, configs i.e. [{addr: 'sensor_mac_address', type: sensor_type_number, configs: {config_name: desired_value}}]"
|
|
4629
|
+
}
|
|
4630
|
+
};
|
|
4631
|
+
continue;
|
|
4632
|
+
// return {error: 'Invalid sensor object in array. Each object in the array must have addr, type, and configs properties i.e. [{addr: "sensor_mac_address", type: sensor_type_number, configs: {config_name: desired_value}}]'};
|
|
4633
|
+
}
|
|
4634
|
+
if(!Object.hasOwn(sensor, 'type') || !Object.hasOwn(sensor, 'configs')){
|
|
4635
|
+
error_msg[sensor.addr] ||= {};
|
|
4636
|
+
error_msg[sensor.addr].syntax_error = {
|
|
4637
|
+
type: 'error',
|
|
4638
|
+
message: 'Invalid sensor object in array. Each object in the array must have addr, type, and configs properties i.e. [{addr: "sensor_mac_address", type: sensor_type_number, configs: {config_name: desired_value}}]',
|
|
4639
|
+
detail: {
|
|
4640
|
+
"text": "Missing type or configs property",
|
|
4641
|
+
"received": sensor,
|
|
4642
|
+
"help": "The following properties are required for each sensor: addr, type, configs. i.e. [{addr: 'sensor_mac_address', type: sensor_type_number, configs: {config_name: desired_value}}]"
|
|
4643
|
+
}
|
|
4644
|
+
};
|
|
4645
|
+
// error_msg[sensor.addr].syntax_error = 'Invalid sensor object in array. Each object in the array must have addr, type, and configs properties i.e. [{addr: "sensor_mac_address", type: sensor_type_number, configs: {config_name: desired_value}}]';
|
|
4646
|
+
continue;
|
|
4647
|
+
}
|
|
4648
|
+
// Force lowercase for consistency
|
|
4649
|
+
sensor.addr = sensor.addr.toLowerCase();
|
|
4650
|
+
// force configs values lowercase for consistency
|
|
4651
|
+
for (const key in sensor.configs){
|
|
4652
|
+
if(typeof sensor.configs[key] == 'string'){
|
|
4653
|
+
sensor.configs[key] = sensor.configs[key].toLowerCase();
|
|
4654
|
+
}
|
|
4655
|
+
}
|
|
4656
|
+
|
|
4657
|
+
// If sensor doesn't exist in sensor_configs, create it and default desired_configs for population.
|
|
4658
|
+
if(!Object.hasOwn(node._gateway_node.sensor_configs, sensor.addr) || !Object.hasOwn(node._gateway_node.sensor_configs[sensor.addr], 'desired_configs')){
|
|
4659
|
+
node._gateway_node.sensor_configs[sensor.addr] = {
|
|
4660
|
+
desired_configs: {}
|
|
4661
|
+
};
|
|
4662
|
+
}
|
|
4663
|
+
if(Object.hasOwn(node._gateway_node.sensor_configs[sensor.addr], 'type')){
|
|
4664
|
+
if(sensor.type != node._gateway_node.sensor_configs[sensor.addr].type){
|
|
4665
|
+
response[sensor.addr] = {error: `Sensor type mismatch for sensor ${sensor.addr}. Expected type ${node._gateway_node.sensor_configs[sensor.addr].type}, but got type ${sensor.type}`, error_object: {"text": "Sensor type mismatch", "expected_type": node._gateway_node.sensor_configs[sensor.addr].type, "received_type": sensor.type}};
|
|
4666
|
+
continue;
|
|
4667
|
+
}
|
|
4668
|
+
}else{
|
|
4669
|
+
node._gateway_node.sensor_configs[sensor.addr].type = sensor.type;
|
|
4670
|
+
_requires_file_update = true;
|
|
4671
|
+
}
|
|
4672
|
+
// Validate configs
|
|
4673
|
+
for (const config_name in sensor.configs){
|
|
4674
|
+
// Check config is valid for sensor type
|
|
4675
|
+
if(Object.hasOwn(node._gateway_node.sensor_type_map, sensor.type) && Object.hasOwn(node._gateway_node.sensor_type_map[sensor.type], 'configs') && Object.hasOwn(node._gateway_node.sensor_type_map[sensor.type].configs, config_name)){
|
|
4676
|
+
let map_key = node._gateway_node.sensor_type_map[sensor.type].configs[config_name];
|
|
4677
|
+
if(Object.hasOwn(node._gateway_node.configuration_map, map_key) && Object.hasOwn(node._gateway_node.configuration_map[map_key], 'validator')){
|
|
4678
|
+
// Check if config is reported by sensor
|
|
4679
|
+
if(Object.hasOwn(node._gateway_node.configuration_map[map_key], 'fly_not_reported') && node._gateway_node.configuration_map[map_key].fly_not_reported.includes(sensor.type)){
|
|
4680
|
+
error_msg[sensor.addr] ||= {};
|
|
4681
|
+
error_msg[sensor.addr][config_name] = {
|
|
4682
|
+
type: 'error',
|
|
4683
|
+
message: `Configuration ${config_name} is not supported for sensor type ${sensor.type} for sensor ${sensor.addr}. This configuration is not reported by the sensor and cannot be programmatically set through the configuration node.`,
|
|
4684
|
+
detail: {
|
|
4685
|
+
"text": "Configuration not supported due to reported configurations",
|
|
4686
|
+
"sensor_type": sensor.type,
|
|
4687
|
+
"config_name": config_name,
|
|
4688
|
+
"help": `Inject this message into the configuration node to get valid configuration values: {topic: 'sensor_config_options', payload: ${sensor.type}}`
|
|
4689
|
+
}
|
|
4690
|
+
};
|
|
4691
|
+
delete sensor.configs[config_name];
|
|
4692
|
+
continue;
|
|
4693
|
+
}
|
|
4694
|
+
if(Object.hasOwn(node._gateway_node.configuration_map[map_key].validator, 'type')){
|
|
4695
|
+
switch(node._gateway_node.configuration_map[map_key].validator.type){
|
|
4696
|
+
case 'hexString':
|
|
4697
|
+
// Remove colons from string
|
|
4698
|
+
sensor.configs[config_name] = sensor.configs[config_name].replace(/:/g, '');
|
|
4699
|
+
|
|
4700
|
+
// Invalid hex string error
|
|
4701
|
+
if (!/^[0-9a-f]+$/.test(sensor.configs[config_name])) {
|
|
4702
|
+
error_msg[sensor.addr] ||= {};
|
|
4703
|
+
error_msg[sensor.addr][config_name] = {
|
|
4704
|
+
type: 'error',
|
|
4705
|
+
message: `Invalid hex string for configuration ${config_name} for sensor ${sensor.addr}. Received value: ${sensor.configs[config_name]}`,
|
|
4706
|
+
detail: {
|
|
4707
|
+
"text": "Invalid hex string",
|
|
4708
|
+
"regex_validator": "/^[0-9a-f]+$/",
|
|
4709
|
+
"received": sensor.configs[config_name],
|
|
4710
|
+
"help": "Hex string should only contain characters 0-9 and a-f. Colons are removed during validation."
|
|
4711
|
+
}
|
|
4712
|
+
};
|
|
4713
|
+
delete sensor.configs[config_name];
|
|
4714
|
+
continue;
|
|
4715
|
+
}
|
|
4716
|
+
// Invalid length error
|
|
4717
|
+
if(Object.hasOwn(node._gateway_node.configuration_map[map_key].validator, 'length') && sensor.configs[config_name].length != node._gateway_node.configuration_map[map_key].validator.length){
|
|
4718
|
+
error_msg[sensor.addr] ||= {};
|
|
4719
|
+
error_msg[sensor.addr][config_name] = {
|
|
4720
|
+
type: 'error',
|
|
4721
|
+
message: `Invalid length for configuration Hex String ${config_name} for sensor ${sensor.addr}. Expected length: ${node._gateway_node.configuration_map[map_key].validator.length}, Received length: ${sensor.configs[config_name].length}`,
|
|
4722
|
+
detail: {
|
|
4723
|
+
"text": "Invalid length for hex string",
|
|
4724
|
+
"expected_length": node._gateway_node.configuration_map[map_key].validator.length,
|
|
4725
|
+
"received_length": sensor.configs[config_name].length,
|
|
4726
|
+
"help": "Add leading or trailing zeros to meet length requirement."
|
|
4727
|
+
}
|
|
4728
|
+
};
|
|
4729
|
+
delete sensor.configs[config_name];
|
|
4730
|
+
continue;
|
|
4731
|
+
}
|
|
4732
|
+
// Warning for missing length validator
|
|
4733
|
+
if (!Object.hasOwn(node._gateway_node.configuration_map[map_key].validator, 'length')) {
|
|
4734
|
+
warning_msg[sensor.addr] ||= {};
|
|
4735
|
+
warning_msg[sensor.addr][config_name] = {
|
|
4736
|
+
type: 'warning',
|
|
4737
|
+
message: `No length validator defined for hex string ${config_name} for sensor ${sensor.addr}.`,
|
|
4738
|
+
detail: {
|
|
4739
|
+
"text": "Missing length validator",
|
|
4740
|
+
"type": "hexString",
|
|
4741
|
+
"help": "This warning does not prevent the configuration from going through."
|
|
4742
|
+
}
|
|
4743
|
+
};
|
|
4744
|
+
}
|
|
4745
|
+
break;
|
|
4746
|
+
default:
|
|
4747
|
+
// Default should be number types. We should have min/max values on all number types.
|
|
4748
|
+
const var_store = sensor.configs[config_name];
|
|
4749
|
+
sensor.configs[config_name] = parseInt(sensor.configs[config_name]);
|
|
4750
|
+
// NaN (Non-Integer/Invalid Value) error
|
|
4751
|
+
if (isNaN(sensor.configs[config_name])) {
|
|
4752
|
+
error_msg[sensor.addr] ||= {};
|
|
4753
|
+
error_msg[sensor.addr][config_name] = {
|
|
4754
|
+
type: 'error',
|
|
4755
|
+
message: `Invalid value for configuration ${config_name} for sensor ${sensor.addr}. Number value expected. Received value: ${sensor.configs[config_name]}`,
|
|
4756
|
+
detail: {
|
|
4757
|
+
"text": "Integer value expected",
|
|
4758
|
+
"received": var_store,
|
|
4759
|
+
"expected_type": "number",
|
|
4760
|
+
"received_type": typeof var_store,
|
|
4761
|
+
"help": "Ensure the value is a valid number or can be evaluated as a number using javascript's parseInt()."
|
|
4762
|
+
}
|
|
4763
|
+
};
|
|
4764
|
+
delete sensor.configs[config_name];
|
|
4765
|
+
continue;
|
|
4766
|
+
}
|
|
4767
|
+
// Value below minimum error
|
|
4768
|
+
if(Object.hasOwn(node._gateway_node.configuration_map[map_key].validator, 'min') && sensor.configs[config_name] < node._gateway_node.configuration_map[map_key].validator.min){
|
|
4769
|
+
error_msg[sensor.addr] ||= {};
|
|
4770
|
+
error_msg[sensor.addr][config_name] = {
|
|
4771
|
+
type: 'error',
|
|
4772
|
+
message: `Invalid value for configuration ${config_name} for sensor ${sensor.addr}. Value ${sensor.configs[config_name]} is less than minimum allowed value of ${node._gateway_node.configuration_map[map_key].validator.min}`,
|
|
4773
|
+
detail: {
|
|
4774
|
+
"text": "Value below minimum",
|
|
4775
|
+
"min_allowed": node._gateway_node.configuration_map[map_key].validator.min,
|
|
4776
|
+
"received": sensor.configs[config_name],
|
|
4777
|
+
"help": `Inject this message into the configuration node to get valid configuration values: {topic: 'sensor_config_options', payload: ${sensor.type}}`
|
|
4778
|
+
}
|
|
4779
|
+
};
|
|
4780
|
+
delete sensor.configs[config_name];
|
|
4781
|
+
continue;
|
|
4782
|
+
// return {error: `Invalid value for configuration ${config_name} for sensor ${sensor.addr}. Value ${sensor.configs[config_name]} is less than minimum allowed value of ${node.configuration_map[map_key].validator.min}`};
|
|
4783
|
+
}
|
|
4784
|
+
// Value above maximum error
|
|
4785
|
+
if(Object.hasOwn(node._gateway_node.configuration_map[map_key].validator, 'max') && sensor.configs[config_name] > node._gateway_node.configuration_map[map_key].validator.max){
|
|
4786
|
+
error_msg[sensor.addr] ||= {};
|
|
4787
|
+
error_msg[sensor.addr][config_name] = {
|
|
4788
|
+
type: 'error',
|
|
4789
|
+
message: `Invalid value for configuration ${config_name} for sensor ${sensor.addr}. Value ${sensor.configs[config_name]} is greater than maximum allowed value of ${node._gateway_node.configuration_map[map_key].validator.max}`,
|
|
4790
|
+
detail: {
|
|
4791
|
+
"text": "Value above maximum",
|
|
4792
|
+
"max_allowed": node._gateway_node.configuration_map[map_key].validator.max,
|
|
4793
|
+
"received": sensor.configs[config_name],
|
|
4794
|
+
"help": `Inject this message into the configuration node to get valid configuration values: {topic: 'sensor_config_options', payload: ${sensor.type}}`
|
|
4795
|
+
}
|
|
4796
|
+
};
|
|
4797
|
+
delete sensor.configs[config_name];
|
|
4798
|
+
continue;
|
|
4799
|
+
// return {error: `Invalid value for configuration ${config_name} for sensor ${sensor.addr}. Value ${sensor.configs[config_name]} is greater than maximum allowed value of ${node.configuration_map[map_key].validator.max}`};
|
|
4800
|
+
}
|
|
4801
|
+
// Warning for missing min/max validators
|
|
4802
|
+
if(!Object.hasOwn(node._gateway_node.configuration_map[map_key].validator, 'min') || !Object.hasOwn(node._gateway_node.configuration_map[map_key].validator, 'max')){
|
|
4803
|
+
warning_msg[sensor.addr] ||= {};
|
|
4804
|
+
warning_msg[sensor.addr][config_name] = {
|
|
4805
|
+
type: 'warning',
|
|
4806
|
+
message: `No min/max validator defined for number type ${config_name} for sensor ${sensor.addr}.`,
|
|
4807
|
+
detail: {
|
|
4808
|
+
"text": "Missing min/max validator",
|
|
4809
|
+
"config_name": config_name,
|
|
4810
|
+
"help": "This warning does not prevent the configuration from going through."
|
|
4811
|
+
}
|
|
4812
|
+
};
|
|
4813
|
+
// console.log('Warning: No min/max validator for number type ' + config_name + ' for sensor type ' + sensor.type);
|
|
4814
|
+
}
|
|
4815
|
+
// If options exist, value must be one of the options
|
|
4816
|
+
// This is assuming that all configs with options are number types
|
|
4817
|
+
if(Object.hasOwn(node._gateway_node.configuration_map[map_key], 'options')){
|
|
4818
|
+
if(!Object.keys(node._gateway_node.configuration_map[map_key].options).includes(String(sensor.configs[config_name]))){
|
|
4819
|
+
error_msg[sensor.addr] ||= {};
|
|
4820
|
+
error_msg[sensor.addr][config_name] = {
|
|
4821
|
+
type: 'error',
|
|
4822
|
+
message: `Invalid option for configuration ${config_name} for sensor ${sensor.addr}. Received value: ${sensor.configs[config_name]}`,
|
|
4823
|
+
detail: {
|
|
4824
|
+
"text": "Invalid option",
|
|
4825
|
+
"valid_options": node._gateway_node.configuration_map[map_key].options,
|
|
4826
|
+
"received": sensor.configs[config_name],
|
|
4827
|
+
"help": `Inject this message into the configuration node to get valid configuration values: {topic: 'sensor_config_options', payload: ${sensor.type}}`
|
|
4828
|
+
}
|
|
4829
|
+
};
|
|
4830
|
+
delete sensor.configs[config_name];
|
|
4831
|
+
continue;
|
|
4832
|
+
}
|
|
4833
|
+
}
|
|
4834
|
+
break;
|
|
4835
|
+
// Add more validators as needed
|
|
4836
|
+
}
|
|
4837
|
+
}else{
|
|
4838
|
+
// Warning: No 'type' validator property found
|
|
4839
|
+
// Return error, but allow the configuration to go through.
|
|
4840
|
+
error_msg[sensor.addr] ||= {};
|
|
4841
|
+
error_msg[sensor.addr][config_name] = {
|
|
4842
|
+
type: 'error',
|
|
4843
|
+
message: `No type validator property found for ${config_name} for sensor type ${sensor.type}.`,
|
|
4844
|
+
detail: {"text":
|
|
4845
|
+
"Missing type validator",
|
|
4846
|
+
"map_key": map_key,
|
|
4847
|
+
"sensor_type": sensor.type,
|
|
4848
|
+
"help": "Contact ncd.io support with a copy of this msg object to have this issue resolved."
|
|
4849
|
+
}
|
|
4850
|
+
};
|
|
4851
|
+
delete sensor.configs[config_name];
|
|
4852
|
+
continue;
|
|
4853
|
+
}
|
|
4854
|
+
}else{
|
|
4855
|
+
// Warning: No 'validator' object found
|
|
4856
|
+
error_msg[sensor.addr] ||= {};
|
|
4857
|
+
error_msg[sensor.addr][config_name] = {
|
|
4858
|
+
type: 'error',
|
|
4859
|
+
message: `No validator object found for configuration ${config_name} for sensor type ${sensor.type}.`,
|
|
4860
|
+
detail: {
|
|
4861
|
+
"text": "Missing validator object",
|
|
4862
|
+
"map_key": map_key,
|
|
4863
|
+
"sensor_type": sensor.type,
|
|
4864
|
+
"help": "Contact ncd.io support with a copy of this msg object to have this issue resolved."
|
|
4865
|
+
}
|
|
4866
|
+
};
|
|
4867
|
+
delete sensor.configs[config_name];
|
|
4868
|
+
continue;
|
|
4869
|
+
}
|
|
4870
|
+
}else{
|
|
4871
|
+
// Error: Configuration name not valid for sensor type
|
|
4872
|
+
error_msg[sensor.addr] ||= {};
|
|
4873
|
+
error_msg[sensor.addr][config_name] = {
|
|
4874
|
+
type: 'error',
|
|
4875
|
+
message: `Configuration ${config_name} is not valid for sensor type ${sensor.type} for sensor ${sensor.addr}`,
|
|
4876
|
+
detail: {
|
|
4877
|
+
"text": "Invalid configuration for sensor type",
|
|
4878
|
+
"sensor_type": sensor.type,
|
|
4879
|
+
"help": "Contact ncd.io support with a copy of this msg object to have this issue resolved."
|
|
4880
|
+
}
|
|
4881
|
+
};
|
|
4882
|
+
delete sensor.configs[config_name];
|
|
4883
|
+
continue;
|
|
4884
|
+
}
|
|
4885
|
+
}
|
|
4886
|
+
let new_desired_configs = {...node._gateway_node.sensor_configs[sensor.addr].desired_configs, ...sensor.configs};
|
|
4887
|
+
|
|
4888
|
+
|
|
4889
|
+
|
|
4890
|
+
// If the desired configs are different than what is already stored we need to update the file
|
|
4891
|
+
if(!isDeepStrictEqual(node._gateway_node.sensor_configs[sensor.addr].desired_configs, new_desired_configs)){
|
|
4892
|
+
console.log('Configs differ, updating desired configs');
|
|
4893
|
+
node._gateway_node.sensor_configs[sensor.addr].desired_configs = {...node._gateway_node.sensor_configs[sensor.addr].desired_configs, ...sensor.configs};
|
|
4894
|
+
_requires_file_update = true;
|
|
4895
|
+
}else{
|
|
4896
|
+
console.log('Configs the same, not updating desired configs');
|
|
4897
|
+
};
|
|
4898
|
+
if(!Object.hasOwn(node._gateway_node.sensor_configs[sensor.addr], 'api_config_override')){
|
|
4899
|
+
node._gateway_node.sensor_configs[sensor.addr].api_config_override = true;
|
|
4900
|
+
_requires_file_update = true;
|
|
4901
|
+
}
|
|
4902
|
+
response[sensor.addr] = node._gateway_node.sensor_configs[sensor.addr];
|
|
4903
|
+
}
|
|
4904
|
+
if(_requires_file_update){
|
|
4905
|
+
node._gateway_node.store_sensor_configs(JSON.stringify(node._gateway_node.sensor_configs));
|
|
4906
|
+
}
|
|
4907
|
+
console.log(Object.keys(warning_msg).length);
|
|
4908
|
+
if(Object.keys(warning_msg).length){
|
|
4909
|
+
response.warnings = warning_msg;
|
|
4910
|
+
}
|
|
4911
|
+
console.log(Object.keys(error_msg).length);
|
|
4912
|
+
if(Object.keys(error_msg).length){
|
|
4913
|
+
response.errors = error_msg;
|
|
4914
|
+
}
|
|
4915
|
+
return response;
|
|
4916
|
+
};
|
|
4917
|
+
|
|
4918
|
+
node.gateway.on('sensor_mode', (d) => {
|
|
4919
|
+
if(d.mode == 'FLY'){
|
|
4920
|
+
if(Object.hasOwn(node._gateway_node.sensor_configs, d.mac) && Object.hasOwn(node._gateway_node.sensor_configs[d.mac], 'api_config_override')){
|
|
4921
|
+
node.send({topic: 'sensor_report', payload: node._gateway_node.sensor_configs[d.mac], addr: d.mac, time: Date.now()});
|
|
4922
|
+
}
|
|
4923
|
+
}else if(d.mode == 'OTF'){
|
|
4924
|
+
if(Object.hasOwn(node._gateway_node.sensor_configs, d.mac) && Object.hasOwn(node._gateway_node.sensor_configs[d.mac], 'api_config_override')){
|
|
4925
|
+
node.send({topic: 'post_update_sensor_report', payload: node._gateway_node.sensor_configs[d.mac], addr: d.mac, time: Date.now()});
|
|
4926
|
+
}
|
|
4927
|
+
}
|
|
4928
|
+
});
|
|
4929
|
+
|
|
4930
|
+
node._gateway_node.on('config_node_msg', (d) => {
|
|
4931
|
+
node.send(d);
|
|
4932
|
+
});
|
|
4933
|
+
node._gateway_node.on('config_node_error', (d) => {
|
|
4934
|
+
node.send(d);
|
|
4935
|
+
});
|
|
4936
|
+
|
|
4937
|
+
node.on('close', (done) => {
|
|
4938
|
+
node._gateway_node.removeAllListeners('config_node_msg');
|
|
4939
|
+
node._gateway_node.removeAllListeners('config_node_error');
|
|
4940
|
+
node._gateway_node.removeAllListeners('sensor_mode');
|
|
4941
|
+
done();
|
|
4942
|
+
});
|
|
4943
|
+
|
|
4944
|
+
|
|
4945
|
+
this.get_all_sensor_info = function(){
|
|
4946
|
+
return node._gateway_node.sensor_configs;
|
|
4947
|
+
};
|
|
4948
|
+
this.get_sensor_array_info = function(sensor_array){
|
|
4949
|
+
let response = {
|
|
4950
|
+
status: 0,
|
|
4951
|
+
body: {}
|
|
4952
|
+
};
|
|
4953
|
+
for (let addr of sensor_array){
|
|
4954
|
+
addr = addr.toLowerCase();
|
|
4955
|
+
if(Object.hasOwn(node._gateway_node.sensor_configs, addr)){
|
|
4956
|
+
response.body[addr] = node._gateway_node.sensor_configs[addr];
|
|
4957
|
+
// Increase by 200 for first succesful read 8 is to account for error below
|
|
4958
|
+
if(response.status < 8){
|
|
4959
|
+
response.status +=200;
|
|
4960
|
+
}
|
|
4961
|
+
}else{
|
|
4962
|
+
response.body[addr] = {error: 'No info for this sensor'};
|
|
4963
|
+
// Increase by 7 for first error read to make 207 partial success or set to 7 for later
|
|
4964
|
+
if(response.status < 7 || response.status == 200){
|
|
4965
|
+
response.status +=7;
|
|
4966
|
+
}
|
|
4967
|
+
}
|
|
4968
|
+
}
|
|
4969
|
+
// Set status to 500 for full error
|
|
4970
|
+
if(response.status == 7){
|
|
4971
|
+
response.status = 500;
|
|
4972
|
+
}
|
|
4973
|
+
return response;
|
|
4974
|
+
};
|
|
4975
|
+
|
|
4976
|
+
// node.gateway.on('sensor_data', (d) => {
|
|
4977
|
+
// node.set_status();
|
|
4978
|
+
// node.send({topic: 'sensor_data', payload: d, time: Date.now()});
|
|
4979
|
+
// });
|
|
4980
|
+
// node.gateway.on('sensor_mode', (d) => {
|
|
4981
|
+
// node.set_status();
|
|
4982
|
+
// node.send({topic: 'sensor_mode', payload: d, time: Date.now()});
|
|
4983
|
+
// });
|
|
4984
|
+
// node.gateway.on('receive_packet-unknown_device',(d)=>{
|
|
4985
|
+
// node.set_status();
|
|
4986
|
+
// msg1 = {topic:'somethingTopic',payload:"something"};
|
|
4987
|
+
// node.send([null,{topic: 'unknown_data', payload:d, time: Date.now()}]);
|
|
4988
|
+
// });
|
|
4989
|
+
// node._gateway_node.on('mode_change', (mode) => {
|
|
4990
|
+
// node.set_status();
|
|
4991
|
+
// if(this.gateway.modem_mac && this._gateway_node.is_config == 0 || this.gateway.modem_mac && this._gateway_node.is_config == 1){
|
|
4992
|
+
// node.send({topic: 'modem_mac', payload: this.gateway.modem_mac, time: Date.now()});
|
|
4993
|
+
// }else{
|
|
4994
|
+
// node.send({topic: 'error', payload: {code: 1, description: 'Wireless module did not respond'}, time: Date.now()});
|
|
4995
|
+
// }
|
|
4996
|
+
// });
|
|
4997
|
+
};
|
|
4998
|
+
// register a new node called ncd-api-config
|
|
4999
|
+
RED.nodes.registerType("ncd-api-configuration-node", NcdAPIConfigurationNode);
|
|
4048
5000
|
};
|
|
4049
5001
|
function getSerialDevices(ftdi, res){
|
|
4050
5002
|
var busses = [];
|