nodejs-poolcontroller 7.2.0 → 7.5.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.
Files changed (64) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  2. package/Changelog +13 -0
  3. package/Dockerfile +1 -0
  4. package/README.md +5 -5
  5. package/app.ts +11 -0
  6. package/config/Config.ts +3 -0
  7. package/config/VersionCheck.ts +8 -4
  8. package/controller/Constants.ts +165 -9
  9. package/controller/Equipment.ts +186 -65
  10. package/controller/Errors.ts +22 -1
  11. package/controller/State.ts +273 -57
  12. package/controller/boards/EasyTouchBoard.ts +194 -95
  13. package/controller/boards/IntelliCenterBoard.ts +115 -42
  14. package/controller/boards/IntelliTouchBoard.ts +104 -30
  15. package/controller/boards/NixieBoard.ts +155 -53
  16. package/controller/boards/SystemBoard.ts +1529 -514
  17. package/controller/comms/Comms.ts +219 -42
  18. package/controller/comms/messages/Messages.ts +16 -4
  19. package/controller/comms/messages/config/ChlorinatorMessage.ts +13 -3
  20. package/controller/comms/messages/config/CircuitGroupMessage.ts +6 -0
  21. package/controller/comms/messages/config/CircuitMessage.ts +1 -1
  22. package/controller/comms/messages/config/CoverMessage.ts +1 -0
  23. package/controller/comms/messages/config/EquipmentMessage.ts +4 -0
  24. package/controller/comms/messages/config/ExternalMessage.ts +43 -25
  25. package/controller/comms/messages/config/FeatureMessage.ts +8 -1
  26. package/controller/comms/messages/config/GeneralMessage.ts +8 -0
  27. package/controller/comms/messages/config/HeaterMessage.ts +15 -9
  28. package/controller/comms/messages/config/IntellichemMessage.ts +4 -1
  29. package/controller/comms/messages/config/OptionsMessage.ts +13 -1
  30. package/controller/comms/messages/config/PumpMessage.ts +4 -20
  31. package/controller/comms/messages/config/RemoteMessage.ts +4 -0
  32. package/controller/comms/messages/config/ScheduleMessage.ts +11 -0
  33. package/controller/comms/messages/config/SecurityMessage.ts +1 -0
  34. package/controller/comms/messages/config/ValveMessage.ts +12 -2
  35. package/controller/comms/messages/status/ChlorinatorStateMessage.ts +14 -6
  36. package/controller/comms/messages/status/EquipmentStateMessage.ts +78 -24
  37. package/controller/comms/messages/status/HeaterStateMessage.ts +25 -5
  38. package/controller/comms/messages/status/IntelliChemStateMessage.ts +55 -26
  39. package/controller/nixie/Nixie.ts +18 -16
  40. package/controller/nixie/NixieEquipment.ts +6 -6
  41. package/controller/nixie/bodies/Body.ts +7 -4
  42. package/controller/nixie/bodies/Filter.ts +7 -4
  43. package/controller/nixie/chemistry/ChemController.ts +800 -283
  44. package/controller/nixie/chemistry/Chlorinator.ts +22 -14
  45. package/controller/nixie/circuits/Circuit.ts +42 -7
  46. package/controller/nixie/heaters/Heater.ts +303 -30
  47. package/controller/nixie/pumps/Pump.ts +57 -30
  48. package/controller/nixie/schedules/Schedule.ts +10 -7
  49. package/controller/nixie/valves/Valve.ts +7 -5
  50. package/defaultConfig.json +32 -1
  51. package/issue_template.md +1 -1
  52. package/logger/DataLogger.ts +37 -22
  53. package/package.json +20 -18
  54. package/web/Server.ts +529 -31
  55. package/web/bindings/influxDB.json +157 -5
  56. package/web/bindings/mqtt.json +112 -13
  57. package/web/bindings/mqttAlt.json +109 -11
  58. package/web/interfaces/baseInterface.ts +2 -1
  59. package/web/interfaces/httpInterface.ts +2 -0
  60. package/web/interfaces/influxInterface.ts +103 -54
  61. package/web/interfaces/mqttInterface.ts +16 -5
  62. package/web/services/config/Config.ts +179 -43
  63. package/web/services/state/State.ts +51 -5
  64. package/web/services/state/StateSocket.ts +19 -2
