nodejs-poolcontroller 7.4.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 (55) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  2. package/Changelog +3 -0
  3. package/README.md +2 -2
  4. package/app.ts +2 -0
  5. package/config/Config.ts +3 -0
  6. package/config/VersionCheck.ts +8 -4
  7. package/controller/Equipment.ts +89 -29
  8. package/controller/Errors.ts +14 -1
  9. package/controller/State.ts +75 -31
  10. package/controller/boards/EasyTouchBoard.ts +81 -36
  11. package/controller/boards/IntelliCenterBoard.ts +96 -32
  12. package/controller/boards/IntelliTouchBoard.ts +103 -29
  13. package/controller/boards/NixieBoard.ts +79 -27
  14. package/controller/boards/SystemBoard.ts +1552 -822
  15. package/controller/comms/Comms.ts +84 -9
  16. package/controller/comms/messages/Messages.ts +10 -4
  17. package/controller/comms/messages/config/ChlorinatorMessage.ts +13 -4
  18. package/controller/comms/messages/config/CircuitGroupMessage.ts +6 -0
  19. package/controller/comms/messages/config/CoverMessage.ts +1 -0
  20. package/controller/comms/messages/config/EquipmentMessage.ts +4 -0
  21. package/controller/comms/messages/config/ExternalMessage.ts +43 -25
  22. package/controller/comms/messages/config/FeatureMessage.ts +8 -1
  23. package/controller/comms/messages/config/GeneralMessage.ts +8 -0
  24. package/controller/comms/messages/config/HeaterMessage.ts +10 -9
  25. package/controller/comms/messages/config/IntellichemMessage.ts +4 -1
  26. package/controller/comms/messages/config/OptionsMessage.ts +13 -1
  27. package/controller/comms/messages/config/PumpMessage.ts +4 -20
  28. package/controller/comms/messages/config/RemoteMessage.ts +4 -0
  29. package/controller/comms/messages/config/ScheduleMessage.ts +11 -0
  30. package/controller/comms/messages/config/SecurityMessage.ts +1 -0
  31. package/controller/comms/messages/config/ValveMessage.ts +12 -2
  32. package/controller/comms/messages/status/ChlorinatorStateMessage.ts +2 -3
  33. package/controller/comms/messages/status/EquipmentStateMessage.ts +74 -22
  34. package/controller/comms/messages/status/HeaterStateMessage.ts +15 -6
  35. package/controller/comms/messages/status/IntelliChemStateMessage.ts +37 -26
  36. package/controller/nixie/Nixie.ts +18 -16
  37. package/controller/nixie/chemistry/ChemController.ts +57 -37
  38. package/controller/nixie/chemistry/Chlorinator.ts +7 -8
  39. package/controller/nixie/circuits/Circuit.ts +17 -0
  40. package/controller/nixie/pumps/Pump.ts +49 -24
  41. package/controller/nixie/schedules/Schedule.ts +1 -1
  42. package/defaultConfig.json +15 -0
  43. package/issue_template.md +1 -1
  44. package/logger/DataLogger.ts +37 -22
  45. package/package.json +3 -1
  46. package/web/Server.ts +515 -27
  47. package/web/bindings/influxDB.json +35 -0
  48. package/web/bindings/mqtt.json +62 -3
  49. package/web/bindings/mqttAlt.json +57 -4
  50. package/web/interfaces/httpInterface.ts +2 -0
  51. package/web/interfaces/influxInterface.ts +3 -2
  52. package/web/interfaces/mqttInterface.ts +12 -1
  53. package/web/services/config/Config.ts +162 -37
  54. package/web/services/state/State.ts +47 -3
  55. package/web/services/state/StateSocket.ts +1 -1
