@ncd-io/node-red-enterprise-sensors 1.6.4 → 2.0.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.
@@ -0,0 +1,1039 @@
1
+ const { toMac, signInt, msbLsb } = require('../utils');
2
+
3
+ // --- 1. DEFINE LOCAL FUNCTIONS ---
4
+ // These are defined as local variables so they can call each other easily.
5
+ module.exports = (globalDevices) => {
6
+
7
+ const get_write_buffer_size = (firmware) => {
8
+ return 22;
9
+ };
10
+
11
+ const get_config_map = (firmware) => {
12
+ console.log('Generating sync map for firmware version', firmware);
13
+
14
+ return {
15
+ "core_version": {
16
+ "read_index": 3,
17
+ "descriptions": {
18
+ "title": "Core Version",
19
+ "main_caption": "The version of the core communication stack."
20
+ },
21
+ "validator": {
22
+ "type": "uint8"
23
+ },
24
+ "tags": [
25
+ "system"
26
+ ]
27
+ },
28
+ "firmware_version": {
29
+ "read_index": 4,
30
+ "descriptions": {
31
+ "title": "Firmware Version",
32
+ "main_caption": "The application-specific firmware version."
33
+ },
34
+ "validator": {
35
+ "type": "uint8"
36
+ },
37
+ "tags": [
38
+ "system"
39
+ ]
40
+ },
41
+ "sensor_type": {
42
+ "read_index": 5,
43
+ "descriptions": {
44
+ "title": "Sensor Type",
45
+ "main_caption": "The hardware identifier for the specific sensor model."
46
+ },
47
+ "validator": {
48
+ "type": "uint16be"
49
+ },
50
+ "tags": [
51
+ "system"
52
+ ]
53
+ },
54
+ "tx_lifetime_counter": {
55
+ "read_index": 7,
56
+ "descriptions": {
57
+ "title": "Sampling Interval",
58
+ "main_caption": "Set how often will the sensor transmit measurement data. Note: For this sensor, this value functions as the sampling interval rather than a traditional delay.",
59
+ "sub_caption": "Default value: 20 milliseconds."
60
+ },
61
+ "validator": {
62
+ "type": "uint32be"
63
+ },
64
+ "tags": [
65
+ "diagnostics"
66
+ ]
67
+ },
68
+ "hardware_id": {
69
+ "read_index": 11,
70
+ "length": 3,
71
+ "descriptions": {
72
+ "title": "Hardware ID",
73
+ "main_caption": "A unique 3-byte hardware identifier."
74
+ },
75
+ "validator": {
76
+ "type": "buffer"
77
+ },
78
+ "tags": [
79
+ "system"
80
+ ]
81
+ },
82
+ "network_id": {
83
+ "read_index": 14,
84
+ "write_index": 3,
85
+ "length": 2,
86
+ "descriptions": {
87
+ "title": "Network ID",
88
+ "main_caption": ""
89
+ },
90
+ "default_value": "7fff",
91
+ "validator": {
92
+ "type": "hex",
93
+ "length": 4
94
+ },
95
+ "html_id": "pan_id",
96
+ "tags": [
97
+ "communications"
98
+ ]
99
+ },
100
+ "destination_address": {
101
+ "read_index": 16,
102
+ "write_index": 5,
103
+ "length": 4,
104
+ "descriptions": {
105
+ "title": "Destination Address",
106
+ "main_caption": ""
107
+ },
108
+ "default_value": "0000ffff",
109
+ "validator": {
110
+ "type": "mac",
111
+ "length": 8
112
+ },
113
+ "html_id": "destination",
114
+ "tags": [
115
+ "communications"
116
+ ]
117
+ },
118
+ "node_id": {
119
+ "read_index": 20,
120
+ "write_index": 9,
121
+ "descriptions": {
122
+ "title": "Node ID",
123
+ "main_caption": ""
124
+ },
125
+ "default_value": "0",
126
+ "validator": {
127
+ "type": "uint8",
128
+ "min": 0,
129
+ "max": 255,
130
+ "generated": true
131
+ },
132
+ "html_id": "node_id",
133
+ "tags": [
134
+ "generic"
135
+ ]
136
+ },
137
+ "gyro_sample_rate": {
138
+ "read_index": 21,
139
+ "write_index": 10,
140
+ "descriptions": {
141
+ "title": "Set Gyroscope ODR",
142
+ "main_caption": ""
143
+ },
144
+ "default_value": 3,
145
+ "validator": {
146
+ "type": "uint8",
147
+ "min": 0,
148
+ "max": 3,
149
+ "generated": true
150
+ },
151
+ "options": {
152
+ "0": "125Hz",
153
+ "1": "250Hz",
154
+ "2": "500Hz",
155
+ "3": "1000Hz"
156
+ },
157
+ "html_id": "output_data_rate_103"
158
+ },
159
+ "acc_sample_rate": {
160
+ "read_index": 22,
161
+ "write_index": 11,
162
+ "descriptions": {
163
+ "title": "Set Accelerometer ODR",
164
+ "main_caption": ""
165
+ },
166
+ "default_value": 2,
167
+ "validator": {
168
+ "type": "uint8",
169
+ "min": 0,
170
+ "max": 4,
171
+ "generated": true
172
+ },
173
+ "options": {
174
+ "0": "8000Hz",
175
+ "1": "4000Hz",
176
+ "2": "1000Hz",
177
+ "3": "100Hz",
178
+ "4": "250Hz"
179
+ },
180
+ "html_id": "acc_output_data_rate_103"
181
+ },
182
+ "sampling_duration": {
183
+ "read_index": 23,
184
+ "write_index": 12,
185
+ "descriptions": {
186
+ "title": "Set Sampling Duration",
187
+ "main_caption": "Set the sampling duration in milliseconds, Example: a value of 1 = 50msec, 2 = 100msec, 100 = 5000msec"
188
+ },
189
+ "default_value": 1,
190
+ "validator": {
191
+ "type": "uint8",
192
+ "min": 1,
193
+ "max": 255,
194
+ "generated": true
195
+ },
196
+ "html_id": "sampling_duration_103"
197
+ },
198
+ "hpf_cutoff": {
199
+ "read_index": 24,
200
+ "write_index": 13,
201
+ "descriptions": {
202
+ "title": "Set HP Filter Cutoff",
203
+ "main_caption": "This setting will set the High Pass Filter freq to Sample Rate multiply by Selected Valu, Example: Sample Rate = 125 and Filter Coefficient = 0.00247 HPF freq (Hz) = 125 * 0.00247"
204
+ },
205
+ "default_value": 0,
206
+ "validator": {
207
+ "type": "uint8",
208
+ "min": 0,
209
+ "max": 6,
210
+ "generated": true
211
+ },
212
+ "options": {
213
+ "0": "Disabled",
214
+ "1": "0.00247",
215
+ "2": "0.00062084",
216
+ "3": "0.00015545",
217
+ "4": "0.00003862",
218
+ "5": "0.00000954",
219
+ "6": "0.00000238"
220
+ },
221
+ "html_id": "enable_hp_filter_cutoff_103"
222
+ },
223
+ "acc_fsr": {
224
+ "read_index": 25,
225
+ "write_index": 14,
226
+ "descriptions": {
227
+ "title": "Set Accelerometer FSR",
228
+ "main_caption": ""
229
+ },
230
+ "default_value": 0,
231
+ "validator": {
232
+ "type": "uint8",
233
+ "min": 0,
234
+ "max": 2,
235
+ "generated": true
236
+ },
237
+ "options": {
238
+ "0": "15g",
239
+ "1": "30g",
240
+ "2": "60g"
241
+ },
242
+ "html_id": "adxl_fsr_103"
243
+ },
244
+ "gyro_fsr": {
245
+ "read_index": 26,
246
+ "write_index": 15,
247
+ "descriptions": {
248
+ "title": "Set Gyroscope FSR",
249
+ "main_caption": ""
250
+ },
251
+ "default_value": 0,
252
+ "validator": {
253
+ "type": "uint8",
254
+ "min": 0,
255
+ "max": 3,
256
+ "generated": true
257
+ },
258
+ "options": {
259
+ "0": "250dsp",
260
+ "1": "500dps",
261
+ "2": "1000dps",
262
+ "3": "3000dps"
263
+ },
264
+ "html_id": "gyro_fsr_103"
265
+ },
266
+ "axis_enabled": {
267
+ "read_index": 27,
268
+ "write_index": 16,
269
+ "descriptions": {
270
+ "title": "Axes Enabled",
271
+ "main_caption": "New Command"
272
+ },
273
+ "validator": {
274
+ "type": "uint8"
275
+ },
276
+ "read_only": true,
277
+ },
278
+ "sampling_interval": {
279
+ "read_index": 28,
280
+ "write_index": 17,
281
+ "descriptions": {
282
+ "title": "Sampling Interval",
283
+ "main_caption": "Set how often will the sensor transmit measurement data."
284
+ },
285
+ "default_value": 1,
286
+ "validator": {
287
+ "type": "uint8",
288
+ "min": 0,
289
+ "max": 7,
290
+ "generated": true
291
+ },
292
+ "options": {
293
+ "0": "5 Minutes",
294
+ "1": "10 Minutes",
295
+ "2": "15 Minutes",
296
+ "3": "20 Minutes",
297
+ "4": "30 Minutes",
298
+ "5": "60 Minutes",
299
+ "6": "120 Minutes",
300
+ "7": "180 Minutes"
301
+ },
302
+ "html_id": "sampling_interval_101"
303
+ },
304
+ "accelerometer_threshold": {
305
+ "read_index": 29,
306
+ "write_index": 18,
307
+ "descriptions": {
308
+ "title": "Set Acceleration Threshold",
309
+ "main_caption": "Set a motion detection threshold for the sensor to trigger a data transmission. This is an interrupt-based configuration."
310
+ },
311
+ "default_value": 1,
312
+ "validator": {
313
+ "type": "uint8",
314
+ "min": 0,
315
+ "max": 255,
316
+ "generated": true
317
+ },
318
+ "html_id": "acc_threshold_103"
319
+ },
320
+ "enabled_sensors": {
321
+ "read_index": 30,
322
+ "write_index": 19,
323
+ "descriptions": {
324
+ "title": "Enable Sensor",
325
+ "main_caption": ""
326
+ },
327
+ "default_value": 2,
328
+ "validator": {
329
+ "type": "uint8",
330
+ "min": 0,
331
+ "max": 2,
332
+ "generated": true
333
+ },
334
+ "options": {
335
+ "0": "Accelerometer only",
336
+ "1": "Gyroscope only",
337
+ "2": "Both enabled"
338
+ },
339
+ "html_id": "enable_sensor_103"
340
+ },
341
+ "max_num_of_motion_tx_per_interval": {
342
+ "read_index": 31,
343
+ "write_index": 20,
344
+ "descriptions": {
345
+ "title": "Set Max Number Motion Tx Per Interval",
346
+ "main_caption": "Set Number of times it will send data due to motion triggers."
347
+ },
348
+ "default_value": 2,
349
+ "validator": {
350
+ "type": "uint8",
351
+ "min": 0,
352
+ "max": 255,
353
+ "generated": true
354
+ },
355
+ },
356
+ "send_raw_status": {
357
+ "read_index": 32,
358
+ "write_index": 21,
359
+ "descriptions": {
360
+ "title": "Set Raw On Motion Only",
361
+ "main_caption": ""
362
+ },
363
+ "validator": {
364
+ "type": "uint8",
365
+ "min": 0,
366
+ "max": 1,
367
+ "generated": true
368
+ },
369
+ "default_value": 0,
370
+ "html_id": "send_raw_on_motion_only_103"
371
+ },
372
+ "rtc": {
373
+ "read_index": 33,
374
+ "descriptions": {
375
+ "title": "Set RTC",
376
+ "main_caption": "Set the value for the Internal Real Time Clock."
377
+ },
378
+ "read_only": true,
379
+ }
380
+ };
381
+ };
382
+
383
+ const sync_parse = (rep_buffer) => {
384
+ let response = {
385
+ 'human_readable': {},
386
+ 'machine_values': {}
387
+ };
388
+
389
+ // Get the map based on the sensor type byte
390
+ const sync_map = get_config_map(rep_buffer[4]);
391
+
392
+ for (const [key, config] of Object.entries(sync_map)) {
393
+ // Destructure 'type' from inside 'validator' and rename 'read_index' to 'idx'
394
+ const { read_index: idx, length, validator: { type } = {}, converter, options } = config;
395
+
396
+ // If for some reason a config doesn't have a validator/type, skip it
397
+ if (!type) continue;
398
+
399
+ switch (type) {
400
+ case 'uint8':
401
+ response.machine_values[key] = rep_buffer[idx];
402
+ break;
403
+ case 'uint16be':
404
+ response.machine_values[key] = rep_buffer.readUInt16BE(idx);
405
+ break;
406
+ case 'uint32be':
407
+ response.machine_values[key] = rep_buffer.readUInt32BE(idx);
408
+ break;
409
+ case 'buffer':
410
+ response.machine_values[key] = rep_buffer.subarray(idx, idx + length);
411
+ break;
412
+ case 'hex':
413
+ response.machine_values[key] = rep_buffer.subarray(idx, idx + length).toString('hex');
414
+ break;
415
+ case 'mac':
416
+ response.machine_values[key] = rep_buffer.subarray(idx, idx + length).toString('hex');
417
+ break;
418
+ }
419
+ let human_value = response.machine_values[key];
420
+ if(options && options[response.machine_values[key]]){
421
+ human_value = options[response.machine_values[key]];
422
+ }else{
423
+ if(converter && converter.multiplier){
424
+ human_value = human_value * converter.multiplier;
425
+ }
426
+ if(converter && converter.units){
427
+ human_value = human_value + converter.units;
428
+ }
429
+ }
430
+ response.human_readable[key] = human_value;
431
+ }
432
+ if (Object.hasOwn(response.machine_values, 'destination_address') && response.machine_values.destination_address.toLowerCase() === '00000000') {
433
+ console.log('##############################');
434
+ console.log('#########Dest Override########');
435
+ console.log('##############################');
436
+ response.destination_address = "0000ffff";
437
+ response.auto_raw_destination_address = "0000ffff";
438
+ };
439
+ return response;
440
+ };
441
+
442
+ const parse_fly = (frame) => {
443
+ let firmware = frame[2];
444
+ if(firmware > 1){
445
+ let frame_data = {};
446
+ switch(frame[12]){
447
+ case 0:
448
+ frame_data.gyro_odr = 125;
449
+ break;
450
+ case 1:
451
+ frame_data.gyro_odr = 250;
452
+ break;
453
+ case 2:
454
+ frame_data.gyro_odr = 500;
455
+ break;
456
+ case 3:
457
+ frame_data.gyro_odr = 1000;
458
+ break;
459
+ }
460
+ switch(frame[13]){
461
+ case 0:
462
+ frame_data.acc_odr = 8000;
463
+ break;
464
+ case 1:
465
+ frame_data.acc_odr = 4000;
466
+ break;
467
+ case 2:
468
+ frame_data.acc_odr = 2000;
469
+ break;
470
+ case 3:
471
+ frame_data.acc_odr = 1000;
472
+ break;
473
+ case 4:
474
+ frame_data.acc_odr = 100;
475
+ break;
476
+ }
477
+ switch(frame[15]){
478
+ case 0:
479
+ frame_data.hpf_cutoff = false;
480
+ break;
481
+ case 1:
482
+ frame_data.hpf_cutoff = 0.00247;
483
+ break;
484
+ case 2:
485
+ frame_data.hpf_cutoff = 0.00062084;
486
+ break;
487
+ case 3:
488
+ frame_data.hpf_cutoff = 0.00015545;
489
+ break;
490
+ case 4:
491
+ frame_data.hpf_cutoff = 0.00003862;
492
+ break;
493
+ case 5:
494
+ frame_data.hpf_cutoff = 0.00000954;
495
+ break;
496
+ case 6:
497
+ frame_data.hpf_cutoff = 0.00000238;
498
+ break;
499
+ }
500
+ switch(frame[16]){
501
+ case 0:
502
+ frame_data.fsr_acc = "15g";
503
+ break;
504
+ case 1:
505
+ frame_data.fsr_acc = "30g";
506
+ break;
507
+ case 2:
508
+ frame_data.fsr_acc = "60g";
509
+ break;
510
+ }
511
+ switch(frame[17]){
512
+ case 0:
513
+ frame_data.fsr_gyro = "250dps";
514
+ break;
515
+ case 1:
516
+ frame_data.fsr_gyro = "500dps";
517
+ break;
518
+ case 2:
519
+ frame_data.fsr_gyro = "1000dps";
520
+ break;
521
+ case 3:
522
+ frame_data.fsr_gyro = "2000dps";
523
+ break;
524
+ }
525
+ switch(frame[18]){
526
+ case 1:
527
+ frame_data.en_axis = "X Axis";
528
+ break;
529
+ case 2:
530
+ frame_data.en_axis = "Y Axis";
531
+ break;
532
+ case 3:
533
+ frame_data.en_axis = "X-Y Axes";
534
+ break;
535
+ case 4:
536
+ frame_data.en_axis = "Z Axis";
537
+ break;
538
+ case 5:
539
+ frame_data.en_axis = "X-Z Axes";
540
+ break;
541
+ case 6:
542
+ frame_data.en_axis = "Y-Z Axes";
543
+ break;
544
+ case 7:
545
+ frame_data.en_axis = "All Axes";
546
+ break;
547
+ }
548
+ switch(frame[19]){
549
+ case 0:
550
+ frame_data.sampling_interval = 5;
551
+ break;
552
+ case 1:
553
+ frame_data.sampling_interval = 10;
554
+ break;
555
+ case 2:
556
+ frame_data.sampling_interval = 15;
557
+ break;
558
+ case 3:
559
+ frame_data.sampling_interval = 20;
560
+ break;
561
+ case 4:
562
+ frame_data.sampling_interval = 30;
563
+ break;
564
+ case 5:
565
+ frame_data.sampling_interval = 60;
566
+ break;
567
+ case 6:
568
+ frame_data.sampling_interval = 120;
569
+ break;
570
+ case 7:
571
+ frame_data.sampling_interval = 180;
572
+ break;
573
+ }
574
+ switch(frame[21]){
575
+ case 0:
576
+ frame_data.en_sensors = "acc_only";
577
+ break;
578
+ case 1:
579
+ frame_data.en_sensors = "gyro_only";
580
+ break;
581
+ case 2:
582
+ frame_data.en_sensors = "both_enabled";
583
+ break;
584
+ }
585
+ frame_data.hpf_cutoff = (frame_data.hpf_cutoff)?((frame_data.hpf_cutoff * frame_data.acc_odr).toFixed(2) + 'Hz'):'disabled';
586
+ return {
587
+ 'firmware': firmware,
588
+ 'gyro_sample_rate': frame_data.gyro_odr + 'Hz',
589
+ 'acc_sample_rate': frame_data.acc_odr + 'Hz',
590
+ 'sampling_duration': (frame[14]* 50) + 'msec',
591
+ 'hpf_cutoff': frame_data.hpf_cutoff,
592
+ 'acc_fsr': frame_data.fsr_acc,
593
+ 'gyro_fsr': frame_data.fsr_gyro,
594
+ 'axis_enabled': frame_data.en_axis,
595
+ 'sampling_interval': frame_data.sampling_interval + 'min',
596
+ 'accelerometer_threshold': (frame[20]* 32) + "mg",
597
+ 'enabled_sensors': frame_data.en_sensors,
598
+ 'max_num_of_motion_tx_per_interval': frame[22],
599
+ 'rtc': [
600
+ String(frame[23]).padStart(2, '0'),
601
+ String(frame[24]).padStart(2, '0'),
602
+ String(frame[25]).padStart(2, '0')
603
+ ].join(':'),
604
+ 'hardware_id': frame.slice(26, 29),
605
+ 'report_rate': frame.slice(29, 33).reduce(msbLsb),
606
+ 'tx_life_counter': frame.slice(33, 37).reduce(msbLsb),
607
+ 'machine_values': {
608
+ 'firmware': frame[2],
609
+ 'gyro_sample_rate': frame[12],
610
+ 'acc_sample_rate': frame[13],
611
+ 'sampling_duration': frame[14],
612
+ 'hpf_cutoff': frame[15],
613
+ 'acc_fsr': frame[16],
614
+ 'gyro_fsr': frame[17],
615
+ 'axis_enabled': frame[18],
616
+ 'sampling_interval': frame[19],
617
+ 'accelerometer_threshold': frame[20],
618
+ 'enabled_sensors': frame[21],
619
+ 'max_num_of_motion_tx_per_interval': frame[22],
620
+ 'hour': frame[23],
621
+ 'minute': frame[24],
622
+ 'second': frame[25],
623
+ 'hardware_id': frame.slice(26, 29),
624
+ 'report_rate': frame.slice(29, 33),
625
+ 'tx_life_counter': frame.slice(33, 37)
626
+ }
627
+ }
628
+ }else{
629
+ let frame_data = {};
630
+ switch(frame[12]){
631
+ case 0:
632
+ frame_data.odr = 125;
633
+ break;
634
+ case 1:
635
+ frame_data.odr = 250;
636
+ break;
637
+ case 2:
638
+ frame_data.odr = 500;
639
+ break;
640
+ case 3:
641
+ frame_data.odr = 1000;
642
+ break;
643
+ }
644
+ switch(frame[15]){
645
+ case 0:
646
+ frame_data.fsr_acc = "10g";
647
+ break;
648
+ case 1:
649
+ frame_data.fsr_acc = "20g";
650
+ break;
651
+ case 2:
652
+ frame_data.fsr_acc = "40g";
653
+ break;
654
+ }
655
+ switch(frame[16]){
656
+ case 0:
657
+ frame_data.fsr_gyro = "250dps";
658
+ break;
659
+ case 1:
660
+ frame_data.fsr_gyro = "500dps";
661
+ break;
662
+ case 2:
663
+ frame_data.fsr_gyro = "1000dps";
664
+ break;
665
+ case 3:
666
+ frame_data.fsr_gyro = "2000dps";
667
+ break;
668
+ }
669
+ switch(frame[17]){
670
+ case 7:
671
+ frame_data.en_axis = "all";
672
+ break;
673
+ }
674
+ switch(frame[20]){
675
+ case 1:
676
+ frame_data.en_sensors = "gyro_only";
677
+ break;
678
+ case 2:
679
+ frame_data.en_sensors = "accel_only";
680
+ break;
681
+ case 3:
682
+ frame_data.en_sensors = "all_enabled";
683
+ break;
684
+ }
685
+ switch(frame[18]){
686
+ case 0:
687
+ frame_data.sampling_interval = 5;
688
+ break;
689
+ case 1:
690
+ frame_data.sampling_interval = 10;
691
+ break;
692
+ case 2:
693
+ frame_data.sampling_interval = 15;
694
+ break;
695
+ case 3:
696
+ frame_data.sampling_interval = 20;
697
+ break;
698
+ case 4:
699
+ frame_data.sampling_interval = 30;
700
+ break;
701
+ case 5:
702
+ frame_data.sampling_interval = 60;
703
+ break;
704
+ case 6:
705
+ frame_data.sampling_interval = 120;
706
+ break;
707
+ case 7:
708
+ frame_data.sampling_interval = 180;
709
+ break;
710
+ }
711
+ switch(frame[14]){
712
+ case 0:
713
+ frame_data.hpf_cutoff = 0.00247;
714
+ break;
715
+ case 1:
716
+ frame_data.hpf_cutoff = 0.00062084;
717
+ break;
718
+ case 2:
719
+ frame_data.hpf_cutoff = 0.00015545;
720
+ break;
721
+ case 3:
722
+ frame_data.hpf_cutoff = 0.00003862;
723
+ break;
724
+ case 4:
725
+ frame_data.hpf_cutoff = 0.00000954;
726
+ break;
727
+ case 5:
728
+ frame_data.hpf_cutoff = 0.00000238;
729
+ break;
730
+ }
731
+ return {
732
+ 'firmware': firmware,
733
+ 'sample_rate': frame_data.odr + 'Hz',
734
+ 'sampling_duration': (frame[13]* 50) + 'msec',
735
+ 'hpf_cutoff': (frame_data.hpf_cutoff * frame_data.odr).toFixed(2) + 'Hz',
736
+ 'acc_fsr': frame_data.fsr_acc,
737
+ 'gyro_fsr': frame_data.fsr_gyro,
738
+ 'axis_enabled': frame_data.en_axis,
739
+ 'sampling_interval': frame_data.sampling_interval + 'min',
740
+ 'accelerometer_threshold': (frame[19]* 32) + "mg",
741
+ 'enabled_sensors': frame_data.en_sensors,
742
+ 'rtc': [
743
+ String(frame[21]).padStart(2, '0'),
744
+ String(frame[22]).padStart(2, '0'),
745
+ String(frame[23]).padStart(2, '0')
746
+ ].join(':'),
747
+ 'hardware_id': frame.slice(24, 27),
748
+ 'report_rate': frame.slice(27, 31).reduce(msbLsb),
749
+ 'tx_life_counter': frame.slice(31, 35).reduce(msbLsb),
750
+ 'machine_values': {
751
+ 'firmware': frame[2],
752
+ 'odr': frame[12],
753
+ 'sampling_duration': frame[13],
754
+ 'hpf_cutoff': frame[14],
755
+ 'acc_fsr': frame[15],
756
+ 'gyro_fsr': frame[16],
757
+ 'axis_enabled': frame[17],
758
+ 'sampling_interval': frame[18],
759
+ 'accelerometer_threshold': frame[19],
760
+ 'enabled_sensors': frame[20],
761
+ 'hour': frame[21],
762
+ 'minute': frame[22],
763
+ 'second': frame[23],
764
+ 'hardware_id': frame.slice(24, 27),
765
+ 'report_rate': frame.slice(27, 31),
766
+ 'tx_life_counter': frame.slice(31, 35)
767
+ }
768
+ }
769
+ }
770
+ };
771
+
772
+ const parse = (payload, parsed, mac) => {
773
+ if(payload[9] === 0){ // mode raw
774
+ var sensor_type = payload[8];
775
+ var deviceAddr = mac;
776
+ var data = {};
777
+ switch(sensor_type){
778
+ case 1:
779
+ data.sensor_type = 'Accel';
780
+ switch(payload[11]){ // for ADXL382
781
+ case 0:
782
+ // data.odr = '8000Hz';
783
+ data.odr = 8000;
784
+ break;
785
+ case 1:
786
+ // data.odr = '4000Hz';
787
+ data.odr = 4000;
788
+ break;
789
+ case 2:
790
+ // data.odr = '2000Hz';
791
+ data.odr = 1000;
792
+ break;
793
+ case 3:
794
+ // data.odr = '1000Hz';
795
+ data.odr = 100;
796
+ break;
797
+ case 4:
798
+ // data.odr = '100Hz';
799
+ data.odr = 250;
800
+ break;
801
+ }
802
+ break;
803
+ case 2:
804
+ data.sensor_type = 'gyro';
805
+ switch(payload[11]){
806
+ case 0:
807
+ data.odr = '125Hz';
808
+ break;
809
+ case 1:
810
+ data.odr = '250Hz';
811
+ break;
812
+ case 2:
813
+ data.odr = '500Hz';
814
+ break;
815
+ case 3:
816
+ data.odr = '1000Hz';
817
+ break;
818
+ }
819
+ break;
820
+ }
821
+ switch(payload[10]){
822
+ case 1:
823
+ data.event_type = 'report';
824
+ break;
825
+ case 2:
826
+ data.event_type = 'motion';
827
+ break;
828
+ }
829
+
830
+ var mode = payload[9];
831
+ var odr = data.odr;
832
+ var en_axis = payload[12] & 7;
833
+ var fsr = payload[12] >> 3;
834
+ var hour = payload[13];
835
+ var minute = payload[14];
836
+ var device_temp = payload.slice(15, 17).reduce(msbLsb) / 100;
837
+ var external_temperature = payload.slice(17, 19).reduce(msbLsb) / 100;
838
+ var expected_packets = payload.slice(19, 21).reduce(msbLsb);
839
+ var current_packet = payload.slice(21, 23).reduce(msbLsb);
840
+ var data_start = 23;
841
+
842
+ if(globalDevices.hasOwnProperty(deviceAddr) || expected_packets == 1){
843
+ if(expected_packets != 1){
844
+ // if current packet is equal to last one (duplicated data). This does not apply to the last package
845
+ if (globalDevices[deviceAddr].last_packet_counter == current_packet){
846
+ console.log('Duplicated message')
847
+ return;
848
+ }
849
+ // if current packet is equal to 1 or last packet counter is higher thant current packet
850
+ if(current_packet == 1 || (globalDevices[deviceAddr].last_packet_counter > current_packet)){
851
+ // clear stream
852
+ delete globalDevices[deviceAddr];
853
+ // create new stream
854
+ globalDevices[deviceAddr] = {
855
+ // stream_size: expected_packets,
856
+ data: {},
857
+ odr: odr,
858
+ mo: mode,
859
+ en_axis: en_axis,
860
+ fsr: fsr,
861
+ hour: hour,
862
+ minute: minute,
863
+ device_temp: device_temp,
864
+ external_temp: external_temperature
865
+ }
866
+ globalDevices[deviceAddr].last_packet_counter = current_packet;
867
+ globalDevices[deviceAddr].data[current_packet] = payload.slice(data_start);
868
+ return;
869
+ }
870
+ else{
871
+ globalDevices[deviceAddr].last_packet_counter = current_packet;
872
+ globalDevices[deviceAddr].data[current_packet] = payload.slice(data_start);
873
+ }
874
+ }
875
+ else{
876
+ globalDevices[deviceAddr] = {
877
+ // stream_size: expected_packets,
878
+ data: {},
879
+ odr: odr,
880
+ mo: mode,
881
+ en_axis: en_axis,
882
+ fsr: fsr,
883
+ hour: hour,
884
+ minute: minute,
885
+ device_temp: device_temp,
886
+ external_temp: external_temperature
887
+ }
888
+ globalDevices[deviceAddr].last_packet_counter = current_packet;
889
+ globalDevices[deviceAddr].data[current_packet] = payload.slice(data_start);
890
+ }
891
+ }
892
+ else{
893
+
894
+ globalDevices[deviceAddr] = {
895
+ data: {},
896
+ odr: odr,
897
+ mo: mode,
898
+ en_axis: en_axis,
899
+ fsr: fsr,
900
+ hour: hour,
901
+ minute: minute,
902
+ device_temp: device_temp,
903
+ external_temp: external_temperature
904
+ }
905
+ globalDevices[deviceAddr].last_packet_counter = current_packet;
906
+ globalDevices[deviceAddr].data[current_packet] = payload.slice(data_start);
907
+ }
908
+ if(current_packet == expected_packets){
909
+ var raw_data = new Array();
910
+ for(const packet in globalDevices[deviceAddr].data){
911
+ raw_data = raw_data.concat(globalDevices[deviceAddr].data[packet]);
912
+ }
913
+ var label = 0;
914
+
915
+ var fft = new Array();
916
+ var fft_concat = {};
917
+
918
+ var en_axis_data = {};
919
+ en_axis_data.x_offset = 0;
920
+ en_axis_data.y_offset = 2;
921
+ en_axis_data.z_offset = 4;
922
+ en_axis_data.increment = 6;
923
+ fft_concat = {x: [], y: [], z: []};
924
+
925
+ /* Evaluate sensor type */
926
+ if(payload[8] == 1){ // accelerometer
927
+ var fsr_mult = 0.00732;
928
+ var fsr_text = "";
929
+ switch(globalDevices[deviceAddr].fsr){
930
+ case 0:
931
+ fsr_mult = 0.00732;
932
+ break;
933
+ case 1:
934
+ fsr_mult = 0.01464;
935
+ break;
936
+ case 2:
937
+ fsr_mult = 0.02929;
938
+ break;
939
+ }
940
+ switch(globalDevices[deviceAddr].fsr){
941
+ case 0:
942
+ // fsr_text = "15g";
943
+ fsr_text = 15;
944
+ break;
945
+ case 1:
946
+ // fsr_text = "30g";
947
+ fsr_text = 30;
948
+ break;
949
+ case 2:
950
+ // fsr_text = "60g";
951
+ fsr_text = 60;
952
+ break;
953
+ }
954
+ }else{ // gyro
955
+ var fsr_mult = 0.0076;
956
+ var fsr_text = "";
957
+ switch(globalDevices[deviceAddr].fsr){
958
+ case 0:
959
+ fsr_mult = 0.0076;
960
+ break;
961
+ case 1:
962
+ fsr_mult = 0.015;
963
+ break;
964
+ case 2:
965
+ fsr_mult = 0.0305;
966
+ break;
967
+ case 3:
968
+ fsr_mult = 0.061;
969
+ break;
970
+ }
971
+ switch(globalDevices[deviceAddr].fsr){
972
+ case 0:
973
+ fsr_text = "250dps";
974
+ break;
975
+ case 1:
976
+ fsr_text = "500dps";
977
+ break;
978
+ case 2:
979
+ fsr_text = "1000dps";
980
+ break;
981
+ case 3:
982
+ fsr_text = "2000dps";
983
+ break;
984
+ }
985
+ }
986
+
987
+ for(var i = 0; i < raw_data.length; i+=en_axis_data.increment){
988
+ label++;
989
+
990
+ if('x_offset' in en_axis_data){
991
+ fft_concat.x.push(parseFloat((signInt(((raw_data[i+en_axis_data.x_offset]<<8)+(raw_data[i+en_axis_data.x_offset+1])), 16)*fsr_mult).toFixed(5)));
992
+ }
993
+ if('y_offset' in en_axis_data){
994
+ fft_concat.y.push(parseFloat((signInt(((raw_data[i+en_axis_data.y_offset]<<8)+(raw_data[i+en_axis_data.y_offset+1])), 16)*fsr_mult).toFixed(5)));
995
+ }
996
+ if('z_offset' in en_axis_data){
997
+ fft_concat.z.push(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)));
998
+ }
999
+ }
1000
+ var fft_concat_obj = {
1001
+ mode: mode,
1002
+ sensor_type: 103,
1003
+ probe_type: data.sensor_type,
1004
+ msg_type: data.event_type,
1005
+ time_id: globalDevices[deviceAddr].hour +':'+ globalDevices[deviceAddr].minute,
1006
+ mac_address: deviceAddr,
1007
+ en_axis: globalDevices[deviceAddr].en_axis,
1008
+ fsr: fsr_text,
1009
+ odr: globalDevices[deviceAddr].odr,
1010
+ device_temp: globalDevices[deviceAddr].device_temp,
1011
+ external_temp: globalDevices[deviceAddr].external_temp,
1012
+ total_samples: label,
1013
+ fft_confidence : ((Object.keys(globalDevices[deviceAddr].data).length / expected_packets) * 100).toFixed(2) + '%',
1014
+ data: fft_concat,
1015
+ raw_data: raw_data
1016
+ };
1017
+ sensor_data = fft_concat_obj;
1018
+ delete globalDevices[deviceAddr];
1019
+ return sensor_data;
1020
+ }
1021
+ else{
1022
+ return;
1023
+ }
1024
+ }
1025
+ };
1026
+
1027
+ // --- 2. EXPORT THE MODULE ---
1028
+ // Export the module with all the necessary functions and properties
1029
+ // that need to be called from outside the scrip
1030
+ return {
1031
+ type: 103,
1032
+ name: 'Custom Wireless Accelerometer Sensor',
1033
+ parse,
1034
+ get_write_buffer_size,
1035
+ get_config_map,
1036
+ sync_parse,
1037
+ parse_fly,
1038
+ };
1039
+ };