nodejs-poolcontroller 7.6.1 → 7.7.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.
Files changed (91) hide show
  1. package/.eslintrc.json +44 -44
  2. package/.github/ISSUE_TEMPLATE/1-bug-report.yml +84 -0
  3. package/.github/ISSUE_TEMPLATE/2-docs.md +12 -0
  4. package/.github/ISSUE_TEMPLATE/3-proposal.md +28 -0
  5. package/.github/ISSUE_TEMPLATE/config.yml +8 -0
  6. package/CONTRIBUTING.md +74 -74
  7. package/Changelog +220 -215
  8. package/Dockerfile +17 -17
  9. package/Gruntfile.js +40 -40
  10. package/LICENSE +661 -661
  11. package/README.md +191 -191
  12. package/app.ts +1 -1
  13. package/config/Config.ts +14 -0
  14. package/config/VersionCheck.ts +2 -2
  15. package/controller/Constants.ts +2 -1
  16. package/controller/Equipment.ts +2484 -2459
  17. package/controller/Errors.ts +180 -180
  18. package/controller/Lockouts.ts +502 -436
  19. package/controller/State.ts +106 -30
  20. package/controller/boards/AquaLinkBoard.ts +1000 -0
  21. package/controller/boards/BoardFactory.ts +49 -45
  22. package/controller/boards/EasyTouchBoard.ts +2859 -2653
  23. package/controller/boards/IntelliCenterBoard.ts +4198 -4230
  24. package/controller/boards/IntelliComBoard.ts +63 -63
  25. package/controller/boards/IntelliTouchBoard.ts +273 -241
  26. package/controller/boards/NixieBoard.ts +1728 -1675
  27. package/controller/boards/SystemBoard.ts +4925 -4697
  28. package/controller/comms/Comms.ts +442 -479
  29. package/controller/comms/messages/Messages.ts +171 -25
  30. package/controller/comms/messages/config/ChlorinatorMessage.ts +5 -2
  31. package/controller/comms/messages/config/CircuitGroupMessage.ts +0 -0
  32. package/controller/comms/messages/config/CircuitMessage.ts +1 -0
  33. package/controller/comms/messages/config/ConfigMessage.ts +0 -0
  34. package/controller/comms/messages/config/CoverMessage.ts +0 -0
  35. package/controller/comms/messages/config/CustomNameMessage.ts +30 -30
  36. package/controller/comms/messages/config/EquipmentMessage.ts +0 -0
  37. package/controller/comms/messages/config/ExternalMessage.ts +0 -0
  38. package/controller/comms/messages/config/FeatureMessage.ts +0 -0
  39. package/controller/comms/messages/config/GeneralMessage.ts +0 -0
  40. package/controller/comms/messages/config/HeaterMessage.ts +142 -10
  41. package/controller/comms/messages/config/IntellichemMessage.ts +0 -0
  42. package/controller/comms/messages/config/OptionsMessage.ts +4 -21
  43. package/controller/comms/messages/config/PumpMessage.ts +53 -35
  44. package/controller/comms/messages/config/RemoteMessage.ts +0 -0
  45. package/controller/comms/messages/config/ScheduleMessage.ts +350 -347
  46. package/controller/comms/messages/config/SecurityMessage.ts +0 -0
  47. package/controller/comms/messages/config/ValveMessage.ts +1 -1
  48. package/controller/comms/messages/status/ChlorinatorStateMessage.ts +38 -86
  49. package/controller/comms/messages/status/EquipmentStateMessage.ts +58 -22
  50. package/controller/comms/messages/status/HeaterStateMessage.ts +116 -86
  51. package/controller/comms/messages/status/IntelliChemStateMessage.ts +445 -445
  52. package/controller/comms/messages/status/IntelliValveStateMessage.ts +35 -35
  53. package/controller/comms/messages/status/PumpStateMessage.ts +23 -1
  54. package/controller/comms/messages/status/VersionMessage.ts +0 -0
  55. package/controller/nixie/Nixie.ts +162 -162
  56. package/controller/nixie/NixieEquipment.ts +103 -103
  57. package/controller/nixie/bodies/Body.ts +120 -120
  58. package/controller/nixie/bodies/Filter.ts +135 -135
  59. package/controller/nixie/chemistry/ChemController.ts +2511 -2498
  60. package/controller/nixie/chemistry/Chlorinator.ts +363 -314
  61. package/controller/nixie/circuits/Circuit.ts +261 -248
  62. package/controller/nixie/heaters/Heater.ts +650 -648
  63. package/controller/nixie/pumps/Pump.ts +906 -661
  64. package/controller/nixie/schedules/Schedule.ts +313 -257
  65. package/controller/nixie/valves/Valve.ts +170 -170
  66. package/defaultConfig.json +306 -286
  67. package/logger/DataLogger.ts +448 -448
  68. package/logger/Logger.ts +0 -0
  69. package/package.json +56 -56
  70. package/tsconfig.json +25 -25
  71. package/web/Server.ts +92 -47
  72. package/web/bindings/aqualinkD.json +505 -0
  73. package/web/bindings/influxDB.json +1051 -1021
  74. package/web/bindings/mqtt.json +702 -654
  75. package/web/bindings/mqttAlt.json +731 -684
  76. package/web/bindings/rulesManager.json +54 -54
  77. package/web/bindings/smartThings-Hubitat.json +31 -31
  78. package/web/bindings/valveRelays.json +20 -20
  79. package/web/bindings/vera.json +25 -25
  80. package/web/interfaces/baseInterface.ts +137 -136
  81. package/web/interfaces/httpInterface.ts +145 -124
  82. package/web/interfaces/influxInterface.ts +276 -245
  83. package/web/interfaces/mqttInterface.ts +535 -475
  84. package/web/services/config/Config.ts +39 -18
  85. package/web/services/config/ConfigSocket.ts +0 -0
  86. package/web/services/state/State.ts +10 -0
  87. package/web/services/state/StateSocket.ts +4 -4
  88. package/web/services/utilities/Utilities.ts +44 -42
  89. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -52
  90. package/config copy.json +0 -300
  91. package/issue_template.md +0 -52
