nodejs-poolcontroller 7.3.1 → 7.6.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 (85) hide show
  1. package/.eslintrc.json +44 -44
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +52 -52
  3. package/CONTRIBUTING.md +74 -74
  4. package/Changelog +215 -195
  5. package/Dockerfile +17 -17
  6. package/Gruntfile.js +40 -40
  7. package/LICENSE +661 -661
  8. package/README.md +191 -186
  9. package/app.ts +2 -0
  10. package/config/Config.ts +27 -2
  11. package/config/VersionCheck.ts +33 -14
  12. package/config copy.json +299 -299
  13. package/controller/Constants.ts +88 -0
  14. package/controller/Equipment.ts +2459 -2225
  15. package/controller/Errors.ts +180 -157
  16. package/controller/Lockouts.ts +437 -0
  17. package/controller/State.ts +364 -79
  18. package/controller/boards/BoardFactory.ts +45 -45
  19. package/controller/boards/EasyTouchBoard.ts +2653 -2489
  20. package/controller/boards/IntelliCenterBoard.ts +4230 -3973
  21. package/controller/boards/IntelliComBoard.ts +63 -63
  22. package/controller/boards/IntelliTouchBoard.ts +241 -167
  23. package/controller/boards/NixieBoard.ts +1675 -1105
  24. package/controller/boards/SystemBoard.ts +4697 -3201
  25. package/controller/comms/Comms.ts +222 -10
  26. package/controller/comms/messages/Messages.ts +13 -9
  27. package/controller/comms/messages/config/ChlorinatorMessage.ts +13 -4
  28. package/controller/comms/messages/config/CircuitGroupMessage.ts +6 -0
  29. package/controller/comms/messages/config/CircuitMessage.ts +0 -0
  30. package/controller/comms/messages/config/ConfigMessage.ts +0 -0
  31. package/controller/comms/messages/config/CoverMessage.ts +1 -0
  32. package/controller/comms/messages/config/CustomNameMessage.ts +30 -30
  33. package/controller/comms/messages/config/EquipmentMessage.ts +4 -0
  34. package/controller/comms/messages/config/ExternalMessage.ts +53 -33
  35. package/controller/comms/messages/config/FeatureMessage.ts +8 -1
  36. package/controller/comms/messages/config/GeneralMessage.ts +8 -0
  37. package/controller/comms/messages/config/HeaterMessage.ts +14 -28
  38. package/controller/comms/messages/config/IntellichemMessage.ts +4 -1
  39. package/controller/comms/messages/config/OptionsMessage.ts +38 -2
  40. package/controller/comms/messages/config/PumpMessage.ts +4 -20
  41. package/controller/comms/messages/config/RemoteMessage.ts +4 -0
  42. package/controller/comms/messages/config/ScheduleMessage.ts +347 -331
  43. package/controller/comms/messages/config/SecurityMessage.ts +1 -0
  44. package/controller/comms/messages/config/ValveMessage.ts +13 -3
  45. package/controller/comms/messages/status/ChlorinatorStateMessage.ts +2 -3
  46. package/controller/comms/messages/status/EquipmentStateMessage.ts +79 -25
  47. package/controller/comms/messages/status/HeaterStateMessage.ts +86 -53
  48. package/controller/comms/messages/status/IntelliChemStateMessage.ts +445 -386
  49. package/controller/comms/messages/status/IntelliValveStateMessage.ts +35 -35
  50. package/controller/comms/messages/status/PumpStateMessage.ts +0 -0
  51. package/controller/comms/messages/status/VersionMessage.ts +0 -0
  52. package/controller/nixie/Nixie.ts +162 -160
  53. package/controller/nixie/NixieEquipment.ts +103 -103
  54. package/controller/nixie/bodies/Body.ts +120 -117
  55. package/controller/nixie/bodies/Filter.ts +135 -135
  56. package/controller/nixie/chemistry/ChemController.ts +2498 -2395
  57. package/controller/nixie/chemistry/Chlorinator.ts +314 -313
  58. package/controller/nixie/circuits/Circuit.ts +248 -210
  59. package/controller/nixie/heaters/Heater.ts +649 -441
  60. package/controller/nixie/pumps/Pump.ts +661 -599
  61. package/controller/nixie/schedules/Schedule.ts +257 -256
  62. package/controller/nixie/valves/Valve.ts +170 -170
  63. package/defaultConfig.json +286 -271
  64. package/issue_template.md +51 -51
  65. package/logger/DataLogger.ts +448 -433
  66. package/logger/Logger.ts +0 -0
  67. package/package.json +56 -54
  68. package/tsconfig.json +25 -25
  69. package/web/Server.ts +522 -31
  70. package/web/bindings/influxDB.json +1022 -894
  71. package/web/bindings/mqtt.json +654 -543
  72. package/web/bindings/mqttAlt.json +684 -574
  73. package/web/bindings/rulesManager.json +54 -54
  74. package/web/bindings/smartThings-Hubitat.json +31 -31
  75. package/web/bindings/valveRelays.json +20 -20
  76. package/web/bindings/vera.json +25 -25
  77. package/web/interfaces/baseInterface.ts +136 -136
  78. package/web/interfaces/httpInterface.ts +124 -122
  79. package/web/interfaces/influxInterface.ts +245 -240
  80. package/web/interfaces/mqttInterface.ts +475 -464
  81. package/web/services/config/Config.ts +181 -152
  82. package/web/services/config/ConfigSocket.ts +0 -0
  83. package/web/services/state/State.ts +118 -7
  84. package/web/services/state/StateSocket.ts +18 -1
  85. package/web/services/utilities/Utilities.ts +42 -42
