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.
- package/.eslintrc.json +44 -44
- package/.github/ISSUE_TEMPLATE/bug_report.md +52 -52
- package/CONTRIBUTING.md +74 -74
- package/Changelog +215 -195
- package/Dockerfile +17 -17
- package/Gruntfile.js +40 -40
- package/LICENSE +661 -661
- package/README.md +191 -186
- package/app.ts +2 -0
- package/config/Config.ts +27 -2
- package/config/VersionCheck.ts +33 -14
- package/config copy.json +299 -299
- package/controller/Constants.ts +88 -0
- package/controller/Equipment.ts +2459 -2225
- package/controller/Errors.ts +180 -157
- package/controller/Lockouts.ts +437 -0
- package/controller/State.ts +364 -79
- package/controller/boards/BoardFactory.ts +45 -45
- package/controller/boards/EasyTouchBoard.ts +2653 -2489
- package/controller/boards/IntelliCenterBoard.ts +4230 -3973
- package/controller/boards/IntelliComBoard.ts +63 -63
- package/controller/boards/IntelliTouchBoard.ts +241 -167
- package/controller/boards/NixieBoard.ts +1675 -1105
- package/controller/boards/SystemBoard.ts +4697 -3201
- package/controller/comms/Comms.ts +222 -10
- package/controller/comms/messages/Messages.ts +13 -9
- package/controller/comms/messages/config/ChlorinatorMessage.ts +13 -4
- package/controller/comms/messages/config/CircuitGroupMessage.ts +6 -0
- package/controller/comms/messages/config/CircuitMessage.ts +0 -0
- package/controller/comms/messages/config/ConfigMessage.ts +0 -0
- package/controller/comms/messages/config/CoverMessage.ts +1 -0
- package/controller/comms/messages/config/CustomNameMessage.ts +30 -30
- package/controller/comms/messages/config/EquipmentMessage.ts +4 -0
- package/controller/comms/messages/config/ExternalMessage.ts +53 -33
- package/controller/comms/messages/config/FeatureMessage.ts +8 -1
- package/controller/comms/messages/config/GeneralMessage.ts +8 -0
- package/controller/comms/messages/config/HeaterMessage.ts +14 -28
- package/controller/comms/messages/config/IntellichemMessage.ts +4 -1
- package/controller/comms/messages/config/OptionsMessage.ts +38 -2
- package/controller/comms/messages/config/PumpMessage.ts +4 -20
- package/controller/comms/messages/config/RemoteMessage.ts +4 -0
- package/controller/comms/messages/config/ScheduleMessage.ts +347 -331
- package/controller/comms/messages/config/SecurityMessage.ts +1 -0
- package/controller/comms/messages/config/ValveMessage.ts +13 -3
- package/controller/comms/messages/status/ChlorinatorStateMessage.ts +2 -3
- package/controller/comms/messages/status/EquipmentStateMessage.ts +79 -25
- package/controller/comms/messages/status/HeaterStateMessage.ts +86 -53
- package/controller/comms/messages/status/IntelliChemStateMessage.ts +445 -386
- package/controller/comms/messages/status/IntelliValveStateMessage.ts +35 -35
- package/controller/comms/messages/status/PumpStateMessage.ts +0 -0
- package/controller/comms/messages/status/VersionMessage.ts +0 -0
- package/controller/nixie/Nixie.ts +162 -160
- package/controller/nixie/NixieEquipment.ts +103 -103
- package/controller/nixie/bodies/Body.ts +120 -117
- package/controller/nixie/bodies/Filter.ts +135 -135
- package/controller/nixie/chemistry/ChemController.ts +2498 -2395
- package/controller/nixie/chemistry/Chlorinator.ts +314 -313
- package/controller/nixie/circuits/Circuit.ts +248 -210
- package/controller/nixie/heaters/Heater.ts +649 -441
- package/controller/nixie/pumps/Pump.ts +661 -599
- package/controller/nixie/schedules/Schedule.ts +257 -256
- package/controller/nixie/valves/Valve.ts +170 -170
- package/defaultConfig.json +286 -271
- package/issue_template.md +51 -51
- package/logger/DataLogger.ts +448 -433
- package/logger/Logger.ts +0 -0
- package/package.json +56 -54
- package/tsconfig.json +25 -25
- package/web/Server.ts +522 -31
- package/web/bindings/influxDB.json +1022 -894
- package/web/bindings/mqtt.json +654 -543
- package/web/bindings/mqttAlt.json +684 -574
- package/web/bindings/rulesManager.json +54 -54
- package/web/bindings/smartThings-Hubitat.json +31 -31
- package/web/bindings/valveRelays.json +20 -20
- package/web/bindings/vera.json +25 -25
- package/web/interfaces/baseInterface.ts +136 -136
- package/web/interfaces/httpInterface.ts +124 -122
- package/web/interfaces/influxInterface.ts +245 -240
- package/web/interfaces/mqttInterface.ts +475 -464
- package/web/services/config/Config.ts +181 -152
- package/web/services/config/ConfigSocket.ts +0 -0
- package/web/services/state/State.ts +118 -7
- package/web/services/state/StateSocket.ts +18 -1
- package/web/services/utilities/Utilities.ts +42 -42
|
@@ -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.
|
|
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) {
|
|
@@ -167,7 +174,7 @@ export class ValveMessage {
|
|
|
167
174
|
// for i10d.
|
|
168
175
|
let ndx: number = 2;
|
|
169
176
|
let id = 1;
|
|
170
|
-
for (let i = 0; i < sys.equipment.maxValves
|
|
177
|
+
for (let i = 0; i < sys.equipment.maxValves; i++) {
|
|
171
178
|
if (id === 3 && !sys.equipment.shared) {
|
|
172
179
|
// The intake/return valves are skipped for non-shared systems.
|
|
173
180
|
sys.valves.removeItemById(3);
|
|
@@ -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.
|
|
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.
|
|
68
|
-
if (typeof chlor.
|
|
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
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
|
|
@@ -163,8 +170,8 @@ export class EquipmentStateMessage {
|
|
|
163
170
|
// 1. IntelliCenter has "manual" time set (Internet will automatically adjust) and autoAdjustDST is enabled
|
|
164
171
|
// 2. *Touch is "manual" (only option) and autoAdjustDST is enabled - (same as #1)
|
|
165
172
|
// 3. clock source is "server" isn't an OCP option but can be enabled on the clients
|
|
166
|
-
if (dt.getMinutes() % 5 === 0 && sys.general.options.clockSource === 'server') {
|
|
167
|
-
if ((Math.abs(dt.getTime() - state.time.getTime()) > 60 *
|
|
173
|
+
if (dt.getMinutes() % 5 === 0 && dt.getSeconds() <= 10 && sys.general.options.clockSource === 'server') {
|
|
174
|
+
if ((Math.abs(dt.getTime() - state.time.getTime()) > 60 * 2 * 1000) && !state.time.isUpdating) {
|
|
168
175
|
state.time.isUpdating = true;
|
|
169
176
|
sys.board.system.setDateTimeAsync({ dt, dst: sys.general.options.adjustDST || 0, })
|
|
170
177
|
.then(() => {
|
|
@@ -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
|
-
|
|
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
|
-
}
|
|
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 (
|
|
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
|
-
}
|
|
237
|
+
}
|
|
238
|
+
else tbody.isOn = false;
|
|
217
239
|
}
|
|
218
240
|
if (sys.bodies.length > 2) {
|
|
219
241
|
state.temps.waterSensor3 = fnTempFromByte(msg.extractPayloadByte(20));
|
|
@@ -390,13 +412,14 @@ export class EquipmentStateMessage {
|
|
|
390
412
|
sys.board.circuits.syncCircuitRelayStates();
|
|
391
413
|
sys.board.circuits.syncVirtualCircuitStates();
|
|
392
414
|
sys.board.valves.syncValveStates();
|
|
415
|
+
sys.board.filters.syncFilterStates();
|
|
393
416
|
state.emitControllerChange();
|
|
394
417
|
state.emitEquipmentChanges();
|
|
395
418
|
sys.board.heaters.syncHeaterStates();
|
|
396
419
|
break;
|
|
397
420
|
}
|
|
398
|
-
case ControllerType.IntelliCom:
|
|
399
421
|
case ControllerType.EasyTouch:
|
|
422
|
+
case ControllerType.IntelliCom:
|
|
400
423
|
case ControllerType.IntelliTouch:
|
|
401
424
|
{
|
|
402
425
|
EquipmentStateMessage.processTouchCircuits(msg);
|
|
@@ -405,6 +428,7 @@ export class EquipmentStateMessage {
|
|
|
405
428
|
sys.board.features.syncGroupStates();
|
|
406
429
|
sys.board.circuits.syncVirtualCircuitStates();
|
|
407
430
|
sys.board.valves.syncValveStates();
|
|
431
|
+
sys.board.filters.syncFilterStates();
|
|
408
432
|
state.emitControllerChange();
|
|
409
433
|
state.emitEquipmentChanges();
|
|
410
434
|
sys.board.heaters.syncHeaterStates();
|
|
@@ -495,8 +519,7 @@ export class EquipmentStateMessage {
|
|
|
495
519
|
state.time.date = msg.extractPayloadByte(6);
|
|
496
520
|
state.time.month = msg.extractPayloadByte(7);
|
|
497
521
|
state.time.year = msg.extractPayloadByte(8);
|
|
498
|
-
sys.equipment.controllerFirmware = (msg.extractPayloadByte(42)
|
|
499
|
-
+ (msg.extractPayloadByte(43) / 1000)).toString();
|
|
522
|
+
sys.equipment.controllerFirmware = (msg.extractPayloadByte(42) + (msg.extractPayloadByte(43) / 1000)).toString();
|
|
500
523
|
if (sys.chlorinators.length > 0) {
|
|
501
524
|
if (msg.extractPayloadByte(37, 255) !== 255) {
|
|
502
525
|
const chlor = state.chlorinators.getItemById(1);
|
|
@@ -508,9 +531,38 @@ export class EquipmentStateMessage {
|
|
|
508
531
|
}
|
|
509
532
|
}
|
|
510
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
|
+
}
|
|
511
564
|
msg.isProcessed = true;
|
|
512
|
-
|
|
513
|
-
// state.emitEquipmentChanges();
|
|
565
|
+
state.emitEquipmentChanges();
|
|
514
566
|
break;
|
|
515
567
|
}
|
|
516
568
|
}
|
|
@@ -528,13 +580,15 @@ export class EquipmentStateMessage {
|
|
|
528
580
|
let circuit = sys.circuits.getItemById(circuitId, false, { isActive: false });
|
|
529
581
|
if (circuit.isActive !== false) {
|
|
530
582
|
let cstate = state.circuits.getItemById(circuitId, circuit.isActive);
|
|
531
|
-
|
|
532
|
-
sys.
|
|
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;
|
|
533
586
|
cstate.isOn = isOn;
|
|
534
587
|
cstate.name = circuit.name;
|
|
535
588
|
cstate.nameId = circuit.nameId;
|
|
536
589
|
cstate.showInFeatures = circuit.showInFeatures;
|
|
537
590
|
cstate.type = circuit.type;
|
|
591
|
+
sys.board.circuits.setEndTime(circuit, cstate, isOn);
|
|
538
592
|
if (sys.controllerType === ControllerType.IntelliCenter) {
|
|
539
593
|
// intellitouch sends a separate msg with themes
|
|
540
594
|
switch (circuit.type) {
|
|
@@ -635,7 +689,7 @@ export class EquipmentStateMessage {
|
|
|
635
689
|
case 144: // swim
|
|
636
690
|
sys.board.circuits.sequenceLightGroupAsync(grp.id, 'swim');
|
|
637
691
|
break;
|
|
638
|
-
case 160: //
|
|
692
|
+
case 160: // set
|
|
639
693
|
sys.board.circuits.sequenceLightGroupAsync(grp.id, 'set');
|
|
640
694
|
break;
|
|
641
695
|
case 190: // save
|
|
@@ -1,54 +1,87 @@
|
|
|
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 { Inbound, Protocol } from "../Messages";
|
|
18
|
-
import { state, BodyTempState, HeaterState } from "../../../State";
|
|
19
|
-
import { sys, ControllerType, Heater } from "../../../Equipment";
|
|
20
|
-
|
|
21
|
-
export class HeaterStateMessage {
|
|
22
|
-
public static process(msg: Inbound) {
|
|
23
|
-
if (msg.protocol === Protocol.Heater) {
|
|
24
|
-
switch (msg.action) {
|
|
25
|
-
case
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// 2
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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 { Inbound, Protocol } from "../Messages";
|
|
18
|
+
import { state, BodyTempState, HeaterState } from "../../../State";
|
|
19
|
+
import { sys, ControllerType, Heater } from "../../../Equipment";
|
|
20
|
+
|
|
21
|
+
export class HeaterStateMessage {
|
|
22
|
+
public static process(msg: Inbound) {
|
|
23
|
+
if (msg.protocol === Protocol.Heater) {
|
|
24
|
+
switch (msg.action) {
|
|
25
|
+
case 112: // This is a message from a master controlling MasterTemp
|
|
26
|
+
case 114: // This is a message from a master controlling UltraTemp
|
|
27
|
+
msg.isProcessed = true;
|
|
28
|
+
break;
|
|
29
|
+
case 116:
|
|
30
|
+
HeaterStateMessage.processMasterTempStatus(msg);
|
|
31
|
+
break;
|
|
32
|
+
case 115:
|
|
33
|
+
HeaterStateMessage.processUltraTempStatus(msg);
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
public static processUltraTempStatus(msg: Inbound) {
|
|
39
|
+
// RKS: 07-03-21 - We only know byte 2 at this point for Ultratemp for the 115 message we are processing here. The
|
|
40
|
+
// byte description
|
|
41
|
+
// ------------------------------------------------
|
|
42
|
+
// 0 Unknown (always seems to be 160 for response)
|
|
43
|
+
// 1 Unknown (always 1)
|
|
44
|
+
// 2 Current heater status 0=off, 1=heat, 2=cool
|
|
45
|
+
// 3-9 Unknown
|
|
46
|
+
|
|
47
|
+
// 114 message - outbound response
|
|
48
|
+
//[165, 0, 112, 16, 114, 10][144, 0, 0, 0, 0, 0, 0, 0, 0, 0][2, 49] // OCP to Heater
|
|
49
|
+
// byte description
|
|
50
|
+
// ------------------------------------------------
|
|
51
|
+
// 0 Unknown (always seems to be 144 for request)
|
|
52
|
+
// 1 Current heater status 0=off, 1=heat, 2=cool
|
|
53
|
+
// 3 Believed to be ofset temp
|
|
54
|
+
// 4-9 Unknown
|
|
55
|
+
|
|
56
|
+
// byto 0: always seems to be 144 for outbound
|
|
57
|
+
// byte 1: Sets heater mode to 0 = Off 1 = Heat 2 = Cool
|
|
58
|
+
//[165, 0, 16, 112, 115, 10][160, 1, 0, 3, 0, 0, 0, 0, 0, 0][2, 70] // Heater Reply
|
|
59
|
+
let heater: Heater = sys.heaters.getItemByAddress(msg.source);
|
|
60
|
+
let sheater = state.heaters.getItemById(heater.id);
|
|
61
|
+
let byte = msg.extractPayloadByte(2);
|
|
62
|
+
sheater.isOn = byte >= 1;
|
|
63
|
+
sheater.isCooling = byte === 2;
|
|
64
|
+
sheater.commStatus = 0;
|
|
65
|
+
state.equipment.messages.removeItemByCode(`heater:${heater.id}:comms`);
|
|
66
|
+
msg.isProcessed = true;
|
|
67
|
+
}
|
|
68
|
+
public static processMasterTempStatus(msg: Inbound) {
|
|
69
|
+
//[255, 0, 255][165, 0, 16, 112, 116, 23][67, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 10, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0][2, 66]
|
|
70
|
+
// Byte 1 is the indicator to which setpoint it is heating to.
|
|
71
|
+
// Byte 8 increments over time when the heater is on.
|
|
72
|
+
// Byte 13 looks like the mode the heater is in for instance it is in cooldown mode.
|
|
73
|
+
// 0 = Normal
|
|
74
|
+
// 2 = ??????
|
|
75
|
+
// 6 = Cooldown
|
|
76
|
+
// Byte 14 looks like the cooldown delay in minutes.
|
|
77
|
+
let heater: Heater = sys.heaters.getItemByAddress(msg.source);
|
|
78
|
+
let sheater = state.heaters.getItemById(heater.id);
|
|
79
|
+
let byte = msg.extractPayloadByte(1);
|
|
80
|
+
sheater.isOn = byte >= 1;
|
|
81
|
+
sheater.isCooling = false;
|
|
82
|
+
sheater.commStatus = 0;
|
|
83
|
+
state.equipment.messages.removeItemByCode(`heater:${heater.id}:comms`);
|
|
84
|
+
msg.isProcessed = true;
|
|
85
|
+
}
|
|
86
|
+
|
|
54
87
|
}
|