package/logger/Logger.ts CHANGED
File without changes
package/package.json CHANGED
@@ -1,56 +1,56 @@
1
- {
2
- "name": "nodejs-poolcontroller",
3
- "version": "7.6.1",
4
- "description": "nodejs-poolController",
5
- "main": "app.js",
6
- "author": {
7
- "name": "Russell Goldin",
8
- "name2": "Robert Strouse"
9
- },
10
- "license": "GNU Affero General Public License v3.0",
11
- "repository": {
12
- "type": "git",
13
- "url": "https://github.com/tagyoureit/nodejs-poolController.git"
14
- },
15
- "scripts": {
16
- "start": "npm run build && node dist/app.js",
17
- "start:cached": "node dist/app.js",
18
- "build": "tsc",
19
- "watch": "tsc -w"
20
- },
21
- "dependencies": {
22
- "@influxdata/influxdb-client": "^1.22.0",
23
- "eslint-config-promise": "^2.0.2",
24
- "express": "^4.17.2",
25
- "extend": "^3.0.2",
26
- "jszip": "^3.7.1",
27
- "mqtt": "^4.3.5",
28
- "multer": "^1.4.4",
29
- "multicast-dns": "^7.2.4",
30
- "node-ssdp": "^4.0.1",
31
- "serialport": "^9.2.8",
32
- "socket.io": "^4.4.1",
33
- "socket.io-client": "^4.4.1",
34
- "source-map-support": "^0.5.21",
35
- "winston": "^3.5.1"
36
- },
37
- "devDependencies": {
38
- "@types/express": "^4.17.13",
39
- "@types/extend": "^3.0.1",
40
- "@types/multer": "^1.4.7",
41
- "@types/node": "^12.20.43",
42
- "@typescript-eslint/eslint-plugin": "^5.11.0",
43
- "@typescript-eslint/parser": "^5.11.0",
44
- "eslint": "^8.8.0",
45
- "eslint-config-defaults": "^9.0.0",
46
- "eslint-config-standard": "^16.0.3",
47
- "eslint-plugin-import": "^2.25.4",
48
- "eslint-plugin-node": "^11.1.0",
49
- "eslint-plugin-promise": "^6.0.0",
50
- "eslint-plugin-standard": "^5.0.0",
51
- "grunt": "^1.4.1",
52
- "grunt-banner": "^0.6.0",
53
- "ts-node": "^10.5.0",
54
- "typescript": "^4.5.5"
55
- }
56
- }
1
+ {
2
+ "name": "nodejs-poolcontroller",
3
+ "version": "7.7.0",
4
+ "description": "nodejs-poolController",
5
+ "main": "app.js",
6
+ "author": {
7
+ "name": "Russell Goldin",
8
+ "name2": "Robert Strouse"
9
+ },
10
+ "license": "GNU Affero General Public License v3.0",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/tagyoureit/nodejs-poolController.git"
14
+ },
15
+ "scripts": {
16
+ "start": "npm run build && node dist/app.js",
17
+ "start:cached": "node dist/app.js",
18
+ "build": "tsc",
19
+ "watch": "tsc -w"
20
+ },
21
+ "dependencies": {
22
+ "@influxdata/influxdb-client": "^1.25.0",
23
+ "eslint-config-promise": "^2.0.2",
24
+ "express": "^4.18.1",
25
+ "extend": "^3.0.2",
26
+ "jszip": "^3.9.1",
27
+ "mqtt": "^4.3.7",
28
+ "multer": "^1.4.4",
29
+ "multicast-dns": "^7.2.4",
30
+ "node-ssdp": "^4.0.1",
31
+ "serialport": "^9.2.8",
32
+ "socket.io": "^4.5.0",
33
+ "socket.io-client": "^4.5.0",
34
+ "source-map-support": "^0.5.21",
35
+ "winston": "^3.7.2"
36
+ },
37
+ "devDependencies": {
38
+ "@types/express": "^4.17.13",
39
+ "@types/extend": "^3.0.1",
40
+ "@types/multer": "^1.4.7",
41
+ "@types/node": "^12.20.52",
42
+ "@typescript-eslint/eslint-plugin": "^5.23.0",
43
+ "@typescript-eslint/parser": "^5.23.0",
44
+ "eslint": "^8.15.0",
45
+ "eslint-config-defaults": "^9.0.0",
46
+ "eslint-config-standard": "^16.0.3",
47
+ "eslint-plugin-import": "^2.26.0",
48
+ "eslint-plugin-node": "^11.1.0",
49
+ "eslint-plugin-promise": "^6.0.0",
50
+ "eslint-plugin-standard": "^5.0.0",
51
+ "grunt": "^1.5.3",
52
+ "grunt-banner": "^0.6.0",
53
+ "ts-node": "^10.7.0",
54
+ "typescript": "^4.6.4"
55
+ }
56
+ }
package/tsconfig.json CHANGED
@@ -1,25 +1,25 @@
1
- {
2
- "compilerOptions": {
3
- "baseUrl": ".",
4
- // "paths": { "*": [ "@types/*" ] },
5
- "target":"esnext",
6
- "module":"commonjs",
7
- "noImplicitAny": false,
8
- "removeComments": true,
9
- "preserveConstEnums": true,
10
- "sourceMap": true,
11
- "outDir": "dist",
12
- "moduleResolution": "node",
13
- "allowJs": false,
14
- "allowSyntheticDefaultImports": false,
15
- "esModuleInterop": false,
16
- "jsx": "react"
17
- },
18
- "include": [
19
- "web/**/*",
20
- "logger/**/*",
21
- "controller/**/*",
22
- "config/**/*",
23
- "**/*.ts"
24
- ]
25
- }
1
+ {
2
+ "compilerOptions": {
3
+ "baseUrl": ".",
4
+ // "paths": { "*": [ "@types/*" ] },
5
+ "target":"esnext",
6
+ "module":"commonjs",
7
+ "noImplicitAny": false,
8
+ "removeComments": true,
9
+ "preserveConstEnums": true,
10
+ "sourceMap": true,
11
+ "outDir": "dist",
12
+ "moduleResolution": "node",
13
+ "allowJs": false,
14
+ "allowSyntheticDefaultImports": false,
15
+ "esModuleInterop": false,
16
+ "jsx": "react"
17
+ },
18
+ "include": [
19
+ "web/**/*",
20
+ "logger/**/*",
21
+ "controller/**/*",
22
+ "config/**/*",
23
+ "**/*.ts"
24
+ ]
25
+ }
package/web/Server.ts CHANGED
@@ -54,6 +54,7 @@ export class WebServer {
54
54
  private _servers: ProtoServer[] = [];
55
55
  private family = 'IPv4';
56
56
  private _autoBackupTimer: NodeJS.Timeout;
57
+ private _httpPort: number;
57
58
  constructor() { }
58
59
  public async init() {
59
60
  try {
@@ -68,12 +69,15 @@ export class WebServer {
68
69
  switch (s) {
69
70
  case 'http':
70
71
  srv = new HttpServer(s, s);
72
+ if (c.enabled !== false) this._httpPort = c.port;
71
73
  break;
72
74
  case 'http2':
73
75
  srv = new Http2Server(s, s);
76
+ if (c.enabled !== false) this._httpPort = c.port;
74
77
  break;
75
78
  case 'https':
76
79
  srv = new HttpsServer(s, s);
80
+ if (c.enabled !== false) this._httpPort = c.port;
77
81
  break;
78
82
  case 'mdns':
79
83
  srv = new MdnsServer(s, s);
@@ -173,12 +177,9 @@ export class WebServer {
173
177
  }
174
178
  }
175
179
  }
176
- public ip() {
177
- return typeof this.getInterface() === 'undefined' ? '0.0.0.0' : this.getInterface().address;
178
- }
179
- public mac() {
180
- return typeof this.getInterface() === 'undefined' ? '00:00:00:00' : this.getInterface().mac;
181
- }
180
+ public ip() { return typeof this.getInterface() === 'undefined' ? '0.0.0.0' : this.getInterface().address; }
181
+ public mac() { return typeof this.getInterface() === 'undefined' ? '00:00:00:00' : this.getInterface().mac; }
182
+ public httpPort(): number { return this._httpPort }
182
183
  public findServer(name: string): ProtoServer { return this._servers.find(elem => elem.name === name); }
183
184
  public findServersByType(type: string) { return this._servers.filter(elem => elem.type === type); }
184
185
  public findServerByGuid(uuid: string) { return this._servers.find(elem => elem.uuid === uuid); }
@@ -618,42 +619,6 @@ export class HttpServer extends ProtoServer {
618
619
  self._sockets = await self.sockServer.fetchSockets();
619
620
  });
620
621
  sock.on('echo', (msg) => { sock.emit('echo', msg); });
621
- /* sock.on('receivePacketRaw', function (incomingPacket: any[]) {
622
- //var str = 'Add packet(s) to incoming buffer: ';
623
- logger.silly('User request (replay.html) to RECEIVE packet: %s', JSON.stringify(incomingPacket));
624
- for (var i = 0; i < incomingPacket.length; i++) {
625
- conn.buffer.pushIn(Buffer.from(incomingPacket[i]));
626
- // str += JSON.stringify(incomingPacket[i]) + ' ';
627
- }
628
- //logger.info(str);
629
- });
630
- sock.on('replayPackets', function (inboundPkts: number[][]) {
631
- // used for replay
632
- logger.debug(`Received replayPackets: ${inboundPkts}`);
633
- inboundPkts.forEach(inbound => {
634
- conn.buffer.pushIn(Buffer.from([].concat.apply([], inbound)));
635
- // conn.queueInboundMessage([].concat.apply([], inbound));
636
- });
637
- });
638
- sock.on('sendPackets', function (bytesToProcessArr: number[][]) {
639
- // takes an input of bytes (src/dest/action/payload) and sends
640
- if (!bytesToProcessArr.length) return;
641
- logger.silly('User request (replay.html) to SEND packet: %s', JSON.stringify(bytesToProcessArr));
642
-
643
- do {
644
- let bytesToProcess: number[] = bytesToProcessArr.shift();
645
-
646
- // todo: logic for chlor packets
647
- let out = Outbound.create({
648
- source: bytesToProcess.shift(),
649
- dest: bytesToProcess.shift(),
650
- action: bytesToProcess.shift(),
651
- payload: bytesToProcess.splice(1, bytesToProcess[0])
652
- });
653
- conn.queueSendMessage(out);
654
- } while (bytesToProcessArr.length > 0);
655
-
656
- }); */
657
622
  sock.on('sendOutboundMessage', (mdata) => {
658
623
  let msg: Outbound = Outbound.create({});
659
624
  Object.assign(msg, mdata);
@@ -733,7 +698,7 @@ export class HttpServer extends ProtoServer {
733
698
  res.header('Access-Control-Allow-Methods', 'OPTIONS, GET, POST, PUT, DELETE');
734
699
  if ('OPTIONS' === req.method) { res.sendStatus(200); }
735
700
  else {
736
- if (req.url !== '/device') {
701
+ if (req.url !== '/upnp.xml') {
737
702
  logger.info(`[${new Date().toLocaleTimeString()}] ${req.ip} ${req.method} ${req.url} ${typeof req.body === 'undefined' ? '' : JSON.stringify(req.body)}`);
738
703
  logger.logAPI(`{"dir":"in","proto":"api","requestor":"${req.ip}","method":"${req.method}","path":"${req.url}",${typeof req.body === 'undefined' ? '' : `"body":${JSON.stringify(req.body)},`}"ts":"${Timestamp.toISOLocal(new Date())}"}${os.EOL}`);
739
704
  }
@@ -824,7 +789,7 @@ export class HttpsServer extends HttpServer {
824
789
  res.header('Access-Control-Allow-Methods', 'OPTIONS, GET, POST, PUT, DELETE');
825
790
  if ('OPTIONS' === req.method) { res.sendStatus(200); }
826
791
  else {
827
- if (req.url !== '/device') {
792
+ if (req.url !== '/upnp.xml') {
828
793
  logger.info(`[${new Date().toLocaleString()}] ${req.ip} ${req.method} ${req.url} ${typeof req.body === 'undefined' ? '' : JSON.stringify(req.body)}`);
829
794
  logger.logAPI(`{"dir":"in","proto":"api","requestor":"${req.ip}","method":"${req.method}","path":"${req.url}",${typeof req.body === 'undefined' ? '' : `"body":${JSON.stringify(req.body)},`}"ts":"${Timestamp.toISOLocal(new Date())}"}${os.EOL}`);
830
795
  }
@@ -874,6 +839,84 @@ export class HttpsServer extends HttpServer {
874
839
  }
875
840
  }
876
841
  export class SsdpServer extends ProtoServer {
842
+ // Simple service discovery protocol
843
+ public server: any; //node-ssdp;
844
+ public deviceUUID: string;
845
+ public upnpPath: string;
846
+ public modelName: string;
847
+ public modelNumber: string;
848
+ public serialNumber: string;
849
+ public deviceType = 'urn:schemas-tagyoureit-org:device:PoolController:1';
850
+ public async init(cfg) {
851
+ this.uuid = cfg.uuid;
852
+ if (cfg.enabled) {
853
+ let self = this;
854
+ logger.info('Starting up SSDP server');
855
+ let ver = JSON.parse(fs.readFileSync(path.posix.join(process.cwd(), '/package.json'), 'utf8')).version || '0.0.0';
856
+ this.deviceUUID = 'uuid:806f52f4-1f35-4e33-9299-' + webApp.mac().replace(/:/g, '');
857
+ this.serialNumber = webApp.mac();
858
+ this.modelName = `njsPC v${ver}`;
859
+ this.modelNumber = `njsPC${ver.replace(/\./g, '-')}`;
860
+ // todo: should probably check if http/https is enabled at this point
861
+ let port = config.getSection('web').servers.http.port || 7777;
862
+ this.upnpPath = 'http://' + webApp.ip() + ':' + port + '/upnp.xml';
863
+ let SSDP = ssdp.Server;
864
+ this.server = new SSDP({
865
+ //customLogger: (...args) => console.log.apply(null, args),
866
+ logLevel: 'INFO',
867
+ udn: this.deviceUUID,
868
+ location: this.upnpPath,
869
+ sourcePort: 1900
870
+ });
871
+ this.server.addUSN('upnp:rootdevice'); // This line will make the server show up in windows.
872
+ this.server.addUSN(this.deviceType);
873
+ // start the server
874
+ this.server.start()
875
+ .then(function () {
876
+ logger.silly('SSDP/UPnP Server started.');
877
+ self.isRunning = true;
878
+ });
879
+
880
+ this.server.on('error', function (e) {
881
+ logger.error('error from SSDP:', e);
882
+ });
883
+ }
884
+ }
885
+ public deviceXML(): string {
886
+ let XML = `<?xml version="1.0"?>
887
+ <root xmlns="urn:schemas-upnp-org:device-1-0">
888
+ <specVersion>
889
+ <major>1</major>
890
+ <minor>0</minor>
891
+ </specVersion>
892
+ <device>
893
+ <deviceType>${this.deviceType}</deviceType>
894
+ <friendlyName>NodeJS Pool Controller</friendlyName>
895
+ <manufacturer>tagyoureit</manufacturer>
896
+ <manufacturerURL>https://github.com/tagyoureit/nodejs-poolController</manufacturerURL>
897
+ <presentationURL>http://${webApp.ip()}:${webApp.httpPort()}/state/all</presentationURL>
898
+ <modelName>${this.modelName}</modelName>
899
+ <modelNumber>${this.modelNumber}</modelNumber>
900
+ <modelDescription>An application to control pool equipment.</modelDescription>
901
+ <serialNumber>${this.serialNumber}</serialNumber>
902
+ <UDN>${this.deviceUUID}::${this.deviceType}</UDN>
903
+ <serviceList></serviceList>
904
+ <deviceList></deviceList>
905
+ </device>
906
+ </root>`;
907
+ return XML;
908
+ }
909
+ public async stopAsync() {
910
+ try {
911
+ if (typeof this.server !== 'undefined') {
912
+ this.server.stop();
913
+ logger.info(`Stopped SSDP server: ${this.name}`);
914
+ }
915
+ } catch (err) { logger.error(`Error stopping SSDP server ${err.message}`); }
916
+ }
917
+ }
918
+ /* RKS DEPRECATED: 05-07-22 - This did not follow the upnp rules so it was not detecting properly. The entire class above emits the proper xml layout.
919
+ export class SsdpServer1 extends ProtoServer {
877
920
  // Simple service discovery protocol
878
921
  public server: any; //node-ssdp;
879
922
  public async init(cfg) {
@@ -939,6 +982,10 @@ export class SsdpServer extends ProtoServer {
939
982
  } catch (err) { logger.error(`Error stopping SSDP server ${err.message}`); }
940
983
  }
941
984
  }
985
+ */
986
+
987
+
988
+
942
989
  export class MdnsServer extends ProtoServer {
943
990
  // Multi-cast DNS server
944
991
  public server;
@@ -1102,7 +1149,6 @@ export class HttpInterfaceServer extends ProtoServer {
1102
1149
  catch (err) { }
1103
1150
  }
1104
1151
  }
1105
-
1106
1152
  export class InfluxInterfaceServer extends ProtoServer {
1107
1153
  public bindingsPath: string;
1108
1154
  public bindings: InfluxInterfaceBindings;
@@ -1163,7 +1209,6 @@ export class InfluxInterfaceServer extends ProtoServer {
1163
1209
  }
1164
1210
  }
1165
1211
  }
1166
-
1167
1212
  export class MqttInterfaceServer extends ProtoServer {
1168
1213
  public bindingsPath: string;
1169
1214
  public bindings: HttpInterfaceBindings;
@@ -1450,7 +1495,7 @@ export class REMInterfaceServer extends ProtoServer {
1450
1495
  }
1451
1496
  private isJSONString(s: string): boolean {
1452
1497
  if (typeof s !== 'string') return false;
1453
- if (typeof s.startsWith('{') || typeof s.startsWith('[')) return true;
1498
+ if (s.startsWith('{') || s.startsWith('[')) return true;
1454
1499
  return false;
1455
1500
  }
1456
1501
  public async getApiService(url: string, data?: any, timeout: number = 3600): Promise<InterfaceServerResponse> {