nodejs-poolcontroller 7.4.0 → 7.5.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 (55) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  2. package/Changelog +3 -0
  3. package/README.md +2 -2
  4. package/app.ts +2 -0
  5. package/config/Config.ts +3 -0
  6. package/config/VersionCheck.ts +8 -4
  7. package/controller/Equipment.ts +89 -29
  8. package/controller/Errors.ts +14 -1
  9. package/controller/State.ts +75 -31
  10. package/controller/boards/EasyTouchBoard.ts +81 -36
  11. package/controller/boards/IntelliCenterBoard.ts +96 -32
  12. package/controller/boards/IntelliTouchBoard.ts +103 -29
  13. package/controller/boards/NixieBoard.ts +79 -27
  14. package/controller/boards/SystemBoard.ts +1552 -822
  15. package/controller/comms/Comms.ts +84 -9
  16. package/controller/comms/messages/Messages.ts +10 -4
  17. package/controller/comms/messages/config/ChlorinatorMessage.ts +13 -4
  18. package/controller/comms/messages/config/CircuitGroupMessage.ts +6 -0
  19. package/controller/comms/messages/config/CoverMessage.ts +1 -0
  20. package/controller/comms/messages/config/EquipmentMessage.ts +4 -0
  21. package/controller/comms/messages/config/ExternalMessage.ts +43 -25
  22. package/controller/comms/messages/config/FeatureMessage.ts +8 -1
  23. package/controller/comms/messages/config/GeneralMessage.ts +8 -0
  24. package/controller/comms/messages/config/HeaterMessage.ts +10 -9
  25. package/controller/comms/messages/config/IntellichemMessage.ts +4 -1
  26. package/controller/comms/messages/config/OptionsMessage.ts +13 -1
  27. package/controller/comms/messages/config/PumpMessage.ts +4 -20
  28. package/controller/comms/messages/config/RemoteMessage.ts +4 -0
  29. package/controller/comms/messages/config/ScheduleMessage.ts +11 -0
  30. package/controller/comms/messages/config/SecurityMessage.ts +1 -0
  31. package/controller/comms/messages/config/ValveMessage.ts +12 -2
  32. package/controller/comms/messages/status/ChlorinatorStateMessage.ts +2 -3
  33. package/controller/comms/messages/status/EquipmentStateMessage.ts +74 -22
  34. package/controller/comms/messages/status/HeaterStateMessage.ts +15 -6
  35. package/controller/comms/messages/status/IntelliChemStateMessage.ts +37 -26
  36. package/controller/nixie/Nixie.ts +18 -16
  37. package/controller/nixie/chemistry/ChemController.ts +57 -37
  38. package/controller/nixie/chemistry/Chlorinator.ts +7 -8
  39. package/controller/nixie/circuits/Circuit.ts +17 -0
  40. package/controller/nixie/pumps/Pump.ts +49 -24
  41. package/controller/nixie/schedules/Schedule.ts +1 -1
  42. package/defaultConfig.json +15 -0
  43. package/issue_template.md +1 -1
  44. package/logger/DataLogger.ts +37 -22
  45. package/package.json +3 -1
  46. package/web/Server.ts +515 -27
  47. package/web/bindings/influxDB.json +35 -0
  48. package/web/bindings/mqtt.json +62 -3
  49. package/web/bindings/mqttAlt.json +57 -4
  50. package/web/interfaces/httpInterface.ts +2 -0
  51. package/web/interfaces/influxInterface.ts +3 -2
  52. package/web/interfaces/mqttInterface.ts +12 -1
  53. package/web/services/config/Config.ts +162 -37
  54. package/web/services/state/State.ts +47 -3
  55. package/web/services/state/StateSocket.ts +1 -1
@@ -219,13 +219,7 @@ export class HeaterMessage {
219
219
  }
220
220
  sys.board.heaters.syncHeaterStates();
221
221
  sys.equipment.setEquipmentIds();
222
- break;
223
- case 114:
224
- // something to do with heat pumps... need equipment or other packets to decipher
225
- // [ 255, 0, 255], [165, 0, 112, 16, 114, 10], [144, 2, 0, 0, 0, 0, 0, 0, 0, 0], [2, 51 ]heat + cool
226
- // [165,0,112,16,114,10][144,0,0,0,0,0,0,0,0,0][2,49] == no Heater, no cool
227
- // [165,0,112,16,114,10][144,2,0,0,0,0,0,0,0,0][2,51] == no heat, cooling
228
- // this might be heatStatus not heatMode?
222
+ msg.isProcessed = true;
229
223
  break;
