nodejs-poolcontroller 7.7.0 → 8.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.
Files changed (82) hide show
  1. package/.eslintrc.json +26 -35
  2. package/Changelog +22 -0
  3. package/README.md +7 -3
  4. package/anslq25/MessagesMock.ts +218 -0
  5. package/anslq25/boards/MockBoardFactory.ts +50 -0
  6. package/anslq25/boards/MockEasyTouchBoard.ts +696 -0
  7. package/anslq25/boards/MockSystemBoard.ts +217 -0
  8. package/anslq25/chemistry/MockChlorinator.ts +75 -0
  9. package/anslq25/pumps/MockPump.ts +84 -0
  10. package/app.ts +10 -14
  11. package/config/Config.ts +13 -9
  12. package/config/VersionCheck.ts +6 -2
  13. package/controller/Constants.ts +58 -25
  14. package/controller/Equipment.ts +225 -41
  15. package/controller/Errors.ts +2 -1
  16. package/controller/Lockouts.ts +34 -2
  17. package/controller/State.ts +491 -48
  18. package/controller/boards/AquaLinkBoard.ts +6 -3
  19. package/controller/boards/BoardFactory.ts +5 -1
  20. package/controller/boards/EasyTouchBoard.ts +1971 -1751
  21. package/controller/boards/IntelliCenterBoard.ts +1311 -1688
  22. package/controller/boards/IntelliComBoard.ts +7 -1
  23. package/controller/boards/IntelliTouchBoard.ts +153 -42
  24. package/controller/boards/NixieBoard.ts +209 -66
  25. package/controller/boards/SunTouchBoard.ts +393 -0
  26. package/controller/boards/SystemBoard.ts +1862 -1543
  27. package/controller/comms/Comms.ts +539 -138
  28. package/controller/comms/ScreenLogic.ts +1663 -0
  29. package/controller/comms/messages/Messages.ts +242 -60
  30. package/controller/comms/messages/config/ChlorinatorMessage.ts +4 -3
  31. package/controller/comms/messages/config/CircuitGroupMessage.ts +5 -2
  32. package/controller/comms/messages/config/CircuitMessage.ts +81 -13
  33. package/controller/comms/messages/config/ConfigMessage.ts +3 -1
  34. package/controller/comms/messages/config/CoverMessage.ts +2 -1
  35. package/controller/comms/messages/config/CustomNameMessage.ts +2 -1
  36. package/controller/comms/messages/config/EquipmentMessage.ts +5 -1
  37. package/controller/comms/messages/config/ExternalMessage.ts +33 -3
  38. package/controller/comms/messages/config/FeatureMessage.ts +2 -1
  39. package/controller/comms/messages/config/GeneralMessage.ts +2 -1
  40. package/controller/comms/messages/config/HeaterMessage.ts +3 -1
  41. package/controller/comms/messages/config/IntellichemMessage.ts +2 -1
  42. package/controller/comms/messages/config/OptionsMessage.ts +12 -6
  43. package/controller/comms/messages/config/PumpMessage.ts +9 -12
  44. package/controller/comms/messages/config/RemoteMessage.ts +80 -13
  45. package/controller/comms/messages/config/ScheduleMessage.ts +43 -3
  46. package/controller/comms/messages/config/SecurityMessage.ts +2 -1
  47. package/controller/comms/messages/config/ValveMessage.ts +43 -26
  48. package/controller/comms/messages/status/ChlorinatorStateMessage.ts +8 -7
  49. package/controller/comms/messages/status/EquipmentStateMessage.ts +93 -20
  50. package/controller/comms/messages/status/HeaterStateMessage.ts +24 -5
  51. package/controller/comms/messages/status/IntelliChemStateMessage.ts +7 -4
  52. package/controller/comms/messages/status/IntelliValveStateMessage.ts +2 -1
  53. package/controller/comms/messages/status/PumpStateMessage.ts +72 -4
  54. package/controller/comms/messages/status/VersionMessage.ts +2 -1
  55. package/controller/nixie/Nixie.ts +15 -4
  56. package/controller/nixie/NixieEquipment.ts +1 -0
  57. package/controller/nixie/chemistry/ChemController.ts +300 -129
  58. package/controller/nixie/chemistry/ChemDoser.ts +806 -0
  59. package/controller/nixie/chemistry/Chlorinator.ts +133 -129
  60. package/controller/nixie/circuits/Circuit.ts +171 -30
  61. package/controller/nixie/heaters/Heater.ts +337 -173
  62. package/controller/nixie/pumps/Pump.ts +264 -236
  63. package/controller/nixie/schedules/Schedule.ts +9 -3
  64. package/defaultConfig.json +46 -5
  65. package/logger/Logger.ts +38 -9
  66. package/package.json +13 -9
  67. package/web/Server.ts +235 -122
  68. package/web/bindings/aqualinkD.json +114 -59
  69. package/web/bindings/homeassistant.json +437 -0
  70. package/web/bindings/influxDB.json +15 -0
  71. package/web/bindings/mqtt.json +28 -9
  72. package/web/bindings/mqttAlt.json +15 -0
  73. package/web/interfaces/baseInterface.ts +58 -7
  74. package/web/interfaces/httpInterface.ts +5 -2
  75. package/web/interfaces/influxInterface.ts +9 -2
  76. package/web/interfaces/mqttInterface.ts +234 -74
  77. package/web/interfaces/ruleInterface.ts +87 -0
  78. package/web/services/config/Config.ts +140 -33
  79. package/web/services/config/ConfigSocket.ts +2 -1
  80. package/web/services/state/State.ts +144 -3
  81. package/web/services/state/StateSocket.ts +65 -14
  82. package/web/services/utilities/Utilities.ts +189 -1