@@ -33,7 +33,7 @@ Follow the instructions to complete a [packet capture](https://github.com/tagyou
33
33
  - Pump(s) manufacturer and model: [e.g. IntelliFlow 2 VST 011056]
34
34
  - Chlorinator: [e.g. iChlor, IntelliChlor-40]
35
35
  - Heater(s): [e.g. gas, solar, heatpump, ultratemp]
36
- - Chemical controller: [e.g. IntelliChem, homegrown]
36
+ - Chemical controller: [e.g. IntelliChem, Relay Equipment Manager (REM)]
37
37
  - Valves: [e.g. Intellivalve]
38
38
  - Any other relevant equipment:
39
39
 
package/Changelog CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 7.5
4
+ 1. Backup/restore
5
+ 2. Intellitouch add expansion modules
6
+ ## 7.4
7
+ 1. Filter object, emit, monitoring
8
+
9
+ ## 7.3.1
10
+ 1. Influx 2.0 support
11
+
12
+ ## 7.3
13
+ 1. Dynamic chlorinating % based on ORP demand for Nixie
14
+ 2. Docker creation updates
15
+
3
16
  ## 7.2
4
17
  1. Refactor Intellichem and Chem Controllers
5
18
 
package/Dockerfile CHANGED
@@ -8,6 +8,7 @@ RUN npm run build
8
8
  RUN npm ci --production
9
9
 
10
10
  FROM node:lts-alpine as prod
11
+ RUN apk add git
11
12
  RUN mkdir /app && chown node:node /app
12
13
  WORKDIR /app
13
14
  COPY --chown=node:node --from=build /app .
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # nodejs-poolController - Version 7.2.0
1
+ # nodejs-poolController - Version 7.5
2
2
 
3
3
  ## What is nodejs-poolController
4
4
 
@@ -15,13 +15,13 @@ Equipment supported
15
15
  1. Pumps: Intelliflow VS/VSF/VF, older models
16
16
  1. Chlorinators: Intellichlor, Aqua-Rite and OEM brands
17
17
  1. Heaters: Gas, solar, heatpump
18
- 1. Intellichem and homegrown chemical controllers
18
+ 1. Intellichem and Relay Equipment Manager (REM) chemical controllers
19
19
  1. Intellivalve (coming soon)
20
20
  1. Home Automation: SmartThings, Hubitat, ISY, Vera, Siri, Echo
21
21
  1. Chemical probes (pH, ORP, flow sensors, EC, etc.)
22
22
 
23
23
  ## Latest Changes
24
- See (Changelog)[https://github.com/tagyoureit/nodejs-poolController/blob/master/Changelog)
24
+ See [Changelog](https://github.com/tagyoureit/nodejs-poolController/blob/master/Changelog)
25
25
 
26
26
  ## What's new in 7.0?
27
27
 
@@ -84,8 +84,8 @@ To do anything with this app, you need a client to connect to it. A client can
84
84
  * Temperature sensors (10k, NTC)
85
85
 
86
86
  ## Web Clients
87
- 1. RECOMMENDED - [nodejs-poolController-dashPanel](https://github.com/rstrouse/nodejs-poolController-dashPanel). Full compatibility with IntelliCenter, *Touch, REM (RelayEquipmentManager).
88
- 1. Limited functionality - [nodejs-poolController-webClient](http://github.com/tagyoureit/nodejs-poolController-webClient). Built primarily around EasyTouch/IntelliTouch but will work with other systems.
87
+ 1. [nodejs-poolController-dashPanel](https://github.com/rstrouse/nodejs-poolController-dashPanel). Full compatibility with IntelliCenter, *Touch, REM (RelayEquipmentManager).
88
+ 1. Deprecated - ~~[nodejs-poolController-webClient](http://github.com/tagyoureit/nodejs-poolController-webClient). Built primarily around EasyTouch/IntelliTouch but will work with other systems.~~
89
89
 
90
90
  * This app has the default to only listen to clients from localhost (127.0.0.1). If you need to have clients connect from other machines you will need to change the [ip](#module_nodejs-poolController--config.json) in `config.json`.
91
91
 
package/app.ts CHANGED
@@ -35,6 +35,7 @@ export async function initAsync() {
35
35
  await state.init();
36
36
  await webApp.init();
37
37
  await sys.start();
38
+ await webApp.initAutoBackup();
38
39
  } catch (err) { console.log(`Error Initializing nodejs-PoolController ${err.message}`); }
39
40
  //return Promise.resolve()
40
41
  // .then(function () { config.init(); })
@@ -70,6 +71,7 @@ export async function stopAsync(): Promise<void> {
70
71
  try {
71
72
  console.log('Shutting down open processes');
72
73
  // await sys.board.virtualPumpControllers.stopAsync();
74
+ await webApp.stopAutoBackup();
73
75
  await sys.stopAsync();
74
76
  await state.stopAsync();
75
77
  await conn.stopAsync();
@@ -98,4 +100,13 @@ else {
98
100
  try { return await stopAsync(); } catch (err) { console.log(`Error shutting down processes ${err.message}`); }
99
101
  });
100
102
  }
103
+ if (typeof process === 'object') {
104
+ process.on('unhandledRejection', (error: Error, promise) => {
105
+ console.group('unhandled rejection');
106
+ console.error("== Node detected an unhandled rejection! ==");
107
+ console.error(error.message);
108
+ console.error(error.stack);
109
+ console.groupEnd();
110
+ });
111
+ }
101
112
  ( async () => { await initAsync() })();
package/config/Config.ts CHANGED
@@ -100,6 +100,8 @@ class Config {
100
100
  c[section] = val;
101
101
  this.update();
102
102
  }
103
+ // RKS: 09-21-21 - We are counting on the return from this being immutable. A copy of the data
104
+ // should always be returned here.
103
105
  public getSection(section?: string, opts?: any): any {
104
106
  if (typeof section === 'undefined') return this._cfg;
105
107
  let c: any = this._cfg;
@@ -118,6 +120,7 @@ class Config {
118
120
  let baseDir = process.cwd();
119
121
  this.ensurePath(baseDir + '/logs/');
120
122
  this.ensurePath(baseDir + '/data/');
123
+ this.ensurePath(baseDir + '/backups/');
121
124
  // this.ensurePath(baseDir + '/replay/');
122
125
  //setTimeout(() => { config.update(); }, 100);
123
126
  }
@@ -41,7 +41,7 @@ class VersionCheck {
41
41
  public checkGitLocal() {
42
42
  // check local git version
43
43
  try {
44
- let res = execSync('git rev-parse --abbrev-ref HEAD');
44
+ let res = execSync('git rev-parse --abbrev-ref HEAD', { stdio: 'pipe' });
45
45
  let out = res.toString().trim();
46
46
  logger.info(`The current git branch output is ${out}`);
47
47
  switch (out) {
@@ -54,10 +54,11 @@ class VersionCheck {
54
54
  }
55
55
  }
56
56
  catch (err) {
57
- logger.error(`Unable to retrieve local git branch. ${err}`);
57
+ state.appVersion.gitLocalBranch = '--';
58
+ logger.warn(`Unable to retrieve local git branch. ${err}`);
58
59
  }
59
60
  try {
60
- let res = execSync('git rev-parse HEAD');
61
+ let res = execSync('git rev-parse HEAD', { stdio: 'pipe' });
61
62
  let out = res.toString().trim();
62
63
  logger.info(`The current git commit output is ${out}`);
63
64
  switch (out) {
@@ -69,7 +70,10 @@ class VersionCheck {
69
70
  state.appVersion.gitLocalCommit = out;
70
71
  }
71
72
  }
72
- catch (err) { logger.error(`Unable to retrieve local git commit. ${err}`); }
73
+ catch (err) {
74
+ state.appVersion.gitLocalCommit = '--';
75
+ logger.warn(`Unable to retrieve local git commit. ${err}`);
76
+ }
73
77
  }
74
78
  private checkAll() {
75
79
  try {
@@ -179,8 +179,9 @@ export class Heliotrope {
179
179
  export class Timestamp {
180
180
  private _dt: Date;
181
181
  public emitter: EventEmitter;
182
- constructor(dt?: Date) {
183
- this._dt = dt || new Date();
182
+ constructor(dt?: Date | string) {
183
+ if (typeof dt === 'string') this._dt = new Date(dt);
184
+ else this._dt = dt || new Date();
184
185
  this.emitter = new EventEmitter();
185
186
  }
186
187
  private _isUpdating: boolean = false;
@@ -265,7 +266,7 @@ export class Timestamp {
265
266
  let dateJan = new Date(this._dt.getFullYear(), 0, 1, 2);
266
267
  let dateJul = new Date(this._dt.getFullYear(), 6, 1, 2);
267
268
  obj.tzOffset = dateJan.getTimezoneOffset() / 60 * -1;
268
- obj.adjustDST = dateJan.getTimezoneOffset() - dateJul.getTimezoneOffset() > 0;
269
+ obj.adjustDST = dateJan.getTimezoneOffset() - dateJul.getTimezoneOffset() > 0;
269
270
  return obj;
270
271
  }
271
272
  public addHours(hours: number, minutes: number = 0, seconds: number = 0, milliseconds: number = 0) {
@@ -302,10 +303,10 @@ export enum ControllerType {
302
303
  Virtual = 'virtual',
303
304
  Nixie = 'nixie'
304
305
  }
305
- export enum VirtualDeviceType {
306
- Pump = 'pump',
307
- Chlorinator = 'chlorinator'
308
- }
306
+ // export enum VirtualDeviceType {
307
+ // Pump = 'pump',
308
+ // Chlorinator = 'chlorinator'
309
+ // }
309
310
  //export class Enums {
310
311
  // public static Addresses = {
311
312
  // 2: { val: 2, name: 'chlorinator', desc: 'Chlorinator' },
@@ -367,6 +368,94 @@ export class Utils {
367
368
  if (typeof fn !== 'undefined' && typeof fn[to.toLowerCase()] === 'function') return fn[to.toLowerCase()](val);
368
369
  }
369
370
  },
371
+ pressure: {
372
+ bar: {
373
+ kpa: (val) => { return val * 100; },
374
+ kilopascal: (val) => { return val * 100; },
375
+ pa: (val) => { return val * 100000; },
376
+ pascal: (val) => { return val * 100000; },
377
+ atm: (val) => { return val * 0.986923; },
378
+ atmosphere: (val) => { return val * 0.986923; },
379
+ psi: (val) => { return val * 14.5038; },
380
+ bar: (val) => { return val; }
381
+ },
382
+ kpa: {
383
+ kpa: (val) => { return val; },
384
+ kilopascal: (val) => { return val; },
385
+ pa: (val) => { return val * 1000; },
386
+ pascal: (val) => { return val * 1000; },
387
+ atm: (val) => { return val / 101.325; },
388
+ atmosphere: (val) => { return val / 101.325; },
389
+ psi: (val) => { return val * 0.145038; },
390
+ bar: (val) => { return val * .01; }
391
+ },
392
+ kilopascal: {
393
+ kpa: (val) => { return val; },
394
+ kilopascal: (val) => { return val; },
395
+ pa: (val) => { return val * 1000; },
396
+ pascal: (val) => { return val * 1000; },
397
+ atm: (val) => { return val / 101.325; },
398
+ atmosphere: (val) => { return val / 101.325; },
399
+ psi: (val) => { return val * 0.145038; },
400
+ bar: (val) => { return val * .01; }
401
+ },
402
+ pa: {
403
+ kpa: (val) => { return val / 1000; },
404
+ kilopascal: (val) => { return val / 1000; },
405
+ pa: (val) => { return val; },
406
+ pascal: (val) => { return val; },
407
+ atm: (val) => { return val / 101325; },
408
+ atmosphere: (val) => { return val / 101325; },
409
+ psi: (val) => { return val * 0.000145038; },
410
+ bar: (val) => { return val / 100000; }
411
+ },
412
+ pascal: {
413
+ kpa: (val) => { return val / 1000; },
414
+ kilopascal: (val) => { return val / 1000; },
415
+ pa: (val) => { return val; },
416
+ pascal: (val) => { return val; },
417
+ atm: (val) => { return val / 101325; },
418
+ atmosphere: (val) => { return val / 101325; },
419
+ psi: (val) => { return val * 0.000145038; },
420
+ bar: (val) => { return val / 100000; }
421
+ },
422
+ atm: {
423
+ kpa: (val) => { return val * 101.325; },
424
+ kilopascal: (val) => { return val * 101.325; },
425
+ pa: (val) => { return val * 101325; },
426
+ pascal: (val) => { return val * 101325; },
427
+ atm: (val) => { return val; },
428
+ atmosphere: (val) => { return val; },
429
+ psi: (val) => { return val * 14.6959; },
430
+ bar: (val) => { return val * 1.01325; }
431
+ },
432
+ atmosphere: {
433
+ kpa: (val) => { return val * 101.325; },
434
+ kilopascal: (val) => { return val * 101.325; },
435
+ pa: (val) => { return val * 101325; },
436
+ pascal: (val) => { return val * 101325; },
437
+ atm: (val) => { return val; },
438
+ atmosphere: (val) => { return val; },
439
+ psi: (val) => { return val * 14.6959; },
440
+ bar: (val) => { return val * 1.01325; }
441
+ },
442
+ psi: {
443
+ kpa: (val) => { return val * 6.89476; },
444
+ kilopascal: (val) => { return val * 6.89476; },
445
+ pa: (val) => { return val * 6894.76; },
446
+ pascal: (val) => { return val * 6894.76; },
447
+ atm: (val) => { return val * 0.068046; },
448
+ atmosphere: (val) => { return 0.068046; },
449
+ psi: (val) => { return val; },
450
+ bar: (val) => { return val * 0.0689476; }
451
+ },
452
+ convertUnits: (val: number, from: string, to: string) => {
453
+ if (typeof val !== 'number') return null;
454
+ let fn = this.convert.pressure[from.toLowerCase()];
455
+ if (typeof fn !== 'undefined' && typeof fn[to.toLowerCase()] === 'function') return fn[to.toLowerCase()](val);
456
+ }
457
+
458
+ },
370
459
  volume: {
371
460
  gal: {
372
461
  l: (val) => { return val * 3.78541; },
@@ -444,7 +533,7 @@ export class Utils {
444
533
  var fmt = '';
445
534
  let hrs = Math.floor(seconds / 3600);
446
535
  let min = Math.floor((seconds - (hrs * 3600)) / 60);
447
- let sec = seconds - ((hrs * 3600) + (min * 60));
536
+ let sec = Math.round(seconds) - ((hrs * 3600) + (min * 60));
448
537
  if (hrs > 1) fmt += (hrs.toString() + 'hrs');
449
538
  else if (hrs > 0) fmt += (hrs.toString() + 'hr');
450
539
 
@@ -479,7 +568,7 @@ export class Utils {
479
568
  }
480
569
  return seconds;
481
570
  }
482
- public isNullOrEmpty(val: any) { return (typeof val === 'string') ? val === null || val === '' : typeof val === 'undefined' || val === null; }
571
+ public isNullOrEmpty(val: any) { return (typeof val === 'string') ? val === null || val === '' : typeof val === 'undefined' || val === null; }
483
572
  public sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
484
573
  // Use this method to get around the circular references for the toJSON function.
485
574
  public serialize(obj, fn?: (key, value) => any): string {
@@ -514,6 +603,73 @@ export class Utils {
514
603
  }
515
604
  return o;
516
605
  }
606
+ public findLineByLeastSquares(values_x: number[], values_y: number[]): number[][] {
607
+ var x_sum = 0;
608
+ var y_sum = 0;
609
+ var xy_sum = 0;
610
+ var xx_sum = 0;
611
+ var count = 0;
612
+
613
+ /*
614
+ * The above is just for quick access, makes the program faster
615
+ */
616
+ var x = 0;
617
+ var y = 0;
618
+ var values_length = values_x.length;
619
+
620
+ if (values_length != values_y.length) {
621
+ throw new Error('The parameters values_x and values_y need to have same size!');
622
+ }
623
+
624
+ /*
625
+ * Above and below cover edge cases
626
+ */
627
+ if (values_length === 0) {
628
+ return [[], []];
629
+ }
630
+
631
+ /*
632
+ * Calculate the sum for each of the parts necessary.
633
+ */
634
+ for (let i = 0; i < values_length; i++) {
635
+ x = values_x[i];
636
+ y = values_y[i];
637
+ x_sum += x;
638
+ y_sum += y;
639
+ xx_sum += x * x;
640
+ xy_sum += x * y;
641
+ count++;
642
+ }
643
+
644
+ /*
645
+ * Calculate m and b for the line equation:
646
+ * y = x * m + b
647
+ */
648
+ var m = (count * xy_sum - x_sum * y_sum) / (count * xx_sum - x_sum * x_sum);
649
+ var b = (y_sum / count) - (m * x_sum) / count;
650
+
651
+ /*
652
+ * We then return the x and y data points according to our fit
653
+ */
654
+ var result_values_x: number[] = [];
655
+ var result_values_y: number[] = [];
656
+
657
+ for (let i = 0; i < values_length; i++) {
658
+ x = values_x[i];
659
+ y = x * m + b;
660
+ result_values_x.push(x);
661
+ result_values_y.push(y);
662
+ }
663
+
664
+ return [result_values_x, result_values_y];
665
+ }
666
+ public slopeOfLeastSquares(values_x: number[], values_y: number[]): number {
667
+ let points = utils.findLineByLeastSquares(values_x, values_y);
668
+ let points_x = points[0];
669
+ let points_y = points[1];
670
+ let slope = (points_y[0] - points_y[points_y.length - 1]) / (points_x[0] - points_x[points_x.length - 1]);
671
+ return slope;
672
+ }
517
673
  }
518
674
 
519
675
  export const utils = new Utils();