@ncd-io/node-red-enterprise-sensors 2.0.0 → 2.0.2

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,581 @@
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 35;
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
+ "debouncing_timeout": {
138
+ "read_index": 21,
139
+ "write_index": 10,
140
+ "descriptions": {
141
+ "title": "Set Input Debounce Time",
142
+ "main_caption": "Configures the debounce time in milliseconds for all inputs. State changes occurring within this debounce period will be ignored."
143
+ },
144
+ "default_value": 10,
145
+ "validator": {
146
+ "type": "uint16be",
147
+ "min": 10,
148
+ "max": 65000,
149
+ "generated": true
150
+ },
151
+ "html_id": "debounce_time_123"
152
+ },
153
+ "input_active_edge": {
154
+ "read_index": 23,
155
+ "write_index": 12,
156
+ "descriptions": {
157
+ "title": "Set Input Detection",
158
+ "main_caption": "Configures how the counter increments and how uptime is calculated for Input."
159
+ },
160
+ "default_value": 0,
161
+ "validator": {
162
+ "type": "uint8",
163
+ "min": 0,
164
+ "max": 1,
165
+ "generated": true
166
+ },
167
+ "options": {
168
+ "0": "Falling Edge Trigger",
169
+ "1": "Rising Edge Trigger"
170
+ },
171
+ "html_id": "input_two_33"
172
+ },
173
+ "counter_threshold": {
174
+ "read_index": 24,
175
+ "write_index": 13,
176
+ "descriptions": {
177
+ "title": "Counter Threshold",
178
+ "main_caption": "The sensor will transmit data when any connected counter reaches a multiple of this threshold value."
179
+ },
180
+ "default_value": 0,
181
+ "validator": {
182
+ "type": "uint32be",
183
+ "min": 1,
184
+ "max": 65534,
185
+ "generated": true
186
+ },
187
+ "html_id": "counter_threshold_108"
188
+ },
189
+ "trasnmit_on_change_status": {
190
+ "read_index": 28,
191
+ "write_index": 17,
192
+ "descriptions": {
193
+ "title": "Enable Push Notification",
194
+ "main_caption": "Enables the sensor to immediately transmit data upon detecting a signal change on the specified input(s)."
195
+ },
196
+ "default_value": 0,
197
+ "validator": {
198
+ "type": "uint8",
199
+ "min": 0,
200
+ "max": 1,
201
+ "generated": true
202
+ },
203
+ "options": {
204
+ "0": "Disabled",
205
+ "1": "Enabled"
206
+ },
207
+ "html_id": "push_notification_35"
208
+ },
209
+ "shift_end_one_hours": {
210
+ "read_index": 29,
211
+ "write_index": 18,
212
+ "descriptions": {
213
+ "title": "Shift 1 End Time Hours",
214
+ "main_caption": "Based on the Real-Time Clock (RTC), configures one of four specific daily times (24-hour format) for the sensor to perform an automatic reset."
215
+ },
216
+ "default_value": 0,
217
+ "validator": {
218
+ "type": "uint8",
219
+ "min": 0,
220
+ "max": 24,
221
+ "generated": true
222
+ },
223
+ "html_id": "shift_one_hours_108",
224
+ "html_active_id": "shift_one_108_active"
225
+ },
226
+ "shift_end_one_minutes": {
227
+ "read_index": 30,
228
+ "write_index": 19,
229
+ "descriptions": {
230
+ "title": "Shift 1 End Time Minutes",
231
+ "main_caption": "Based on the Real-Time Clock (RTC), configures one of four specific daily times (24-hour format) for the sensor to perform an automatic reset."
232
+ },
233
+ "default_value": 0,
234
+ "validator": {
235
+ "type": "uint8",
236
+ "min": 0,
237
+ "max": 60,
238
+ "generated": true
239
+ },
240
+ "html_id": "shift_one_minutes_108",
241
+ "html_active_id": "shift_one_108_active"
242
+ },
243
+ "shift_end_two_hours": {
244
+ "read_index": 31,
245
+ "write_index": 20,
246
+ "descriptions": {
247
+ "title": "Shift 2 End Time Hours",
248
+ "main_caption": "Based on the Real-Time Clock (RTC), configures two of four specific daily times (24-hour format) for the sensor to perform an automatic reset."
249
+ },
250
+ "default_value": 0,
251
+ "validator": {
252
+ "type": "uint8",
253
+ "min": 0,
254
+ "max": 24,
255
+ "generated": true
256
+ },
257
+ "html_id": "shift_two_hours_108",
258
+ "html_active_id": "shift_two_108_active"
259
+ },
260
+ "shift_end_two_minutes": {
261
+ "read_index": 32,
262
+ "write_index": 21,
263
+ "descriptions": {
264
+ "title": "Shift 2 End Time Minutes",
265
+ "main_caption": "Based on the Real-Time Clock (RTC), configures two of four specific daily times (24-hour format) for the sensor to perform an automatic reset."
266
+ },
267
+ "default_value": 0,
268
+ "validator": {
269
+ "type": "uint8",
270
+ "min": 0,
271
+ "max": 60,
272
+ "generated": true
273
+ },
274
+ "html_id": "shift_two_minutes_108",
275
+ "html_active_id": "shift_two_108_active"
276
+ },
277
+ "shift_end_three_hours": {
278
+ "read_index": 33,
279
+ "write_index": 22,
280
+ "descriptions": {
281
+ "title": "Shift 3 End Time Hours",
282
+ "main_caption": "Based on the Real-Time Clock (RTC), configures three of four specific daily times (24-hour format) for the sensor to perform an automatic reset."
283
+ },
284
+ "default_value": 0,
285
+ "validator": {
286
+ "type": "uint8",
287
+ "min": 0,
288
+ "max": 24,
289
+ "generated": true
290
+ },
291
+ "html_id": "shift_three_hours_108",
292
+ "html_active_id": "shift_three_108_active"
293
+ },
294
+ "shift_end_three_minutes": {
295
+ "read_index": 34,
296
+ "write_index": 23,
297
+ "descriptions": {
298
+ "title": "Shift 3 End Time Minutes",
299
+ "main_caption": "Based on the Real-Time Clock (RTC), configures three of four specific daily times (24-hour format) for the sensor to perform an automatic reset."
300
+ },
301
+ "default_value": 0,
302
+ "validator": {
303
+ "type": "uint8",
304
+ "min": 0,
305
+ "max": 60,
306
+ "generated": true
307
+ },
308
+ "html_id": "shift_three_minutes_108",
309
+ "html_active_id": "shift_three_108_active"
310
+ },
311
+ "shift_end_four_hours": {
312
+ "read_index": 35,
313
+ "write_index": 24,
314
+ "descriptions": {
315
+ "title": "Shift 4 End Time Hours",
316
+ "main_caption": "Based on the Real-Time Clock (RTC), configures four of four specific daily times (24-hour format) for the sensor to perform an automatic reset."
317
+ },
318
+ "default_value": 0,
319
+ "validator": {
320
+ "type": "uint8",
321
+ "min": 0,
322
+ "max": 24,
323
+ "generated": true
324
+ },
325
+ "html_id": "shift_four_hours_108",
326
+ "html_active_id": "shift_four_108_active"
327
+ },
328
+ "shift_end_four_minutes": {
329
+ "read_index": 36,
330
+ "write_index": 25,
331
+ "descriptions": {
332
+ "title": "Shift 4 End Time Minutes",
333
+ "main_caption": "Based on the Real-Time Clock (RTC), configures four of four specific daily times (24-hour format) for the sensor to perform an automatic reset."
334
+ },
335
+ "default_value": 0,
336
+ "validator": {
337
+ "type": "uint8",
338
+ "min": 0,
339
+ "max": 60,
340
+ "generated": true
341
+ },
342
+ "html_id": "shift_four_minutes_108",
343
+ "html_active_id": "shift_four_108_active"
344
+ },
345
+ "reset_timeout": {
346
+ "read_index": 37,
347
+ "write_index": 26,
348
+ "descriptions": {
349
+ "title": "Reset Timeout",
350
+ "main_caption": "Defines the duration (in seconds) after which the sensor will automatically reset. Before resetting, it will transmit its current data values."
351
+ },
352
+ "default_value": 60,
353
+ "validator": {
354
+ "type": "uint16be",
355
+ "min": 10,
356
+ "max": 65000,
357
+ "generated": true
358
+ },
359
+ "html_id": "reset_timeout_108"
360
+ },
361
+ "counter_reset_mode": {
362
+ "read_index": 39,
363
+ "write_index": 28,
364
+ "descriptions": {
365
+ "title": "Set Reset Mode",
366
+ "main_caption": "This setting specifies which automatic reset option the sensor will utilize."
367
+ },
368
+ "default_value": 0,
369
+ "validator": {
370
+ "type": "uint8",
371
+ "min": 0,
372
+ "max": 2,
373
+ "generated": true
374
+ },
375
+ "options": {
376
+ "0": "Do not reset counters",
377
+ "1": "Based on Shift Ends",
378
+ "2": "Based on the Timeout Provided"
379
+ },
380
+ "html_id": "reset_mode_to_disabled_108"
381
+ },
382
+ "sampling_interval": {
383
+ "read_index": 40,
384
+ "write_index": 29,
385
+ "descriptions": {
386
+ "title": "Data Transmission Interval",
387
+ "main_caption": "Sets the regular interval at which the sensor wakes up and transmits its data. This interval operates independently of any interrupt-driven (Push Notifications or Resets)."
388
+ },
389
+ "default_value": 2,
390
+ "validator": {
391
+ "type": "uint8",
392
+ "min": 0,
393
+ "max": 12,
394
+ "generated": true
395
+ },
396
+ "options": {
397
+ "0": "1 minute",
398
+ "1": "5 minutes",
399
+ "2": "15 minutes",
400
+ "3": "30 minutes",
401
+ "4": "1 hour",
402
+ "5": "2 hours",
403
+ "6": "3 hours",
404
+ "7": "6 hours",
405
+ "8": "12 hours",
406
+ "9": "5 seconds",
407
+ "10": "10 seconds",
408
+ "11": "15 seconds",
409
+ "12": "30 seconds"
410
+ },
411
+ "html_id": "transmission_interval_108"
412
+ },
413
+ "interrupt_timeout": {
414
+ "read_index": 41,
415
+ "write_index": 30,
416
+ "descriptions": {
417
+ "title": "Set Interrupt Timeout",
418
+ "main_caption": "Set the sensor to detect an initial IO (input/output) change and not transmit subsequent IO changes for a specified duration; set the duration value to control how long changes are ignored in milliseconds, set it to 0 to disable ignoring."
419
+ },
420
+ "default_value": 0,
421
+ "validator": {
422
+ "type": "uint16be",
423
+ "min": 0,
424
+ "max": 65000,
425
+ "generated": true
426
+ },
427
+ "html_id": "interrupt_timeout_35"
428
+ },
429
+ "current_sensor_1_ct": {
430
+ "read_index": 43,
431
+ "write_index": 32,
432
+ "descriptions": {
433
+ "title": "Set Sensor One CT",
434
+ "main_caption": "Select the AC Current probe type for Input 1."
435
+ },
436
+ "default_value": 0,
437
+ "validator": {
438
+ "type": "uint8",
439
+ "min": 0,
440
+ "max": 3,
441
+ "generated": true
442
+ },
443
+ "options": {
444
+ "0": "100A",
445
+ "1": "200A",
446
+ "2": "600A",
447
+ "3": "1000A"
448
+ },
449
+ "html_id": "probe_one_126"
450
+ },
451
+ "threshold_current_sensor_1": {
452
+ "read_index": 44,
453
+ "write_index": 33,
454
+ "descriptions": {
455
+ "title": "Set AC Current Threshold One",
456
+ "main_caption": "The sensor increments the cycle counter and calculates uptime once the measured AC Current exceeds this threshold."
457
+ },
458
+ "default_value": 3,
459
+ "validator": {
460
+ "type": "uint16be",
461
+ "min": 0,
462
+ "max": 65000,
463
+ "generated": true
464
+ },
465
+ "html_id": "threshold_probe_one_126"
466
+ }
467
+ };
468
+ };
469
+
470
+ const sync_parse = (rep_buffer) => {
471
+ let response = {
472
+ 'human_readable': {},
473
+ 'machine_values': {}
474
+ };
475
+
476
+ // Get the map based on the sensor type byte
477
+ const sync_map = get_config_map(rep_buffer[4]);
478
+
479
+ for (const [key, config] of Object.entries(sync_map)) {
480
+ // Destructure 'type' from inside 'validator' and rename 'read_index' to 'idx'
481
+ const { read_index: idx, length, validator: { type } = {}, converter, options } = config;
482
+
483
+ // If for some reason a config doesn't have a validator/type, skip it
484
+ if (!type) continue;
485
+
486
+ switch (type) {
487
+ case 'uint8':
488
+ response.machine_values[key] = rep_buffer[idx];
489
+ break;
490
+ case 'uint16be':
491
+ response.machine_values[key] = rep_buffer.readUInt16BE(idx);
492
+ break;
493
+ case 'uint32be':
494
+ response.machine_values[key] = rep_buffer.readUInt32BE(idx);
495
+ break;
496
+ case 'buffer':
497
+ response.machine_values[key] = rep_buffer.subarray(idx, idx + length);
498
+ break;
499
+ case 'hex':
500
+ response.machine_values[key] = rep_buffer.subarray(idx, idx + length).toString('hex');
501
+ break;
502
+ case 'mac':
503
+ response.machine_values[key] = rep_buffer.subarray(idx, idx + length).toString('hex');
504
+ break;
505
+ }
506
+ let human_value = response.machine_values[key];
507
+ if(options && options[response.machine_values[key]]){
508
+ human_value = options[response.machine_values[key]];
509
+ }else{
510
+ if(converter && converter.multiplier){
511
+ human_value = human_value * converter.multiplier;
512
+ }
513
+ if(converter && converter.units){
514
+ human_value = human_value + converter.units;
515
+ }
516
+ }
517
+ response.human_readable[key] = human_value;
518
+ }
519
+ if (Object.hasOwn(response.machine_values, 'destination_address') && response.machine_values.destination_address.toLowerCase() === '00000000') {
520
+ console.log('##############################');
521
+ console.log('#########Dest Override########');
522
+ console.log('##############################');
523
+ response.destination_address = "0000ffff";
524
+ response.auto_raw_destination_address = "0000ffff";
525
+ };
526
+ return response;
527
+ };
528
+
529
+ const parse = (payload, parsed, mac) => {
530
+ if(parsed.firmware > 4){ // 5 and above
531
+ let report_type = "Regular";
532
+ switch(payload[17]){
533
+ case 0:
534
+ report_type = "Regular";
535
+ break;
536
+ case 1:
537
+ report_type = "Shift end";
538
+ break;
539
+ case 2:
540
+ report_type = "Interrupt";
541
+ break;
542
+ case 3:
543
+ report_type = "Threshold";
544
+ break;
545
+ }
546
+ return {
547
+ input_counter: payload.slice(8, 12).reduce(msbLsb),
548
+ input_uptime: payload.slice(12, 16).reduce(msbLsb),
549
+ input: payload[16] & 1 ? 1 : 0,
550
+ report_type: report_type,
551
+ rtc: [
552
+ String(payload[18]).padStart(2, '0'),
553
+ String(payload[19]).padStart(2, '0'),
554
+ String(payload[20]).padStart(2, '0')
555
+ ].join(':')
556
+ };
557
+ } else if(parsed.firmware > 3){ // 4
558
+ return {
559
+ current_detect: payload[8],
560
+ total_uptime: payload.slice(9, 13).reduce(msbLsb),
561
+ total_cycle_count: payload.slice(13, 17).reduce(msbLsb)
562
+ };
563
+ }else{
564
+ return {
565
+ input_1: payload[8]
566
+ };
567
+ };
568
+ };
569
+
570
+ // --- 2. EXPORT THE MODULE ---
571
+ // Export the module with all the necessary functions and properties
572
+ // that need to be called from outside the scrip
573
+ return {
574
+ type: 33,
575
+ name: 'AC Current Detect Sensor',
576
+ parse,
577
+ get_write_buffer_size,
578
+ get_config_map,
579
+ sync_parse
580
+ };
581
+ };