@@ -0,0 +1,217 @@
1
+ /* nodejs-poolController. An application to control pool equipment.
2
+ Copyright (C) 2016, 2017, 2018, 2019, 2020, 2021, 2022.
3
+ Russell Goldin, tagyoureit. russ.goldin@gmail.com
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU Affero General Public License as
7
+ published by the Free Software Foundation, either version 3 of the
8
+ License, or (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU Affero General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Affero General Public License
16
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+ import { logger } from "../../logger/Logger";
20
+ import { setTimeout as setTimeoutSync } from 'timers';
21
+ import { Inbound, Outbound, Protocol } from "../../controller/comms/messages/Messages";
22
+ import { byteValueMap, byteValueMaps, SystemBoard } from "../../controller/boards/SystemBoard";
23
+ import { Anslq25, PoolSystem, sys } from "../../controller/Equipment";
24
+ import { ControllerType, utils } from "../../controller/Constants";
25
+ import { conn } from "../../controller/comms/Comms";
26
+ import { MockEasyTouch } from "./MockEasyTouchBoard";
27
+
28
+ export class MockSystemBoard {
29
+ public valueMaps: byteValueMaps = new byteValueMaps();
30
+ protected _statusTimer: NodeJS.Timeout;
31
+ protected _statusCheckRef: number = 0;
32
+ protected _statusInterval: number = 5000;
33
+ constructor(system: PoolSystem) {
34
+ // sys.anslq25.portId = 0; // pass this in.
35
+ setTimeout(() => {
36
+ this.processStatusAsync().then(() => { });
37
+ }, 5000);
38
+ }
39
+ public expansionBoards: byteValueMap = new byteValueMap();
40
+ public get statusInterval(): number { return this._statusInterval };
41
+ public system: MockSystemCommands = new MockSystemCommands(this);
42
+ public circuits: MockCircuitCommands = new MockCircuitCommands(this);
43
+ public schedules: MockScheduleCommands = new MockScheduleCommands(this);
44
+ public heaters: MockHeaterCommands = new MockHeaterCommands(this);
45
+ public valves: MockValveCommands = new MockValveCommands(this);
46
+ public remotes: MockRemoteCommands = new MockRemoteCommands(this);
47
+ public pumps: MockPumpCommands = new MockPumpCommands(this);
48
+ public static convertOutbound(outboundMsg: Outbound) { };
49
+ public async sendAsync(msg: Outbound){
50
+ return await msg.sendAsync();
51
+ // is the controller on a real/physical port or a mock port?
52
+ /* let port = conn.findPortById(sys.anslq25.portId);
53
+ if (port.mockPort) {
54
+ let inbound = new Inbound();
55
+ inbound.protocol = msg.protocol;
56
+ inbound.header = msg.header;
57
+ inbound.payload = msg.payload;
58
+ inbound.term = msg.term;
59
+ inbound.portId = msg.portId;
60
+ // don't need to wait for packet to process
61
+ setTimeout(()=>{conn.sendMockPacket(inbound)}, 10);
62
+ return Promise.resolve();
63
+ }
64
+ else {
65
+ return await msg.sendAsync();
66
+ } */
67
+ }
68
+ public process(msg: Inbound): Outbound { return new Outbound(Protocol.Broadcast,0,0,0,[]); }
69
+ protected killStatusCheck() {
70
+ if (typeof this._statusTimer !== 'undefined' && this._statusTimer) clearTimeout(this._statusTimer);
71
+ this._statusTimer = undefined;
72
+ this._statusCheckRef = 0;
73
+ }
74
+ public suspendStatus(bSuspend: boolean) {
75
+ // The way status suspension works is by using a reference value that is incremented and decremented
76
+ // the status check is only performed when the reference value is 0. So suspending the status check 3 times and un-suspending
77
+ // it 2 times will still result in the status check being suspended. This method also ensures the reference never falls below 0.
78
+ if (bSuspend) this._statusCheckRef++;
79
+ else this._statusCheckRef = Math.max(0, this._statusCheckRef - 1);
80
+ if (this._statusCheckRef > 1) logger.verbose(`Suspending ANSLQ25 status check: ${bSuspend} -- ${this._statusCheckRef}`);
81
+ }
82
+ public async setAnslq25Async(data: any): Promise<Anslq25> {
83
+ let self = this;
84
+ try {
85
+ this.suspendStatus(true);
86
+ // if (typeof data.isActive === 'undefined') return Promise.reject(`Mock System Board: No isActive flag provided.`);
87
+ if (typeof data.anslq25portId === 'undefined') return Promise.reject(new Error(`Mock System Board: No portId provided.`));
88
+ if (typeof data.anslq25ControllerType === 'undefined') return Promise.reject(new Error(`Mock System Board: No controller type provided.`));
89
+ if (typeof data.anslq25model === 'undefined') return Promise.reject(new Error(`Mock System Board: No model provided.`));
90
+ //for (let i = 1; i <= )
91
+ let isActive = true; // utils.makeBool(data.isActive);
92
+ let portId = parseInt(data.anslq25portId, 10);
93
+ let port = conn.findPortById(portId);
94
+ if (typeof port === 'undefined') return Promise.reject(new Error(`Mock System Board: Invalid portId provided.`));
95
+ if (portId === 0) return Promise.reject(new Error(`Please choose a port other than the primary port.`));
96
+ let mockControllerType = data.anslq25ControllerType;
97
+ let model = parseInt(data.anslq25model, 10);
98
+ let broadcastComms = data.broadcastComms;
99
+ if (typeof broadcastComms === 'undefined') return Promise.reject(new Error(`A value for broadcast comms must be provided.`));
100
+ sys.anslq25.portId = portId;
101
+ sys.anslq25.broadcastComms = broadcastComms;
102
+ switch (mockControllerType) {
103
+ case ControllerType.EasyTouch:{
104
+ sys.anslq25ControllerType = ControllerType.EasyTouch;
105
+ // (sys.anslq25Board as MockEasyTouch).initExpansionModules(model);
106
+ break;
107
+ }
108
+ default: {
109
+ logger.warn(`No ANSLQ25 Mock Board definiton yet for: ${mockControllerType}`);
110
+ return Promise.reject(new Error(`No ANSLQ25 Mock Board definiton yet for: ${mockControllerType}`));
111
+ }
112
+ }
113
+ sys.anslq25.isActive = isActive;
114
+ sys.anslq25.model = model;
115
+
116
+ } catch (err) {
117
+ logger.error(`Error changing port id: ${err.message}`);
118
+ }
119
+ finally {
120
+ this.suspendStatus(false);
121
+ this._statusTimer = setTimeoutSync(async () => await self.processStatusAsync(), this.statusInterval);
122
+ }
123
+ }
124
+ public async deleteAnslq25Async(data: any) {
125
+ try {
126
+
127
+ this.killStatusCheck();
128
+ this.closeAsync();
129
+ sys.anslq25.isActive = false;
130
+ sys.anslq25.portId = undefined;
131
+ sys.anslq25.model = undefined;
132
+ sys.anslq25ControllerType = ControllerType.None;
133
+ }
134
+ catch (err){
135
+
136
+ }
137
+ finally {
138
+ this.suspendStatus(false);
139
+ }
140
+
141
+ }
142
+
143
+ public async processStatusAsync() {
144
+ let self = this;
145
+ try {
146
+ if (this._statusCheckRef > 0) return;
147
+ this.suspendStatus(true);
148
+
149
+ await sys.anslq25Board.system.sendStatusAsync();
150
+ }
151
+ catch (err) {
152
+ logger.error(`Error running mock processStatusAsync: ${err}`);
153
+ }
154
+ finally {
155
+ this.suspendStatus(false);
156
+ if (sys.anslq25.isActive){
157
+ if (this.statusInterval > 0) this._statusTimer = setTimeoutSync(async () => await self.processStatusAsync(), this.statusInterval);
158
+ }
159
+
160
+ }
161
+ }
162
+ // public async setPortId(portId: number) {
163
+ // let self = this;
164
+ // try {
165
+ // this.suspendStatus(true);
166
+ // sys.anslq25.portId = portId;
167
+
168
+ // } catch (err) {
169
+ // logger.error(`Error changing port id: ${err.message}`);
170
+ // }
171
+ // finally {
172
+ // this.suspendStatus(false);
173
+ // this._statusTimer = setTimeoutSync(async () => await self.processStatusAsync(), this.statusInterval);
174
+ // }
175
+ // }
176
+ public async closeAsync() {
177
+ try {
178
+ }
179
+ catch (err) { logger.error(err); }
180
+ }
181
+ }
182
+ export class MockBoardCommands {
183
+ protected mockBoard: MockSystemBoard = null;
184
+ constructor(parent: MockSystemBoard) { this.mockBoard = parent; }
185
+ }
186
+ export class MockSystemCommands extends MockBoardCommands {
187
+ public sendAck(msg:Inbound) { };
188
+ public async processDateTimeAsync(msg: Inbound){ };
189
+ public async processCustomNameAsync(msg: Inbound){ };
190
+ public async processSettingsAsync(msg: Inbound){ };
191
+ public async sendStatusAsync() { };
192
+ }
193
+
194
+ export class MockCircuitCommands extends MockBoardCommands {
195
+ public async processCircuitAsync( msg: Inbound) { };
196
+ public async processLightGroupAsync( msg: Inbound) { };
197
+ }
198
+ export class MockScheduleCommands extends MockBoardCommands {
199
+ public async processScheduleAsync( msg: Inbound) { };
200
+ }
201
+ export class MockHeaterCommands extends MockBoardCommands {
202
+ public async processHeatModesAsync(msg: Inbound) { };
203
+ public async processHeaterConfigAsync(msg: Inbound) { };
204
+ }
205
+ export class MockValveCommands extends MockBoardCommands {
206
+ public async processValveOptionsAsync(msg: Inbound) { };
207
+ public async processValveAssignmentsAsync(msg: Inbound) { };
208
+ }
209
+ export class MockRemoteCommands extends MockBoardCommands {
210
+ public async processIS4IS10RemoteAsync(msg: Inbound) { };
211
+ public async processQuickTouchRemoteAsync(msg: Inbound) { };
212
+ public async processSpaCommandRemoteAsync(msg: Inbound) { };
213
+ }
214
+ export class MockPumpCommands extends MockBoardCommands {
215
+ public async processPumpConfigAsync(msg: Inbound) { };
216
+ public async processHighSpeedCircuitsAsync(msg: Inbound) { };
217
+ }
@@ -0,0 +1,75 @@
1
+ import { logger } from "../../logger/Logger";
2
+ import { Inbound, Outbound } from "../../controller/comms/messages/Messages";
3
+ import { conn } from "../../controller/comms/Comms";
4
+
5
+ export class MockChlorinator {
6
+ constructor(){}
7
+
8
+ public process(inbound: Inbound){
9
+ let response: Outbound = Outbound.create({
10
+ portId: inbound.portId,
11
+ protocol: inbound.protocol,
12
+ dest: 0
13
+ });
14
+
15
+ switch (inbound.action){
16
+ case 0: // Set control OCP->Chlorinator: [16,2,80,0][0][98,16,3]
17
+ this.chlorSetControl(inbound, response);
18
+ case 17: // OCP->Chlorinator set output. [16,2,80,17][15][130,16,3]
19
+ this.chlorSetOutput(inbound, response);
20
+ case 19: // iChlor keep alive(?) [16, 2, 80, 19][117, 16, 3]
21
+ // need response
22
+ break;
23
+ case 20: // OCP->Chlorinator Get model [16,2,80,20][0][118,16,3]
24
+ this.chlorGetModel(inbound, response);
25
+ default:
26
+ logger.info(`No mock chlorinator response for ${inbound.toShortPacket()} `);
27
+ }
28
+ }
29
+
30
+ public async chlorSetControl(inbound: Inbound, response: Outbound){
31
+ /*
32
+ {"port":0,"id":42633,"valid":true,"dir":"out","proto":"chlorinator","pkt":[[],[], [16,2,80,0], [0],[98,16,3]],"ts":"2022-07-19T21:45:59.959-0700"}
33
+ {"port":0,"id":42634,"valid":true,"dir":"in","proto":"chlorinator","for":[42633],"pkt":[[],[],[16,2,0,1],[0,0],[19,16,3]],"ts": "2022-07-19T21:45:59.999-0700"} */
34
+ try {
35
+
36
+ response.action = 1;
37
+ response.appendPayloadBytes(0, 2);
38
+ await response.sendAsync()
39
+ }
40
+ catch (err){
41
+ logger.error(`Error sending mock chlor packet ${response.toPacket}`);
42
+ }
43
+ }
44
+ public chlorSetOutput(inbound: Inbound, response: Outbound){
45
+ /*
46
+ {"port":0,"id":42639,"valid":true,"dir":"out","proto":"chlorinator","pkt":[[],[], [16,2,80,17], [100],[215,16,3]],"ts":"2022-07-19T21:46:00.302-0700"}
47
+ {"port":0,"id":42640,"valid":true,"dir":"in","proto":"chlorinator","for":[42639],"pkt":[[],[],[16,2,0,18],[78,128],[242,16,3]],"ts": "2022-07-19T21:46:00.341-0700"} */
48
+ response.action = 18;
49
+ response.appendPayloadBytes(0, 2);
50
+ // ideal high = 4500 = 90 * 50; ideal low = 2800 = 56 * 50
51
+ response.setPayloadByte(0, this.random(90-56, true)+56, 75)
52
+ response.setPayloadByte(1, 128);
53
+ conn.queueSendMessage(response);
54
+ }
55
+ public chlorGetModel(inbound: Inbound, response: Outbound){
56
+ /*
57
+ {"port":0,"id":42645,"valid":true,"dir":"out","proto":"chlorinator","pkt":[[],[], [16,2,80,20], [0],[118,16,3]],"ts":"2022-07-19T21:46:00.645-0700"}
58
+ {"port":0,"id":42646,"valid":true,"dir":"in","proto":"chlorinator","for":[42645],"pkt":[[],[],[16,2,0,3],[0,73,110,116,101,108,108,105,99,104,108,111,114,45,45,54,48],[190,16,3]],"ts": "2022-07-19T21:46:00.700-0700"} */
59
+ response.action = 3;
60
+ response.appendPayloadBytes(0, 17);
61
+ response.insertPayloadString(1, 'INTELLICHLOR--60');
62
+ conn.queueSendMessage(response);
63
+ }
64
+
65
+ private random(bounds: number, onlyPositive: boolean = false){
66
+ let rand = Math.random() * bounds;
67
+ if (!onlyPositive) {
68
+ if (Math.random()<=.5) rand = rand * -1;
69
+ }
70
+ return rand;
71
+ }
72
+
73
+ }
74
+
75
+ export var mockChlor: MockChlorinator = new MockChlorinator();
@@ -0,0 +1,84 @@
1
+ import { sys } from "../../controller/Equipment";
2
+ import { PumpState, state } from "../../controller/State";
3
+ import { Outbound } from "../../controller/comms/messages/Messages";
4
+ import { conn } from "controller/comms/Comms";
5
+
6
+ export class MockPump {
7
+ constructor(){}
8
+
9
+ public process(outboundMsg: Outbound){
10
+ let response: Outbound = Outbound.create({
11
+ portId: outboundMsg.portId,
12
+ protocol: outboundMsg.protocol
13
+ });
14
+
15
+ switch (outboundMsg.action){
16
+ case 7:
17
+ this.pumpStatus(outboundMsg, response);
18
+ default:
19
+ this.pumpAck(outboundMsg, response);
20
+ }
21
+ }
22
+
23
+ public pumpStatus(outboundMsg: Outbound, response: Outbound){
24
+ let pState:PumpState = state.pumps.getItemById(outboundMsg.dest - 96);
25
+ let pt = sys.board.valueMaps.pumpTypes.get(pState.type);
26
+ response.action = 7;
27
+ response.source = outboundMsg.dest;
28
+ response.dest = outboundMsg.source;
29
+ response.appendPayloadBytes(0, 15);
30
+ response.setPayloadByte(0, pState.command, 2);
31
+ response.setPayloadByte(1, pState.mode, 0);
32
+ response.setPayloadByte(2, pState.driveState, 2);
33
+ let watts = 0;
34
+ if (Math.max(pState.rpm, pState.flow) > 0){
35
+ if (pState.rpm > 0) watts = pState.rpm/pt.maxSpeed * 2000 + this.random(100);
36
+ else if (pState.flow > 0) watts = pState.flow/pt.maxFlow * 2000 + this.random(100);
37
+ else //ss, ds, etc
38
+ watts = 2000 + this.random(250);
39
+ }
40
+ response.setPayloadByte(3, Math.floor(watts / 256), 0);
41
+ response.setPayloadByte(4, watts % 256, 0);
42
+ response.setPayloadByte(5, Math.floor(pState.rpm / 256), 0);
43
+ response.setPayloadByte(6, pState.rpm % 256, 0);
44
+ response.setPayloadByte(7, pState.flow, 0);
45
+ response.setPayloadByte(8, pState.ppc, 0);
46
+ // 9, 10 = unknown
47
+ // 11, 12 = Status code;
48
+ response.setPayloadByte(11, Math.floor(pState.status / 256), 0);
49
+ response.setPayloadByte(12, pState.status % 256, 1);
50
+ let time = new Date();
51
+ response.setPayloadByte(13, time.getHours() * 60);
52
+ response.setPayloadByte(14, time.getMinutes());
53
+
54
+ conn.queueSendMessage(response);
55
+ }
56
+
57
+ public pumpAck(outboundMsg: Outbound, response: Outbound){
58
+ response.action = outboundMsg.action;
59
+ response.source = outboundMsg.dest;
60
+ response.dest = outboundMsg.source;
61
+ switch (outboundMsg.action){
62
+ case 1:
63
+ case 10: {
64
+ response.appendPayloadByte(outboundMsg.payload[2]);
65
+ response.appendPayloadByte(outboundMsg.payload[3]);
66
+ break;
67
+ }
68
+ default:
69
+ response.appendPayloadByte(outboundMsg.payload[0]);
70
+ }
71
+ conn.queueSendMessage(response);
72
+ }
73
+
74
+ private random(bounds: number, onlyPositive: boolean = false){
75
+ let rand = Math.random() * bounds;
76
+ if (!onlyPositive) {
77
+ if (Math.random()<=.5) rand = rand * -1;
78
+ }
79
+ return rand;
80
+ }
81
+
82
+ }
83
+
84
+ export var mockPump: MockPump = new MockPump();
package/app.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /* nodejs-poolController. An application to control pool equipment.
2
- Copyright (C) 2016, 2017, 2018, 2019, 2020. Russell Goldin, tagyoureit. russ.goldin@gmail.com
2
+ Copyright (C) 2016, 2017, 2018, 2019, 2020, 2021, 2022.
3
+ Russell Goldin, tagyoureit. russ.goldin@gmail.com
3
4
 
4
5
  This program is free software: you can redistribute it and/or modify
5
6
  it under the terms of the GNU Affero General Public License as
@@ -15,36 +16,31 @@ You should have received a copy of the GNU Affero General Public License
15
16
  along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17
  */
