nodejs-poolcontroller 8.0.1 → 8.0.4

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 (41) hide show
  1. package/.github/workflows/docker-publish-njsPC-linux.yml +50 -0
  2. package/Dockerfile +5 -3
  3. package/README.md +4 -1
  4. package/config/Config.ts +1 -1
  5. package/controller/Constants.ts +164 -67
  6. package/controller/Equipment.ts +78 -18
  7. package/controller/Lockouts.ts +15 -0
  8. package/controller/State.ts +281 -7
  9. package/controller/boards/EasyTouchBoard.ts +225 -101
  10. package/controller/boards/IntelliCenterBoard.ts +84 -23
  11. package/controller/boards/IntelliTouchBoard.ts +2 -4
  12. package/controller/boards/NixieBoard.ts +84 -27
  13. package/controller/boards/SunTouchBoard.ts +8 -2
  14. package/controller/boards/SystemBoard.ts +3262 -3242
  15. package/controller/comms/ScreenLogic.ts +47 -44
  16. package/controller/comms/messages/Messages.ts +4 -4
  17. package/controller/comms/messages/config/ChlorinatorMessage.ts +10 -3
  18. package/controller/comms/messages/config/ExternalMessage.ts +4 -1
  19. package/controller/comms/messages/config/PumpMessage.ts +8 -7
  20. package/controller/comms/messages/config/RemoteMessage.ts +48 -43
  21. package/controller/comms/messages/status/ChlorinatorStateMessage.ts +8 -2
  22. package/controller/comms/messages/status/EquipmentStateMessage.ts +9 -4
  23. package/controller/comms/messages/status/PumpStateMessage.ts +1 -1
  24. package/controller/nixie/NixieEquipment.ts +1 -1
  25. package/controller/nixie/bodies/Body.ts +1 -1
  26. package/controller/nixie/chemistry/ChemController.ts +37 -28
  27. package/controller/nixie/circuits/Circuit.ts +48 -7
  28. package/controller/nixie/heaters/Heater.ts +24 -5
  29. package/controller/nixie/pumps/Pump.ts +159 -97
  30. package/controller/nixie/schedules/Schedule.ts +207 -126
  31. package/defaultConfig.json +3 -3
  32. package/logger/DataLogger.ts +7 -7
  33. package/package.json +2 -2
  34. package/sendSocket.js +32 -0
  35. package/web/Server.ts +17 -11
  36. package/web/bindings/homeassistant.json +2 -2
  37. package/web/interfaces/mqttInterface.ts +18 -18
  38. package/web/services/config/Config.ts +34 -1
  39. package/web/services/state/State.ts +10 -3
  40. package/web/services/state/StateSocket.ts +7 -3
  41. package/web/services/utilities/Utilities.ts +3 -3
@@ -912,21 +912,21 @@ class Controller {
912
912
  }
913
913
  ], */
914
914
  }
915
- public static decodeHighSpeed(highSpeed: number[]) {
916
- let maxCircuits = sys.controllerType === ControllerType.IntelliTouch ? 8 : 4;
917
- let arrCircuits = [];
918
- let pump = sys.pumps.getDualSpeed(true);
919
- for (let i = 0; i < maxCircuits && i < highSpeed.length; i++) {
920
- let val = highSpeed[i];
921
- if (val > 0) arrCircuits.push(val);
922
- else pump.circuits.removeItemById(i);
923
- }
924
- if (arrCircuits.length > 0) {
925
- let pump = sys.pumps.getDualSpeed(true);
926
- for (let j = 1; j <= arrCircuits.length; j++) pump.circuits.getItemById(j, true).circuit = arrCircuits[j - 1];
927
- }
928
- else sys.pumps.removeItemById(10);
929
- }
915
+ public static decodeHighSpeed(highSpeed: number[]) {
916
+ let maxCircuits = sys.controllerType === ControllerType.IntelliTouch ? 8 : 4;
917
+ let arrCircuits = [];
918
+ let pump = sys.pumps.find(x => { return x.master !== 1 && x.type === 65 });
919
+ for (let i = 0; i < maxCircuits && i < highSpeed.length; i++) {
920
+ let val = highSpeed[i];
921
+ if (val > 0) arrCircuits.push(val);
922
+ else if (typeof pump !== 'undefined') pump.circuits.removeItemById(i);
923
+ }
924
+ if (arrCircuits.length > 0) {
925
+ let pump = sys.pumps.getDualSpeed(true);
926
+ for (let j = 1; j <= arrCircuits.length; j++) pump.circuits.getItemById(j, true).circuit = arrCircuits[j - 1];
927
+ }
928
+ else if (typeof pump !== 'undefined') sys.pumps.removeItemById(pump.id);
929
+ }
930
930
  public static decodeRemote(remoteDataArray) {
931
931
  if (sys.controllerType === ControllerType.EasyTouch) {
932
932
 
@@ -1071,35 +1071,38 @@ class Controller {
1071
1071
  await sys.board.pumps.setPumpAsync(pData, false);
1072
1072
  })
1073
1073
  }