@@ -335,15 +335,16 @@ export class NixiePumpRS485 extends NixiePump {
335
335
  let pt = sys.board.valueMaps.pumpTypes.get(this.pump.type);
336
336
  // Since these process are async the closing flag can be set
337
337
  // between calls. We need to check it in between each call.
338
- if (!this.closing) await this.setDriveStateAsync(pstate);
339
- if (!this.closing) {
340
- if (this._targetSpeed >= pt.minFlow && this._targetSpeed <= pt.maxFlow) await this.setPumpGPMAsync(pstate);
341
- else if (this._targetSpeed >= pt.minSpeed && this._targetSpeed <= pt.maxSpeed) await this.setPumpRPMAsync(pstate);
342
- }
338
+ try { if (!this.closing) await this.setDriveStateAsync(); } catch (err) {}
339
+ try { if (!this.closing) {
340
+ if (this._targetSpeed >= pt.minFlow && this._targetSpeed <= pt.maxFlow) await this.setPumpGPMAsync();
341
+ else if (this._targetSpeed >= pt.minSpeed && this._targetSpeed <= pt.maxSpeed) await this.setPumpRPMAsync();
342
+ } } catch (err) {}
343
343
 
344
- if(!this.closing) await utils.sleep(2000);
345
- if(!this.closing) await this.requestPumpStatus(pstate);
346
- if(!this.closing) await this.setPumpToRemoteControl(pstate);
344
+ try { if(!this.closing) await this.setPumpFeature(6); } catch (err) {};
345
+ try { if(!this.closing) await utils.sleep(1000); } catch (err) {};
346
+ try { if(!this.closing) await this.requestPumpStatus(); } catch (err) {};
347
+ try { if(!this.closing) await this.setPumpToRemoteControl(); } catch (err) {};
347
348
  return new InterfaceServerResponse(200, 'Success');
348
349
  }