17
18
  // add source map support for .js to .ts files
18
- require('source-map-support').install();
19
+ //require('source-map-support').install();
20
+ import 'source-map-support/register';
19
21
 
20
22
  import { logger } from "./logger/Logger";
21
23
  import { config } from "./config/Config";
22
24
  import { conn } from "./controller/comms/Comms";
23
- import { sys, ControllerType } from "./controller/Equipment";
25
+ import { sys } from "./controller/Equipment";
24
26
 
25
27
  import { state } from "./controller/State";
26
28
  import { webApp } from "./web/Server";
27
29
  import * as readline from 'readline';
30
+ import { sl } from './controller/comms/ScreenLogic'
28
31
 
29
32
  export async function initAsync() {
30
33
  try {
31
34
  await config.init();
32
35
  await logger.init();
33
- await conn.initAsync();
34
36
  await sys.init();
35
37
  await state.init();
36
38
  await webApp.init();
39
+ await conn.initAsync();
37
40
  await sys.start();
38
41
  await webApp.initAutoBackup();
42
+ await sl.openAsync();
39
43
  } catch (err) { console.log(`Error Initializing nodejs-PoolController ${err.message}`); }
40
- //return Promise.resolve()
41
- // .then(function () { config.init(); })
42
- // .then(function () { logger.init(); })
43
- // .then(function () { conn.init(); })
44
- // .then(function () { sys.init(); })
45
- // .then(function () { state.init(); })
46
- // .then(function () { webApp.init(); })
47
- // .then(function () { sys.start(); });
48
44
  }