1074
- public static async decodePumpStatusAsync(id: number, slpump: SLPumpStatusData) {
1075
- /* {
1076
- pumpCircuits: [
1077
- { circuitId: 6,speed: 2000,isRPMs: true, },
1078
- { circuitId: 8, speed:2700,isRPMs: true, },
1079
- { circuitId: 2,speed: 2710,isRPMs: true, },
1080
- { circuitId: 2,speed:1000, isRPMs: true,},
1081
- { circuitId: 5,speed:2830, isRPMs: true,},
1082
- { circuitId: 0,speed: 30,isRPMs: false,},
1083
- { circuitId: 0,speed: 30,isRPMs: false,},
1084
- { circuitId: 0,speed: 30,isRPMs: false,},
1085
- ],
1086
- pumpType: 4,
1087
- isRunning: false,
1088
- pumpWatts: 0,
1089
- pumpRPMs: 0,
1090
- pumpUnknown1: 0,
1091
- pumpGPMs: 0,
1092
- pumpUnknown2: 255,
1093
- }
1094
- */
1095
-
1096
- let pstate = state.pumps.getItemById(id);
1097
- pstate.watts = slpump.pumpWatts;
1098
- pstate.rpm = slpump.pumpRPMs;
1099
- pstate.flow = slpump.pumpGPMs === 255 ? 0 : slpump.pumpGPMs;
1100
- pstate.command = (pstate.rpm > 0 || pstate.watts > 0) ? 10 : 0;
1101
- state.emitEquipmentChanges();
1102
- }
1074
+ public static async decodePumpStatusAsync(id: number, slpump: SLPumpStatusData) {
1075
+ /* {
1076
+ pumpCircuits: [
1077
+ { circuitId: 6,speed: 2000,isRPMs: true, },
1078
+ { circuitId: 8, speed:2700,isRPMs: true, },
1079
+ { circuitId: 2,speed: 2710,isRPMs: true, },
1080
+ { circuitId: 2,speed:1000, isRPMs: true,},
1081
+ { circuitId: 5,speed:2830, isRPMs: true,},
1082
+ { circuitId: 0,speed: 30,isRPMs: false,},
1083
+ { circuitId: 0,speed: 30,isRPMs: false,},
1084
+ { circuitId: 0,speed: 30,isRPMs: false,},
1085
+ ],
1086
+ pumpType: 4,
1087
+ isRunning: false,
1088
+ pumpWatts: 0,
1089
+ pumpRPMs: 0,
1090
+ pumpUnknown1: 0,
1091
+ pumpGPMs: 0,
1092
+ pumpUnknown2: 255,
1093
+ }
1094
+ */
1095
+ // RKS: 05-07-23 - This process of getting the pump by its id is flawed. We need to pull this information by its address.
1096
+ //let pstate = state.pumps.getItemById(id);
1097
+ let pstate = state.pumps.find(x => x.address === 95 + id);
1098
+ if (typeof pstate !== 'undefined') {
1099
+ pstate.watts = slpump.pumpWatts;
1100
+ pstate.rpm = slpump.pumpRPMs;
1101
+ pstate.flow = slpump.pumpGPMs === 255 ? 0 : slpump.pumpGPMs;
1102
+ pstate.command = (pstate.rpm > 0 || pstate.watts > 0) ? 10 : 0;
1103
+ state.emitEquipmentChanges();
1104
+ }
1105
+ }
1103
1106
  public static async decodeSchedules(slrecurring: SLScheduleData, slrunonce: SLScheduleData) {
1104
1107
  /* reccuring schedules: [{"scheduleId":1,"circuitId":6,"startTime":"1800","stopTime":"0700","dayMask":127,"flags":0,"heatCmd":4,"heatSetPoint":70,"days":["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]},
1105
1108
 
@@ -75,7 +75,7 @@ export class Message {
75
75
  private static _messageId: number = 0;
76
76
  public static get nextMessageId(): number {
77
77
  let i = this._messageId < 80000 ? ++this._messageId : this._messageId = 0;
78
- logger.debug(`Assigning message id ${i}`)
78
+ //logger.debug(`Assigning message id ${i}`)
79
79
  return i; }
80
80
  public portId = 0; // This will be the target or source port for the message. If this is from or to an Aux RS485 port the value will be > 0.
81
81
  public timestamp: Date = new Date();
@@ -507,7 +507,7 @@ export class Inbound extends Message {
507
507
  ndx = bytes.length - 5;
508
508
  let arr = bytes.slice(0, ndx);
509
509
  // Remove all but the last 4 bytes. This will result in nothing anyway.
510
- logger.verbose(`Tossed Inbound Bytes ${arr} due to an unrecoverable collision.`);
510
+ logger.verbose(`[Port ${this.portId}] Tossed Inbound Bytes ${arr} due to an unrecoverable collision.`);
511
511
  }
512
512
  this.padding = [];
513
513
  break;
@@ -1169,12 +1169,12 @@ export class Response extends OutboundCommon {
1169
1169
  // Scenario 1. Request for pump status.
1170
1170
  // Msg In: [165,0,16, 96, 7,15], [4,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,17,31], [1,95]
1171
1171
  // Msg Out: [165,0,96, 16, 7, 0],[1,28]
1172
- if (msgIn.source !== msgOut.dest || msgIn.dest !== msgOut.source) { return false; }
1172
+ if (msgIn.source !== msgOut.dest || (msgIn.dest !== msgOut.source && msgIn.dest != 16)) { return false; }
1173
1173
  if (msgIn.action === 7 && msgOut.action === 7) { return true; }
1174
1174
  return false;
1175
1175
  default:
1176
1176
  //Scenario 2, pump messages are mimics of each other but the dest/src are swapped
1177
- if (msgIn.source !== msgOut.dest || msgIn.dest !== msgOut.source) { return false; }
1177
+ if (msgIn.source !== msgOut.dest || (msgIn.dest !== msgOut.source && msgIn.dest != 16)) { return false; }
1178
1178
  // sub-case
1179
1179
  // Msg In: [165,0,16, 96, 1, 2], [3,32],[1,59]
1180
1180
  // Msg Out: [165,0,96,16, 1,4],[3,39, 3,32], [1,103]
@@ -80,6 +80,7 @@ export class ChlorinatorMessage {
80
80
  if (isActive) {
81
81
  let chlor = sys.chlorinators.getItemById(1, true);
82
82
  let schlor = state.chlorinators.getItemById(1, true);
83
+ chlor.master = 0;
83
84
  chlor.isActive = schlor.isActive = isActive;
84
85
  if (!chlor.disabled) {
85
86
  // RKS: We don't want these setpoints if our chem controller disabled the
@@ -87,10 +88,16 @@ export class ChlorinatorMessage {
87
88
  schlor.spaSetpoint = chlor.spaSetpoint = msg.extractPayloadByte(0) >> 1;
88
89
  schlor.poolSetpoint = chlor.poolSetpoint = msg.extractPayloadByte(1);
89
90
  chlor.address = msg.dest;
90
- schlor.body = chlor.body = sys.equipment.maxBodies >= 1 || sys.equipment.shared === true ? 32 : 0;
91
+ schlor.body = chlor.body = sys.equipment.shared === true ? 32 : 0;
92
+ }
93
+ let name = msg.extractPayloadString(6, 16).trimEnd();
94
+ if (typeof chlor.name === 'undefined') schlor.name = chlor.name = name;
95
+ if (typeof chlor.model === 'undefined') {
96
+ chlor.model = sys.board.valueMaps.chlorinatorModel.getValue(schlor.name.toLowerCase());
97
+ if (typeof chlor.model === 'undefined') {
98
+ if (name.startsWith('iChlor')) chlor.model = sys.board.valueMaps.chlorinatorModel.getValue('ichlor-ic30');
99
+ }
91
100
  }
92
- if (typeof chlor.name === 'undefined') schlor.name = chlor.name = msg.extractPayloadString(6, 16);
93
- if (typeof chlor.model === 'undefined') chlor.model = sys.board.valueMaps.chlorinatorModel.getValue(schlor.name.toLowerCase());
94
101
  if (typeof chlor.type === 'undefined') chlor.type = schlor.type = 0;
95
102
  schlor.saltLevel = msg.extractPayloadByte(3) * 50 || schlor.saltLevel;
96
103
  schlor.status = msg.extractPayloadByte(4) & 0x007F; // Strip off the high bit. The chlorinator does not actually report this.;
@@ -329,6 +329,7 @@ export class ExternalMessage {
329
329
  case 8: // Intellibrite
330
330
  case 10: // Colorcascade
331
331
  cstate.lightingTheme = circuit.lightingTheme;
332
+ if (!isOn) cstate.action = 0;
332
333
  break;
333
334
  case 9: // Dimmer
334
335
  cstate.level = circuit.level;
@@ -354,7 +355,8 @@ export class ExternalMessage {
354
355
  if (schedule.isActive) {
355
356
  if (schedule.circuit > 0) { // Don't get the schedule state if we haven't determined the entire config for it yet.
356
357
  let sstate = state.schedules.getItemById(scheduleId, schedule.isActive);
357
- sstate.isOn = ((byte & (1 << (j))) >> j) > 0;
358
+ let isOn = ((byte & (1 << (j))) >> j) > 0;
359
+ sstate.isOn = isOn;
358
360
  sstate.circuit = schedule.circuit;
359
361
  sstate.endTime = schedule.endTime;
360
362
  sstate.startDate = schedule.startDate;
@@ -365,6 +367,7 @@ export class ExternalMessage {
365
367
  sstate.heatSource = schedule.heatSource;
366
368
  sstate.startTimeType = schedule.startTimeType;
367
369
  sstate.endTimeType = schedule.endTimeType;
370
+ sstate.startDate = schedule.startDate;
368
371
  }
369
372
  }
370
373
  else
@@ -35,13 +35,14 @@ export class PumpMessage {
35
35
  }
36
36
  }
37
37
  public static processPumpConfig_IT(msg: Inbound) {
38
- // packet 24/27/152/155 - Pump Config: IntelliTouch
38
+ // packet 24/27/152/155 - Pump Config: IntelliTouch. These will always be addressable pumps ds & ss are not included.
39
39
  const pumpId = msg.extractPayloadByte(0);
40
40
  let type = msg.extractPayloadByte(1); // Avoid setting this then setting it back if we are mapping to a different value.
41
41
  let isActive = type !== 0 && pumpId <= sys.equipment.maxPumps;
42
42
  // RKS: 04-14-21 - Only create the pump if it is available. If the pump was previously defined as another type
43
43
  // then it will be removed and recreated.
44
- let pump: Pump = sys.pumps.getItemById(pumpId, isActive);
44
+ // RKS: 05-06-23 - The original code did not search for the pump by its address. This is not correct.
45
+ let pump: Pump = sys.pumps.getPumpByAddress(95 + pumpId, isActive);
45
46
  if(isActive) {
46
47
  // Remap the combination pump types.
47
48
  switch (type) {
@@ -59,8 +60,8 @@ export class PumpMessage {
59
60
  break;
60
61
  }
61
62
  if (pump.type !== type) {
62
- sys.pumps.removeItemById(pumpId);
63
- pump = sys.pumps.getItemById(pumpId, isActive);
63
+ sys.pumps.removePumpByAddress(95 + pumpId);
64
+ if (isActive) pump = sys.pumps.getPumpByAddress(95 + pumpId, isActive);
64
65
  }
65
66
  pump.address = pumpId + 95;
66
67
  pump.master = 0;
@@ -308,7 +309,7 @@ export class PumpMessage {
308
309
  // Sample Packet
309
310
  // [255, 0, 255], [165, 33, 15, 16, 27, 46], [1, 128, 1, 2, 0, 1, 6, 2, 12, 4, 9, 11, 7, 6, 7, 128, 8, 132, 3, 15, 5, 3, 234, 128, 46, 108, 58, 2, 232, 220, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [8, 5]
310
311
  const pumpId = msg.extractPayloadByte(0);
311
- const pump = sys.pumps.getItemById(pumpId);
312
+ const pump = sys.pumps.getPumpByAddress(95 + pumpId);
312
313
  // [1, 128, 0, 2, 0, 6, 5, 1, 5, 158, 9, 2, 10, 0, 3, 0, 3, 0, 3, 0, 3, 3, 120, 20, 146, 240, 232, 232, 232, 232, 232]
313
314
  // byte | val |
314
315
  // 0 | 1 | PumpId = 1
@@ -359,7 +360,7 @@ export class PumpMessage {
359
360
  // Sample Packet
360
361
  // [255, 0, 255], [165, 33, 15, 16, 27, 46], [2, 6, 15, 2, 0, 1, 29, 11, 35, 0, 30, 0, 30, 0, 30, 0, 30, 0, 30, 0, 30, 30, 55, 5, 10, 60, 5, 1, 50, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [3, 41]
361
362
  const pumpId = msg.extractPayloadByte(0);
362
- const pump = sys.pumps.getItemById(pumpId);
363
+ const pump = sys.pumps.getPumpByAddress(95 + pumpId);
363
364
  if (typeof pump.model === 'undefined') pump.model = 0;
364
365
  for (let circuitId = 1; circuitId <= sys.board.valueMaps.pumpTypes.get(pump.type).maxCircuits; circuitId++) {
365
366
  let _circuit = msg.extractPayloadByte(circuitId * 2 + 3);
@@ -395,7 +396,7 @@ export class PumpMessage {
395
396
  //[255, 0, 255][165, 33, 15, 16, 27, 46][2, 64, 0, 0, 2, 1, 33, 2, 4, 0, 30, 0, 30, 0, 30, 0, 30, 0, 30, 0, 30, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2, 94]
396
397
  //[255, 0, 255][165, 1, 15, 16, 24, 31][1, 64, 0, 0, 0, 6, 5, 2, 8, 1, 11, 7, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 152, 184, 122, 0, 0, 0, 0, 0][4, 24]
397
398
  const pumpId = msg.extractPayloadByte(0);
398
- const pump = sys.pumps.getItemById(pumpId);
399
+ const pump = sys.pumps.getPumpByAddress(95 + pumpId);
399
400
  if (typeof pump.model === 'undefined') pump.model = 0;
400
401
  for (let circuitId = 1; circuitId <= sys.board.valueMaps.pumpTypes.get(pump.type).maxCircuits; circuitId++) {
401
402
  let _circuit = msg.extractPayloadByte(circuitId * 2 + 3);
@@ -158,52 +158,57 @@ export class RemoteMessage {
158
158
  // RKS: 12-1-22 This message is a message that has been mis-interpreted for quite some time
159
159
  // it appears that early versions of EasyTouch did not include the ability to add more than one pump and only 4 potential
160
160
  // circuits could be set. This comes as 3 bytes per pump setting. If there are no circuits assigned then the pump is not installed.
161
- let isActive = (msg.extractPayloadByte(1, 0) + msg.extractPayloadByte(4, 0) + msg.extractPayloadByte(7, 0) + msg.extractPayloadByte(10, 0)) > 0;
162
- let pump = sys.pumps.find(x => x.address === 96 && (x.master || 0) === 0);
163
- if (!isActive) {
164
- if (typeof pump !== 'undefined') {
165
- let spump = state.pumps.getItemById(pump.id, false);
166
- spump.address = 96;
167
- spump.isActive = false;
168
- sys.pumps.removeItemById(pump.id);
169
- state.pumps.removeItemById(pump.id);
170
- spump.emitEquipmentChange();
171
- }
172
- }
173
- else {
174
- if (typeof pump === 'undefined') pump = sys.pumps.getPumpByAddress(96, true,
175
- {
176
- id: sys.pumps.getNextEquipmentId(),
177
- master: 0,
178
- address: 96,
179
- type: 128,
180
- name: `Pump${sys.pumps.length + 1}`,
181
- flowStepSize: 1,
182
- primingTime: 0,
183
- primingSpeed: 450,
184
- minSpeed: 450,
185
- maxSpeed: 3450
161
+ // RKS: 05-13-23 - As it turns out ScreenLogic always asks for this bullshit and all panels return it. However, if the firmware version is
162
+ // greater than 1.6 it should be ignored.
163
+ let fwVersion = parseFloat(sys.equipment.controllerFirmware);
164
+ if (!isNaN(fwVersion) && fwVersion <= 1.6) {
165
+ let isActive = (msg.extractPayloadByte(1, 0) + msg.extractPayloadByte(4, 0) + msg.extractPayloadByte(7, 0) + msg.extractPayloadByte(10, 0)) > 0;
166
+ let pump = sys.pumps.find(x => x.address === 96 && (x.master || 0) === 0);
167
+ if (!isActive) {
168
+ if (typeof pump !== 'undefined') {
169
+ let spump = state.pumps.getItemById(pump.id, false);
170
+ spump.address = 96;
171
+ spump.isActive = false;
172
+ sys.pumps.removeItemById(pump.id);
173
+ state.pumps.removeItemById(pump.id);
174
+ spump.emitEquipmentChange();
186
175
  }
187
- );
188
- let spump = state.pumps.getItemById(pump.id, true);
189
- spump.name = pump.name;
190
- spump.address = pump.address = 96;
191
- spump.type = pump.type = 128;
192
- pump.isActive = spump.isActive = true;
193
- // Set the circuits on the pump.
194
- let cid = 0;
195
- for (let i = 1; i <= 10; i += 3) {
196
- let circuitId = msg.extractPayloadByte(i, 0);
197
- if (circuitId > 0) {
198
- cid++;
199
- let circ = pump.circuits.getItemById(cid, true);
200
- circ.circuit = circuitId;
201
- circ.speed = (msg.extractPayloadByte(i + 1, 0) * 256) + msg.extractPayloadByte(i + 2, 0);
202
- circ.units = 0;
176
+ }
177
+ else {
178
+ if (typeof pump === 'undefined') pump = sys.pumps.getPumpByAddress(96, true,
179
+ {
180
+ id: sys.pumps.getNextEquipmentId(),
181
+ master: 0,
182
+ address: 96,
183
+ type: 128,
184
+ name: `Pump${sys.pumps.length + 1}`,
185
+ flowStepSize: 1,
186
+ primingTime: 0,
187
+ primingSpeed: 450,
188
+ minSpeed: 450,
189
+ maxSpeed: 3450
190
+ }
191
+ );
192
+ let spump = state.pumps.getItemById(pump.id, true);
193
+ spump.name = pump.name;
194
+ spump.address = pump.address = 96;
195
+ spump.type = pump.type = 128;
196
+ pump.isActive = spump.isActive = true;
197
+ // Set the circuits on the pump.
198
+ let cid = 0;
199
+ for (let i = 1; i <= 10; i += 3) {
200
+ let circuitId = msg.extractPayloadByte(i, 0);
201
+ if (circuitId > 0) {
202
+ cid++;
203
+ let circ = pump.circuits.getItemById(cid, true);
204
+ circ.circuit = circuitId;
205
+ circ.speed = (msg.extractPayloadByte(i + 1, 0) * 256) + msg.extractPayloadByte(i + 2, 0);
206
+ circ.units = 0;
207
+ }
203
208
  }
209
+ if (cid < 4) for (let i = 4; i > cid && i > 0; i--) pump.circuits.removeItemById(i);
210
+ spump.emitEquipmentChange();
204
211
  }
205
- if (cid < 4) for (let i = 4; i > cid && i > 0; i--) pump.circuits.removeItemById(i);
206
- spump.emitEquipmentChange();
207
212
  }
208
213
  }
209
214
  private static processRemoteType(msg: Inbound) {
@@ -67,9 +67,15 @@ export class ChlorinatorStateMessage {
67
67
  // I n t e l l i c h l o r - - 4 0
68
68
  //[16, 2, 0, 3][0, 73, 110, 116, 101, 108, 108, 105, 99, 104, 108, 111, 114, 45, 45, 52, 48][188, 16, 3]
69
69
  // This is the model number of the chlorinator and the address is actually the second byte.
70
- let name = msg.extractPayloadString(1, 16);
70
+ let name = msg.extractPayloadString(1, 16).trimEnd();
71
71
  if (typeof chlor.name === 'undefined' || chlor.name === '') chlor.name = cstate.name = name;
72
- if (typeof chlor.model === 'undefined' || chlor.model === 0) chlor.model = sys.board.valueMaps.chlorinatorModel.getValue(name.toLowerCase());
72
+ if (typeof chlor.model === 'undefined' || chlor.model === 0) {
73
+ chlor.model = sys.board.valueMaps.chlorinatorModel.getValue(name.toLowerCase());
74
+ // With iChlor it does not report the model.
75
+ if (typeof chlor.model === 'undefined') {
76
+ if (name.startsWith('iChlor')) chlor.model = sys.board.valueMaps.chlorinatorModel.getValue('ichlor-ic30');
77
+ }
78
+ }
73
79
  cstate.isActive = chlor.isActive;
74
80
  state.emitEquipmentChanges();
75
81
  break;
@@ -121,8 +121,12 @@ export class EquipmentStateMessage {
121
121
  // Start over because we didn't have communication before but we now do. This will fall into the if
122
122
  // below so that it goes through the intialization process. In this case we didn't see an OCP when we started
123
123
  // but there clearly is one now.
124
- sys.controllerType = ControllerType.Unknown;
125
- state.status = 0;
124
+ (async () => {
125
+ await sys.board.closeAsync();
126
+ logger.info(`Closed ${sys.controllerType} board`);
127
+ sys.controllerType = ControllerType.Unknown;
128
+ state.status = 0;
129
+ })();
126
130
  }
127
131
  if (!state.isInitialized) {
128
132
  msg.isProcessed = true;
@@ -592,9 +596,9 @@ export class EquipmentStateMessage {
592
596
  case 204: // IntelliCenter only.
593
597
  state.batteryVoltage = msg.extractPayloadByte(2) / 50;
594
598
  state.comms.keepAlives = msg.extractPayloadInt(4);
595
- state.time.date = msg.extractPayloadByte(6);
596
- state.time.month = msg.extractPayloadByte(7);
597
599
  state.time.year = msg.extractPayloadByte(8);
600
+ state.time.month = msg.extractPayloadByte(7);
601
+ state.time.date = msg.extractPayloadByte(6);
598
602
  sys.equipment.controllerFirmware = (msg.extractPayloadByte(42) + (msg.extractPayloadByte(43) / 1000)).toString();
599
603
  if (sys.chlorinators.length > 0) {
600
604
  if (msg.extractPayloadByte(37, 255) !== 255) {
@@ -637,6 +641,7 @@ export class EquipmentStateMessage {
637
641
  scover2.name = cover2.name;
638
642
  state.temps.bodies.getItemById(cover2.body + 1).isCovered = scover2.isClosed = (msg.extractPayloadByte(30) & 0x0002) > 0;
639
643
  }
644
+ sys.board.schedules.syncScheduleStates();
640
645
  msg.isProcessed = true;
641
646
  state.emitEquipmentChanges();
642
647
  break;
@@ -105,7 +105,7 @@ export class PumpStateMessage {
105
105
  pump.mode = msg.extractPayloadByte(1);
106
106
  pump.driveState = msg.extractPayloadByte(2);
107
107
  pump.watts = (msg.extractPayloadByte(3) * 256) + msg.extractPayloadByte(4);
108
- pump.rpm = (typeof ptype !== 'undefined' && ptype.maxSpeed > 0) ? (msg.extractPayloadByte(5) * 256) + msg.extractPayloadByte(6) : 0;
108
+ pump.rpm = (typeof ptype !== 'undefined' && (ptype.maxSpeed > 0 || ptype.name === 'vf')) ? (msg.extractPayloadByte(5) * 256) + msg.extractPayloadByte(6) : 0;
109
109
  pump.flow = (typeof ptype !== 'undefined' && ptype.maxFlow > 0) ? msg.extractPayloadByte(7) : 0;
110
110
  pump.ppc = msg.extractPayloadByte(8);
111
111
  pump.status = (msg.extractPayloadByte(11) * 256) + msg.extractPayloadByte(12); // 16-bits of error codes.
@@ -62,7 +62,7 @@ export class NixieEquipment {
62
62
  public async closeAsync() {
63
63
  try {
64
64
  }
65
- catch (err) { logger.error(err); }
65
+ catch (err) { logger.error(`Error closing Nixie Equipment: ${err.message}`); }
66
66
  }
67
67
  }
68
68
  export class NixieChildEquipment extends NixieEquipment {
@@ -79,7 +79,7 @@ export class NixieBody extends NixieEquipment {
79
79
  try {
80
80
  // Here we go we need to set the valve state.
81
81
  if (bstate.isOn !== isOn) {
82
- logger.info(`Nixie: Set Body ${bstate.id}-${bstate.name} to ${isOn}`);
82
+ logger.info(`Nixie: Set Body ${bstate.id}-${bstate.name} to ${isOn}`);
83
83
  }
84
84
  bstate.isOn = isOn;
85
85
  } catch (err) { logger.error(`Nixie Error setting body state ${bstate.id}-${bstate.name}: ${err.message}`); }