230
224
  case 168:
231
225
  {
@@ -245,7 +239,7 @@ export class HeaterMessage {
245
239
  }
246
240
  // Spa Manual Heat on/off
247
241
  sys.general.options.manualHeat = msg.extractPayloadByte(4) === 1 ? true : false;
248
-
242
+ msg.isProcessed = true;
249
243
  }
250
244
  }
251
245
  }
@@ -265,6 +259,7 @@ export class HeaterMessage {
265
259
  })();
266
260
  }
267
261
  }
262
+ msg.isProcessed = true;
268
263
  }
269
264
 
270
265
  //private static processBody(msg: Inbound) {
@@ -305,12 +300,14 @@ export class HeaterMessage {
305
300
 
306
301
  }
307
302
  sys.board.heaters.updateHeaterServices();
303
+ msg.isProcessed = true;
308
304
  }
309
305
  private static processMaxBoostTemp(msg: Inbound) {
310
306
  for (let i = 0; i < msg.payload.length - 1 && i < sys.equipment.maxHeaters; i++) {
311
307
  var heater: Heater = sys.heaters.getItemById(i + 1);
312
308
  heater.maxBoostTemp = msg.extractPayloadByte(i + 2);
313
309
  }
310
+ msg.isProcessed = true;
314
311
  }
315
312
  private static processStartStopDelta(msg: Inbound) {
316
313
  for (let i = 1; i < msg.payload.length - 1 && i <= sys.equipment.maxHeaters; i++) {
@@ -318,6 +315,7 @@ export class HeaterMessage {
318
315
  heater.startTempDelta = msg.extractPayloadByte(i + 1);
319
316
  heater.stopTempDelta = msg.extractPayloadByte(i + 18);
320
317
  }
318
+ msg.isProcessed = true;
321
319
  }
322
320
  private static processCoolingSetTemp(msg: Inbound) {
323
321
  for (let i = 1; i < msg.payload.length - 1 && i <= sys.equipment.maxHeaters; i++) {
@@ -325,20 +323,22 @@ export class HeaterMessage {
325
323
  heater.coolingEnabled = msg.extractPayloadByte(i + 1) > 0;
326
324
  heater.differentialTemp = msg.extractPayloadByte(i + 18);
327
325
  }
326
+ msg.isProcessed = true;
328
327
  }
329
328
  private static processAddress(msg: Inbound) {
330
329
  for (let i = 1; i < msg.payload.length - 1 && i <= sys.equipment.maxHeaters; i++) {
331
330
  var heater: Heater = sys.heaters.getItemById(i);
332
331
  heater.address = msg.extractPayloadByte(i + 1);
333
332
  }
333
+ msg.isProcessed = true;
334
334
  }
335
335
  private static processEfficiencyMode(msg: Inbound) {
336
336
  for (let i = 1; i < msg.payload.length - 1 && i <= sys.equipment.maxHeaters; i++) {
337
337
  var heater: Heater = sys.heaters.getItemById(i);
338
338
  heater.efficiencyMode = msg.extractPayloadByte(i + 1);
339
339
  }
340
+ msg.isProcessed = true;
340
341
  }
341
-
342
342
  private static processHeaterNames(msg: Inbound) {
343
343
  var heaterId = ((msg.extractPayloadByte(1) - 5) * 2) + 1;
344
344
  if (heaterId <= sys.equipment.maxHeaters) {
@@ -349,5 +349,6 @@ export class HeaterMessage {
349
349
  let hstate = state.heaters.getItemById(heaterId);
350
350
  hstate.name = sys.heaters.getItemById(heaterId++).name = msg.extractPayloadString(18, 16);
351
351
  }
352
+ msg.isProcessed = true;
352
353
  }
353
354
  }
@@ -138,7 +138,8 @@ export class IntellichemMessage {
138
138
  let controller = sys.chemControllers.getItemById(id, isActive, { id: i + 1, type: 1 });
139
139
  let scontroller = state.chemControllers.getItemById(controller.id, isActive);
140
140
  scontroller.isActive = controller.isActive = true;
141
- controller.isVirtual = false;
141
+ // controller.isVirtual = false;
142
+ controller.master = 0;
142
143
  if (!controller.isActive) {
143
144
  sys.chemControllers.removeItemById(controller.id);
144
145
  state.chemControllers.removeItemById(controller.id);
@@ -163,6 +164,7 @@ export class IntellichemMessage {
163
164
  }
164
165
  }
165
166
  }
167
+ msg.isProcessed = true;
166
168
  break;
167
169
  case 1:
168
170
  for (let i = 0; i < 4; i++) {
@@ -175,6 +177,7 @@ export class IntellichemMessage {
175
177
  controller.alkalinity = msg.extractPayloadInt((i * 2) + 26);
176
178
  }
177
179
  }
180
+ msg.isProcessed = true;
178
181
  break;
179
182
  }
180
183
  }
