nodejs-poolcontroller 7.6.1 → 8.0.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.
- package/.eslintrc.json +36 -45
- package/.github/ISSUE_TEMPLATE/1-bug-report.yml +84 -0
- package/.github/ISSUE_TEMPLATE/2-docs.md +12 -0
- package/.github/ISSUE_TEMPLATE/3-proposal.md +28 -0
- package/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/CONTRIBUTING.md +74 -74
- package/Changelog +242 -215
- package/Dockerfile +17 -17
- package/Gruntfile.js +40 -40
- package/LICENSE +661 -661
- package/README.md +195 -191
- package/anslq25/MessagesMock.ts +218 -0
- package/anslq25/boards/MockBoardFactory.ts +50 -0
- package/anslq25/boards/MockEasyTouchBoard.ts +696 -0
- package/anslq25/boards/MockSystemBoard.ts +217 -0
- package/anslq25/chemistry/MockChlorinator.ts +75 -0
- package/anslq25/pumps/MockPump.ts +84 -0
- package/app.ts +10 -14
- package/config/Config.ts +26 -8
- package/config/VersionCheck.ts +8 -4
- package/controller/Constants.ts +59 -25
- package/controller/Equipment.ts +2667 -2459
- package/controller/Errors.ts +181 -180
- package/controller/Lockouts.ts +534 -436
- package/controller/State.ts +596 -77
- package/controller/boards/AquaLinkBoard.ts +1003 -0
- package/controller/boards/BoardFactory.ts +53 -45
- package/controller/boards/EasyTouchBoard.ts +3079 -2653
- package/controller/boards/IntelliCenterBoard.ts +3821 -4230
- package/controller/boards/IntelliComBoard.ts +69 -63
- package/controller/boards/IntelliTouchBoard.ts +384 -241
- package/controller/boards/NixieBoard.ts +1871 -1675
- package/controller/boards/SunTouchBoard.ts +393 -0
- package/controller/boards/SystemBoard.ts +5244 -4697
- package/controller/comms/Comms.ts +905 -541
- package/controller/comms/ScreenLogic.ts +1663 -0
- package/controller/comms/messages/Messages.ts +382 -54
- package/controller/comms/messages/config/ChlorinatorMessage.ts +8 -4
- package/controller/comms/messages/config/CircuitGroupMessage.ts +5 -2
- package/controller/comms/messages/config/CircuitMessage.ts +82 -13
- package/controller/comms/messages/config/ConfigMessage.ts +3 -1
- package/controller/comms/messages/config/CoverMessage.ts +2 -1
- package/controller/comms/messages/config/CustomNameMessage.ts +31 -30
- package/controller/comms/messages/config/EquipmentMessage.ts +5 -1
- package/controller/comms/messages/config/ExternalMessage.ts +33 -3
- package/controller/comms/messages/config/FeatureMessage.ts +2 -1
- package/controller/comms/messages/config/GeneralMessage.ts +2 -1
- package/controller/comms/messages/config/HeaterMessage.ts +145 -11
- package/controller/comms/messages/config/IntellichemMessage.ts +2 -1
- package/controller/comms/messages/config/OptionsMessage.ts +16 -27
- package/controller/comms/messages/config/PumpMessage.ts +62 -47
- package/controller/comms/messages/config/RemoteMessage.ts +80 -13
- package/controller/comms/messages/config/ScheduleMessage.ts +390 -347
- package/controller/comms/messages/config/SecurityMessage.ts +2 -1
- package/controller/comms/messages/config/ValveMessage.ts +44 -27
- package/controller/comms/messages/status/ChlorinatorStateMessage.ts +44 -91
- package/controller/comms/messages/status/EquipmentStateMessage.ts +139 -30
- package/controller/comms/messages/status/HeaterStateMessage.ts +135 -86
- package/controller/comms/messages/status/IntelliChemStateMessage.ts +448 -445
- package/controller/comms/messages/status/IntelliValveStateMessage.ts +36 -35
- package/controller/comms/messages/status/PumpStateMessage.ts +92 -2
- package/controller/comms/messages/status/VersionMessage.ts +2 -1
- package/controller/nixie/Nixie.ts +173 -162
- package/controller/nixie/NixieEquipment.ts +104 -103
- package/controller/nixie/bodies/Body.ts +120 -120
- package/controller/nixie/bodies/Filter.ts +135 -135
- package/controller/nixie/chemistry/ChemController.ts +2682 -2498
- package/controller/nixie/chemistry/ChemDoser.ts +806 -0
- package/controller/nixie/chemistry/Chlorinator.ts +367 -314
- package/controller/nixie/circuits/Circuit.ts +402 -248
- package/controller/nixie/heaters/Heater.ts +815 -649
- package/controller/nixie/pumps/Pump.ts +934 -661
- package/controller/nixie/schedules/Schedule.ts +319 -257
- package/controller/nixie/valves/Valve.ts +170 -170
- package/defaultConfig.json +346 -286
- package/logger/DataLogger.ts +448 -448
- package/logger/Logger.ts +38 -9
- package/package.json +60 -56
- package/tsconfig.json +25 -25
- package/web/Server.ts +275 -117
- package/web/bindings/aqualinkD.json +560 -0
- package/web/bindings/homeassistant.json +437 -0
- package/web/bindings/influxDB.json +1066 -1021
- package/web/bindings/mqtt.json +721 -654
- package/web/bindings/mqttAlt.json +746 -684
- 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 +188 -136
- package/web/interfaces/httpInterface.ts +148 -124
- package/web/interfaces/influxInterface.ts +283 -245
- package/web/interfaces/mqttInterface.ts +695 -475
- package/web/interfaces/ruleInterface.ts +87 -0
- package/web/services/config/Config.ts +177 -49
- package/web/services/config/ConfigSocket.ts +2 -1
- package/web/services/state/State.ts +154 -3
- package/web/services/state/StateSocket.ts +69 -18
- package/web/services/utilities/Utilities.ts +232 -42
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -52
- package/config copy.json +0 -300
- package/issue_template.md +0 -52
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* nodejs-poolController. An application to control pool equipment.
|
|
2
|
-
Copyright (C) 2016, 2017, 2018, 2019, 2020
|
|
2
|
+
Copyright (C) 2016, 2017, 2018, 2019, 2020, 2021, 2022.
|
|
3
|
+
Russell Goldin, tagyoureit. russ.goldin@gmail.com
|
|
3
4
|
|
|
4
5
|
This program is free software: you can redistribute it and/or modify
|
|
5
6
|
it under the terms of the GNU Affero General Public License as
|
|
@@ -63,7 +64,9 @@ export class HeaterMessage {
|
|
|
63
64
|
break;
|
|
64
65
|
case ControllerType.IntelliTouch:
|
|
65
66
|
case ControllerType.EasyTouch:
|
|
67
|
+
case ControllerType.SunTouch:
|
|
66
68
|
HeaterMessage.processIntelliTouch(msg);
|
|
69
|
+
break;
|
|
67
70
|
}
|
|
68
71
|
}
|
|
69
72
|
private static processIntelliTouch(msg: Inbound) {
|
|
@@ -71,8 +74,22 @@ export class HeaterMessage {
|
|
|
71
74
|
// Gas heater setup in EquipmentStateMessage upon *Touch discovery
|
|
72
75
|
switch (msg.action) {
|
|
73
76
|
// 1 = gas heater, 2 = solar, 3 = heat pump
|
|
74
|
-
case 34:
|
|
75
|
-
case 162:
|
|
77
|
+
case 34: // Somebody requested the configuration
|
|
78
|
+
case 162: // Somebody set the configuration
|
|
79
|
+
// Release any heaters that are tied to Nixie that should not be.
|
|
80
|
+
for (let i = sys.heaters.length - 1; i >= 0; i--) {
|
|
81
|
+
let heater = sys.heaters.getItemByIndex(i);
|
|
82
|
+
if (heater.id <= 4 && heater.master === 1) {
|
|
83
|
+
// Return the heater control back to Touch
|
|
84
|
+
(async function () {
|
|
85
|
+
try {
|
|
86
|
+
await ncp.heaters.deleteHeaterAsync(heater.id);
|
|
87
|
+
logger.debug(`${heater.name} control returned to OCP.`);
|
|
88
|
+
}
|
|
89
|
+
catch (err) { logger.error(`Error with OCP reclaiming control over gas ${heater.name}: ${err}`) }
|
|
90
|
+
})();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
76
93
|
// byte 0
|
|
77
94
|
// 21 = solar or heat pump disabled
|
|
78
95
|
// 23 = solar or heat pump enabled
|
|
@@ -94,6 +111,121 @@ export class HeaterMessage {
|
|
|
94
111
|
// on/off (16) = solar as a heat pump
|
|
95
112
|
// bits 7,8 = stop temp delta
|
|
96
113
|
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
// Determine what type of heater should be in id number 1. If this is a hybrid heater
|
|
117
|
+
// we will be installing it in id 1 although it will perform dual purpose.
|
|
118
|
+
let hasHeater = (msg.extractPayloadByte(0) & 0x01) === 0x01 || true;
|
|
119
|
+
let hasSolar = (msg.extractPayloadByte(0) & 0x02) === 0x02;
|
|
120
|
+
let hasHeatpump = (msg.extractPayloadByte(1) & 0x20) === 0x20;
|
|
121
|
+
let hasHybrid = !hasHeatpump && (msg.extractPayloadByte(1) & 0x10) === 0x10;
|
|
122
|
+
|
|
123
|
+
// Ok so it appears that the heater ids are as follows.
|
|
124
|
+
// 1 = Gas Heater
|
|
125
|
+
// 2 = Solar
|
|
126
|
+
// 3 = UltraTemp (HEATPUMPCOM)
|
|
127
|
+
// 4 = UltraTemp ETi (Hybrid)
|
|
128
|
+
// If an UltraTemp ETi is installed, no other heaters can be installed so they should be removed. This is not
|
|
129
|
+
// an available option for IntelliTouch i10D so it does not apply to it.
|
|
130
|
+
if (!hasHeater) {
|
|
131
|
+
sys.heaters.removeItemById(1);
|
|
132
|
+
state.heaters.removeItemById(1);
|
|
133
|
+
sys.heaters.removeItemById(2);
|
|
134
|
+
state.heaters.removeItemById(2);
|
|
135
|
+
sys.heaters.removeItemById(3);
|
|
136
|
+
state.heaters.removeItemById(3);
|
|
137
|
+
sys.heaters.removeItemById(4);
|
|
138
|
+
state.heaters.removeItemById(4);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
if (hasHybrid) {
|
|
142
|
+
sys.heaters.removeItemById(1);
|
|
143
|
+
state.heaters.removeItemById(1);
|
|
144
|
+
sys.heaters.removeItemById(2);
|
|
145
|
+
state.heaters.removeItemById(2);
|
|
146
|
+
sys.heaters.removeItemById(3);
|
|
147
|
+
state.heaters.removeItemById(3);
|
|
148
|
+
let hybrid = sys.heaters.getItemById(4, true);
|
|
149
|
+
let shybrid = state.heaters.getItemById(4, true);
|
|
150
|
+
// [5, { name: 'hybrid', desc: 'Hybrid', hasAddress: true }],
|
|
151
|
+
shybrid.type = hybrid.type = 5;
|
|
152
|
+
hybrid.address = 112; // Touch only supports address 1.
|
|
153
|
+
hybrid.isActive = true;
|
|
154
|
+
hybrid.master = 0;
|
|
155
|
+
hybrid.body = sys.equipment.shared ? 32 : 0;
|
|
156
|
+
if (typeof hybrid.name === 'undefined') shybrid.name = hybrid.name = 'UltraTemp ETi';
|
|
157
|
+
// The following 2 values need to come from somewhere.
|
|
158
|
+
if (typeof hybrid.economyTime === 'undefined') hybrid.economyTime = 1;
|
|
159
|
+
if (typeof hybrid.maxBoostTemp === 'undefined') hybrid.maxBoostTemp = 5;
|
|
160
|
+
hasHeatpump = false; // You cannot have a heatpump and a hybrid heater.
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
// Hybrid heaters and gas heaters cannot co-exist but it appears you cannot disable the gas
|
|
164
|
+
// heater on the touch panels.
|
|
165
|
+
sys.heaters.removeItemById(4);
|
|
166
|
+
state.heaters.removeItemById(4);
|
|
167
|
+
let heater = sys.heaters.getItemById(1, true);
|
|
168
|
+
let hstate = state.heaters.getItemById(1, true);
|
|
169
|
+
heater.body = sys.equipment.shared ? 32 : 0;
|
|
170
|
+
// [1, { name: 'gas', desc: 'Gas Heater', hasAddress: false }],
|
|
171
|
+
heater.type = hstate.type = 1;
|
|
172
|
+
heater.isActive = true;
|
|
173
|
+
heater.master = 0;
|
|
174
|
+
if (typeof heater.name === 'undefined') heater.name = hstate.name = 'Gas Heater';
|
|
175
|
+
if (typeof heater.cooldownDelay === 'undefined') heater.cooldownDelay = 5;
|
|
176
|
+
}
|
|
177
|
+
// Check to see if a heatpump is installed. This will replace the solar heater so they cannot coexist.
|
|
178
|
+
if (hasHeatpump) {
|
|
179
|
+
// Remove the solar heater. This will be replaced with the heatpump.
|
|
180
|
+
sys.heaters.removeItemById(2);
|
|
181
|
+
state.heaters.removeItemById(2);
|
|
182
|
+
let heatpump = sys.heaters.getItemById(3, true);
|
|
183
|
+
let sheatpump = state.heaters.getItemById(3, true);
|
|
184
|
+
// [3, { name: 'heatpump', desc: 'Heat Pump', hasAddress: true, hasPreference: true }],
|
|
185
|
+
heatpump.type = sheatpump.type = 3;
|
|
186
|
+
heatpump.body = sys.equipment.shared ? 32 : 0;
|
|
187
|
+
heatpump.isActive = true;
|
|
188
|
+
heatpump.master = 0;
|
|
189
|
+
|
|
190
|
+
if (typeof heatpump.name === 'undefined') sheatpump.name = heatpump.name = 'UltraTemp';
|
|
191
|
+
heatpump.heatingEnabled = (msg.extractPayloadByte(1) & 0x01) === 1;
|
|
192
|
+
heatpump.coolingEnabled = (msg.extractPayloadByte(1) & 0x02) === 2;
|
|
193
|
+
sys.board.equipmentIds.invalidIds.add(20); // exclude Aux Extra
|
|
194
|
+
}
|
|
195
|
+
else if (hasSolar) {
|
|
196
|
+
sys.heaters.removeItemById(3);
|
|
197
|
+
state.heaters.removeItemById(3);
|
|
198
|
+
let solar = sys.heaters.getItemById(2, true);
|
|
199
|
+
let ssolar = sys.heaters.getItemById(2, true);
|
|
200
|
+
// [2, { name: 'solar', desc: 'Solar Heater', hasAddress: false, hasPreference: true }],
|
|
201
|
+
solar.type = ssolar.type = 2;
|
|
202
|
+
solar.body = sys.equipment.shared ? 32 : 0;
|
|
203
|
+
solar.isActive = true;
|
|
204
|
+
solar.master = 0;
|
|
205
|
+
if (typeof solar.name === 'undefined') solar.name = ssolar.name = 'Solar Heater';
|
|
206
|
+
solar.freeze = (msg.extractPayloadByte(1) & 0x80) >> 7 === 1;
|
|
207
|
+
solar.coolingEnabled = (msg.extractPayloadByte(1) & 0x20) >> 5 === 1;
|
|
208
|
+
solar.startTempDelta = ((msg.extractPayloadByte(2) & 0xE) >> 1) + 3;
|
|
209
|
+
solar.stopTempDelta = ((msg.extractPayloadByte(2) & 0xC0) >> 6) + 2;
|
|
210
|
+
sys.board.equipmentIds.invalidIds.add(20); // exclude Aux Extra
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
sys.board.equipmentIds.invalidIds.remove(20); // Allow access to Aux Extra
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
sys.board.heaters.updateHeaterServices();
|
|
217
|
+
for (let i = 0; i < sys.bodies.length; i++) {
|
|
218
|
+
let body = sys.bodies.getItemByIndex(i);
|
|
219
|
+
let btemp = state.temps.bodies.getItemById(body.id, body.isActive !== false);
|
|
220
|
+
let opts = sys.board.heaters.getInstalledHeaterTypes(body.id);
|
|
221
|
+
btemp.heaterOptions = opts;
|
|
222
|
+
}
|
|
223
|
+
sys.board.heaters.syncHeaterStates();
|
|
224
|
+
sys.equipment.setEquipmentIds();
|
|
225
|
+
msg.isProcessed = true;
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
/*
|
|
97
229
|
// gas heater only; solar/heatpump/ultratemp disabled
|
|
98
230
|
if ((msg.extractPayloadByte(0) & 0x2) === 0) {
|
|
99
231
|
let heater = sys.heaters.getItemById(1);
|
|
@@ -112,14 +244,14 @@ export class HeaterMessage {
|
|
|
112
244
|
sys.heaters.getItemById(3).isActive = false;
|
|
113
245
|
sys.heaters.getItemById(4).isActive = false;
|
|
114
246
|
sys.board.equipmentIds.invalidIds.remove(20); // include Aux Extra
|
|
115
|
-
|
|
116
|
-
for (let i = 0; i < sys.bodies.length; i++) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
return;
|
|
247
|
+
//sys.equipment.setEquipmentIds();
|
|
248
|
+
//for (let i = 0; i < sys.bodies.length; i++) {
|
|
249
|
+
// let body = sys.bodies.getItemByIndex(i);
|
|
250
|
+
// let btemp = state.temps.bodies.getItemById(body.id, body.isActive !== false);
|
|
251
|
+
// let opts = sys.board.heaters.getInstalledHeaterTypes(body.id);
|
|
252
|
+
// btemp.heaterOptions = opts;
|
|
253
|
+
//}
|
|
254
|
+
return;
|
|
123
255
|
}
|
|
124
256
|
// Ultratemp (+ cooling?);
|
|
125
257
|
else if ((msg.extractPayloadByte(2) & 0x30) === 0x30) {
|
|
@@ -220,7 +352,9 @@ export class HeaterMessage {
|
|
|
220
352
|
sys.board.heaters.syncHeaterStates();
|
|
221
353
|
sys.equipment.setEquipmentIds();
|
|
222
354
|
msg.isProcessed = true;
|
|
355
|
+
*/
|
|
223
356
|
break;
|
|
357
|
+
|
|
224
358
|
}
|
|
225
359
|
}
|
|
226
360
|
private static processCooldownDelay(msg: Inbound) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* nodejs-poolController. An application to control pool equipment.
|
|
2
|
-
Copyright (C) 2016, 2017, 2018, 2019, 2020
|
|
2
|
+
Copyright (C) 2016, 2017, 2018, 2019, 2020, 2021, 2022.
|
|
3
|
+
Russell Goldin, tagyoureit. russ.goldin@gmail.com
|
|
3
4
|
|
|
4
5
|
This program is free software: you can redistribute it and/or modify
|
|
5
6
|
it under the terms of the GNU Affero General Public License as
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* nodejs-poolController. An application to control pool equipment.
|
|
2
|
-
Copyright (C) 2016, 2017, 2018, 2019, 2020
|
|
2
|
+
Copyright (C) 2016, 2017, 2018, 2019, 2020, 2021, 2022.
|
|
3
|
+
Russell Goldin, tagyoureit. russ.goldin@gmail.com
|
|
3
4
|
|
|
4
5
|
This program is free software: you can redistribute it and/or modify
|
|
5
6
|
it under the terms of the GNU Affero General Public License as
|
|
@@ -25,6 +26,7 @@ export class OptionsMessage {
|
|
|
25
26
|
OptionsMessage.processIntelliCenter(msg);
|
|
26
27
|
break;
|
|
27
28
|
case ControllerType.IntelliCom:
|
|
29
|
+
case ControllerType.SunTouch:
|
|
28
30
|
case ControllerType.EasyTouch:
|
|
29
31
|
case ControllerType.IntelliTouch:
|
|
30
32
|
OptionsMessage.processIntelliTouch(msg);
|
|
@@ -123,16 +125,18 @@ export class OptionsMessage {
|
|
|
123
125
|
// We don't want the dual speed pump to even exist unless there are no circuit controlling it.
|
|
124
126
|
// It should not be showing up in our pumps list or emitting state unless the user has defined
|
|
125
127
|
// circuits to it on *Touch interfaces.
|
|
128
|
+
// RSG 1/5/23 - Intellitouch (and Dual Body) accept 8 high speed circuits
|
|
129
|
+
let maxCircuits = sys.controllerType === ControllerType.IntelliTouch ? 8 : 4;
|
|
126
130
|
let arrCircuits = [];
|
|
127
131
|
let pump = sys.pumps.getDualSpeed(true);
|
|
128
|
-
for (let i = 0; i
|
|
132
|
+
for (let i = 0; i < maxCircuits; i++) {
|
|
129
133
|
let val = msg.extractPayloadByte(i);
|
|
130
134
|
if (val > 0) arrCircuits.push(val);
|
|
131
135
|
else pump.circuits.removeItemById(i);
|
|
132
136
|
}
|
|
133
137
|
if (arrCircuits.length > 0) {
|
|
134
138
|
let pump = sys.pumps.getDualSpeed(true);
|
|
135
|
-
for (let j = 1; j <= arrCircuits.length; j++) pump.circuits.getItemById(j, true).circuit = arrCircuits[j];
|
|
139
|
+
for (let j = 1; j <= arrCircuits.length; j++) pump.circuits.getItemById(j, true).circuit = arrCircuits[j-1];
|
|
136
140
|
}
|
|
137
141
|
else sys.pumps.removeItemById(10);
|
|
138
142
|
msg.isProcessed = true;
|
|
@@ -145,42 +149,27 @@ export class OptionsMessage {
|
|
|
145
149
|
// [165,33,16,34,168,10],[0,0,0,254,0,0,0,0,0,0],[2,168 = manual heat mode off
|
|
146
150
|
// [165,33,16,34,168,10],[0,0,0,254,1,0,0,0,0,0],[2,169] = manual heat mode on
|
|
147
151
|
sys.general.options.manualHeat = msg.extractPayloadByte(4) === 1;
|
|
152
|
+
// From https://github.com/tagyoureit/nodejs-poolController/issues/362 = Intellitouch
|
|
153
|
+
// [0,0,0,0,1,x,0,0,0,0] x=0 Manual OP heat Off; x=1 Manual OP heat On
|
|
154
|
+
sys.general.options.manualPriority = msg.extractPayloadByte(5) === 1;
|
|
148
155
|
if ((msg.extractPayloadByte(3) & 0x01) === 1) {
|
|
149
156
|
// only support for 1 ic with EasyTouch
|
|
150
157
|
let chem = sys.chemControllers.getItemByAddress(144, true);
|
|
151
|
-
let schem = state.chemControllers.getItemById(chem.id, true);
|
|
158
|
+
//let schem = state.chemControllers.getItemById(chem.id, true);
|
|
152
159
|
chem.ph.tank.capacity = chem.orp.tank.capacity = 6;
|
|
153
160
|
chem.ph.tank.units = chem.orp.tank.units = '';
|
|
154
161
|
|
|
155
162
|
}
|
|
156
163
|
else {
|
|
157
|
-
|
|
158
|
-
state.chemControllers.removeItemById(chem.id);
|
|
159
|
-
sys.chemControllers.removeItemById(chem.id);
|
|
160
|
-
}
|
|
161
|
-
msg.isProcessed = true;
|
|
162
|
-
break;
|
|
163
|
-
}
|
|
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 {
|
|
164
|
+
if (sys.controllerType !== ControllerType.SunTouch) {
|
|
176
165
|
let chem = sys.chemControllers.getItemByAddress(144);
|
|
177
166
|
state.chemControllers.removeItemById(chem.id);
|
|
178
167
|
sys.chemControllers.removeItemById(chem.id);
|
|
179
168
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
169
|
+
}
|
|
170
|
+
msg.isProcessed = true;
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
184
173
|
}
|
|
185
174
|
}
|
|
186
175
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* nodejs-poolController. An application to control pool equipment.
|
|
2
|
-
Copyright (C) 2016, 2017, 2018, 2019, 2020
|
|
2
|
+
Copyright (C) 2016, 2017, 2018, 2019, 2020, 2021, 2022.
|
|
3
|
+
Russell Goldin, tagyoureit. russ.goldin@gmail.com
|
|
3
4
|
|
|
4
5
|
This program is free software: you can redistribute it and/or modify
|
|
5
6
|
it under the terms of the GNU Affero General Public License as
|
|
@@ -25,6 +26,7 @@ export class PumpMessage {
|
|
|
25
26
|
case ControllerType.IntelliCenter:
|
|
26
27
|
PumpMessage.processIntelliCenterPump(msg);
|
|
27
28
|
break;
|
|
29
|
+
case ControllerType.SunTouch:
|
|
28
30
|
case ControllerType.IntelliCom:
|
|
29
31
|
case ControllerType.EasyTouch:
|
|
30
32
|
case ControllerType.IntelliTouch:
|
|
@@ -36,43 +38,60 @@ export class PumpMessage {
|
|
|
36
38
|
// packet 24/27/152/155 - Pump Config: IntelliTouch
|
|
37
39
|
const pumpId = msg.extractPayloadByte(0);
|
|
38
40
|
let type = msg.extractPayloadByte(1); // Avoid setting this then setting it back if we are mapping to a different value.
|
|
41
|
+
let isActive = type !== 0 && pumpId <= sys.equipment.maxPumps;
|
|
39
42
|
// RKS: 04-14-21 - Only create the pump if it is available. If the pump was previously defined as another type
|
|
40
43
|
// then it will be removed and recreated.
|
|
41
|
-
let pump: Pump = sys.pumps.getItemById(pumpId,
|
|
42
|
-
if
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
pump
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
44
|
+
let pump: Pump = sys.pumps.getItemById(pumpId, isActive);
|
|
45
|
+
if(isActive) {
|
|
46
|
+
// Remap the combination pump types.
|
|
47
|
+
switch (type) {
|
|
48
|
+
case 0:
|
|
49
|
+
case 64:
|
|
50
|
+
case 169:
|
|
51
|
+
break;
|
|
52
|
+
case 255:
|
|
53
|
+
case 128:
|
|
54
|
+
case 134:
|
|
55
|
+
type = 128;
|
|
56
|
+
break;
|
|
57
|
+
default:
|
|
58
|
+
type = 1;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
if (pump.type !== type) {
|
|
62
|
+
sys.pumps.removeItemById(pumpId);
|
|
63
|
+
pump = sys.pumps.getItemById(pumpId, isActive);
|
|
64
|
+
}
|
|
65
|
+
pump.address = pumpId + 95;
|
|
66
|
+
pump.master = 0;
|
|
67
|
+
switch (type) {
|
|
68
|
+
case 0: // none
|
|
69
|
+
pump.type = 0;
|
|
70
|
+
pump.isActive = false;
|
|
71
|
+
break;
|
|
72
|
+
case 64: // vsf
|
|
73
|
+
pump.type = type;
|
|
74
|
+
pump.isActive = true;
|
|
75
|
+
PumpMessage.processVSF_IT(msg);
|
|
76
|
+
break;
|
|
77
|
+
case 255: // vs 3050 on old panels.
|
|
78
|
+
case 128: // vs
|
|
79
|
+
case 134: // vs Ultra Efficiency
|
|
80
|
+
pump.type = 128;
|
|
81
|
+
pump.isActive = true;
|
|
82
|
+
PumpMessage.processVS_IT(msg);
|
|
83
|
+
break;
|
|
84
|
+
case 169: // vs+svrs
|
|
85
|
+
pump.type = 169;
|
|
86
|
+
pump.isActive = true;
|
|
87
|
+
PumpMessage.processVS_IT(msg);
|
|
88
|
+
break;
|
|
89
|
+
default: // vf - type is the background circuit
|
|
90
|
+
pump.type = 1; // force to type 1?
|
|
91
|
+
pump.isActive = true;
|
|
92
|
+
PumpMessage.processVF_IT(msg);
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
76
95
|
if (typeof pump.name === 'undefined') pump.name = sys.board.valueMaps.pumpTypes.get(pump.type).desc;
|
|
77
96
|
const spump = state.pumps.getItemById(pump.id, true);
|
|
78
97
|
spump.name = pump.name;
|
|
@@ -224,6 +243,7 @@ export class PumpMessage {
|
|
|
224
243
|
}
|
|
225
244
|
if (typeof pump.model === 'undefined') pump.model = 0;
|
|
226
245
|
pump.type = type;
|
|
246
|
+
pump.master = 0;
|
|
227
247
|
let spump = state.pumps.getItemById(pump.id, true);
|
|
228
248
|
spump.type = pump.type;
|
|
229
249
|
spump.isActive = pump.isActive = true;
|
|
@@ -312,9 +332,8 @@ export class PumpMessage {
|
|
|
312
332
|
// 18 | 3 | Big endian speed for the speed (1000 rpm with byte(28))
|
|
313
333
|
// 19 | 0 | Circuit speed #8 = No circuit
|
|
314
334
|
// 20 | 3 | Big endian speed for the speed (1000 rpm with byte(29))
|
|
315
|
-
// 21 | 3 | Big
|
|
335
|
+
// 21 | 3 | Big endian speed for the priming speed (1000 rpm with byte(30))
|
|
316
336
|
// All 30 bytes on this message are accounted for except for byte 3 & 4.
|
|
317
|
-
|
|
318
337
|
if (typeof pump.model === 'undefined') pump.model = 0;
|
|
319
338
|
for (let circuitId = 1; circuitId <= sys.board.valueMaps.pumpTypes.get(pump.type).maxCircuits; circuitId++) {
|
|
320
339
|
let _circuit = msg.extractPayloadByte(circuitId * 2 + 3);
|
|
@@ -373,7 +392,8 @@ export class PumpMessage {
|
|
|
373
392
|
}
|
|
374
393
|
private static processVSF_IT(msg: Inbound) {
|
|
375
394
|
// Sample packet
|
|
376
|
-
//
|
|
395
|
+
//[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
|
+
//[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]
|
|
377
397
|
const pumpId = msg.extractPayloadByte(0);
|
|
378
398
|
const pump = sys.pumps.getItemById(pumpId);
|
|
379
399
|
if (typeof pump.model === 'undefined') pump.model = 0;
|
|
@@ -382,14 +402,9 @@ export class PumpMessage {
|
|
|
382
402
|
if (_circuit !== 0){
|
|
383
403
|
const circuit: PumpCircuit = pump.circuits.getItemById(circuitId, true);
|
|
384
404
|
circuit.circuit = _circuit;
|
|
385
|
-
circuit.units =
|
|
386
|
-
(msg.extractPayloadByte(
|
|
387
|
-
|
|
388
|
-
circuit.flow = msg.extractPayloadByte(circuitId * 2 + 4);
|
|
389
|
-
else
|
|
390
|
-
circuit.speed =
|
|
391
|
-
msg.extractPayloadByte(circuitId * 2 + 4) * 256 +
|
|
392
|
-
msg.extractPayloadByte(circuitId + 21);
|
|
405
|
+
circuit.units = (msg.extractPayloadByte(4) >> circuitId - 1 & 1) === 0 ? 1 : 0;
|
|
406
|
+
if (circuit.units) circuit.flow = msg.extractPayloadByte(circuitId * 2 + 4);
|
|
407
|
+
else circuit.speed = msg.extractPayloadByte(circuitId * 2 + 4) * 256 + msg.extractPayloadByte(circuitId + 21);
|
|
393
408
|
}
|
|
394
409
|
else {
|
|
395
410
|
pump.circuits.removeItemById(_circuit);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* nodejs-poolController. An application to control pool equipment.
|
|
2
|
-
Copyright (C) 2016, 2017, 2018, 2019, 2020
|
|
2
|
+
Copyright (C) 2016, 2017, 2018, 2019, 2020, 2021, 2022.
|
|
3
|
+
Russell Goldin, tagyoureit. russ.goldin@gmail.com
|
|
3
4
|
|
|
4
5
|
This program is free software: you can redistribute it and/or modify
|
|
5
6
|
it under the terms of the GNU Affero General Public License as
|
|
@@ -15,7 +16,8 @@ You should have received a copy of the GNU Affero General Public License
|
|
|
15
16
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
17
|
*/
|
|
17
18
|
import {Inbound} from "../Messages";
|
|
18
|
-
import {sys, Remote} from "../../../Equipment";
|
|
19
|
+
import { sys, Remote } from "../../../Equipment";
|
|
20
|
+
import { state } from "../../../State";
|
|
19
21
|
import {ControllerType} from "../../../Constants";
|
|
20
22
|
export class RemoteMessage {
|
|
21
23
|
private static maxCircuits: number=8;
|
|
@@ -58,7 +60,7 @@ export class RemoteMessage {
|
|
|
58
60
|
public static processRemote_IT(msg: Inbound) {
|
|
59
61
|
/* process Spa-side remotes
|
|
60
62
|
for is4 [165,33,16,34,33,11],[id,button1,button2,button3,button4,5,6,7,8,9,10],[chkh,chkl]
|
|
61
|
-
for is10:[165,33,16,34,
|
|
63
|
+
for is10:[165,33,16,34,32,11],[id,button1,button2,button3,button4,btn5,btn1bot,btn2bot,btn3bot,btn4bot,btn5bot],[chkh,chkl]
|
|
62
64
|
[255, 0, 255], [165, 33, 15, 16, 32, 11], [0, 1, 5, 18, 13, 5, 6, 7, 8, 9, 10], [1, 98]
|
|
63
65
|
[255, 0, 255], [165, 33, 15, 16, 32, 11], [1, 8, 2, 7, 7, 5, 8, 9, 8, 9, 3], [1, 83]
|
|
64
66
|
for quicktouch:
|
|
@@ -73,17 +75,29 @@ export class RemoteMessage {
|
|
|
73
75
|
Note: For systems with four iS10/SpaCommand remotes, adding one or two iS4 remotes will affect button function assignments as follows: Assigned button functions 1 - 4 on iS4 #1 are linked with the same functions to buttons 1 - 4 (top row) of iS10 #4. Also, buttons 1 - 4 on iS4 #2 are linked to buttons 6 - 10 (bottom row) of iS10 #4. For example, button 6 on the bottom row of iS10 #4 is linked to button 1 of iS4 #2, button 7 on iS10 #4 is linked to button 2 of iS4 #2, etc.
|
|
74
76
|
|
|
75
77
|
Not sure how packets will come through with 6 controllers on it.
|
|
78
|
+
|
|
79
|
+
// RSG 1.6.23 - Per Screenlogic Config, the IS10#4 shares the bytes with IS4#1/IS4#2.
|
|
80
|
+
// Byte 1 - IS10#1-1 IS4#1-1
|
|
81
|
+
// Byte 2 - IS10#1-2 IS4#1-2
|
|
82
|
+
// Byte 3 - IS10#1-3 IS4#1-3
|
|
83
|
+
// Byte 4 - IS10#1-4 IS4#1-4
|
|
84
|
+
// Byte 5 - IS10#1-5
|
|
85
|
+
// Byte 6 - IS10#1-6 IS4#2-1
|
|
86
|
+
// Byte 7 - IS10#1-7 IS4#2-2
|
|
87
|
+
// Byte 8 - IS10#1-8 IS4#2-3
|
|
88
|
+
// Byte 9 - IS10#1-9 IS4#2-4
|
|
89
|
+
// Byte 10 - IS10#1-10
|
|
76
90
|
|
|
77
91
|
Fixing ID's for lack of having better info.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
92
|
+
1-4 = is10
|
|
93
|
+
5-6 = is4
|
|
94
|
+
7 = QuickTouch
|
|
95
|
+
8 = Spa Command
|
|
82
96
|
*/
|
|
83
97
|
switch (msg.action) {
|
|
84
98
|
case 33: // quicktouch
|
|
85
99
|
{
|
|
86
|
-
const remoteId =
|
|
100
|
+
const remoteId = 7; // what determines 2nd is4?
|
|
87
101
|
const remote: Remote = sys.remotes.getItemById(remoteId, true);
|
|
88
102
|
remote.type = remoteId;
|
|
89
103
|
remote.button1 = msg.extractPayloadByte(0);
|
|
@@ -129,16 +143,69 @@ export class RemoteMessage {
|
|
|
129
143
|
// sample packet from EasyTouch
|
|
130
144
|
// [165,33,16,34,150,16],[0,1,7,8,0,2,250,10,1,144,13,122,15,130,0,0],[4,93]
|
|
131
145
|
// note: spa command may be tied to an already present is10. Need to clarify.
|
|
132
|
-
const remoteId =
|
|
133
|
-
const remote: Remote = sys.remotes.getItemById(remoteId, true);
|
|
134
|
-
remote.pumpId = msg.extractPayloadByte(5);
|
|
135
|
-
remote.stepSize = msg.extractPayloadByte(6);
|
|
136
|
-
remote.type =
|
|
146
|
+
//const remoteId = 8;
|
|
147
|
+
//const remote: Remote = sys.remotes.getItemById(remoteId, true);
|
|
148
|
+
//remote.pumpId = msg.extractPayloadByte(5);
|
|
149
|
+
//remote.stepSize = msg.extractPayloadByte(6);
|
|
150
|
+
//remote.type = 8;
|
|
151
|
+
RemoteMessage.processIntelliFlo4(msg);
|
|
137
152
|
msg.isProcessed = true;
|
|
138
153
|
break;
|
|
139
154
|
}
|
|
140
155
|
}
|
|
141
156
|
}
|
|
157
|
+
private static processIntelliFlo4(msg: Inbound) {
|
|
158
|
+
// RKS: 12-1-22 This message is a message that has been mis-interpreted for quite some time
|
|
159
|
+
// it appears that early versions of EasyTouch did not include the ability to add more than one pump and only 4 potential
|
|
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
|
|
186
|
+
}
|
|
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;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (cid < 4) for (let i = 4; i > cid && i > 0; i--) pump.circuits.removeItemById(i);
|
|
206
|
+
spump.emitEquipmentChange();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
142
209
|
private static processRemoteType(msg: Inbound) {
|
|
143
210
|
let remoteId = 1;
|
|
144
211
|
for (let i = 28; i < msg.payload.length && remoteId <= sys.equipment.maxRemotes; i++) {
|