349
350
  catch (err) {
@@ -353,7 +354,7 @@ export class NixiePumpRS485 extends NixiePump {
353
354
  finally { this.suspendPolling = false; }
354
355
 
355
356
  };
356
- protected async setDriveStateAsync(pstate: PumpState, running: boolean = true) {
357
+ protected async setDriveStateAsync(running: boolean = true) {
357
358
  return new Promise<void>((resolve, reject) => {
358
359
  let out = Outbound.create({
359
360
  protocol: Protocol.Pump,
@@ -373,7 +374,7 @@ export class NixiePumpRS485 extends NixiePump {
373
374
  conn.queueSendMessage(out);
374
375
  });
375
376
  };
376
- protected async requestPumpStatus(pstate: PumpState) {
377
+ protected async requestPumpStatus() {
377
378
  return new Promise<void>((resolve, reject) => {
378
379
  let out = Outbound.create({
379
380
  protocol: Protocol.Pump,
@@ -393,7 +394,7 @@ export class NixiePumpRS485 extends NixiePump {
393
394
  conn.queueSendMessage(out);
394
395
  })
395
396
  };
396
- protected setPumpToRemoteControl(spump: PumpState, running: boolean = true) {
397
+ protected setPumpToRemoteControl(running: boolean = true) {
397
398
  return new Promise<void>((resolve, reject) => {
398
399
  let out = Outbound.create({
399
400
  protocol: Protocol.Pump,
@@ -414,13 +415,15 @@ export class NixiePumpRS485 extends NixiePump {
414
415
  conn.queueSendMessage(out);
415
416
  });
416
417
  }
417
- protected setPumpManual(pstate: PumpState) {
418
+ protected setPumpFeature(feature?: number) {
419
+ // empty payload (possibly 0?, too) is no feature
420
+ // 6: Feature 1
418
421
  return new Promise<void>((resolve, reject) => {
419
422
  let out = Outbound.create({
420
423
  protocol: Protocol.Pump,
421
424
  dest: this.pump.address,
422
425
  action: 5,
423
- payload: [],
426
+ payload: typeof feature === 'undefined' ? [] : [ feature ],
424
427
  retries: 2,
425
428
  repsonse: true,
426
429
  onComplete: (err, msg: Outbound) => {
@@ -434,7 +437,7 @@ export class NixiePumpRS485 extends NixiePump {
434
437
  conn.queueSendMessage(out);
435
438
  });
436
439
  };
437
- protected async setPumpRPMAsync(pstate: PumpState) {
440
+ protected async setPumpRPMAsync() {
438
441
  return new Promise<void>((resolve, reject) => {
439
442
  let out = Outbound.create({
440
443
  protocol: Protocol.Pump,
@@ -455,14 +458,14 @@ export class NixiePumpRS485 extends NixiePump {
455
458
  conn.queueSendMessage(out);
456
459
  });
457
460
  };
458
- protected async setPumpGPMAsync(pstate: PumpState) {
461
+ protected async setPumpGPMAsync() {
459
462
  // packet for vf; vsf will override
460
463
  return new Promise<void>((resolve, reject) => {
461
464
  let out = Outbound.create({
462
465
  protocol: Protocol.Pump,
463
466
  dest: this.pump.address,
464
- action: 10,
465
- payload: [1, 4, 2, 228, this._targetSpeed, 0],
467
+ action: 1,
468
+ payload: [2, 228, 0, this._targetSpeed],
466
469
  retries: 1,
467
470
  response: true,
468
471
  onComplete: (err, msg) => {
@@ -484,10 +487,10 @@ export class NixiePumpRS485 extends NixiePump {
484
487
  this._pollTimer = null;
485
488
  let pstate = state.pumps.getItemById(this.pump.id);
486
489
  this._targetSpeed = 0;
487
- try { await this.setDriveStateAsync(pstate, false); } catch (err) { logger.error(`Error closing pump ${this.pump.name}: ${err.message}`) }
488
- try { await this.setPumpManual(pstate); } catch (err) { logger.error(`Error closing pump ${this.pump.name}: ${err.message}`) }
489
- try { await this.setDriveStateAsync(pstate, false); } catch (err) { logger.error(`Error closing pump ${this.pump.name}: ${err.message}`) }
490
- try { await this.setPumpToRemoteControl(pstate, false); } catch (err) { logger.error(`Error closing pump ${this.pump.name}: ${err.message}`) }
490
+ try { await this.setDriveStateAsync(false); } catch (err) { logger.error(`Error closing pump ${this.pump.name}: ${err.message}`) }
491
+ try { await this.setPumpFeature(); } catch (err) { logger.error(`Error closing pump ${this.pump.name}: ${err.message}`) }
492
+ try { await this.setDriveStateAsync(false); } catch (err) { logger.error(`Error closing pump ${this.pump.name}: ${err.message}`) }
493
+ try { await this.setPumpToRemoteControl(false); } catch (err) { logger.error(`Error closing pump ${this.pump.name}: ${err.message}`) }
491
494
  this.closing = true;
492
495
  // Make sure the polling timer is dead after we have closted this all off. That way we do not
493
496
  // have another process that revives it from the dead.
@@ -574,14 +577,36 @@ export class NixiePumpVSF extends NixiePumpRS485 {
574
577
  if (this._targetSpeed !== _newSpeed) logger.info(`NCP: Setting Pump ${this.pump.name} to ${_newSpeed} ${flows > 0 ? 'GPM' : 'RPM'}.`);
575
578
  this._targetSpeed = _newSpeed;
576
579
  }
577
- protected async setPumpGPMAsync(pstate: PumpState) {
578
- // vsf payload; different from vf payload
580
+ protected async setPumpRPMAsync() {
581
+ // vsf action is 10 for rpm
579
582
  return new Promise<void>((resolve, reject) => {
580
583
  let out = Outbound.create({
581
584
  protocol: Protocol.Pump,
582
585
  dest: this.pump.address,
583
586
  action: 10,
584
- payload: [1, 4, 2, 196, this._targetSpeed, 0],
587
+ payload: [2, 196, Math.floor(this._targetSpeed / 256), this._targetSpeed % 256],
588
+ retries: 1,
589
+ // timeout: 250,
590
+ response: true,
591
+ onComplete: (err, msg) => {
592
+ if (err) {
593
+ logger.error(`Error sending setPumpRPMAsync for ${this.pump.name}: ${err.message}`);
594
+ reject(err);
595
+ }
596
+ else resolve();
597
+ }
598
+ });
599
+ conn.queueSendMessage(out);
600
+ });
601
+ };
602
+ protected async setPumpGPMAsync() {
603
+ // vsf payload; different from vf payload
604
+ return new Promise<void>((resolve, reject) => {
605
+ let out = Outbound.create({
606
+ protocol: Protocol.Pump,
607
+ dest: this.pump.address,
608
+ action: 9,
609
+ payload: [2, 196, 0, this._targetSpeed],
585
610
  retries: 1,
586
611
  response: true,
587
612
  onComplete: (err, msg) => {
@@ -234,7 +234,7 @@ export class NixieSchedule extends NixieEquipment {
234
234
  }
235
235
  public logData(filename: string, data: any) { this.controlPanel.logData(filename, data); }
236
236
  }
237
- class NixieScheduleContext {
237
+ class NixieScheduleContext {
238
238
  constructor() {
239
239
 
240
240
  }
@@ -17,7 +17,18 @@
17
17
  "autoOpen": false,
18
18
  "lock": false
19
19
  }
20
+ },
21
+ "backups": {
22
+ "automatic": false,
23
+ "interval": {
24
+ "days": 30,
25
+ "hours": 0
26
+ },
27
+ "keepCount": 5,
28
+ "njsPC": true,
29
+ "servers": []
20
30
  }
31
+
21
32
  },
22
33
  "web": {
23
34
  "servers": {
@@ -52,6 +63,7 @@
52
63
  "interfaces": {
53
64
  "smartThings": {
54
65
  "name": "SmartThings",
66
+ "type": "rest",
55
67
  "enabled": false,
56
68
  "fileName": "smartThings-Hubitat.json",
57
69
  "globals": {},
@@ -62,6 +74,7 @@
62
74
  },
63
75
  "hubitat": {
64
76
  "name": "Hubitat",
77
+ "type": "rest",
65
78
  "enabled": false,
66
79
  "fileName": "smartThings-Hubitat.json",
67
80
  "globals": {},
@@ -72,6 +85,7 @@
72
85
  },
73
86
  "vera": {
74
87
  "name": "Vera",
88
+ "type": "rest",
75
89
  "enabled": false,
76
90
  "fileName": "vera.json",
77
91
  "vars": {
@@ -83,6 +97,7 @@
83
97
  }
84
98
  },
85
99
  "valveRelay": {
100
+ "type": "rest",
86
101
  "name": "Valve Relays",
87
102
  "enabled": false,
88
103
  "fileName": "valveRelays.json",
package/issue_template.md CHANGED
@@ -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
 
@@ -29,8 +29,10 @@ export class DataLogger {
29
29
  }
30
30
  let arr: T[] = [];
31
31
  for (let i = 0; i < lines.length; i++) {
32
- let entry = DataLogger.createEntry<T>(type, lines[i]);
33
- arr.push(entry);
32
+ try {
33
+ let entry = DataLogger.createEntry<T>(type, lines[i]);
34
+ arr.push(entry);
35
+ } catch (err) { logger.error(`Skipping invalid dose history entry: ${err.message}`); }
34
36
  }
35
37
  return arr;
36
38
  } catch (err) { logger.error(err); }
@@ -47,6 +49,7 @@ export class DataLogger {
47
49
  let newLines = ['\r', '\n'];
48
50
  let arr: T[] = [];
49
51
  if (fs.existsSync(logPath)) {
52
+ console.log(`Reading logfile ${logPath}`);
50
53
  // Alright what we have created here is a method to read the data from the end of
51
54
  // a log file in reverse order (tail) that works for all os implementations. It is
52
55
  // really dumb that this isn't part of the actual file processing.
@@ -81,15 +84,16 @@ export class DataLogger {
81
84
  // record then we shoud save off the line and read the next record.
82
85
  if (newLines.includes(char) || pos === 0) {
83
86
  if (chars.length > 0) {
84
- let entry = DataLogger.createEntry<T>(type, chars.join(''));
85
- if (typeof fn === 'function') {
86
- let rc = fn(arr.length + 1, entry, arr);
87
- console.log(rc);
88
- if (rc === true) arr.push(entry);
89
- else if (rc === false) break;
90
- }
91
- else
92
- arr.push(entry);
87
+ try {
88
+ let entry = DataLogger.createEntry<T>(type, chars.join(''));
89
+ if (typeof fn === 'function') {
90
+ let rc = fn(arr.length + 1, entry, arr);
91
+ if (rc === true) arr.push(entry);
92
+ else if (rc === false) break;
93
+ }
94
+ else
95
+ arr.push(entry);
96
+ } catch (err) { logger.error(`Skipping invalid dose history entry: ${err.message}`); }
93
97
  }
94
98
  chars = [];
95
99
  }
@@ -142,14 +146,16 @@ export class DataLogger {
142
146
  // record then we shoud save off the line and read the next record.
143
147
  if (newLines.includes(char) || pos === 0) {
144
148
  if (chars.length > 0) {
145
- let entry = DataLogger.createEntry<T>(type, chars.join(''));
146
- if (typeof fn === 'function') {
147
- let rc = fn(arr.length + 1, entry, arr);
148
- if (rc === true) arr.push(entry);
149
- else if (rc === false) break;
150
- }
151
- else
152
- arr.push(entry);
149
+ try {
150
+ let entry = DataLogger.createEntry<T>(type, chars.join(''));
151
+ if (typeof fn === 'function') {
152
+ let rc = fn(arr.length + 1, entry, arr);
153
+ if (rc === true) arr.push(entry);
154
+ else if (rc === false) break;
155
+ }
156
+ else
157
+ arr.push(entry);
158
+ } catch (err) { logger.error(`Skipping invalid dose history entry: ${err.message}`); }
153
159
  }
154
160
  chars = [];
155
161
  }
@@ -276,7 +282,6 @@ export class DataLogger {
276
282
  let entry = DataLogger.createEntry<T>(type, chars.join(''));
277
283
  if (typeof fn === 'function') {
278
284
  let rc = fn(arr.length + 1, entry, arr);
279
- console.log(rc);
280
285
  if (rc === true) arr.push(entry);
281
286
  else if (rc === false) break;
282
287
  }
@@ -399,11 +404,21 @@ export class DataLoggerEntry {
399
404
  // Parse the data from the log entry if it exists.
400
405
  if (typeof entry === 'object') entry = JSON.stringify(entry);
401
406
  if (typeof entry === 'string') this.parse(entry);
407
+ else {
408
+ //console.log(`A DATALOGGER ENTRY DOES NOT HAVE A PROPER TYPE ${typeof entry} *************************************`);
409
+ //console.log(entry);
410
+ }
402
411
  }
403
- public createInstance(entry?: string) { return new DataLoggerEntry(entry); }
412
+ public static createInstance(entry?: string) { return new DataLoggerEntry(entry); }
404
413
  public parse(entry: string) {
405
414
  let obj = typeof entry !== 'undefined' ? JSON.parse(entry, this.dateParser) : {};
406
- extend(true, this, obj);
415
+ if (typeof entry === 'undefined') {
416
+ console.log(`A DATALOGGER ENTRY WAS NOT DEFINED *************************`);
417
+ }
418
+ else if (entry === '') {
419
+ console.log(`THE INCOMING DATALOGGER ENTRY WAS EMPTY ***************************`)
420
+ }
421
+ let o = extend(true, this, obj);
407
422
  }
408
423
  protected dateParser(key, value) {
409
424
  if (typeof value === 'string') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodejs-poolcontroller",
3
- "version": "7.4.0",
3
+ "version": "7.5.1",
4
4
  "description": "nodejs-poolController",
5
5
  "main": "app.js",
6
6
  "author": {
@@ -25,6 +25,7 @@
25
25
  "extend": "^3.0.2",
26
26
  "jszip": "^3.7.1",
27
27
  "mqtt": "^4.2.8",
28
+ "multer": "^1.4.3",
28
29
  "multicast-dns": "^7.2.3",
29
30
  "node-ssdp": "^4.0.1",
30
31
  "serialport": "^9.2.1",
@@ -36,6 +37,7 @@
36
37
  "devDependencies": {
37
38
  "@types/express": "^4.17.13",
38
39
  "@types/extend": "^3.0.1",
40
+ "@types/multer": "^1.4.7",
39
41
  "@types/node": "^12.20.23",
40
42
  "@typescript-eslint/eslint-plugin": "^4.30.0",
41
43
  "@typescript-eslint/parser": "^4.30.0",