@@ -92,9 +92,21 @@ export class OptionsMessage {
92
92
  //body = sys.bodies.getItemById(4, sys.equipment.maxBodies > 3);
93
93
  //body.heatMode = msg.extractPayloadByte(27);
94
94
  //body.heatSetpoint = msg.extractPayloadByte(23);
95
+ msg.isProcessed = true;
95
96
  break;
96
97
  }
97
- case 1: // Unknown
98
+ case 1: // Vacation mode
99
+ let yy = msg.extractPayloadByte(4) + 2000;
100
+ let mm = msg.extractPayloadByte(5);
101
+ let dd = msg.extractPayloadByte(6);
102
+ sys.general.options.vacation.startDate = new Date(yy, mm - 1, dd);
103
+ yy = msg.extractPayloadByte(7) + 2000;
104
+ mm = msg.extractPayloadByte(8);
105
+ dd = msg.extractPayloadByte(9);
106
+ sys.general.options.vacation.endDate = new Date(yy, mm - 1, dd);
107
+ sys.general.options.vacation.enabled = msg.extractPayloadByte(2) > 0;
108
+ sys.general.options.vacation.useTimeframe = msg.extractPayloadByte(3) > 0;
109
+ msg.isProcessed = true;
98
110
  break;
99
111
  }
100
112
  msg.isProcessed = true;
@@ -132,8 +132,10 @@ export class PumpMessage {
132
132
  }
133
133
  }
134
134
  }
135
+ msg.isProcessed = true;
135
136
  switch (msgId) {
136
137
  case 0:
138
+ msg.isProcessed = true;
137
139
  break;
138
140
  case 1:
139
141
  PumpMessage.processFlowStepSize(msg);
@@ -347,38 +349,20 @@ export class PumpMessage {
347
349
  circuit.circuit = _circuit;
348
350
  circuit.flow = msg.extractPayloadByte(circuitId * 2 + 4);
349
351
  circuit.units = 1;
350
- switch (circuit.circuit) {
351
- case 1:
352
- {
353
- let body = sys.bodies.getItemById(2, sys.equipment.maxBodies >= 2);
354
- let sbody = state.temps.bodies.getItemById(2, sys.equipment.maxBodies >= 2);
355
- sbody.type = body.type = 1; // spa
356
- body.isActive = true;
357
- break;
358
- }
359
- case 6:
360
- {
361
- let body = sys.bodies.getItemById(1, sys.equipment.maxBodies >= 1);
362
- let sbody = state.temps.bodies.getItemById(1, sys.equipment.maxBodies >= 1);
363
- sbody.type = body.type = 0; // pool
364
- body.isActive = true;
365
- body.capacity = msg.extractPayloadByte(6) * 1000;
366
- break;
367
- }
368
- }
369
352
  }
370
353
  else {
371
354
  pump.circuits.removeItemById(_circuit);
372
355
  }
373
356
  }
374
357
  pump.backgroundCircuit = msg.extractPayloadByte(1);
358
+ pump.filterSize = msg.extractPayloadByte(2) * 1000;
375
359
  pump.turnovers = msg.extractPayloadByte(3);
360
+ pump.manualFilterGPM = msg.extractPayloadByte(21);
376
361
  pump.primingSpeed = msg.extractPayloadByte(22);
377
362
  pump.primingTime = (msg.extractPayloadByte(23) & 0xf);
378
363
  pump.minFlow = sys.board.valueMaps.pumpTypes.get(pump.type).minFlow;
379
364
  pump.maxFlow = sys.board.valueMaps.pumpTypes.get(pump.type).maxFlow;
380
365
  pump.flowStepSize = sys.board.valueMaps.pumpTypes.get(pump.type).flowStepSize;
381
- pump.manualFilterGPM = msg.extractPayloadByte(21);
382
366
  pump.maxSystemTime = msg.extractPayloadByte(23) >> 4;
383
367
  pump.maxPressureIncrease = msg.extractPayloadByte(24);
384
368
  pump.backwashFlow = msg.extractPayloadByte(25);
@@ -93,6 +93,7 @@ export class RemoteMessage {
93
93
  if (!remote.button1 && !remote.button2 && !remote.button3 && !remote.button4) remote.isActive = false;
94
94
  else remote.isActive = true;
95
95
  remote.name = "QuickTouch";
96
+ msg.isProcessed = true;
96
97
  break;
97
98
  }
