@ncd-io/node-red-enterprise-sensors 0.1.23 → 1.0.0
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/lib/DigiParser.js +3 -2
- package/lib/WirelessGateway.js +46 -16
- package/package.json +1 -1
- package/wireless.html +2 -4
- package/wireless.js +343 -3
package/lib/DigiParser.js
CHANGED
|
@@ -122,6 +122,7 @@ module.exports = class DigiComm{
|
|
|
122
122
|
that.serial.write(packet, (err) => {
|
|
123
123
|
that.lastSent = packet;
|
|
124
124
|
if(err){
|
|
125
|
+
console.log('_send frame error');
|
|
125
126
|
console.log(err);
|
|
126
127
|
}
|
|
127
128
|
});
|
|
@@ -172,8 +173,8 @@ class outgoingFrame{
|
|
|
172
173
|
var config = this.transmissionOptions(opts);
|
|
173
174
|
var frame = [17, this.master.getId()];
|
|
174
175
|
frame.push(...mac);
|
|
175
|
-
var
|
|
176
|
-
frame.push(...
|
|
176
|
+
var payload = [255, 254, source, destination, cluster[0], cluster[1], profile[0], profile[1], (config >> 8), (config & 255)];
|
|
177
|
+
frame.push(...payload);
|
|
177
178
|
if(data.constructor != Array) data = [data];
|
|
178
179
|
frame.push(...data);
|
|
179
180
|
return this.master._send(frame);
|
package/lib/WirelessGateway.js
CHANGED
|
@@ -136,6 +136,11 @@ module.exports = class WirelessSensor{
|
|
|
136
136
|
var is_new = typeof this.sensor_pool[frame.mac] == 'undefined';
|
|
137
137
|
var new_mode = is_new;
|
|
138
138
|
var mode = (type == 'power_up') ? data.mode : ((type == 'sensor_data') ? 'RUN' : ((type == 'config_ack') ? 'ACK' : 'PGM'));
|
|
139
|
+
if(mode == 'ACK'){
|
|
140
|
+
if(data.data.length == 37){
|
|
141
|
+
this._emitter.emit('manifest_received', data);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
139
144
|
// #OTF
|
|
140
145
|
var otf_devices = [23,26,39,45,48,52,76,78,79,80,81,82,84,88,89,90,91,101,102,107,108,180,181,519,520,521,531,535,537];
|
|
141
146
|
var device_type = msbLsb(frame.data[6], frame.data[7]);
|
|
@@ -492,18 +497,6 @@ module.exports = class WirelessSensor{
|
|
|
492
497
|
if('z_offset' in en_axis_data){
|
|
493
498
|
fft_concat[label].z = parseFloat((signInt(((raw_data[i+en_axis_data.z_offset]<<8)+(raw_data[i+en_axis_data.z_offset+1])), 16)*fsr_mult).toFixed(5));
|
|
494
499
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
// fft.push(fft_data);
|
|
498
|
-
// if(label< 40){
|
|
499
|
-
// fft_concat[label] = {
|
|
500
|
-
// // label: label,
|
|
501
|
-
// x: parseFloat((signInt(((raw_data[i]<<8)+(raw_data[i+1]&255)), 16)*.00006).toFixed(5)),
|
|
502
|
-
// y: parseFloat((signInt(((raw_data[i+2]<<8)+(raw_data[i+3]&255)), 16)*.00006).toFixed(5)),
|
|
503
|
-
// z: parseFloat((signInt(((raw_data[i+4]<<8)+(raw_data[i+5]&255)), 16)*.00006).toFixed(5)),
|
|
504
|
-
// };
|
|
505
|
-
// }
|
|
506
|
-
|
|
507
500
|
}
|
|
508
501
|
var fft_concat_obj = {
|
|
509
502
|
time_id: globalDevices[deviceAddr].hour +':'+ globalDevices[deviceAddr].minute,
|
|
@@ -733,6 +726,41 @@ module.exports = class WirelessSensor{
|
|
|
733
726
|
}
|
|
734
727
|
return parsed;
|
|
735
728
|
}
|
|
729
|
+
firmware_set_to_ota_mode(sensor_mac){
|
|
730
|
+
console.log('firmware_set_to_ota_mode');
|
|
731
|
+
var packet = [245, 56, 0, 0, 0];
|
|
732
|
+
return this.config_send(sensor_mac, packet);
|
|
733
|
+
}
|
|
734
|
+
// TODO no code basis
|
|
735
|
+
firmware_exit_ota_mode(sensor_mac){
|
|
736
|
+
console.log('firmware_exit_ota_mode');
|
|
737
|
+
var packet = [245, 57, 0, 0, 0];
|
|
738
|
+
return this.config_send(sensor_mac, packet);
|
|
739
|
+
}
|
|
740
|
+
firmware_request_manifest(sensor_mac){
|
|
741
|
+
console.log('firmware_request_manifest');
|
|
742
|
+
var packet = [245, 60, 0, 0, 0];
|
|
743
|
+
return this.config_send(sensor_mac, packet);
|
|
744
|
+
}
|
|
745
|
+
firmware_send_manifest(sensor_mac, manifest){
|
|
746
|
+
console.log('firmware_send_manifest');
|
|
747
|
+
// sensor_mac = "00:00:00:00:00:00:ff:ff";
|
|
748
|
+
let packet = [245, 58, 0, 0, 0].concat(Array.prototype.slice.call(manifest));
|
|
749
|
+
return this.config_send(sensor_mac, packet);
|
|
750
|
+
}
|
|
751
|
+
firmware_send_chunk(sensor_mac, offset, chunk){
|
|
752
|
+
console.log('firmware_send_chunk');
|
|
753
|
+
// sensor_mac = "00:00:00:00:00:00:ff:ff";
|
|
754
|
+
let packet = [245, 59, 0, 0, 0].concat(offset, Array.prototype.slice.call(chunk));
|
|
755
|
+
// console.log(packet);
|
|
756
|
+
return this.config_send(sensor_mac, packet);
|
|
757
|
+
}
|
|
758
|
+
firmware_request_last_segment(sensor_mac){
|
|
759
|
+
console.log('firmware_request_last_segment');
|
|
760
|
+
let packet = [245, 61, 0, 0, 0];
|
|
761
|
+
// console.log(packet);
|
|
762
|
+
return this.config_send(sensor_mac, packet);
|
|
763
|
+
}
|
|
736
764
|
config_reboot_sensor(sensor_mac){
|
|
737
765
|
console.log('config_reboot_sensor: '+sensor_mac)
|
|
738
766
|
var packet = [247, 64, 0, 0, 0];
|
|
@@ -916,7 +944,6 @@ module.exports = class WirelessSensor{
|
|
|
916
944
|
console.log('config_set_sensor_forced_calibration_535');
|
|
917
945
|
// convert before processing
|
|
918
946
|
var packet = [244, 32, 0, 0, 0];
|
|
919
|
-
console.log(packet);
|
|
920
947
|
return this.config_send(sensor_mac, packet);
|
|
921
948
|
}
|
|
922
949
|
config_set_sensor_temperature_offset_44(sensor_mac, value){
|
|
@@ -1136,7 +1163,7 @@ module.exports = class WirelessSensor{
|
|
|
1136
1163
|
return this.config_send(sensor_mac, packet);
|
|
1137
1164
|
}
|
|
1138
1165
|
config_set_roll_threshold_47(sensor_mac, threshold){
|
|
1139
|
-
console.log('
|
|
1166
|
+
console.log('config_set_roll_threshold_47');
|
|
1140
1167
|
var packet = [244, 1, 0, 0, 47, 0, threshold];
|
|
1141
1168
|
console.log(packet);
|
|
1142
1169
|
return this.config_send(sensor_mac, packet);
|
|
@@ -1147,7 +1174,6 @@ module.exports = class WirelessSensor{
|
|
|
1147
1174
|
console.log(packet);
|
|
1148
1175
|
return this.config_send(sensor_mac, packet);
|
|
1149
1176
|
}
|
|
1150
|
-
|
|
1151
1177
|
config_set_accelerometer_threshold_108(sensor_mac, value){
|
|
1152
1178
|
console.log('config_set_accelerometer_threshold_108');
|
|
1153
1179
|
var packet = [244, 32, 0, 0, 0, 1, value];
|
|
@@ -1498,6 +1524,11 @@ module.exports = class WirelessSensor{
|
|
|
1498
1524
|
};
|
|
1499
1525
|
return this.config_send(sensor_mac, [(data ? 247 : 248), params[param], ...data]);
|
|
1500
1526
|
}
|
|
1527
|
+
clear_queue(){
|
|
1528
|
+
this.queue.queue = new Array;
|
|
1529
|
+
delete this.queue;
|
|
1530
|
+
this.queue = new Queue(1);
|
|
1531
|
+
}
|
|
1501
1532
|
config_send(sensor_mac, data, opts){
|
|
1502
1533
|
var that = this;
|
|
1503
1534
|
return new Promise((fulfill, reject) => {
|
|
@@ -4093,7 +4124,6 @@ function sensor_types(parent){
|
|
|
4093
4124
|
}
|
|
4094
4125
|
}
|
|
4095
4126
|
},
|
|
4096
|
-
|
|
4097
4127
|
'82': {
|
|
4098
4128
|
name: 'Condition Based/Predictive Maintenance Sensor',
|
|
4099
4129
|
parse: (payload, parsed, mac) => {
|
package/package.json
CHANGED
package/wireless.html
CHANGED
|
@@ -953,7 +953,7 @@
|
|
|
953
953
|
</select>
|
|
954
954
|
</div>
|
|
955
955
|
</div>
|
|
956
|
-
<div class="ncd-dependent" data-sensor-7 data-sensor-24>
|
|
956
|
+
<div class="ncd-dependent" data-sensor-7 data-sensor-24 data-sensor-25>
|
|
957
957
|
<hr>
|
|
958
958
|
<div class="form-row ncd-active-check">
|
|
959
959
|
<div>
|
|
@@ -1026,7 +1026,7 @@
|
|
|
1026
1026
|
</div>
|
|
1027
1027
|
</div>
|
|
1028
1028
|
</div>
|
|
1029
|
-
<div class="ncd-dependent" data-sensor-24>
|
|
1029
|
+
<div class="ncd-dependent" data-sensor-24 data-sensor-25>
|
|
1030
1030
|
<div class="form-row">
|
|
1031
1031
|
<label for="node-input-activ_interr_x"><i class="icon-tag"></i> Interrupt X-Axis</label>
|
|
1032
1032
|
<select id="node-input-activ_interr_x">
|
|
@@ -1820,7 +1820,6 @@
|
|
|
1820
1820
|
</div>
|
|
1821
1821
|
</div>
|
|
1822
1822
|
</div>
|
|
1823
|
-
|
|
1824
1823
|
<div class="ncd-dependent" data-sensor-108>
|
|
1825
1824
|
<div class="form-row ncd-active-check">
|
|
1826
1825
|
<strong>Enable Accelerometer Error Reporting</strong>
|
|
@@ -1872,7 +1871,6 @@
|
|
|
1872
1871
|
</div>
|
|
1873
1872
|
</div>
|
|
1874
1873
|
</div>
|
|
1875
|
-
|
|
1876
1874
|
<div class="ncd-dependent" data-sensor-35 data-sensor-36>
|
|
1877
1875
|
<hr>
|
|
1878
1876
|
<div class="form-row ncd-active-check">
|
package/wireless.js
CHANGED
|
@@ -3,7 +3,8 @@ const comms = require('ncd-red-comm');
|
|
|
3
3
|
const sp = require('serialport');
|
|
4
4
|
const Queue = require("promise-queue");
|
|
5
5
|
const events = require("events");
|
|
6
|
-
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const home_dir = require('os').homedir
|
|
7
8
|
module.exports = function(RED) {
|
|
8
9
|
var gateway_pool = {};
|
|
9
10
|
function NcdGatewayConfig(config){
|
|
@@ -14,6 +15,8 @@ module.exports = function(RED) {
|
|
|
14
15
|
|
|
15
16
|
this.listeners = [];
|
|
16
17
|
this.sensor_pool = [];
|
|
18
|
+
// TODO sensor_list is a temporary property, should be combined with sensor_pool
|
|
19
|
+
this.sensor_list = {};
|
|
17
20
|
this._emitter = new events.EventEmitter();
|
|
18
21
|
this.on = (e,c) => this._emitter.on(e, c);
|
|
19
22
|
|
|
@@ -72,6 +75,67 @@ module.exports = function(RED) {
|
|
|
72
75
|
node.gateway.digi.serial.reconnect();
|
|
73
76
|
});
|
|
74
77
|
}
|
|
78
|
+
// Event listener to make sure this only triggers once no matter how many gateway nodes there are
|
|
79
|
+
node.gateway.on('sensor_mode', (d) => {
|
|
80
|
+
if(d.mode == "FLY"){
|
|
81
|
+
if(Object.hasOwn(node.sensor_list, d.mac) && Object.hasOwn(node.sensor_list[d.mac], 'update_request')){
|
|
82
|
+
node.request_manifest(d.mac);
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
node.gateway.on('manifest_received', (manifest_data) => {
|
|
87
|
+
// read manifest length is 37. Could use the same event for both
|
|
88
|
+
if(Object.hasOwn(node.sensor_list, manifest_data.addr) && Object.hasOwn(node.sensor_list[manifest_data.addr], 'update_request')){
|
|
89
|
+
// TODO check manifest data and start update process
|
|
90
|
+
}
|
|
91
|
+
manifest_data.data = node._parse_manifest_read(manifest_data.data);
|
|
92
|
+
node._emitter.emit('send_manifest', manifest_data);
|
|
93
|
+
let firmware_data = node._compare_manifest(manifest_data);
|
|
94
|
+
if(!firmware_data){
|
|
95
|
+
delete node.sensor_list[manifest_data.addr].update_request;
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// TODO Right now assume everything is good
|
|
100
|
+
// node.gateway.firmware_set_to_ota_mode(manifest_data.addr);
|
|
101
|
+
|
|
102
|
+
setTimeout(() => {
|
|
103
|
+
var tout = setTimeout(() => {
|
|
104
|
+
console.log('Start OTA Timed Out');
|
|
105
|
+
}, 10000);
|
|
106
|
+
|
|
107
|
+
var promises = {};
|
|
108
|
+
promises.firmware_set_to_ota_mode = node.gateway.firmware_set_to_ota_mode(manifest_data.addr);
|
|
109
|
+
promises.finish = new Promise((fulfill, reject) => {
|
|
110
|
+
node.gateway.queue.add(() => {
|
|
111
|
+
return new Promise((f, r) => {
|
|
112
|
+
clearTimeout(tout);
|
|
113
|
+
// node.status(modes.FLY);
|
|
114
|
+
fulfill();
|
|
115
|
+
f();
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
for(var i in promises){
|
|
120
|
+
(function(name){
|
|
121
|
+
promises[name].then((f) => {
|
|
122
|
+
if(name != 'finish'){
|
|
123
|
+
console.log(name);
|
|
124
|
+
}
|
|
125
|
+
else{
|
|
126
|
+
// enter ota mode
|
|
127
|
+
node.gateway.digi.send.at_command("ID", [0x7a, 0xaa]).then().catch().then(() => {
|
|
128
|
+
node.start_firmware_update(manifest_data, firmware_data);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}).catch((err) => {
|
|
132
|
+
console.log(err);
|
|
133
|
+
// msg[name] = err;
|
|
134
|
+
});
|
|
135
|
+
})(i);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
});
|
|
75
139
|
}));
|
|
76
140
|
});
|
|
77
141
|
node.gateway.digi.serial.on('closed_comms', () => {
|
|
@@ -102,6 +166,81 @@ module.exports = function(RED) {
|
|
|
102
166
|
});
|
|
103
167
|
};
|
|
104
168
|
|
|
169
|
+
node.start_firmware_update = function(manifest_data, firmware_data){
|
|
170
|
+
return new Promise((top_fulfill, top_reject) => {
|
|
171
|
+
var success = {};
|
|
172
|
+
|
|
173
|
+
setTimeout(() => {
|
|
174
|
+
let chunk_size = 128;
|
|
175
|
+
let image_start = firmware_data.firmware.slice(1, 5).reduce(msbLsb)+6;
|
|
176
|
+
|
|
177
|
+
var promises = {};
|
|
178
|
+
promises.manifest = node.gateway.firmware_send_manifest(manifest_data.addr, firmware_data.firmware.slice(5, image_start-1));
|
|
179
|
+
firmware_data.firmware = firmware_data.firmware.slice(image_start+4);
|
|
180
|
+
|
|
181
|
+
var index = 0;
|
|
182
|
+
if(Object.hasOwn(node.sensor_list[manifest_data.addr], 'last_chunk_success')){
|
|
183
|
+
index = node.sensor_list[manifest_data.addr].last_chunk_success;
|
|
184
|
+
}
|
|
185
|
+
var temp_count = 0;
|
|
186
|
+
while(index*chunk_size < firmware_data.manifest.image_size){
|
|
187
|
+
let offset = index*chunk_size;
|
|
188
|
+
// console.log(index);
|
|
189
|
+
// let packet = [254, 59, 0, 0, 0];
|
|
190
|
+
let offset_bytes = int2Bytes(offset, 4);
|
|
191
|
+
let firmware_chunk = firmware_data.firmware.slice(index*chunk_size, index*chunk_size+chunk_size);
|
|
192
|
+
temp_count += 1;
|
|
193
|
+
// packet = packet.concat(offset_bytes, firmware_chunk);
|
|
194
|
+
promises[index] = node.gateway.firmware_send_chunk(manifest_data.addr, offset_bytes, firmware_chunk);
|
|
195
|
+
index++;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
promises.reboot = node.gateway.config_reboot_sensor(manifest_data.addr);
|
|
199
|
+
|
|
200
|
+
for(var i in promises){
|
|
201
|
+
(function(name){
|
|
202
|
+
promises[name].then((f) => {
|
|
203
|
+
if(name == 'manifest'){
|
|
204
|
+
// delete node.sensor_list[manifest_data.addr].promises[name];
|
|
205
|
+
node.sensor_list[manifest_data.addr].test_check = {name: true};
|
|
206
|
+
node.sensor_list[manifest_data.addr].update_in_progress = true;
|
|
207
|
+
}else {
|
|
208
|
+
success[name] = true;
|
|
209
|
+
node.sensor_list[manifest_data.addr].test_check[name] = true;
|
|
210
|
+
node.sensor_list[manifest_data.addr].last_chunk_success = name;
|
|
211
|
+
// delete node.sensor_list[manifest_data.addr].promises[name];
|
|
212
|
+
}
|
|
213
|
+
}).catch((err) => {
|
|
214
|
+
if(name != 'reboot'){
|
|
215
|
+
node.gateway.clear_queue();
|
|
216
|
+
success[name] = err;
|
|
217
|
+
}else{
|
|
218
|
+
delete node.sensor_list[manifest_data.addr].last_chunk_success;
|
|
219
|
+
delete node.sensor_list[manifest_data.addr].update_request;
|
|
220
|
+
node._emitter.emit('send_firmware_stats', {state: success, addr: manifest_data.addr});
|
|
221
|
+
// #OTF
|
|
222
|
+
// node.send({topic: 'Config Results', payload: success, time: Date.now(), addr: manifest_data.addr});
|
|
223
|
+
top_fulfill(success);
|
|
224
|
+
}
|
|
225
|
+
node._emitter.emit('send_firmware_stats', {state: success, addr: manifest_data.addr});
|
|
226
|
+
node.resume_normal_operation();
|
|
227
|
+
});
|
|
228
|
+
})(i);
|
|
229
|
+
}
|
|
230
|
+
}, 1000);
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
node.resume_normal_operation = function(){
|
|
234
|
+
let pan_id = parseInt(config.pan_id, 16);
|
|
235
|
+
node.gateway.digi.send.at_command("ID", [pan_id >> 8, pan_id & 255]).then().catch().then(() => {
|
|
236
|
+
console.log('Set Pan ID to: '+pan_id);
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
node.request_manifest = function(sensor_addr){
|
|
241
|
+
// Request Manifest
|
|
242
|
+
node.gateway.firmware_request_manifest(sensor_addr);
|
|
243
|
+
};
|
|
105
244
|
|
|
106
245
|
node.close_comms = function(){
|
|
107
246
|
// node.gateway._emitter.removeAllListeners('sensor_data');
|
|
@@ -118,7 +257,55 @@ module.exports = function(RED) {
|
|
|
118
257
|
// });
|
|
119
258
|
}
|
|
120
259
|
}
|
|
260
|
+
}
|
|
261
|
+
node._compare_manifest = function(sensor_manifest){
|
|
262
|
+
let firmware_dir = home_dir()+'/.node-red/node_modules/@ncd-io/node-red-enterprise-sensors/firmware_files';
|
|
263
|
+
let filename = '/' + sensor_manifest.data.device_type + '-' + sensor_manifest.data.hardware_id[0] + '_' + sensor_manifest.data.hardware_id[1] + '_' + sensor_manifest.data.hardware_id[2] + '.ncd';
|
|
264
|
+
|
|
265
|
+
try {
|
|
266
|
+
let firmware_file = fs.readFileSync(firmware_dir+filename,)
|
|
267
|
+
let stored_manifest = node._parse_manifest(firmware_file);
|
|
268
|
+
if(stored_manifest.firmware_version === sensor_manifest.data.firmware_version){
|
|
269
|
+
console.log('firmware versions SAME');
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
121
272
|
|
|
273
|
+
if(stored_manifest.max_image_size < sensor_manifest.data.image_size){
|
|
274
|
+
console.log('firmware image too large');
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
return {manifest: stored_manifest, firmware: firmware_file};
|
|
278
|
+
} catch(err){
|
|
279
|
+
console.log(err);
|
|
280
|
+
return err;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
node._parse_manifest = function(bin_data){
|
|
284
|
+
return {
|
|
285
|
+
manifest_check: bin_data[0] == 0x01,
|
|
286
|
+
manifest_size: bin_data.slice(1, 5).reduce(msbLsb),
|
|
287
|
+
firmware_version: bin_data[5],
|
|
288
|
+
image_start_address: bin_data.slice(6, 10).reduce(msbLsb),
|
|
289
|
+
image_size: bin_data.slice(10, 14).reduce(msbLsb),
|
|
290
|
+
max_image_size: bin_data.slice(14, 18).reduce(msbLsb),
|
|
291
|
+
image_digest: bin_data.slice(18, 34),
|
|
292
|
+
device_type: bin_data.slice(34, 36).reduce(msbLsb),
|
|
293
|
+
hardware_id: bin_data.slice(36, 39),
|
|
294
|
+
reserve_bytes: bin_data.slice(39, 42)
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
node._parse_manifest_read = function(bin_data){
|
|
298
|
+
return {
|
|
299
|
+
// manifest_size: bin_data.slice(0,4).reduce(msbLsb),
|
|
300
|
+
firmware_version: bin_data[0],
|
|
301
|
+
image_start_address: bin_data.slice(1, 5).reduce(msbLsb),
|
|
302
|
+
image_size: bin_data.slice(5, 9).reduce(msbLsb),
|
|
303
|
+
max_image_size: bin_data.slice(9, 13).reduce(msbLsb),
|
|
304
|
+
image_digest: bin_data.slice(13, 29),
|
|
305
|
+
device_type: bin_data.slice(29, 31).reduce(msbLsb),
|
|
306
|
+
hardware_id: bin_data.slice(31, 34),
|
|
307
|
+
reserve_bytes: bin_data.slice(34, 37)
|
|
308
|
+
}
|
|
122
309
|
}
|
|
123
310
|
}
|
|
124
311
|
|
|
@@ -149,7 +336,17 @@ module.exports = function(RED) {
|
|
|
149
336
|
node.set_status = function(){
|
|
150
337
|
node.status(statuses[node._gateway_node.is_config]);
|
|
151
338
|
};
|
|
152
|
-
|
|
339
|
+
node._gateway_node.on('send_manifest', (manifest_data) => {
|
|
340
|
+
node.send({
|
|
341
|
+
topic: 'sensor_manifest',
|
|
342
|
+
payload: {
|
|
343
|
+
addr: manifest_data.addr,
|
|
344
|
+
sensor_type: manifest_data.sensor_type,
|
|
345
|
+
manifest: manifest_data.data
|
|
346
|
+
},
|
|
347
|
+
time: Date.now()
|
|
348
|
+
});
|
|
349
|
+
});
|
|
153
350
|
node.on('input', function(msg){
|
|
154
351
|
switch(msg.topic){
|
|
155
352
|
case "route_trace":
|
|
@@ -187,7 +384,133 @@ module.exports = function(RED) {
|
|
|
187
384
|
// if(msg.topic == "fidelity_test"){
|
|
188
385
|
// }
|
|
189
386
|
});
|
|
387
|
+
node._gateway_node.on('send_firmware_stats', (data) => {
|
|
388
|
+
node.send({
|
|
389
|
+
topic: 'update_stats',
|
|
390
|
+
payload: data.state,
|
|
391
|
+
addr: data.addr,
|
|
392
|
+
time: Date.now()
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
node.on('input', function(msg){
|
|
396
|
+
switch(msg.topic){
|
|
397
|
+
case "route_trace":
|
|
398
|
+
var opts = {trace:1};
|
|
399
|
+
node.gateway.route_discover(msg.payload.address,opts).then().catch(console.log);
|
|
400
|
+
break;
|
|
401
|
+
case "link_test":
|
|
402
|
+
node.gateway.link_test(msg.payload.source_address,msg.payload.destination_address,msg.payload.options);
|
|
403
|
+
break;
|
|
404
|
+
case "fidelity_test":
|
|
405
|
+
break;
|
|
406
|
+
case "add_firmware_file":
|
|
407
|
+
// Parse Manifest to grab information and store it for later use
|
|
408
|
+
// msg.payload = [0x01, 0x00, ...]
|
|
409
|
+
let new_msg = {
|
|
410
|
+
topic: 'add_firmware_file_response',
|
|
411
|
+
payload: node._gateway_node._parse_manifest(msg.payload)
|
|
412
|
+
}
|
|
413
|
+
let firmware_dir = home_dir()+'/.node-red/node_modules/@ncd-io/node-red-enterprise-sensors/firmware_files';
|
|
414
|
+
if (!fs.existsSync(firmware_dir)) {
|
|
415
|
+
fs.mkdirSync(firmware_dir);
|
|
416
|
+
};
|
|
417
|
+
let filename = '/' + new_msg.payload.device_type + '-' + new_msg.payload.hardware_id[0] + '_' + new_msg.payload.hardware_id[1] + '_' + new_msg.payload.hardware_id[2] + '.ncd';
|
|
418
|
+
fs.writeFile(firmware_dir+filename, msg.payload, function(err){
|
|
419
|
+
if(err){
|
|
420
|
+
console.log(err);
|
|
421
|
+
};
|
|
422
|
+
console.log('Success');
|
|
423
|
+
});
|
|
424
|
+
node.send(new_msg);
|
|
425
|
+
break;
|
|
426
|
+
// case "get_firmware_file":
|
|
427
|
+
// Commented out as I'd rather use a flow to request the file. More robust. Maybe more complicated, wait for feedback.
|
|
428
|
+
// // This input makes a request to the specified url and downloads a firmware file at that location
|
|
429
|
+
// // msg.payload = "https://github.com/ncd-io/WiFi_MQTT_Temperature_Firmware/raw/main/v1.0.3/firmware.bin"
|
|
430
|
+
|
|
431
|
+
case "check_firmware_file":
|
|
432
|
+
// Read file that should be at location and spit out the binary
|
|
433
|
+
// Example msg.payload
|
|
434
|
+
// msg.payload = {
|
|
435
|
+
// device_type: 80,
|
|
436
|
+
// hardware_id: [88, 88, 88]
|
|
437
|
+
// }
|
|
438
|
+
break;
|
|
439
|
+
case "ota_firmware_update_single":
|
|
440
|
+
// msg.payload = {
|
|
441
|
+
// 'address': "00:13:a2:00:42:2c:d2:aa"
|
|
442
|
+
// }
|
|
443
|
+
if(!Object.hasOwn(node._gateway_node.sensor_list, msg.payload)){
|
|
444
|
+
node._gateway_node.sensor_list[msg.payload] = {};
|
|
445
|
+
};
|
|
446
|
+
if(!Object.hasOwn(node._gateway_node.sensor_list[msg.payload], 'update_request')){
|
|
447
|
+
node._gateway_node.sensor_list[msg.payload].update_request = true;
|
|
448
|
+
};
|
|
449
|
+
break;
|
|
450
|
+
case "ota_firmware_update_multiple":
|
|
451
|
+
// set the devices user wants to upload new firmware to
|
|
452
|
+
// msg.payload = {
|
|
453
|
+
// 'addresses': [
|
|
454
|
+
// "00:13:a2:00:42:2c:d2:aa",
|
|
455
|
+
// "00:13:a2:00:42:2c:d2:ab"
|
|
456
|
+
// ];
|
|
457
|
+
// }
|
|
458
|
+
// TODO unfinished
|
|
459
|
+
msg.payload.addresses.forEach((address) => {
|
|
460
|
+
if(!Object.hasOwn(node._gateway_node.sensor_list, msg.payload.address)){
|
|
461
|
+
node._gateway_node.sensor_list[address] = {};
|
|
462
|
+
};
|
|
463
|
+
if(!Object.hasOwn(node._gateway_node.sensor_list[msg.payload.address], 'update_request')){
|
|
464
|
+
node._gateway_node.sensor_list[address].update_request = true;
|
|
465
|
+
};
|
|
466
|
+
});
|
|
467
|
+
break;
|
|
468
|
+
case "get_manifest":
|
|
469
|
+
// Allows user to request manifest from one or more devices
|
|
470
|
+
// Primarily envisioned used for troubleshooting or engineer determination
|
|
471
|
+
// msg.payload = {
|
|
472
|
+
// 'addresses': [
|
|
473
|
+
// "00:13:a2:00:42:2c:d2:aa",
|
|
474
|
+
// "00:13:a2:00:42:2c:d2:ab"
|
|
475
|
+
// ];
|
|
476
|
+
// }
|
|
477
|
+
// OR
|
|
478
|
+
// msg.payload = {
|
|
479
|
+
// 'address': "00:13:a2:00:42:2c:d2:aa"
|
|
480
|
+
// }
|
|
481
|
+
break;
|
|
482
|
+
default:
|
|
483
|
+
const byteArrayToHexString = byteArray => Array.from(msg.payload.address, byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join('');
|
|
484
|
+
node.gateway.control_send(msg.payload.address, msg.payload.data, msg.payload.options).then().catch(console.log);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
// console.log("input triggered, topic:"+msg.topic);
|
|
489
|
+
// if(msg.topic == "transmit"){
|
|
490
|
+
// const byteArrayToHexString = byteArray => Array.from(msg.payload.address, byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join('');
|
|
491
|
+
// node.gateway.control_send(msg.payload.address, msg.payload.data, msg.payload.options).then().catch(console.log);
|
|
492
|
+
// }
|
|
493
|
+
// if(msg.topic == "route_trace"){
|
|
494
|
+
// var opts = {trace:1};
|
|
495
|
+
// node.gateway.route_discover(msg.payload.address,opts).then().catch(console.log);
|
|
496
|
+
// }
|
|
497
|
+
// if(msg.topic == "link_test"){
|
|
498
|
+
// node.gateway.link_test(msg.payload.source_address,msg.payload.destination_address,msg.payload.options);
|
|
499
|
+
// }
|
|
500
|
+
// if(msg.topic == "fft_request"){
|
|
190
501
|
|
|
502
|
+
// }
|
|
503
|
+
// if(msg.topic == "fidelity_test"){
|
|
504
|
+
// }
|
|
505
|
+
});
|
|
506
|
+
node.gateway.on('ncd_error', (data) => {
|
|
507
|
+
node.send({
|
|
508
|
+
topic: 'ncd_error',
|
|
509
|
+
data: data,
|
|
510
|
+
payload: data.error,
|
|
511
|
+
time: Date.now()
|
|
512
|
+
});
|
|
513
|
+
});
|
|
191
514
|
node.gateway.on('sensor_data', (d) => {
|
|
192
515
|
node.set_status();
|
|
193
516
|
node.send({topic: 'sensor_data', payload: d, time: Date.now()});
|
|
@@ -237,7 +560,7 @@ module.exports = function(RED) {
|
|
|
237
560
|
this.config_gateway = this.config_gateway_node.gateway;
|
|
238
561
|
dedicated_config = true;
|
|
239
562
|
}
|
|
240
|
-
this.queue = new Queue(1);
|
|
563
|
+
// this.queue = new Queue(1);
|
|
241
564
|
var node = this;
|
|
242
565
|
var modes = {
|
|
243
566
|
PGM: {fill:"red",shape:"dot",text:"Config Mode"},
|
|
@@ -247,6 +570,7 @@ module.exports = function(RED) {
|
|
|
247
570
|
RUN: {fill:"green",shape:"dot",text:"Running"},
|
|
248
571
|
PUM: {fill:"yellow",shape:"ring",text:"Module was factory reset"},
|
|
249
572
|
ACK: {fill:"green",shape:"ring",text:"Configuration Acknowledged"},
|
|
573
|
+
STREAM_ERR: {fill:"red",shape:"ring",text:"Multi-Packet Stream Error"},
|
|
250
574
|
// FLY: {fill:"yellow",shape:"ring",text:"FLY notification received"},
|
|
251
575
|
// OTN: {fill:"yellow",shape:"ring",text:"OTN Received, OTF Configuration Initiated"},
|
|
252
576
|
// OFF: {fill:"green",shape:"dot",text:"OFF Recieved, OTF Configuration Completed"}
|
|
@@ -498,6 +822,21 @@ module.exports = function(RED) {
|
|
|
498
822
|
}
|
|
499
823
|
var interr = parseInt(config.activ_interr_x) | parseInt(config.activ_interr_y) | parseInt(config.activ_interr_z) | parseInt(config.activ_interr_op);
|
|
500
824
|
promises.activity_interrupt = node.config_gateway.config_set_interrupt_24(mac, interr);
|
|
825
|
+
case 25:
|
|
826
|
+
if(config.impact_accel_active){
|
|
827
|
+
promises.impact_accel = node.config_gateway.config_set_acceleration_range_24(mac, parseInt(config.impact_accel));
|
|
828
|
+
}
|
|
829
|
+
if(config.impact_data_rate_active){
|
|
830
|
+
promises.impact_data_rate = node.config_gateway.config_set_data_rate_24(mac, parseInt(config.impact_data_rate));
|
|
831
|
+
}
|
|
832
|
+
if(config.impact_threshold_active){
|
|
833
|
+
promises.impact_threshold = node.config_gateway.config_set_threshold_24(mac, parseInt(config.impact_threshold));
|
|
834
|
+
}
|
|
835
|
+
if(config.impact_duration_active){
|
|
836
|
+
promises.impact_duration = node.config_gateway.config_set_duration_24(mac, parseInt(config.impact_duration));
|
|
837
|
+
}
|
|
838
|
+
var interr = parseInt(config.activ_interr_x) | parseInt(config.activ_interr_y) | parseInt(config.activ_interr_z) | parseInt(config.activ_interr_op);
|
|
839
|
+
promises.activity_interrupt = node.config_gateway.config_set_interrupt_24(mac, interr);
|
|
501
840
|
case 35:
|
|
502
841
|
if(config.counter_threshold_35_active){
|
|
503
842
|
promises.config_set_counter_threshold_35 = node.config_gateway.config_set_counter_threshold_35(mac, parseInt(config.counter_threshold_35));
|
|
@@ -1600,3 +1939,4 @@ function toHex(n){return ('00' + n.toString(16)).substr(-2);}
|
|
|
1600
1939
|
function toMac(arr){
|
|
1601
1940
|
return arr.reduce((h,c,i) => {return ((i==1?toHex(h):h)+':'+toHex(c)).toUpperCase();});
|
|
1602
1941
|
}
|
|
1942
|
+
function msbLsb(m,l){return (m<<8)+l;};
|