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
@@ -64,6 +64,7 @@ export class HeaterMessage {
64
64
  case ControllerType.IntelliTouch:
65
65
  case ControllerType.EasyTouch:
66
66
  HeaterMessage.processIntelliTouch(msg);
67
+ break;
67
68
  }
68
69
  }
69
70
  private static processIntelliTouch(msg: Inbound) {
@@ -71,8 +72,22 @@ export class HeaterMessage {
71
72
  // Gas heater setup in EquipmentStateMessage upon *Touch discovery
72
73
  switch (msg.action) {
73
74
  // 1 = gas heater, 2 = solar, 3 = heat pump
74
- case 34:
75
- case 162:
75
+ case 34: // Somebody requested the configuration
76
+ case 162: // Somebody set the configuration
77
+ // Release any heaters that are tied to Nixie that should not be.
78
+ for (let i = sys.heaters.length - 1; i >= 0; i--) {
79
+ let heater = sys.heaters.getItemByIndex(i);
80
+ if (heater.id <= 4 && heater.master === 1) {
81
+ // Return the heater control back to Touch
82
+ (async function () {
83
+ try {
84
+ await ncp.heaters.deleteHeaterAsync(heater.id);
85
+ logger.debug(`${heater.name} control returned to OCP.`);
86
+ }
87
+ catch (err) { logger.error(`Error with OCP reclaiming control over gas ${heater.name}: ${err}`) }
88
+ })();
89
+ }
90
+ }
76
91
  // byte 0
77
92
  // 21 = solar or heat pump disabled
78
93
  // 23 = solar or heat pump enabled
@@ -94,6 +109,121 @@ export class HeaterMessage {
94
109
  // on/off (16) = solar as a heat pump
95
110
  // bits 7,8 = stop temp delta
96
111
 
112
+
113
+
114
+ // Determine what type of heater should be in id number 1. If this is a hybrid heater
115
+ // we will be installing it in id 1 although it will perform dual purpose.
116
+ let hasHeater = (msg.extractPayloadByte(0) & 0x01) === 0x01 || true;
117
+ let hasSolar = (msg.extractPayloadByte(0) & 0x02) === 0x02;
118
+ let hasHeatpump = (msg.extractPayloadByte(1) & 0x20) === 0x20;
119
+ let hasHybrid = !hasHeatpump && (msg.extractPayloadByte(1) & 0x10) === 0x10;
120
+
121
+ // Ok so it appears that the heater ids are as follows.
122
+ // 1 = Gas Heater
123
+ // 2 = Solar
124
+ // 3 = UltraTemp (HEATPUMPCOM)
125
+ // 4 = UltraTemp ETi (Hybrid)
126
+ // If an UltraTemp ETi is installed, no other heaters can be installed so they should be removed. This is not
127
+ // an available option for IntelliTouch i10D so it does not apply to it.
128
+ if (!hasHeater) {
129
+ sys.heaters.removeItemById(1);
130
+ state.heaters.removeItemById(1);
131
+ sys.heaters.removeItemById(2);
132
+ state.heaters.removeItemById(2);
133
+ sys.heaters.removeItemById(3);
134
+ state.heaters.removeItemById(3);
135
+ sys.heaters.removeItemById(4);
136
+ state.heaters.removeItemById(4);
137
+ }
138
+ else {
139
+ if (hasHybrid) {
140
+ sys.heaters.removeItemById(1);
141
+ state.heaters.removeItemById(1);
142
+ sys.heaters.removeItemById(2);
143
+ state.heaters.removeItemById(2);
144
+ sys.heaters.removeItemById(3);
145
+ state.heaters.removeItemById(3);
146
+ let hybrid = sys.heaters.getItemById(4, true);
147
+ let shybrid = state.heaters.getItemById(4, true);
148
+ // [5, { name: 'hybrid', desc: 'Hybrid', hasAddress: true }],
149
+ shybrid.type = hybrid.type = 5;
150
+ hybrid.address = 112; // Touch only supports address 1.
151
+ hybrid.isActive = true;
152
+ hybrid.master = 0;
153
+ hybrid.body = sys.equipment.shared ? 32 : 0;
154
+ if (typeof hybrid.name === 'undefined') shybrid.name = hybrid.name = 'UltraTemp ETi';
155
+ // The following 2 values need to come from somewhere.
156
+ if (typeof hybrid.economyTime === 'undefined') hybrid.economyTime = 1;
157
+ if (typeof hybrid.maxBoostTemp === 'undefined') hybrid.maxBoostTemp = 5;
158
+ hasHeatpump = false; // You cannot have a heatpump and a hybrid heater.
159
+ }
160
+ else {
161
+ // Hybrid heaters and gas heaters cannot co-exist but it appears you cannot disable the gas
162
+ // heater on the touch panels.
163
+ sys.heaters.removeItemById(4);
164
+ state.heaters.removeItemById(4);
165
+ let heater = sys.heaters.getItemById(1, true);
166
+ let hstate = state.heaters.getItemById(1, true);
167
+ heater.body = sys.equipment.shared ? 32 : 0;
168
+ // [1, { name: 'gas', desc: 'Gas Heater', hasAddress: false }],
169
+ heater.type = hstate.type = 1;
170
+ heater.isActive = true;
171
+ heater.master = 0;
172
+ if (typeof heater.name === 'undefined') heater.name = hstate.name = 'Gas Heater';
173
+ if (typeof heater.cooldownDelay === 'undefined') heater.cooldownDelay = 5;
174
+ }
175
+ // Check to see if a heatpump is installed. This will replace the solar heater so they cannot coexist.
176
+ if (hasHeatpump) {
177
+ // Remove the solar heater. This will be replaced with the heatpump.
178
+ sys.heaters.removeItemById(2);
179
+ state.heaters.removeItemById(2);
180
+ let heatpump = sys.heaters.getItemById(3, true);
181
+ let sheatpump = state.heaters.getItemById(3, true);
182
+ // [3, { name: 'heatpump', desc: 'Heat Pump', hasAddress: true, hasPreference: true }],
183
+ heatpump.type = sheatpump.type = 3;
184
+ heatpump.body = sys.equipment.shared ? 32 : 0;
185
+ heatpump.isActive = true;
186
+ heatpump.master = 0;
187
+
188
+ if (typeof heatpump.name === 'undefined') sheatpump.name = heatpump.name = 'UltraTemp';
189
+ heatpump.heatingEnabled = (msg.extractPayloadByte(1) & 0x01) === 1;
190
+ heatpump.coolingEnabled = (msg.extractPayloadByte(1) & 0x02) === 2;
191
+ sys.board.equipmentIds.invalidIds.add(20); // exclude Aux Extra
192
+ }
193
+ else if (hasSolar) {
194
+ sys.heaters.removeItemById(3);
195
+ state.heaters.removeItemById(3);
196
+ let solar = sys.heaters.getItemById(2, true);
197
+ let ssolar = sys.heaters.getItemById(2, true);
198
+ // [2, { name: 'solar', desc: 'Solar Heater', hasAddress: false, hasPreference: true }],
199
+ solar.type = ssolar.type = 2;
200
+ solar.body = sys.equipment.shared ? 32 : 0;
201
+ solar.isActive = true;
202
+ solar.master = 0;
203
+ if (typeof solar.name === 'undefined') solar.name = ssolar.name = 'Solar Heater';
204
+ solar.freeze = (msg.extractPayloadByte(1) & 0x80) >> 7 === 1;
205
+ solar.coolingEnabled = (msg.extractPayloadByte(1) & 0x20) >> 5 === 1;
206
+ solar.startTempDelta = ((msg.extractPayloadByte(2) & 0xE) >> 1) + 3;
207
+ solar.stopTempDelta = ((msg.extractPayloadByte(2) & 0xC0) >> 6) + 2;
208
+ sys.board.equipmentIds.invalidIds.add(20); // exclude Aux Extra
209
+ }
210
+ else {
211
+ sys.board.equipmentIds.invalidIds.remove(20); // Allow access to Aux Extra
212
+ }
213
+ }
214
+ sys.board.heaters.updateHeaterServices();
215
+ for (let i = 0; i < sys.bodies.length; i++) {
216
+ let body = sys.bodies.getItemByIndex(i);
217
+ let btemp = state.temps.bodies.getItemById(body.id, body.isActive !== false);
218
+ let opts = sys.board.heaters.getInstalledHeaterTypes(body.id);
219
+ btemp.heaterOptions = opts;
220
+ }
221
+ sys.board.heaters.syncHeaterStates();
222
+ sys.equipment.setEquipmentIds();
223
+ msg.isProcessed = true;
224
+
225
+
226
+ /*
97
227
  // gas heater only; solar/heatpump/ultratemp disabled
98
228
  if ((msg.extractPayloadByte(0) & 0x2) === 0) {
99
229
  let heater = sys.heaters.getItemById(1);
@@ -112,14 +242,14 @@ export class HeaterMessage {
112
242
  sys.heaters.getItemById(3).isActive = false;
113
243
  sys.heaters.getItemById(4).isActive = false;
114
244
  sys.board.equipmentIds.invalidIds.remove(20); // include Aux Extra
115
- /* sys.equipment.setEquipmentIds();
116
- for (let i = 0; i < sys.bodies.length; i++) {
117
- let body = sys.bodies.getItemByIndex(i);
118
- let btemp = state.temps.bodies.getItemById(body.id, body.isActive !== false);
119
- let opts = sys.board.heaters.getInstalledHeaterTypes(body.id);
120
- btemp.heaterOptions = opts;
121
- }
122
- return; */
245
+ //sys.equipment.setEquipmentIds();
246
+ //for (let i = 0; i < sys.bodies.length; i++) {
247
+ // let body = sys.bodies.getItemByIndex(i);
248
+ // let btemp = state.temps.bodies.getItemById(body.id, body.isActive !== false);
249
+ // let opts = sys.board.heaters.getInstalledHeaterTypes(body.id);
250
+ // btemp.heaterOptions = opts;
251
+ //}
252
+ return;
123
253
  }
124
254
  // Ultratemp (+ cooling?);
125
255
  else if ((msg.extractPayloadByte(2) & 0x30) === 0x30) {
@@ -220,7 +350,9 @@ export class HeaterMessage {
220
350
  sys.board.heaters.syncHeaterStates();
221
351
  sys.equipment.setEquipmentIds();
222
352
  msg.isProcessed = true;
353
+ */
223
354
  break;
355
+
224
356
  }
225
357
  }
226
358
  private static processCooldownDelay(msg: Inbound) {
@@ -145,10 +145,13 @@ export class OptionsMessage {
145
145
  // [165,33,16,34,168,10],[0,0,0,254,0,0,0,0,0,0],[2,168 = manual heat mode off
146
146
  // [165,33,16,34,168,10],[0,0,0,254,1,0,0,0,0,0],[2,169] = manual heat mode on
147
147
  sys.general.options.manualHeat = msg.extractPayloadByte(4) === 1;
148
+ // From https://github.com/tagyoureit/nodejs-poolController/issues/362 = Intellitouch
149
+ // [0,0,0,0,1,x,0,0,0,0] x=0 Manual OP heat Off; x=1 Manual OP heat On
150
+ sys.general.options.manualPriority = msg.extractPayloadByte(5) === 1;
148
151
  if ((msg.extractPayloadByte(3) & 0x01) === 1) {
149
152
  // only support for 1 ic with EasyTouch
150
153
  let chem = sys.chemControllers.getItemByAddress(144, true);
151
- let schem = state.chemControllers.getItemById(chem.id, true);
154
+ //let schem = state.chemControllers.getItemById(chem.id, true);
152
155
  chem.ph.tank.capacity = chem.orp.tank.capacity = 6;
153
156
  chem.ph.tank.units = chem.orp.tank.units = '';
154
157
 
@@ -161,26 +164,6 @@ export class OptionsMessage {
161
164
  msg.isProcessed = true;
162
165
  break;
163
166
  }
164
- /* case 168:
165
- {
166
- // IntelliChem Installed
167
- if ((msg.extractPayloadByte(3) & 0x01) === 1) {
168
- // only support for 1 ic with EasyTouch
169
- let chem = sys.chemControllers.getItemByAddress(144, true);
170
- let schem = state.chemControllers.getItemById(chem.id, true);
171
- chem.ph.tank.capacity = chem.orp.tank.capacity = 6;
172
- chem.ph.tank.units = chem.orp.tank.units = '';
173
-
174
- }
175
- else {
176
- let chem = sys.chemControllers.getItemByAddress(144);
177
- state.chemControllers.removeItemById(chem.id);
178
- sys.chemControllers.removeItemById(chem.id);
179
- }
180
- // Spa Manual Heat on/off
181
- sys.general.options.manualHeat = msg.extractPayloadByte(4) === 1 ? true : false;
182
- msg.isProcessed = true;
183
- } */
184
167
  }
185
168
  }
186
169
  }
@@ -36,43 +36,60 @@ export class PumpMessage {
36
36
  // packet 24/27/152/155 - Pump Config: IntelliTouch
37
37
  const pumpId = msg.extractPayloadByte(0);
38
38
  let type = msg.extractPayloadByte(1); // Avoid setting this then setting it back if we are mapping to a different value.
39
+ let isActive = type !== 0 && pumpId <= sys.equipment.maxPumps;
39
40
  // RKS: 04-14-21 - Only create the pump if it is available. If the pump was previously defined as another type
40
41
  // then it will be removed and recreated.
41
- let pump: Pump = sys.pumps.getItemById(pumpId, pumpId <= sys.equipment.maxPumps && type !== 0);
42
- if (pump.type !== type && type !== 0) {
43
- sys.pumps.removeItemById(pumpId);
44
- pump = sys.pumps.getItemById(pumpId, true);
45
- }
46
- pump.address = pumpId + 95;
47
- switch (type) {
48
- case 0: // none
49
- pump.type = 0;
50
- pump.isActive = false;
51
- break;
52
- case 64: // vsf
53
- pump.type = type;
54
- pump.isActive = true;
55
- PumpMessage.processVSF_IT(msg);
56
- break;
57
- case 255: // vs 3050 on old panels.
58
- case 128: // vs
59
- case 134: // vs Ultra Efficiency
60
- pump.type = 128;
61
- pump.isActive = true;
62
- PumpMessage.processVS_IT(msg);
63
- break;
64
- case 169: // vs+svrs
65
- pump.type = 169;
66
- pump.isActive = true;
67
- PumpMessage.processVS_IT(msg);
68
- break;
69
- default: // vf - type is the background circuit
70
- pump.type = 1; // force to type 1?
71
- pump.isActive = true;
72
- PumpMessage.processVF_IT(msg);
73
- break;
74
- }
75
- if (pump.isActive) {
42
+ let pump: Pump = sys.pumps.getItemById(pumpId, isActive);
43
+ if(isActive) {
44
+ // Remap the combination pump types.
45
+ switch (type) {
46
+ case 0:
47
+ case 64:
48
+ case 169:
49
+ break;
50
+ case 255:
51
+ case 128:
52
+ case 134:
53
+ type = 128;
54
+ break;
55
+ default:
56
+ type = 1;
57
+ break;
58
+ }
59
+ if (pump.type !== type) {
60
+ sys.pumps.removeItemById(pumpId);
61
+ pump = sys.pumps.getItemById(pumpId, isActive);
62
+ }
63
+ pump.address = pumpId + 95;
64
+ pump.master = 0;
65
+ switch (type) {
66
+ case 0: // none
67
+ pump.type = 0;
68
+ pump.isActive = false;
69
+ break;
70
+ case 64: // vsf
71
+ pump.type = type;
72
+ pump.isActive = true;
73
+ PumpMessage.processVSF_IT(msg);
74
+ break;
75
+ case 255: // vs 3050 on old panels.
76
+ case 128: // vs
77
+ case 134: // vs Ultra Efficiency
78
+ pump.type = 128;
79
+ pump.isActive = true;
80
+ PumpMessage.processVS_IT(msg);
81
+ break;
82
+ case 169: // vs+svrs
83
+ pump.type = 169;
84
+ pump.isActive = true;
85
+ PumpMessage.processVS_IT(msg);
86
+ break;
87
+ default: // vf - type is the background circuit
88
+ pump.type = 1; // force to type 1?
89
+ pump.isActive = true;
90
+ PumpMessage.processVF_IT(msg);
91
+ break;
92
+ }
76
93
  if (typeof pump.name === 'undefined') pump.name = sys.board.valueMaps.pumpTypes.get(pump.type).desc;
77
94
  const spump = state.pumps.getItemById(pump.id, true);
78
95
  spump.name = pump.name;
@@ -224,6 +241,7 @@ export class PumpMessage {
224
241
  }
225
242
  if (typeof pump.model === 'undefined') pump.model = 0;
226
243
  pump.type = type;
244
+ pump.master = 0;
227
245
  let spump = state.pumps.getItemById(pump.id, true);
228
246
  spump.type = pump.type;
229
247
  spump.isActive = pump.isActive = true;
File without changes