98
99
  case 32: // is4/is10
@@ -120,6 +121,7 @@ export class RemoteMessage {
120
121
  remote.type = 1;
121
122
  remote.name = "is4";
122
123
  }
124
+ msg.isProcessed = true;
123
125
  break;
124
126
  }
125
127
  case 22: // Spa Command spa side remote additional config
@@ -132,6 +134,7 @@ export class RemoteMessage {
132
134
  remote.pumpId = msg.extractPayloadByte(5);
133
135
  remote.stepSize = msg.extractPayloadByte(6);
134
136
  remote.type = 7;
137
+ msg.isProcessed = true;
135
138
  break;
136
139
  }
137
140
  }
@@ -187,5 +190,6 @@ export class RemoteMessage {
187
190
  }
188
191
  remote["button" + (i + 1)] = msg.extractPayloadByte(i + 2);
189
192
  }
193
+ msg.isProcessed = true;
190
194
  }
191
195
  }
@@ -187,6 +187,7 @@ export class ScheduleMessage {
187
187
  const schedule: Schedule = sys.schedules.getItemById(schedId++, false, { isActive: false });
188
188
  if (schedule.isActive !== false) schedule.startMonth = msg.extractPayloadByte(i + 1);
189
189
  }
190
+ msg.isProcessed = true;
190
191
  }
191
192
  private static processStartDay(msg: Inbound) {
192
193
  let schedId = (msg.extractPayloadByte(1) - 17) * 40 + 1;
@@ -198,6 +199,7 @@ export class ScheduleMessage {
198
199
  csched.startTime = schedule.startTime;
199
200
  }
200
201
  }
202
+ msg.isProcessed = true;
201
203
  }
202
204
  private static processStartYear(msg: Inbound) {
203
205
  let schedId = (msg.extractPayloadByte(1) - 20) * 40 + 1;
@@ -207,6 +209,7 @@ export class ScheduleMessage {
207
209
  schedule.startYear = msg.extractPayloadByte(i + 1);
208
210
  }
209
211
  }
212
+ msg.isProcessed = true;
210
213
  }
211
214
  private static processStartTimes(msg: Inbound) {
212
215
  let schedId = msg.extractPayloadByte(1) * 20 + 1;
@@ -226,6 +229,7 @@ export class ScheduleMessage {
226
229
  i += 2;
227
230
  }
228
231
  ScheduleMessage._maxSchedId = sys.schedules.getMaxId(true, 0);
232
+ msg.isProcessed = true;
229
233
  }
230
234
  private static processEndTimes(msg: Inbound) {
231
235
  let schedId = (msg.extractPayloadByte(1) - 23) * 20 + 1;
@@ -239,6 +243,7 @@ export class ScheduleMessage {
239
243
  }
240
244
  i += 2;
241
245
  }
246
+ msg.isProcessed = true;
242
247
  }
243
248
  private static processCircuit(msg: Inbound) {
244
249
  let schedId = (msg.extractPayloadByte(1) - 5) * 40 + 1;
@@ -258,6 +263,7 @@ export class ScheduleMessage {
258
263
  csched.circuit = schedule.circuit;
259
264
  }
260
265
  }
266
+ msg.isProcessed = true;
261
267
  }
262
268
  private static processRunOnce(msg: Inbound) {
263
269
  let schedId = (msg.extractPayloadByte(1) - 8) * 40 + 1;
@@ -280,6 +286,7 @@ export class ScheduleMessage {
280
286
  csched.scheduleType = schedule.scheduleType;
281
287
  }
282
288
  }
289
+ msg.isProcessed = true;
283
290
  }
284
291
  private static processDays(msg: Inbound) {
285
292
  let schedId = (msg.extractPayloadByte(1) - 11) * 40 + 1;
@@ -291,6 +298,7 @@ export class ScheduleMessage {
291
298
  csched.scheduleDays = csched.scheduleType === 128 ? schedule.scheduleDays : 0;
292
299
  }
293
300
  }
301
+ msg.isProcessed = true;
294
302
  }
295
303
  private static processHeatSource(msg: Inbound) {
296
304
  let schedId = (msg.extractPayloadByte(1) - 28) * 40 + 1;
@@ -305,6 +313,7 @@ export class ScheduleMessage {
305
313
  csched.heatSource = schedule.heatSource;
306
314
  }
307
315
  }
316
+ msg.isProcessed = true;
308
317
  }