49
45
 
50
46
  export async function startPacketCapture(bResetLogs: boolean) {
@@ -70,13 +66,13 @@ export async function stopPacketCaptureAsync() {
70
66
  export async function stopAsync(): Promise<void> {
71
67
  try {
72
68
  console.log('Shutting down open processes');
73
- // await sys.board.virtualPumpControllers.stopAsync();
74
69
  await webApp.stopAutoBackup();
75
70
  await sys.stopAsync();
76
71
  await state.stopAsync();
77
72
  await conn.stopAsync();
73
+ await sl.closeAsync();
78
74
  await webApp.stopAsync();
79
- config.update();
75
+ await config.updateAsync();
80
76
  await logger.stopAsync();
81
77
  // RKS: Uncomment below to see the shutdown process
82
78
  //await new Promise<void>((resolve, reject) => { setTimeout(() => { resolve(); }, 20000); });
package/config/Config.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /* nodejs-poolController. An application to control pool equipment.
2
- Copyright (C) 2016, 2017, 2018, 2019, 2020. Russell Goldin, tagyoureit. russ.goldin@gmail.com
2
+ Copyright (C) 2016, 2017, 2018, 2019, 2020, 2021, 2022.
3
+ Russell Goldin, tagyoureit. russ.goldin@gmail.com
3
4
 
4
5
  This program is free software: you can redistribute it and/or modify
5
6
  it under the terms of the GNU Affero General Public License as
@@ -20,6 +21,7 @@ import { EventEmitter } from 'events';
20
21
  const extend = require("extend");
21
22
  import { logger } from "../logger/Logger";
22
23
  import { utils } from "../controller/Constants";
24
+ import { setTimeout } from 'timers/promises';
23
25
  class Config {
24
26
  private cfgPath: string;
25
27
  private _cfg: any;
@@ -39,7 +41,7 @@ class Config {
39
41
  const packageJson = JSON.parse(fs.readFileSync(path.join(process.cwd(), "/package.json"), "utf8").trim());
40
42
  this._cfg = extend(true, {}, def, this._cfg, { appVersion: packageJson.version });
41
43
  this._isInitialized = true;
42
- this.update((err) => {
44
+ this.updateAsync((err) => {
43
45
  if (typeof err === 'undefined') {
44
46
  fs.watch(this.cfgPath, (event, fileName) => {
45
47
  if (fileName && event === 'change') {
@@ -55,7 +57,7 @@ class Config {
55
57
  }
56
58
  });
57
59
  }
58
- else throw err;
60
+ else return Promise.reject(err);
59
61
  });
60
62
  this._isLoading = false;
61
63
  this.getEnvVariables();
@@ -65,7 +67,7 @@ class Config {
65
67
  throw err;
66
68
  }
67
69
  }
68
- public update(callback?: (err?) => void) {
70
+ public async updateAsync(callback?: (err?) => void) {
69
71
  // Don't overwrite the configuration if we failed during the initialization.
70
72
  try {
71
73
  if (!this._isInitialized) {
@@ -78,7 +80,8 @@ class Config {
78
80
  JSON.stringify(this._cfg, undefined, 2)
79
81
  );
80
82
  if (typeof callback === 'function') callback();
81
- setTimeout(()=>{this._isLoading = false;}, 2000);
83
+ await setTimeout(2000);
84
+ this._isLoading = false;
82
85
  }
83
86
  catch (err) {
84
87
  logger.error("Error writing configuration file %s", err);
@@ -98,7 +101,7 @@ class Config {
98
101
  section = arr[arr.length - 1];
99
102
  }
100
103
  if(typeof c[section] !== 'undefined') delete c[section];
101
- this.update();
104
+ this.updateAsync();
102
105
  }
103
106
  public setSection(section: string, val) {
104
107
  let c = this._cfg;
@@ -112,7 +115,7 @@ class Config {
112
115
  section = arr[arr.length - 1];
113
116
  }
114
117
  c[section] = val;
115
- this.update();
118
+ this.updateAsync();
116
119
  }
117
120
  // RKS: 09-21-21 - We are counting on the return from this being immutable. A copy of the data
118
121
  // should always be returned here.
@@ -135,6 +138,7 @@ class Config {
135
138
  this.ensurePath(baseDir + '/logs/');
136
139
  this.ensurePath(baseDir + '/data/');
137
140
  this.ensurePath(baseDir + '/backups/');
141
+ this.ensurePath(baseDir + '/web/bindings/custom/')
138
142
  // this.ensurePath(baseDir + '/replay/');
139
143
  //setTimeout(() => { config.update(); }, 100);
140
144
  }
@@ -152,7 +156,7 @@ class Config {
152
156
  for (var i in interfaces) {
153
157
  if (interfaces[i].uuid === obj.uuid) {
154
158
  interfaces[i] = obj;
155
- this.update();
159
+ this.updateAsync();
156
160
  return {[i]: interfaces[i]};
157
161
  }
158
162
  }
@@ -185,7 +189,7 @@ class Config {
185
189
  this._cfg.controller.comms.netPort = env.POOL_NET_PORT;
186
190
  bUpdate = true;
187
191
  }
188
- if (bUpdate) this.update();
192
+ if (bUpdate) this.updateAsync();
189
193
  }
190
194
  }
191
195
  export const config: Config = new Config();
@@ -1,5 +1,6 @@
1
1
  /* nodejs-poolController. An application to control pool equipment.
2
- Copyright (C) 2016, 2017, 2018, 2019, 2020. Russell Goldin, tagyoureit. russ.goldin@gmail.com
2
+ Copyright (C) 2016, 2017, 2018, 2019, 2020, 2021, 2022.
3
+ Russell Goldin, tagyoureit. russ.goldin@gmail.com
3
4
 
4
5
  This program is free software: you can redistribute it and/or modify
5
6
  it under the terms of the GNU Affero General Public License as
@@ -124,7 +125,7 @@ class VersionCheck {
124
125
  if (this.redirects >= 20) return Promise.reject(`Too many redirects.`)
125
126
  return new Promise<string>((resolve, reject) => {
126
127
  try {
127
- https.request(url, options, async res => {
128
+ let req = https.request(url, options, async res => {
128
129
  if (res.statusCode > 300 && res.statusCode < 400 && res.headers.location) await this.getLatestRelease(res.headers.location);
129
130
  let data = '';
130
131
  res.on('data', d => { data += d; });
@@ -137,6 +138,9 @@ class VersionCheck {
137
138
  })
138
139
  })
139
140
  .end();
141
+ req.on('error', (err) => {
142
+ logger.error(`Error getting Github API latest release. ${err.message}`)
143
+ })
140
144
  }
141
145
  catch (err) {
142
146
  logger.error('Error contacting Github for latest published release: ' + err);