nodejs-poolcontroller 7.6.1 → 8.0.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.
- package/.eslintrc.json +36 -45
- package/.github/ISSUE_TEMPLATE/1-bug-report.yml +84 -0
- package/.github/ISSUE_TEMPLATE/2-docs.md +12 -0
- package/.github/ISSUE_TEMPLATE/3-proposal.md +28 -0
- package/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/CONTRIBUTING.md +74 -74
- package/Changelog +242 -215
- package/Dockerfile +17 -17
- package/Gruntfile.js +40 -40
- package/LICENSE +661 -661
- package/README.md +195 -191
- package/anslq25/MessagesMock.ts +218 -0
- package/anslq25/boards/MockBoardFactory.ts +50 -0
- package/anslq25/boards/MockEasyTouchBoard.ts +696 -0
- package/anslq25/boards/MockSystemBoard.ts +217 -0
- package/anslq25/chemistry/MockChlorinator.ts +75 -0
- package/anslq25/pumps/MockPump.ts +84 -0
- package/app.ts +10 -14
- package/config/Config.ts +26 -8
- package/config/VersionCheck.ts +8 -4
- package/controller/Constants.ts +59 -25
- package/controller/Equipment.ts +2667 -2459
- package/controller/Errors.ts +181 -180
- package/controller/Lockouts.ts +534 -436
- package/controller/State.ts +596 -77
- package/controller/boards/AquaLinkBoard.ts +1003 -0
- package/controller/boards/BoardFactory.ts +53 -45
- package/controller/boards/EasyTouchBoard.ts +3079 -2653
- package/controller/boards/IntelliCenterBoard.ts +3821 -4230
- package/controller/boards/IntelliComBoard.ts +69 -63
- package/controller/boards/IntelliTouchBoard.ts +384 -241
- package/controller/boards/NixieBoard.ts +1871 -1675
- package/controller/boards/SunTouchBoard.ts +393 -0
- package/controller/boards/SystemBoard.ts +5244 -4697
- package/controller/comms/Comms.ts +905 -541
- package/controller/comms/ScreenLogic.ts +1663 -0
- package/controller/comms/messages/Messages.ts +382 -54
- package/controller/comms/messages/config/ChlorinatorMessage.ts +8 -4
- package/controller/comms/messages/config/CircuitGroupMessage.ts +5 -2
- package/controller/comms/messages/config/CircuitMessage.ts +82 -13
- package/controller/comms/messages/config/ConfigMessage.ts +3 -1
- package/controller/comms/messages/config/CoverMessage.ts +2 -1
- package/controller/comms/messages/config/CustomNameMessage.ts +31 -30
- package/controller/comms/messages/config/EquipmentMessage.ts +5 -1
- package/controller/comms/messages/config/ExternalMessage.ts +33 -3
- package/controller/comms/messages/config/FeatureMessage.ts +2 -1
- package/controller/comms/messages/config/GeneralMessage.ts +2 -1
- package/controller/comms/messages/config/HeaterMessage.ts +145 -11
- package/controller/comms/messages/config/IntellichemMessage.ts +2 -1
- package/controller/comms/messages/config/OptionsMessage.ts +16 -27
- package/controller/comms/messages/config/PumpMessage.ts +62 -47
- package/controller/comms/messages/config/RemoteMessage.ts +80 -13
- package/controller/comms/messages/config/ScheduleMessage.ts +390 -347
- package/controller/comms/messages/config/SecurityMessage.ts +2 -1
- package/controller/comms/messages/config/ValveMessage.ts +44 -27
- package/controller/comms/messages/status/ChlorinatorStateMessage.ts +44 -91
- package/controller/comms/messages/status/EquipmentStateMessage.ts +139 -30
- package/controller/comms/messages/status/HeaterStateMessage.ts +135 -86
- package/controller/comms/messages/status/IntelliChemStateMessage.ts +448 -445
- package/controller/comms/messages/status/IntelliValveStateMessage.ts +36 -35
- package/controller/comms/messages/status/PumpStateMessage.ts +92 -2
- package/controller/comms/messages/status/VersionMessage.ts +2 -1
- package/controller/nixie/Nixie.ts +173 -162
- package/controller/nixie/NixieEquipment.ts +104 -103
- package/controller/nixie/bodies/Body.ts +120 -120
- package/controller/nixie/bodies/Filter.ts +135 -135
- package/controller/nixie/chemistry/ChemController.ts +2682 -2498
- package/controller/nixie/chemistry/ChemDoser.ts +806 -0
- package/controller/nixie/chemistry/Chlorinator.ts +367 -314
- package/controller/nixie/circuits/Circuit.ts +402 -248
- package/controller/nixie/heaters/Heater.ts +815 -649
- package/controller/nixie/pumps/Pump.ts +934 -661
- package/controller/nixie/schedules/Schedule.ts +319 -257
- package/controller/nixie/valves/Valve.ts +170 -170
- package/defaultConfig.json +346 -286
- package/logger/DataLogger.ts +448 -448
- package/logger/Logger.ts +38 -9
- package/package.json +60 -56
- package/tsconfig.json +25 -25
- package/web/Server.ts +275 -117
- package/web/bindings/aqualinkD.json +560 -0
- package/web/bindings/homeassistant.json +437 -0
- package/web/bindings/influxDB.json +1066 -1021
- package/web/bindings/mqtt.json +721 -654
- package/web/bindings/mqttAlt.json +746 -684
- package/web/bindings/rulesManager.json +54 -54
- package/web/bindings/smartThings-Hubitat.json +31 -31
- package/web/bindings/valveRelays.json +20 -20
- package/web/bindings/vera.json +25 -25
- package/web/interfaces/baseInterface.ts +188 -136
- package/web/interfaces/httpInterface.ts +148 -124
- package/web/interfaces/influxInterface.ts +283 -245
- package/web/interfaces/mqttInterface.ts +695 -475
- package/web/interfaces/ruleInterface.ts +87 -0
- package/web/services/config/Config.ts +177 -49
- package/web/services/config/ConfigSocket.ts +2 -1
- package/web/services/state/State.ts +154 -3
- package/web/services/state/StateSocket.ts +69 -18
- package/web/services/utilities/Utilities.ts +232 -42
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -52
- package/config copy.json +0 -300
- package/issue_template.md +0 -52
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* nodejs-poolController. An application to control pool equipment.
|
|
2
|
-
Copyright (C) 2016, 2017, 2018, 2019, 2020
|
|
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
|
|
@@ -22,14 +23,64 @@ import { sys } from "../../../controller/Equipment";
|
|
|
22
23
|
import { utils } from '../../../controller/Constants';
|
|
23
24
|
import { logger } from "../../../logger/Logger";
|
|
24
25
|
import { DataLogger } from "../../../logger/DataLogger";
|
|
26
|
+
import { conn } from "../../../controller/comms/Comms";
|
|
27
|
+
import { config } from "../../../config/Config";
|
|
25
28
|
|
|
26
29
|
import { ServiceParameterError } from "../../../controller/Errors";
|
|
27
30
|
|
|
28
31
|
export class StateRoute {
|
|
29
32
|
public static initRoutes(app: express.Application) {
|
|
33
|
+
app.get('/state/rs485Port/:id', async (req, res, next) => {
|
|
34
|
+
try {
|
|
35
|
+
let portId = parseInt(req.params.id, 10);
|
|
36
|
+
if (isNaN(portId)) throw new ServiceParameterError(`RS485 port id not supplied`, '/state/rs485Port/:id', 'portId', req.params.id);
|
|
37
|
+
let cfg = config.getSection(portId === 0 ? 'controller.comms' : `controller.comms${portId}`);
|
|
38
|
+
if (typeof cfg === 'undefined') throw new ServiceParameterError(`RS485 port id not found`, '/state/rs485Port/:id', 'portId', req.params.id);
|
|
39
|
+
let port = conn.findPortById(portId);
|
|
40
|
+
let sport: any = {
|
|
41
|
+
portId: portId,
|
|
42
|
+
enabled: cfg.enabled || false,
|
|
43
|
+
netConnect: cfg.netConnect,
|
|
44
|
+
reconnects: 0,
|
|
45
|
+
inactivityRetry: cfg.inactivityRetry,
|
|
46
|
+
isOpen: false,
|
|
47
|
+
mock: cfg.mock || false
|
|
48
|
+
}
|
|
49
|
+
if (cfg.netConnect) sport.netConnect = { host: cfg.netHost, port: cfg.netPort }
|
|
50
|
+
else if (typeof cfg.type !== 'undefined' && cfg.type === 'screenlogic'){
|
|
51
|
+
sport.screenlogic = cfg.screenlogic;
|
|
52
|
+
}
|
|
53
|
+
else sport.settings = extend(true, { name: cfg.rs485Port }, cfg.portSettings);
|
|
54
|
+
if (typeof port !== 'undefined' && port.type !== 'screenlogic') {
|
|
55
|
+
let stats = port.stats;
|
|
56
|
+
sport.reconnects = port.reconnects;
|
|
57
|
+
sport.isOpen = port.isOpen;
|
|
58
|
+
sport.received = {
|
|
59
|
+
bytes: stats.bytesReceived,
|
|
60
|
+
success: stats.recSuccess,
|
|
61
|
+
failed: stats.recFailed,
|
|
62
|
+
collisions: stats.recCollisions,
|
|
63
|
+
rewinds: stats.recFRewinds,
|
|
64
|
+
failureRate: stats.recFailureRate
|
|
65
|
+
};
|
|
66
|
+
sport.sent = {
|
|
67
|
+
bytes: stats.bytesSent,
|
|
68
|
+
success: stats.sndSuccess,
|
|
69
|
+
aborted: stats.sndAborted,
|
|
70
|
+
retries: stats.sndRetries,
|
|
71
|
+
failureRate: stats.sndFailureRate
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
res.status(200).send(sport);
|
|
75
|
+
}
|
|
76
|
+
catch (err) { next(err); }
|
|
77
|
+
});
|
|
30
78
|
app.get('/state/chemController/:id', (req, res) => {
|
|
31
79
|
res.status(200).send(state.chemControllers.getItemById(parseInt(req.params.id, 10)).getExtended());
|
|
32
80
|
});
|
|
81
|
+
app.get('/state/chemDoser/:id', (req, res) => {
|
|
82
|
+
res.status(200).send(state.chemDosers.getItemById(parseInt(req.params.id, 10)).getExtended());
|
|
83
|
+
});
|
|
33
84
|
app.put('/state/chemController', async (req, res, next) => {
|
|
34
85
|
try {
|
|
35
86
|
let schem = await sys.board.chemControllers.setChemControllerStateAsync(req.body);
|
|
@@ -37,6 +88,13 @@ export class StateRoute {
|
|
|
37
88
|
}
|
|
38
89
|
catch (err) { next(err); }
|
|
39
90
|
});
|
|
91
|
+
app.put('/state/chemDoser', async (req, res, next) => {
|
|
92
|
+
try {
|
|
93
|
+
let schem = await sys.board.chemDosers.setChemDoserStateAsync(req.body);
|
|
94
|
+
return res.status(200).send(schem.getExtended());
|
|
95
|
+
}
|
|
96
|
+
catch (err) { next(err); }
|
|
97
|
+
});
|
|
40
98
|
app.put('/state/chemController/manualDose', async (req, res, next) => {
|
|
41
99
|
try {
|
|
42
100
|
let schem = await sys.board.chemControllers.manualDoseAsync(req.body);
|
|
@@ -44,6 +102,14 @@ export class StateRoute {
|
|
|
44
102
|
}
|
|
45
103
|
catch (err) { next(err); }
|
|
46
104
|
});
|
|
105
|
+
app.put('/state/chemDoser/manualDose', async (req, res, next) => {
|
|
106
|
+
try {
|
|
107
|
+
let schem = await sys.board.chemDosers.manualDoseAsync(req.body);
|
|
108
|
+
return res.status(200).send(schem.getExtended());
|
|
109
|
+
}
|
|
110
|
+
catch (err) { next(err); }
|
|
111
|
+
});
|
|
112
|
+
|
|
47
113
|
app.put('/state/chemController/manualMix', async (req, res, next) => {
|
|
48
114
|
try {
|
|
49
115
|
logger.debug(`Starting manual mix`);
|
|
@@ -53,6 +119,13 @@ export class StateRoute {
|
|
|
53
119
|
}
|
|
54
120
|
catch (err) { next(err); }
|
|
55
121
|
});
|
|
122
|
+
app.put('/state/chemDoser/manualMix', async (req, res, next) => {
|
|
123
|
+
try {
|
|
124
|
+
let schem = await sys.board.chemDosers.manualMixAsync(req.body);
|
|
125
|
+
return res.status(200).send(schem.getExtended());
|
|
126
|
+
}
|
|
127
|
+
catch (err) { next(err); }
|
|
128
|
+
});
|
|
56
129
|
app.get('/state/chemController/:id/doseHistory', (req, res) => {
|
|
57
130
|
let schem = state.chemControllers.getItemById(parseInt(req.params.id));
|
|
58
131
|
let hist = { ph: [], orp: [] };
|
|
@@ -62,6 +135,11 @@ export class StateRoute {
|
|
|
62
135
|
hist.orp.push(schem.orp.doseHistory[i]);
|
|
63
136
|
return res.status(200).send(hist);
|
|
64
137
|
});
|
|
138
|
+
app.get('/state/chemDoser/:id/doseHistory', (req, res) => {
|
|
139
|
+
let schem = state.chemDosers.getItemById(parseInt(req.params.id));
|
|
140
|
+
return res.status(200).send(schem.doseHistory);
|
|
141
|
+
});
|
|
142
|
+
|
|
65
143
|
app.put('/state/chemController/:id/doseHistory/orp/clear', async (req, res, next) => {
|
|
66
144
|
try {
|
|
67
145
|
let schem = state.chemControllers.getItemById(parseInt(req.params.id));
|
|
@@ -71,6 +149,16 @@ export class StateRoute {
|
|
|
71
149
|
}
|
|
72
150
|
catch (err) { next(err); }
|
|
73
151
|
});
|
|
152
|
+
app.put('/state/chemDoser/:id/doseHistory/clear', async (req, res, next) => {
|
|
153
|
+
try {
|
|
154
|
+
let schem = state.chemDosers.getItemById(parseInt(req.params.id));
|
|
155
|
+
schem.doseHistory = [];
|
|
156
|
+
schem.calcDoseHistory();
|
|
157
|
+
return res.status(200).send(schem.doseHistory);
|
|
158
|
+
}
|
|
159
|
+
catch (err) { next(err); }
|
|
160
|
+
});
|
|
161
|
+
|
|
74
162
|
app.put('/state/chemController/:id/doseHistory/ph/clear', async (req, res, next) => {
|
|
75
163
|
try {
|
|
76
164
|
let schem = state.chemControllers.getItemById(parseInt(req.params.id));
|
|
@@ -95,6 +183,21 @@ export class StateRoute {
|
|
|
95
183
|
}
|
|
96
184
|
catch (err) { next(err); }
|
|
97
185
|
});
|
|
186
|
+
app.get('/state/chemDoser/:id/doseLog', async (req, res, next) => {
|
|
187
|
+
try {
|
|
188
|
+
let schem = state.chemDosers.getItemById(parseInt(req.params.id));
|
|
189
|
+
let filter = req.body || {};
|
|
190
|
+
let dh = await DataLogger.readFromEndAsync(`chemDosage_Peristalic.log`, ChemicalDoseState, (lineNumber: number, entry: ChemicalDoseState, arr: ChemicalDoseState[]): boolean => {
|
|
191
|
+
if (entry.id !== schem.id) return false;
|
|
192
|
+
if (typeof filter.lines !== 'undefined' && filter.lines <= arr.length) return false;
|
|
193
|
+
if (typeof filter.date !== 'undefined' && entry.end < filter.date) return false;
|
|
194
|
+
return true;
|
|
195
|
+
});
|
|
196
|
+
return res.status(200).send(dh);
|
|
197
|
+
}
|
|
198
|
+
catch (err) { next(err); }
|
|
199
|
+
});
|
|
200
|
+
|
|
98
201
|
app.search('/state/chemController/:id/doseLog/ph', async (req, res, next) => {
|
|
99
202
|
try {
|
|
100
203
|
let schem = state.chemControllers.getItemById(parseInt(req.params.id));
|
|
@@ -144,6 +247,13 @@ export class StateRoute {
|
|
|
144
247
|
}
|
|
145
248
|
catch (err) { next(err); }
|
|
146
249
|
});
|
|
250
|
+
app.put('/state/chemDoser/cancelDosing', async (req, res, next) => {
|
|
251
|
+
try {
|
|
252
|
+
let schem = await sys.board.chemDosers.cancelDosingAsync(req.body);
|
|
253
|
+
return res.status(200).send(schem.getExtended());
|
|
254
|
+
}
|
|
255
|
+
catch (err) { next(err); }
|
|
256
|
+
});
|
|
147
257
|
app.put('/state/chemController/cancelMixing', async (req, res, next) => {
|
|
148
258
|
try {
|
|
149
259
|
let schem = await sys.board.chemControllers.cancelMixingAsync(req.body);
|
|
@@ -151,6 +261,13 @@ export class StateRoute {
|
|
|
151
261
|
}
|
|
152
262
|
catch (err) { next(err); }
|
|
153
263
|
});
|
|
264
|
+
app.put('/state/chemDoser/cancelMixing', async (req, res, next) => {
|
|
265
|
+
try {
|
|
266
|
+
let schem = await sys.board.chemDosers.cancelMixingAsync(req.body);
|
|
267
|
+
return res.status(200).send(schem.getExtended());
|
|
268
|
+
}
|
|
269
|
+
catch (err) { next(err); }
|
|
270
|
+
});
|
|
154
271
|
|
|
155
272
|
app.get('/state/chlorinator/:id', (req, res) => {
|
|
156
273
|
res.status(200).send(state.chlorinators.getItemById(parseInt(req.params.id, 10), false).getExtended());
|
|
@@ -161,6 +278,9 @@ export class StateRoute {
|
|
|
161
278
|
app.get('/state/feature/:id', (req, res) => {
|
|
162
279
|
res.status(200).send(state.features.getItemById(parseInt(req.params.id, 10)).get());
|
|
163
280
|
});
|
|
281
|
+
app.get('/state/schedule/:id', (req, res) => {
|
|
282
|
+
res.status(200).send(state.schedules.getItemById(parseInt(req.params.id, 10)).get());
|
|
283
|
+
});
|
|
164
284
|
app.get('/state/circuitGroup/:id', (req, res) => {
|
|
165
285
|
res.status(200).send(state.circuitGroups.getItemById(parseInt(req.params.id, 10)).get());
|
|
166
286
|
});
|
|
@@ -230,6 +350,13 @@ export class StateRoute {
|
|
|
230
350
|
}
|
|
231
351
|
catch (err) { next(err); }
|
|
232
352
|
});
|
|
353
|
+
app.put('/state/light/:id/colorSync', async (req, res, next) => {
|
|
354
|
+
try {
|
|
355
|
+
let slight = await sys.board.circuits.runLightCommandAsync({ id: parseInt(req.params.id, 10), command: 'colorsync' });
|
|
356
|
+
return res.status(200).send(slight.get(true));
|
|
357
|
+
}
|
|
358
|
+
catch (err) { next(err); }
|
|
359
|
+
});
|
|
233
360
|
app.put('/state/light/:id/colorHold', async (req, res, next) => {
|
|
234
361
|
try {
|
|
235
362
|
let slight = await sys.board.circuits.runLightCommandAsync({ id: parseInt(req.params.id, 10), command: 'colorhold' });
|
|
@@ -303,6 +430,7 @@ export class StateRoute {
|
|
|
303
430
|
// RKS: 06-24-20 -- Changed this so that users can send in the body id, circuit id, or the name.
|
|
304
431
|
// RKS: 05-14-21 -- Added cooling setpoints for the body.
|
|
305
432
|
try {
|
|
433
|
+
|
|
306
434
|
let body = sys.bodies.findByObject(req.body);
|
|
307
435
|
if (typeof body === 'undefined') return next(new ServiceParameterError(`Cannot set body setPoint. You must supply a valid id, circuit, name, or type for the body`, 'body', 'id', req.body.id));
|
|
308
436
|
if (typeof req.body.coolSetpoint !== 'undefined' && !isNaN(parseInt(req.body.coolSetpoint, 10)))
|
|
@@ -367,6 +495,13 @@ export class StateRoute {
|
|
|
367
495
|
}
|
|
368
496
|
catch (err) { next(err); }
|
|
369
497
|
});
|
|
498
|
+
app.put('/state/manualOperationPriority', async (req, res, next) => {
|
|
499
|
+
try {
|
|
500
|
+
let cstate = await sys.board.system.setManualOperationPriority(parseInt(req.body.id, 10));
|
|
501
|
+
return res.status(200).send(cstate.get(true));
|
|
502
|
+
}
|
|
503
|
+
catch (err) { next(err); }
|
|
504
|
+
});
|
|
370
505
|
app.put('/state/lightGroup/runCommand', async (req, res, next) => {
|
|
371
506
|
try {
|
|
372
507
|
let sgroup = await sys.board.circuits.runLightGroupCommandAsync(req.body);
|
|
@@ -416,8 +551,24 @@ export class StateRoute {
|
|
|
416
551
|
}
|
|
417
552
|
catch (err) { next(err); }
|
|
418
553
|
});
|
|
419
|
-
|
|
420
|
-
|
|
554
|
+
app.put('/state/panelMode', async (req, res, next) => {
|
|
555
|
+
try {
|
|
556
|
+
await sys.board.system.setPanelModeAsync(req.body);
|
|
557
|
+
return res.status(200).send(state.controllerState);
|
|
558
|
+
} catch (err) { next(err); }
|
|
559
|
+
});
|
|
560
|
+
app.put('/state/toggleServiceMode', async (req, res, next) => {
|
|
561
|
+
try {
|
|
562
|
+
let data = extend({}, req.body);
|
|
563
|
+
if (state.mode === 0) {
|
|
564
|
+
if (typeof data.timeout !== 'undefined' && !isNaN(data.timeout)) data.mode = 'timeout';
|
|
565
|
+
else data.mode = 'service';
|
|
566
|
+
await sys.board.system.setPanelModeAsync(req.body);
|
|
567
|
+
}
|
|
568
|
+
else sys.board.system.setPanelModeAsync({ mode: 'auto' });
|
|
569
|
+
return res.status(200).send(state.controllerState);
|
|
570
|
+
} catch (err) { next(err); }
|
|
571
|
+
});
|
|
421
572
|
app.get('/state/emitAll', (req, res) => {
|
|
422
573
|
res.status(200).send(state.emitAllEquipmentChanges());
|
|
423
574
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* nodejs-poolController. An application to control pool equipment.
|
|
2
|
-
Copyright (C) 2016, 2017, 2018, 2019, 2020
|
|
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
|
|
@@ -28,7 +29,7 @@ export class StateSocket {
|
|
|
28
29
|
await state.circuits.toggleCircuitStateAsync(parseInt(data.id, 10));
|
|
29
30
|
// return res.status(200).send(cstate);
|
|
30
31
|
}
|
|
31
|
-
catch (err) {logger.error(err);}
|
|
32
|
+
catch (err) {logger.error(`Socket processing error /state/circuit/toggleState: ${err.message}`);}
|
|
32
33
|
});
|
|
33
34
|
sock.on('/state/body/heatMode', async (data: any) => {
|
|
34
35
|
// RKS: 06-24-20 -- Changed this so that users can send in the body id, circuit id, or the name.
|
|
@@ -52,7 +53,8 @@ export class StateSocket {
|
|
|
52
53
|
}
|
|
53
54
|
await sys.board.bodies.setHeatModeAsync(body, mode);
|
|
54
55
|
// return res.status(200).send(tbody);
|
|
55
|
-
}
|
|
56
|
+
}
|
|
57
|
+
catch (err) { logger.error(`Socket processing error /state/body/heatmode: ${err.message}`); }
|
|
56
58
|
});
|
|
57
59
|
sock.on('/state/body/setPoint', async (data: any) => {
|
|
58
60
|
// RKS: 06-24-20 -- Changed this so that users can send in the body id, circuit id, or the name.
|
|
@@ -65,14 +67,14 @@ export class StateSocket {
|
|
|
65
67
|
}
|
|
66
68
|
await sys.board.bodies.setHeatSetpointAsync(body, parseInt(data.setPoint, 10));
|
|
67
69
|
// return res.status(200).send(tbody);
|
|
68
|
-
} catch (err) { logger.error(err); }
|
|
70
|
+
} catch (err) { logger.error(`Socket processing error /state/body/setPoint: ${err.message}`); }
|
|
69
71
|
});
|
|
70
72
|
sock.on('/temps', async (data: any) => {
|
|
71
73
|
try {
|
|
72
74
|
data = JSON.parse(data);
|
|
73
75
|
await sys.board.system.setTempsAsync(data).catch(err => logger.error(err));
|
|
74
76
|
}
|
|
75
|
-
catch (err) { logger.error(err); }
|
|
77
|
+
catch (err) { logger.error(`Socket processing error /temps: ${err.message}`); }
|
|
76
78
|
});
|
|
77
79
|
|
|
78
80
|
sock.on('/chlorinator', async (data: any) => {
|
|
@@ -98,7 +100,7 @@ export class StateSocket {
|
|
|
98
100
|
schlor.emitEquipmentChange();
|
|
99
101
|
}
|
|
100
102
|
}
|
|
101
|
-
catch (err) { logger.error(err); }
|
|
103
|
+
catch (err) { logger.error(`Socket processing error /chlorinator: ${err.message}`); }
|
|
102
104
|
});
|
|
103
105
|
sock.on('/filter', async (data: any) => {
|
|
104
106
|
try {
|
|
@@ -112,9 +114,7 @@ export class StateSocket {
|
|
|
112
114
|
await sys.board.filters.setFilterPressure(filter.id, data.pressure, data.pressureUnits || pu.name);
|
|
113
115
|
sfilter.emitEquipmentChange();
|
|
114
116
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
} catch (err) { logger.error(err); }
|
|
117
|
+
} catch (err) { logger.error(`Socket processing error /filter: ${err.message}`); }
|
|
118
118
|
});
|
|
119
119
|
sock.on('/chemController', async (data: any) => {
|
|
120
120
|
try {
|
|
@@ -160,7 +160,25 @@ export class StateSocket {
|
|
|
160
160
|
if (!isNaN(parseFloat(data.orpTank.capacity))) scontroller.orp.tank.capacity = controller.orp.tank.capacity = parseFloat(data.orpTank.capacity);
|
|
161
161
|
if (typeof data.orpTank.units === 'string') scontroller.orp.tank.units = controller.orp.tank.units = data.orpTank.units;
|
|
162
162
|
}
|
|
163
|
+
if (typeof data.acidPump !== 'undefined' || typeof data.orpPump !== 'undefined') {
|
|
164
|
+
let chem = typeof data.acidPump !== 'undefined' ? controller.ph : controller.orp;
|
|
165
|
+
let schem = typeof data.acidPump !== 'undefined' ? scontroller.ph : scontroller.orp;
|
|
166
|
+
let vals = typeof data.acidPump !== 'undefined' ? data.acidPump : data.orpPump;
|
|
167
|
+
let pump = chem.pump;
|
|
168
|
+
switch (sys.board.valueMaps.chemPumpTypes.getName(pump.type)) {
|
|
169
|
+
case 'ezo-pmp':
|
|
170
|
+
if (typeof vals.dispense !== 'undefined') {
|
|
171
|
+
pump.ratedFlow = typeof vals.dispense.ratedFlow === 'number' ? vals.dispense.ratedFlow : pump.ratedFlow;
|
|
172
|
+
}
|
|
173
|
+
if (typeof vals.tank !== 'undefined') {
|
|
174
|
+
if (!isNaN(parseFloat(vals.tank.level))) schem.tank.level = parseFloat(vals.tank.level);
|
|
175
|
+
if (!isNaN(parseFloat(vals.tank.capacity))) schem.tank.capacity = chem.tank.capacity = parseFloat(vals.tank.capacity);
|
|
176
|
+
if (typeof vals.tank.units === 'string') schem.tank.units = chem.tank.units = vals.tank.units;
|
|
177
|
+
}
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
163
180
|
|
|
181
|
+
}
|
|
164
182
|
// Need to build this out to include the type of controller. If this is REM Chem we
|
|
165
183
|
// will send the whole rest of the nut over to it. Intellichem will only let us
|
|
166
184
|
// set specific values.
|
|
@@ -169,12 +187,12 @@ export class StateSocket {
|
|
|
169
187
|
}
|
|
170
188
|
}
|
|
171
189
|
}
|
|
172
|
-
catch (err) { logger.error(err); }
|
|
190
|
+
catch (err) { logger.error(`Socket processing error /chemController: ${err.message}`); }
|
|
173
191
|
});
|
|
174
192
|
sock.on('/circuit', async (data: any) => {
|
|
175
193
|
try {
|
|
176
194
|
data = JSON.parse(data);
|
|
177
|
-
let id =
|
|
195
|
+
let id = parseInt(data.id, 10);
|
|
178
196
|
if (!isNaN(id) && (typeof data.isOn !== 'undefined' || typeof data.state !== 'undefined')) {
|
|
179
197
|
await sys.board.circuits.setCircuitStateAsync(id, utils.makeBool(data.isOn || typeof data.state));
|
|
180
198
|
}
|
|
@@ -184,35 +202,68 @@ export class StateSocket {
|
|
|
184
202
|
sock.on('/feature', async (data: any) => {
|
|
185
203
|
try {
|
|
186
204
|
data = JSON.parse(data);
|
|
187
|
-
let id =
|
|
205
|
+
let id = parseInt(data.id, 10);
|
|
188
206
|
if (!isNaN(id) && (typeof data.isOn !== 'undefined' || typeof data.state !== 'undefined')) {
|
|
189
207
|
await sys.board.features.setFeatureStateAsync(id, utils.makeBool(data.isOn || typeof data.state));
|
|
190
208
|
}
|
|
191
209
|
}
|
|
192
|
-
catch (err) { logger.error(err); }
|
|
210
|
+
catch (err) { logger.error(`Socket processing error /feature: ${err.message}`); }
|
|
193
211
|
});
|
|
194
212
|
sock.on('/circuitGroup', async (data: any) => {
|
|
195
213
|
try {
|
|
196
214
|
data = JSON.parse(data);
|
|
197
|
-
let id =
|
|
215
|
+
let id = parseInt(data.id, 10);
|
|
198
216
|
if (!isNaN(id) && (typeof data.isOn !== 'undefined' || typeof data.state !== 'undefined')) {
|
|
199
217
|
await sys.board.circuits.setCircuitGroupStateAsync(id, utils.makeBool(data.isOn || typeof data.state));
|
|
200
218
|
}
|
|
201
219
|
}
|
|
202
|
-
catch (err) { logger.error(err); }
|
|
220
|
+
catch (err) { logger.error(`Socket processing error /circuitGroup: ${err.message}`); }
|
|
203
221
|
});
|
|
204
222
|
sock.on('/lightGroup', async (data: any) => {
|
|
205
223
|
try {
|
|
206
224
|
data = JSON.parse(data);
|
|
207
|
-
let id =
|
|
225
|
+
let id = parseInt(data.id, 10);
|
|
208
226
|
if (!isNaN(id) && (typeof data.isOn !== 'undefined' || typeof data.state !== 'undefined')) {
|
|
209
227
|
await sys.board.circuits.setLightGroupStateAsync(id, utils.makeBool(data.isOn || typeof data.state));
|
|
210
228
|
}
|
|
211
229
|
if (!isNaN(id) && typeof data.theme !== 'undefined') await sys.board.circuits.setLightGroupThemeAsync(id, data.theme);
|
|
212
230
|
}
|
|
213
|
-
catch (err) { logger.error(err); }
|
|
231
|
+
catch (err) { logger.error(`Socket processing error /lightGroup: ${err.message}`); }
|
|
232
|
+
});
|
|
233
|
+
sock.on('/panelMode', async (data: any) => {
|
|
234
|
+
try {
|
|
235
|
+
data = JSON.parse(data);
|
|
236
|
+
let obj = {};
|
|
237
|
+
if (typeof data.isOn !== 'undefined' && !utils.makeBool(data.isOn)) return; // This is just in case it is sent by REM for a toggle button.
|
|
238
|
+
if (typeof data.timeout !== 'undefined' && !isNaN(data.timeout) && data.timeout) {
|
|
239
|
+
switch (data.timeUnits.toLowerCase()) {
|
|
240
|
+
case 'min':
|
|
241
|
+
case 'mins':
|
|
242
|
+
case 'm':
|
|
243
|
+
case 'minute':
|
|
244
|
+
case 'minutes':
|
|
245
|
+
data.timeout = data.timeout * 60;
|
|
246
|
+
break;
|
|
247
|
+
case 'hr':
|
|
248
|
+
case 'hrs':
|
|
249
|
+
case 'h':
|
|
250
|
+
case 'hour':
|
|
251
|
+
data.timeout = data.timeout * 3600;
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (typeof data.mode === 'undefined' || data.mode === 'toggle') {
|
|
256
|
+
if (state.mode === 0) {
|
|
257
|
+
if (typeof data.timeout !== 'undefined' && !isNaN(data.timeout) && data.timeout)
|
|
258
|
+
data.mode = 'timeout';
|
|
259
|
+
else data.mode = 'service';
|
|
260
|
+
await sys.board.system.setPanelModeAsync(data);
|
|
261
|
+
}
|
|
262
|
+
else sys.board.system.setPanelModeAsync({ mode: 'auto' });
|
|
263
|
+
}
|
|
264
|
+
else await sys.board.system.setPanelModeAsync(data);
|
|
265
|
+
} catch (err) { logger.error(`Socket processing error /panelMode: ${err.message}`); }
|
|
214
266
|
});
|
|
215
|
-
|
|
216
267
|
/*
|
|
217
268
|
app.get('/state/chemController/:id', (req, res) => {
|
|
218
269
|
res.status(200).send(state.chemControllers.getItemById(parseInt(req.params.id, 10)).getExtended());
|