309
318
  private static processHeatSetpoint(msg: Inbound) {
310
319
  let schedId = (msg.extractPayloadByte(1) - 31) * 40 + 1;
@@ -316,6 +325,7 @@ export class ScheduleMessage {
316
325
  csched.heatSetpoint = schedule.heatSetpoint;
317
326
  }
318
327
  }
328
+ msg.isProcessed = true;
319
329
  }
320
330
  private static processCoolSetpoint(msg: Inbound) {
321
331
  let schedId = (msg.extractPayloadByte(1) - 34) * 40 + 1;
@@ -327,5 +337,6 @@ export class ScheduleMessage {
327
337
  csched.coolSetpoint = schedule.coolSetpoint;
328
338
  }
329
339
  }
340
+ msg.isProcessed = true;
330
341
  }
331
342
  }
@@ -34,5 +34,6 @@ export class SecurityMessage {
34
34
  role.flag2 = msg.extractPayloadByte(3);
35
35
  role.pin = msg.extractPayloadByte(21).toString() + msg.extractPayloadByte(22).toString() + msg.extractPayloadByte(23).toString() + msg.extractPayloadByte(24).toString();
36
36
  }
37
+ msg.isProcessed = true;
37
38
  }
38
39
  }
@@ -32,6 +32,7 @@ export class ValveMessage {
32
32
  ValveMessage.processValveNames(msg);
33
33
  break;
34
34
  case 3: // Skip the secondary intake/return
35
+ msg.isProcessed = true;
35
36
  break;
36
37
  case 4:
37
38
  case 5:
@@ -70,6 +71,7 @@ export class ValveMessage {
70
71
  // [165,33,15,16,35,2],[132,0],[1,142]
71
72
  // ^^^ 128 = Pump off during valve operation
72
73
  sys.general.options.pumpDelay = msg.extractPayloadByte(0) >> 7 === 1;
74
+ msg.isProcessed = true;
73
75
  }
74
76
  private static process_ValveAssignment_IT(msg: Inbound) {
75
77
  // sample packet
@@ -91,6 +93,7 @@ export class ValveMessage {
91
93
  let svalve = state.valves.getItemById(id, true);
92
94
  svalve.name = valve.name;
93
95
  svalve.type = valve.type;
96
+ valve.master = 0;
94
97
  }
95
98
  else {
96
99
  sys.valves.removeItemById(id);
@@ -110,6 +113,7 @@ export class ValveMessage {
110
113
  let svalve = state.valves.getItemById(id, true);
111
114
  svalve.name = valve.name;
112
115
  svalve.type = valve.type;
116
+ valve.master = 0;
113
117
  }
114
118
  else {
115
119
  sys.valves.removeItemById(id);
@@ -136,17 +140,20 @@ export class ValveMessage {
136
140
  let svalve = state.valves.getItemById(id, true);
137
141
  svalve.name = valve.name;
138
142
  svalve.type = valve.type;
143
+ valve.master = 0;
139
144
  }
140
145
  if (!valve.isActive) {
141
146
  sys.valves.removeItemById(id);
142
147
  state.valves.removeItemById(id);
143
148
  }
144
149
  else {
145
- valve.isVirtual = false;
150
+ valve.master = 0;
151
+ // valve.isVirtual = false;
146
152
  valve.type = 0;
147
153
  }
148
154
  id++;
149
155
  }
156
+ msg.isProcessed = true;
150
157
  }
151
158
  private static getName(id: number, cir: number) {
152
159
  if (cir <= 0 || cir >= 255 || cir === 6) {
@@ -187,7 +194,8 @@ export class ValveMessage {
187
194
  ndx += 2;
188
195
  }
189
196
  let valve: Valve = sys.valves.getItemById(id, true);
190
- valve.isVirtual = false;
197
+ valve.master = 0;
198
+ // valve.isVirtual = false;
191
199
  if (id === 3 || id === 5) {
192
200
  valve.circuit = 247; // Hardcode the intake/return to pool/spa;
193
201
  valve.isIntake = true;
@@ -214,6 +222,7 @@ export class ValveMessage {
214
222
  }
215
223
  // Sort them so they are in valve id order. This will ensure any OCP valves come first in the list. Valves ids > 50 are virtual valves.
216
224
  sys.valves.sortById();
225
+ msg.isProcessed = true;
217
226
  }
218
227
  private static processValveNames(msg: Inbound) {
219
228
  let byte = msg.extractPayloadByte(1);
@@ -228,5 +237,6 @@ export class ValveMessage {
228
237
  if (typeof sys.valves.find(elem => elem.id === valveId) !== 'undefined') {
229
238
  state.valves.getItemById(valveId).name = sys.valves.getItemById(valveId++).name = msg.extractPayloadString(18, 16);
230
239
  }
240
+ msg.isProcessed = true;
231
241
  }
232
242
  }
@@ -64,9 +64,8 @@ export class ChlorinatorStateMessage {
64
64
  //[16, 2, 0, 3][0, 73, 110, 116, 101, 108, 108, 105, 99, 104, 108, 111, 114, 45, 45, 52, 48][188, 16, 3]
65
65
  // This is the model number of the chlorinator and the address is actually the second byte.
66
66
  let name = msg.extractPayloadString(1, 16);
67
- chlor.model = name;
68
- if (typeof chlor.name === 'undefined' || chlor.name === '') chlor.name = name;
69
- cstate.name = chlor.name;
67
+ if (typeof chlor.name === 'undefined' || chlor.name === '') chlor.name = cstate.name = name;
68
+ if (typeof chlor.model === 'undefined') chlor.model = sys.board.valueMaps.chlorinatorModel.getValue(name.toLowerCase());
70
69
  cstate.isActive = chlor.isActive;
71
70
  state.emitEquipmentChanges();
72
71
  break;
@@ -101,7 +101,9 @@ export class EquipmentStateMessage {
101
101
  Message.headerSubByte = msg.header[1];
102
102
  //console.log(process.memoryUsage());
103
103
  if (msg.action === 2 && state.isInitialized && sys.controllerType === ControllerType.Nixie) {
104
- // Start over because we didn't have communication before but we now do.
104
+ // Start over because we didn't have communication before but we now do. This will fall into the if
105
+ // below so that it goes through the intialization process. In this case we didn't see an OCP when we started
106
+ // but there clearly is one now.
105
107
  sys.controllerType = ControllerType.Unknown;
106
108
  state.status = 0;
107
109
  }
@@ -139,19 +141,24 @@ export class EquipmentStateMessage {
139
141
 
140
142
  // Shared
141
143
  let dt = new Date();
142
- if (state.chemControllers.length > 0) {
143
- // TODO: move this to chemController when we understand the packets better
144
- for (let i = 0; i < state.chemControllers.length; i++) {
145
- let ccontroller = state.chemControllers.getItemByIndex(i);
146
- if (sys.board.valueMaps.chemControllerTypes.getName(ccontroller.type) === 'intellichem') {
147
- if (dt.getTime() - ccontroller.lastComm > 60000) ccontroller.status = 1;
148
- }
149
- }
150
- }
144
+ // RKS: This was moved to the ChemControllerState message. This is flawed in that it incorrectly sets IntelliChem to no comms.
145
+ //if (state.chemControllers.length > 0) {
146
+ // // TODO: move this to chemController when we understand the packets better
147
+ // for (let i = 0; i < state.chemControllers.length; i++) {
148
+ // let ccontroller = state.chemControllers.getItemByIndex(i);
149
+ // if (sys.board.valueMaps.chemControllerTypes.getName(ccontroller.type) === 'intellichem') {
150
+ // if (dt.getTime() - ccontroller.lastComm > 60000) ccontroller.status = 1;
151
+ // }
152
+ // }
153
+ //}
151
154
  state.time.hours = msg.extractPayloadByte(0);
152
155
  state.time.minutes = msg.extractPayloadByte(1);
153
156
  state.time.seconds = dt.getSeconds();
154
- state.mode = msg.extractPayloadByte(9) & 0x81;
157
+ state.mode = sys.controllerType !== ControllerType.IntelliCenter ? (msg.extractPayloadByte(9) & 0x81) : (msg.extractPayloadByte(9) & 0x01);
158
+
159
+ // RKS: The units have been normalized for English and Metric for the overall panel. It is important that the val numbers match for at least the temp units since
160
+ // the only unit of measure native to the Touch controllers is temperature they chose to name these C or F. However, with the njsPC extensions this is non-semantic
161
+ // since pressure, volume, and length have been introduced.
155
162
  sys.general.options.units = state.temps.units = msg.extractPayloadByte(9) & 0x04;
156
163
  state.valve = msg.extractPayloadByte(10);
157
164
 
@@ -197,10 +204,19 @@ export class EquipmentStateMessage {
197
204
  tbody.name = cbody.name;
198
205
  tbody.circuit = cbody.circuit = 6;
199
206
  tbody.heatStatus = msg.extractPayloadByte(11) & 0x0F;
200
- if ((msg.extractPayloadByte(2) & 0x20) === 32) {
207
+ // With the IntelliCenter i10D, bit 6 is not reliable. It is not set properly and requires the 204 message
208
+ // to process the data.
209
+ if (!sys.equipment.dual) {
210
+ if ((msg.extractPayloadByte(2) & 0x20) === 32) {
211
+ tbody.temp = state.temps.waterSensor1;
212
+ tbody.isOn = true;
213
+ } else tbody.isOn = false;
214
+ }
215
+ else if (state.circuits.getItemById(6).isOn === true) {
201
216
  tbody.temp = state.temps.waterSensor1;
202
217
  tbody.isOn = true;
203
- } else tbody.isOn = false;
218
+ }
219
+ else tbody.isOn = false;
204
220
  }
205
221
  if (sys.bodies.length > 1) {
206
222
  const tbody: BodyTempState = state.temps.bodies.getItemById(2, true);
@@ -210,10 +226,16 @@ export class EquipmentStateMessage {
210
226
  tbody.name = cbody.name;
211
227
  tbody.circuit = cbody.circuit = 1;
212
228
  tbody.heatStatus = (msg.extractPayloadByte(11) & 0xF0) >> 4;
213
- if ((msg.extractPayloadByte(2) & 0x01) === 1) {
229
+ if (!sys.equipment.dual) {
230
+ if ((msg.extractPayloadByte(2) & 0x01) === 1) {
231
+ tbody.temp = sys.equipment.shared ? state.temps.waterSensor1 : state.temps.waterSensor2;
232
+ tbody.isOn = true;
233
+ } else tbody.isOn = false;
234
+ } else if (state.circuits.getItemById(1).isOn === true) {
214
235
  tbody.temp = sys.equipment.shared ? state.temps.waterSensor1 : state.temps.waterSensor2;
215
236
  tbody.isOn = true;
216
- } else tbody.isOn = false;
237
+ }
238
+ else tbody.isOn = false;
217
239
  }
218
240
  if (sys.bodies.length > 2) {
219
241
  state.temps.waterSensor3 = fnTempFromByte(msg.extractPayloadByte(20));
@@ -396,8 +418,8 @@ export class EquipmentStateMessage {
396
418
  sys.board.heaters.syncHeaterStates();
397
419
  break;
398
420
  }
399
- case ControllerType.IntelliCom:
400
421
  case ControllerType.EasyTouch:
422
+ case ControllerType.IntelliCom:
401
423
  case ControllerType.IntelliTouch:
402
424
  {
403
425
  EquipmentStateMessage.processTouchCircuits(msg);
@@ -497,8 +519,7 @@ export class EquipmentStateMessage {
497
519
  state.time.date = msg.extractPayloadByte(6);
498
520
  state.time.month = msg.extractPayloadByte(7);
499
521
  state.time.year = msg.extractPayloadByte(8);
500
- sys.equipment.controllerFirmware = (msg.extractPayloadByte(42)
501
- + (msg.extractPayloadByte(43) / 1000)).toString();
522
+ sys.equipment.controllerFirmware = (msg.extractPayloadByte(42) + (msg.extractPayloadByte(43) / 1000)).toString();
502
523
  if (sys.chlorinators.length > 0) {
503
524
  if (msg.extractPayloadByte(37, 255) !== 255) {
504
525
  const chlor = state.chlorinators.getItemById(1);
@@ -510,9 +531,38 @@ export class EquipmentStateMessage {
510
531
  }
511
532
  }
512
533
  ExternalMessage.processFeatureState(9, msg);
534
+ //if (sys.equipment.dual === true) {
535
+ // // For IntelliCenter i10D the body state is on byte 26 of the 204. This impacts circuit 6.
536
+ // let byte = msg.extractPayloadByte(26);
537
+ // let pstate = state.circuits.getItemById(6, true);
538
+ // let oldstate = pstate.isOn;
539
+ // pstate.isOn = ((byte & 0x0010) === 0x0010);
540
+ // logger.info(`Checking i10D pool state ${byte} old:${oldstate} new: ${pstate.isOn}`);
541
+ // //if (oldstate !== pstate.isOn) {
542
+ // state.temps.bodies.getItemById(1, true).isOn = pstate.isOn;
543
+ // sys.board.circuits.syncCircuitRelayStates();
544
+ // sys.board.circuits.syncVirtualCircuitStates();
545
+ // sys.board.valves.syncValveStates();
546
+ // sys.board.filters.syncFilterStates();
547
+ // sys.board.heaters.syncHeaterStates();
548
+ // //}
549
+ // if (oldstate !== pstate.isOn) pstate.emitEquipmentChange();
550
+ //}
551
+ // At this point normally on is ignored. Not sure what this does.
552
+ let cover1 = sys.covers.getItemById(1);
553
+ let cover2 = sys.covers.getItemById(2);
554
+ if (cover1.isActive) {
555
+ let scover1 = state.covers.getItemById(1, true);
556
+ scover1.name = cover1.name;
557
+ state.temps.bodies.getItemById(cover1.body + 1).isCovered = scover1.isClosed = (msg.extractPayloadByte(30) & 0x0001) > 0;
558
+ }
559
+ if (cover2.isActive) {
560
+ let scover2 = state.covers.getItemById(2, true);
561
+ scover2.name = cover2.name;
562
+ state.temps.bodies.getItemById(cover2.body + 1).isCovered = scover2.isClosed = (msg.extractPayloadByte(30) & 0x0002) > 0;
563
+ }
513
564
  msg.isProcessed = true;
514
- // state.emitControllerChange();
515
- // state.emitEquipmentChanges();
565
+ state.emitEquipmentChanges();
516
566
  break;
517
567
  }
518
568
  }
@@ -530,13 +580,15 @@ export class EquipmentStateMessage {
530
580
  let circuit = sys.circuits.getItemById(circuitId, false, { isActive: false });
531
581
  if (circuit.isActive !== false) {
532
582
  let cstate = state.circuits.getItemById(circuitId, circuit.isActive);
533
- let isOn = (byte & (1 << j)) > 0;
534
- sys.board.circuits.setEndTime(circuit, cstate, isOn);
583
+ // For IntelliCenter i10D body circuits are not reported here.
584
+ let isOn = ((circuitId === 6 || circuitId === 1) && sys.equipment.dual === true) ? cstate.isOn : (byte & (1 << j)) > 0;
585
+ //let isOn = (byte & (1 << j)) > 0;
535
586
  cstate.isOn = isOn;
536
587
  cstate.name = circuit.name;
537
588
  cstate.nameId = circuit.nameId;
538
589
  cstate.showInFeatures = circuit.showInFeatures;
539
590
  cstate.type = circuit.type;
591
+ sys.board.circuits.setEndTime(circuit, cstate, isOn);
540
592
  if (sys.controllerType === ControllerType.IntelliCenter) {
541
593
  // intellitouch sends a separate msg with themes
542
594
  switch (circuit.type) {
@@ -34,16 +34,25 @@ export class HeaterStateMessage {
34
34
  // RKS: 07-03-21 - We only know byte 2 at this point for Ultratemp for the 115 message we are processing here. The
35
35
  // byte description
36
36
  // ------------------------------------------------
37
- // 0 Unknown
38
- // 1 Unknown
37
+ // 0 Unknown (always seems to be 160 for response)
38
+ // 1 Unknown (always 1)
39
39
  // 2 Current heater status 0=off, 1=heat, 2=cool
40
40
  // 3-9 Unknown
41
- let heater: Heater = sys.heaters.getItemByAddress(msg.source);
42
- let sheater = state.heaters.getItemById(heater.id);
43
- // We need to decode the message. For a 2 of
44
- //[165, 1, 15, 16, 2, 29][16, 42, 3, 0, 0, 0, 0, 0, 0, 32, 0, 0, 2, 0, 88, 88, 0, 241, 95, 100, 24, 246, 0, 0, 0, 0, 0, 40, 0][4, 221]
41
+
42
+ // 114 message - outbound response
45
43
  //[165, 0, 112, 16, 114, 10][144, 0, 0, 0, 0, 0, 0, 0, 0, 0][2, 49] // OCP to Heater
44
+ // byte description
45
+ // ------------------------------------------------
46
+ // 0 Unknown (always seems to be 144 for request)
47
+ // 1 Current heater status 0=off, 1=heat, 2=cool
48
+ // 3 Believed to be ofset temp
49
+ // 4-9 Unknown
50
+
51
+ // byto 0: always seems to be 144 for outbound
52
+ // byte 1: Sets heater mode to 0 = Off 1 = Heat 2 = Cool
46
53
  //[165, 0, 16, 112, 115, 10][160, 1, 0, 3, 0, 0, 0, 0, 0, 0][2, 70] // Heater Reply
54
+ let heater: Heater = sys.heaters.getItemByAddress(msg.source);
55
+ let sheater = state.heaters.getItemById(heater.id);
47
56
  let byte = msg.extractPayloadByte(2);
48
57
  sheater.isOn = byte >= 1;
49
58
  sheater.isCooling = byte === 2;