@@ -15,6 +15,8 @@ You should have received a copy of the GNU Affero General Public License
15
15
  along with this program. If not, see <http://www.gnu.org/licenses/>.
16
16
  */
17
17
  import * as express from "express";
18
+ import * as extend from "extend";
19
+
18
20
  import { state, ICircuitState, LightGroupState, ICircuitGroupState, ChemicalDoseState } from "../../../controller/State";
19
21
  import { sys } from "../../../controller/Equipment";
20
22
  import { utils } from '../../../controller/Constants';
@@ -79,7 +81,21 @@ export class StateRoute {
79
81
  catch (err) { next(err); }
80
82
 
81
83
  });
82
- app.search('/state/chemController/:id/doseHistory/ph', async (req, res, next) => {
84
+ app.get('/state/chemController/:id/doseLog/ph', async (req, res, next) => {
85
+ try {
86
+ let schem = state.chemControllers.getItemById(parseInt(req.params.id));
87
+ let filter = req.body || {};
88
+ let dh = await DataLogger.readFromEndAsync(`chemDosage_${schem.ph.chemType}.log`, ChemicalDoseState, (lineNumber: number, entry: ChemicalDoseState, arr: ChemicalDoseState[]): boolean => {
89
+ if (entry.id !== schem.id) return false;
90
+ if (typeof filter.lines !== 'undefined' && filter.lines <= arr.length) return false;
91
+ if (typeof filter.date !== 'undefined' && entry.end < filter.date) return false;
92
+ return true;
93
+ });
94
+ return res.status(200).send(dh);
95
+ }
96
+ catch (err) { next(err); }
97
+ });
98
+ app.search('/state/chemController/:id/doseLog/ph', async (req, res, next) => {
83
99
  try {
84
100
  let schem = state.chemControllers.getItemById(parseInt(req.params.id));
85
101
  let filter = req.body || {};
@@ -93,6 +109,34 @@ export class StateRoute {
93
109
  }
94
110
  catch (err) { next(err); }
95
111
  });
112
+ app.get('/state/chemController/:id/doseLog/orp', async (req, res, next) => {
113
+ try {
114
+ let schem = state.chemControllers.getItemById(parseInt(req.params.id));
115
+ let filter = req.body || {};
116
+ let dh = await DataLogger.readFromEndAsync(`chemDosage_orp.log`, ChemicalDoseState, (lineNumber: number, entry: ChemicalDoseState, arr: ChemicalDoseState[]): boolean => {
117
+ if (entry.id !== schem.id) return false;
118
+ if (typeof filter.lines !== 'undefined' && filter.lines <= arr.length) return false;
119
+ if (typeof filter.date !== 'undefined' && entry.end < filter.date) return false;
120
+ return true;
121
+ });
122
+ return res.status(200).send(dh);
123
+ }
124
+ catch (err) { next(err); }
125
+ });
126
+ app.search('/state/chemController/:id/doseLog/orp', async (req, res, next) => {
127
+ try {
128
+ let schem = state.chemControllers.getItemById(parseInt(req.params.id));
129
+ let filter = req.body || {};
130
+ let dh = DataLogger.readFromEnd(`chemDosage_orp.log`, ChemicalDoseState, (lineNumber: number, entry: ChemicalDoseState, arr: ChemicalDoseState[]): boolean => {
131
+ if (entry.id !== schem.id) return;
132
+ if (typeof filter.lines !== 'undefined' && filter.lines <= arr.length) return false;
133
+ if (typeof filter.date !== 'undefined' && entry.end < filter.date) return false;
134
+ return true;
135
+ });
136
+ return res.status(200).send(dh);
137
+ }
138
+ catch (err) { next(err); }
139
+ });
96
140
  app.put('/state/chemController/cancelDosing', async (req, res, next) => {
97
141
  try {
98
142
  let schem = await sys.board.chemControllers.cancelDosingAsync(req.body);
@@ -109,7 +153,7 @@ export class StateRoute {
109
153
  });
110
154
 
111
155
  app.get('/state/chlorinator/:id', (req, res) => {
112
- res.status(200).send(state.chlorinators.getItemById(parseInt(req.params.id, 10)).get());
156
+ res.status(200).send(state.chlorinators.getItemById(parseInt(req.params.id, 10), false).getExtended());
113
157
  });
114
158
  app.get('/state/circuit/:id', (req, res) => {
115
159
  res.status(200).send(state.circuits.getItemById(parseInt(req.params.id, 10)).get());
@@ -170,7 +214,44 @@ export class StateRoute {
170
214
  return res.status(200).send(theme.get(true));
171
215
  }
172
216
  catch (err) { next(err); }
173
- });
217
+ });
218
+ app.put('/state/light/setTheme', async (req, res, next) => {
219
+ try {
220
+ let theme = await state.circuits.setLightThemeAsync(parseInt(req.body.id, 10), sys.board.valueMaps.lightThemes.encode(req.body.theme));
221
+ return res.status(200).send(theme.get(true));
222
+ }
223
+ catch (err) { next(err); }
224
+ });
225
+
226
+ app.put('/state/light/runCommand', async (req, res, next) => {
227
+ try {
228
+ let slight = await sys.board.circuits.runLightCommandAsync(req.body);
229
+ return res.status(200).send(slight.get(true));
230
+ }
231
+ catch (err) { next(err); }
232
+ });
233
+ app.put('/state/light/:id/colorHold', async (req, res, next) => {
234
+ try {
235
+ let slight = await sys.board.circuits.runLightCommandAsync({ id: parseInt(req.params.id, 10), command: 'colorhold' });
236
+ return res.status(200).send(slight.get(true));
237
+ }
238
+ catch (err) { next(err); }
239
+ });
240
+ app.put('/state/light/:id/colorRecall', async (req, res, next) => {
241
+ try {
242
+ let slight = await sys.board.circuits.runLightCommandAsync({ id: parseInt(req.params.id, 10), command: 'colorecall' });
243
+ return res.status(200).send(slight.get(true));
244
+ }
245
+ catch (err) { next(err); }
246
+ });
247
+ app.put('/state/light/:id/lightThumper', async (req, res, next) => {
248
+ try {
249
+ let slight = await sys.board.circuits.runLightCommandAsync({ id: parseInt(req.params.id, 10), command: 'lightthumper' });
250
+ return res.status(200).send(slight.get(true));
251
+ }
252
+ catch (err) { next(err); }
253
+ });
254
+
174
255
  /* app.put('/state/intellibrite/setTheme', (req, res) => {
175
256
  let id = sys.board.equipmentIds.circuitGroups.start;
176
257
  if (typeof req.body.theme !== 'undefined') id = parseInt(req.body.id, 10);
@@ -229,7 +310,7 @@ export class StateRoute {
229
310
  if (typeof req.body.heatSetpoint !== 'undefined' && !isNaN(parseInt(req.body.heatSetpoint, 10)))
230
311
  await sys.board.bodies.setHeatSetpointAsync(body, parseInt(req.body.heatSetpoint, 10));
231
312
  else if (typeof req.body.setPoint !== 'undefined' && !isNaN(parseInt(req.body.setPoint, 10)))
232
- await sys.board.bodies.setHeatSetpointAsync(body, parseInt(req.body.heatSetpoint, 10));
313
+ await sys.board.bodies.setHeatSetpointAsync(body, parseInt(req.body.setpoint, 10));
233
314
  let tbody = state.temps.bodies.getItemById(body.id);
234
315
  return res.status(200).send(tbody.get(true));
235
316
  } catch (err) { next(err); }
@@ -286,27 +367,57 @@ export class StateRoute {
286
367
  }
287
368
  catch (err) { next(err); }
288
369
  });
370
+ app.put('/state/lightGroup/runCommand', async (req, res, next) => {
371
+ try {
372
+ let sgroup = await sys.board.circuits.runLightGroupCommandAsync(req.body);
373
+ return res.status(200).send(sgroup.get(true));
374
+ }
375
+ catch (err) { next(err); }
376
+ });
289
377
  app.put('/state/lightGroup/:id/colorSync', async (req, res, next) => {
290
378
  try {
291
- let sgroup = await sys.board.circuits.sequenceLightGroupAsync(parseInt(req.params.id, 10), 'sync');
379
+ let sgroup = await sys.board.circuits.sequenceLightGroupAsync(parseInt(req.params.id, 10), 'colorsync');
292
380
  return res.status(200).send(sgroup.get(true));
293
381
  }
294
382
  catch (err) { next(err); }
295
383
  });
296
384
  app.put('/state/lightGroup/:id/colorSet', async (req, res, next) => {
297
385
  try {
298
- let sgroup = await sys.board.circuits.sequenceLightGroupAsync(parseInt(req.params.id, 10), 'set');
386
+ let sgroup = await sys.board.circuits.sequenceLightGroupAsync(parseInt(req.params.id, 10), 'colorset');
299
387
  return res.status(200).send(sgroup.get(true));
300
388
  }
301
389
  catch (err) { next(err); }
302
390
  });
303
391
  app.put('/state/lightGroup/:id/colorSwim', async (req, res, next) => {
304
392
  try {
305
- let sgroup = await sys.board.circuits.sequenceLightGroupAsync(parseInt(req.params.id, 10), 'swim');
393
+ let sgroup = await sys.board.circuits.sequenceLightGroupAsync(parseInt(req.params.id, 10), 'colorswim');
394
+ return res.status(200).send(sgroup.get(true));
395
+ }
396
+ catch (err) { next(err); }
397
+ });
398
+ app.put('/state/lightGroup/:id/colorHold', async (req, res, next) => {
399
+ try {
400
+ let sgroup = await sys.board.circuits.runLightGroupCommandAsync({ id: parseInt(req.params.id, 10), command: 'colorhold' });
401
+ return res.status(200).send(sgroup.get(true));
402
+ }
403
+ catch (err) { next(err); }
404
+ });
405
+ app.put('/state/lightGroup/:id/colorRecall', async (req, res, next) => {
406
+ try {
407
+ let sgroup = await sys.board.circuits.runLightGroupCommandAsync({ id: parseInt(req.params.id, 10), command: 'colorrecall' });
408
+ return res.status(200).send(sgroup.get(true));
409
+ }
410
+ catch (err) { next(err); }
411
+ });
412
+ app.put('/state/lightGroup/:id/lightThumper', async (req, res, next) => {
413
+ try {
414
+ let sgroup = await sys.board.circuits.runLightGroupCommandAsync({ id: parseInt(req.params.id, 10), command: 'lightthumper' });
306
415
  return res.status(200).send(sgroup.get(true));
307
416
  }
308
417
  catch (err) { next(err); }
309
418
  });
419
+
420
+
310
421
  app.get('/state/emitAll', (req, res) => {
311
422
  res.status(200).send(state.emitAllEquipmentChanges());
312
423
  });
@@ -74,6 +74,7 @@ export class StateSocket {
74
74
  }
75
75
  catch (err) { logger.error(err); }
76
76
  });
77
+
77
78
  sock.on('/chlorinator', async (data: any) => {
78
79
  try {
79
80
  data = JSON.parse(data);
@@ -99,6 +100,22 @@ export class StateSocket {
99
100
  }
100
101
  catch (err) { logger.error(err); }
101
102
  });
103
+ sock.on('/filter', async (data: any) => {
104
+ try {
105
+ data = JSON.parse(data);
106
+ let id = parseInt(data.id, 10);
107
+ let filter = sys.filters.find(elem => elem.id === id);
108
+ if (typeof filter !== 'undefined' && filter.isActive && !isNaN(filter.id)) {
109
+ let sfilter = state.filters.getItemById(filter.id, filter.isActive)
110
+ let pu = sys.board.valueMaps.pressureUnits.transform(filter.pressureUnits);
111
+ if (typeof data.pressure !== 'undefined')
112
+ await sys.board.filters.setFilterPressure(filter.id, data.pressure, data.pressureUnits || pu.name);
113
+ sfilter.emitEquipmentChange();
114
+ }
115
+
116
+
117
+ } catch (err) { logger.error(err); }
118
+ });
102
119
  sock.on('/chemController', async (data: any) => {
103
120
  try {
104
121
  //console.log(`chemController: ${data}`);
@@ -144,7 +161,7 @@ export class StateSocket {
144
161
  if (typeof data.orpTank.units === 'string') scontroller.orp.tank.units = controller.orp.tank.units = data.orpTank.units;
145
162
  }
146
163
 
147
- // Need to build this out to include the type of controller. If this is Homegrown or REM Chem we
164
+ // Need to build this out to include the type of controller. If this is REM Chem we
148
165
  // will send the whole rest of the nut over to it. Intellichem will only let us
149
166
  // set specific values.
150
167
  if (controller.type === 3) {
@@ -1,43 +1,43 @@
1
- /* nodejs-poolController. An application to control pool equipment.
2
- Copyright (C) 2016, 2017, 2018, 2019, 2020. Russell Goldin, tagyoureit. russ.goldin@gmail.com
3
-
4
- This program is free software: you can redistribute it and/or modify
5
- it under the terms of the GNU Affero General Public License as
6
- published by the Free Software Foundation, either version 3 of the
7
- License, or (at your option) any later version.
8
-
9
- This program is distributed in the hope that it will be useful,
10
- but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- GNU Affero General Public License for more details.
13
-
14
- You should have received a copy of the GNU Affero General Public License
15
- along with this program. If not, see <http://www.gnu.org/licenses/>.
16
- */
17
- import * as express from 'express';
18
- import { SsdpServer} from '../../Server';
19
- import { state } from "../../../controller/State";
20
- import { sys } from "../../../controller/Equipment";
21
-
22
- const extend = require("extend");
23
- export class UtilitiesRoute {
24
-
25
- public static initRoutes(app: express.Application) {
26
- app.get('/device', function(req, res) {
27
- // there's got to be a better way to get this than instantiating SsdpServer() again.
28
- // RKS: There was I made the function static.
29
- let xml = SsdpServer.deviceXML();
30
- res.status(200).set('Content-Type', 'text/xml').send(xml);
31
- });
32
- app.get('/extended/:section', (req, res) => {
33
- let cfg = sys.getSection(req.params.section);
34
- let st = state.getState(req.params.section);
35
- let arr = [];
36
- for (let i = 0; i < cfg.length; i++){
37
- let p = extend(true, {}, cfg[i], st.find(s => s.id === cfg[i].id));
38
- arr.push(p);
39
- }
40
- return res.status(200).send(arr);
41
- });
42
- }
1
+ /* nodejs-poolController. An application to control pool equipment.
2
+ Copyright (C) 2016, 2017, 2018, 2019, 2020. Russell Goldin, tagyoureit. russ.goldin@gmail.com
3
+
4
+ This program is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU Affero General Public License as
6
+ published by the Free Software Foundation, either version 3 of the
7
+ License, or (at your option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU Affero General Public License for more details.
13
+
14
+ You should have received a copy of the GNU Affero General Public License
15
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ */
17
+ import * as express from 'express';
18
+ import { SsdpServer} from '../../Server';
19
+ import { state } from "../../../controller/State";
20
+ import { sys } from "../../../controller/Equipment";
21
+
22
+ const extend = require("extend");
23
+ export class UtilitiesRoute {
24
+
25
+ public static initRoutes(app: express.Application) {
26
+ app.get('/device', function(req, res) {
27
+ // there's got to be a better way to get this than instantiating SsdpServer() again.
28
+ // RKS: There was I made the function static.
29
+ let xml = SsdpServer.deviceXML();
30
+ res.status(200).set('Content-Type', 'text/xml').send(xml);
31
+ });
32
+ app.get('/extended/:section', (req, res) => {
33
+ let cfg = sys.getSection(req.params.section);
34
+ let st = state.getState(req.params.section);
35
+ let arr = [];
36
+ for (let i = 0; i < cfg.length; i++){
37
+ let p = extend(true, {}, cfg[i], st.find(s => s.id === cfg[i].id));
38
+ arr.push(p);
39
+ }
40
+ return res.status(200).send(arr);
41
+ });
42
+ }
43
43
  }