nodejs-poolcontroller 8.3.0 → 8.4.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 +36 -36
- package/.github/ISSUE_TEMPLATE/1-bug-report.yml +84 -84
- package/.github/ISSUE_TEMPLATE/2-docs.md +12 -12
- package/.github/ISSUE_TEMPLATE/3-proposal.md +28 -28
- package/.github/ISSUE_TEMPLATE/config.yml +8 -8
- package/.github/copilot-instructions.md +63 -63
- package/.github/workflows/ghcr-publish.yml +67 -67
- package/157_issues.md +101 -0
- package/AGENTS.md +613 -0
- package/CONTRIBUTING.md +74 -74
- package/Changelog +292 -284
- package/Dockerfile +62 -62
- package/Gruntfile.js +40 -40
- package/LICENSE +661 -661
- package/README.md +329 -309
- package/anslq25/MessagesMock.ts +221 -221
- package/anslq25/boards/MockBoardFactory.ts +49 -49
- package/anslq25/boards/MockEasyTouchBoard.ts +696 -696
- package/anslq25/boards/MockSystemBoard.ts +216 -216
- package/anslq25/chemistry/MockChlorinator.ts +98 -98
- package/anslq25/pumps/MockPump.ts +83 -83
- package/app.ts +115 -115
- package/config/Config.ts +0 -0
- package/config/VersionCheck.ts +0 -0
- package/controller/Constants.ts +809 -805
- package/controller/Equipment.ts +2737 -2664
- package/controller/Errors.ts +181 -181
- package/controller/Lockouts.ts +549 -549
- package/controller/State.ts +3746 -3701
- package/controller/boards/AquaLinkBoard.ts +1175 -1003
- package/controller/boards/BoardFactory.ts +53 -53
- package/controller/boards/EasyTouchBoard.ts +3246 -3202
- package/controller/boards/IntelliCenterBoard.ts +4581 -3899
- package/controller/boards/IntelliComBoard.ts +69 -69
- package/controller/boards/IntelliTouchBoard.ts +382 -382
- package/controller/boards/NixieBoard.ts +1947 -1944
- package/controller/boards/SunTouchBoard.ts +401 -400
- package/controller/boards/SystemBoard.ts +5303 -5268
- package/controller/comms/Comms.ts +1278 -1255
- package/controller/comms/ScreenLogic.ts +1665 -1665
- package/controller/comms/messages/Messages.ts +1627 -1406
- package/controller/comms/messages/config/ChlorinatorMessage.ts +5 -0
- package/controller/comms/messages/config/CircuitGroupMessage.ts +0 -0
- package/controller/comms/messages/config/CircuitMessage.ts +0 -0
- package/controller/comms/messages/config/ConfigMessage.ts +6 -0
- package/controller/comms/messages/config/CoverMessage.ts +0 -0
- package/controller/comms/messages/config/CustomNameMessage.ts +31 -31
- package/controller/comms/messages/config/EquipmentMessage.ts +250 -210
- package/controller/comms/messages/config/ExternalMessage.ts +1051 -903
- package/controller/comms/messages/config/FeatureMessage.ts +0 -0
- package/controller/comms/messages/config/GeneralMessage.ts +65 -0
- package/controller/comms/messages/config/HeaterMessage.ts +0 -0
- package/controller/comms/messages/config/IntellichemMessage.ts +0 -0
- package/controller/comms/messages/config/OptionsMessage.ts +207 -174
- package/controller/comms/messages/config/PumpMessage.ts +427 -421
- package/controller/comms/messages/config/RemoteMessage.ts +0 -0
- package/controller/comms/messages/config/ScheduleMessage.ts +401 -390
- package/controller/comms/messages/config/SecurityMessage.ts +37 -13
- package/controller/comms/messages/config/ValveMessage.ts +0 -0
- package/controller/comms/messages/status/ChlorinatorStateMessage.ts +0 -0
- package/controller/comms/messages/status/EquipmentStateMessage.ts +940 -822
- package/controller/comms/messages/status/HeaterStateMessage.ts +147 -135
- package/controller/comms/messages/status/IntelliChemStateMessage.ts +448 -448
- package/controller/comms/messages/status/IntelliValveStateMessage.ts +36 -36
- package/controller/comms/messages/status/NeptuneModbusStateMessage.ts +217 -0
- package/controller/comms/messages/status/PumpStateMessage.ts +0 -0
- package/controller/comms/messages/status/RegalModbusStateMessage.ts +410 -410
- package/controller/comms/messages/status/VersionMessage.ts +152 -41
- package/controller/nixie/Nixie.ts +173 -173
- package/controller/nixie/NixieEquipment.ts +104 -104
- package/controller/nixie/bodies/Body.ts +120 -120
- package/controller/nixie/bodies/Filter.ts +135 -135
- package/controller/nixie/chemistry/ChemController.ts +2756 -2724
- package/controller/nixie/chemistry/ChemDoser.ts +806 -806
- package/controller/nixie/chemistry/Chlorinator.ts +367 -367
- package/controller/nixie/circuits/Circuit.ts +478 -478
- package/controller/nixie/heaters/Heater.ts +843 -834
- package/controller/nixie/pumps/Pump.ts +1336 -1193
- package/controller/nixie/schedules/Schedule.ts +401 -401
- package/controller/nixie/valves/Valve.ts +170 -170
- package/defaultConfig.json +352 -352
- package/docker-compose.yml +32 -31
- package/logger/DataLogger.ts +448 -448
- package/logger/Logger.ts +459 -436
- package/package.json +58 -58
- package/sendSocket.js +32 -32
- package/tsconfig.json +26 -25
- package/types/express-multer.d.ts +32 -32
- package/web/Server.ts +1939 -1927
- package/web/bindings/aqualinkD.json +559 -559
- package/web/bindings/influxDB.json +1066 -1066
- package/web/bindings/mqtt.json +721 -721
- package/web/bindings/mqttAlt.json +746 -746
- 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 -188
- package/web/interfaces/httpInterface.ts +148 -148
- package/web/interfaces/influxInterface.ts +283 -283
- package/web/interfaces/mqttInterface.ts +695 -695
- package/web/interfaces/ruleInterface.ts +101 -87
- package/web/services/config/Config.ts +1212 -1053
- package/web/services/config/ConfigSocket.ts +0 -0
- package/web/services/state/State.ts +21 -0
- package/web/services/state/StateSocket.ts +28 -0
- package/web/services/utilities/Utilities.ts +233 -233
|
File without changes
|
|
@@ -17,45 +17,110 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
17
17
|
*/
|
|
18
18
|
import { Inbound } from "../Messages";
|
|
19
19
|
import { sys, General } from "../../../Equipment";
|
|
20
|
+
import { ControllerType } from "../../../Constants";
|
|
20
21
|
import { logger } from "../../../../logger/Logger";
|
|
21
22
|
export class GeneralMessage {
|
|
23
|
+
private static isIntellicenterV3(): boolean {
|
|
24
|
+
return sys.controllerType === ControllerType.IntelliCenter && sys.equipment.isIntellicenterV3 === true;
|
|
25
|
+
}
|
|
26
|
+
private static getTrimmed(msg: Inbound, start: number, len: number): string {
|
|
27
|
+
return (msg.extractPayloadString(start, len) || '').replace(/\0+$/g, '').trim();
|
|
28
|
+
}
|
|
22
29
|
public static process(msg: Inbound): void {
|
|
30
|
+
const isIntellicenterV3 = GeneralMessage.isIntellicenterV3();
|
|
23
31
|
switch (msg.extractPayloadByte(1)) {
|
|
24
32
|
case 0:
|
|
33
|
+
if (isIntellicenterV3) {
|
|
34
|
+
// v3.008+ sends location-focused data for item 0.
|
|
35
|
+
const zip = GeneralMessage.getTrimmed(msg, 2, 6);
|
|
36
|
+
if (zip.length > 0) sys.general.location.zip = zip;
|
|
37
|
+
// In captured v3.008 packets, bytes 13/14 map cleanly to longitude magnitude.
|
|
38
|
+
const lonLo = msg.extractPayloadByte(13, 255);
|
|
39
|
+
const lonHi = msg.extractPayloadByte(14, 255);
|
|
40
|
+
if (lonLo !== 255 && lonHi !== 255) {
|
|
41
|
+
const lon = ((lonHi * 256) + lonLo) / 100;
|
|
42
|
+
if (!isNaN(lon) && lon > 0 && lon <= 180) sys.general.location.longitude = -lon;
|
|
43
|
+
}
|
|
44
|
+
msg.isProcessed = true;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
25
47
|
sys.general.alias = msg.extractPayloadString(2, 16);
|
|
26
48
|
sys.general.owner.name = msg.extractPayloadString(18, 16);
|
|
27
49
|
sys.general.location.zip = msg.extractPayloadString(34, 6);
|
|
28
50
|
msg.isProcessed = true;
|
|
29
51
|
break;
|
|
30
52
|
case 1:
|
|
53
|
+
if (isIntellicenterV3) {
|
|
54
|
+
// v3.008+ item 1 carries city text (not phone fields).
|
|
55
|
+
const city = GeneralMessage.getTrimmed(msg, 2, 32);
|
|
56
|
+
if (city.length > 0) sys.general.location.city = city;
|
|
57
|
+
msg.isProcessed = true;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
31
60
|
sys.general.owner.phone = msg.extractPayloadString(2, 20);
|
|
32
61
|
sys.general.owner.phone2 = msg.extractPayloadString(21, 15);
|
|
33
62
|
sys.general.location.latitude = ((msg.extractPayloadByte(35) * 256) + msg.extractPayloadByte(34)) / 100;
|
|
34
63
|
msg.isProcessed = true;
|
|
35
64
|
break;
|
|
36
65
|
case 2:
|
|
66
|
+
if (isIntellicenterV3) {
|
|
67
|
+
const owner = GeneralMessage.getTrimmed(msg, 2, 16);
|
|
68
|
+
if (owner.length > 0) sys.general.owner.name = owner;
|
|
69
|
+
msg.isProcessed = true;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
37
72
|
sys.general.location.address = msg.extractPayloadString(2, 32);
|
|
38
73
|
sys.general.location.longitude = -(((msg.extractPayloadByte(35) * 256) + msg.extractPayloadByte(34)) / 100);
|
|
39
74
|
msg.isProcessed = true;
|
|
40
75
|
break;
|
|
41
76
|
case 3:
|
|
77
|
+
if (isIntellicenterV3) {
|
|
78
|
+
const email = GeneralMessage.getTrimmed(msg, 2, 32);
|
|
79
|
+
if (email.length > 0) sys.general.owner.email = email;
|
|
80
|
+
msg.isProcessed = true;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
42
83
|
sys.general.owner.email = msg.extractPayloadString(2, 32);
|
|
43
84
|
sys.general.location.timeZone = msg.extractPayloadByte(34);
|
|
44
85
|
msg.isProcessed = true;
|
|
45
86
|
break;
|
|
46
87
|
case 4:
|
|
88
|
+
if (isIntellicenterV3) {
|
|
89
|
+
const email2 = GeneralMessage.getTrimmed(msg, 2, 32);
|
|
90
|
+
if (email2.length > 0) sys.general.owner.email2 = email2;
|
|
91
|
+
msg.isProcessed = true;
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
47
94
|
sys.general.owner.email2 = msg.extractPayloadString(2, 32);
|
|
48
95
|
msg.isProcessed = true;
|
|
49
96
|
break;
|
|
50
97
|
case 5:
|
|
98
|
+
if (isIntellicenterV3) {
|
|
99
|
+
const country = GeneralMessage.getTrimmed(msg, 2, 32);
|
|
100
|
+
if (country.length > 0) sys.general.location.country = country;
|
|
101
|
+
msg.isProcessed = true;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
51
104
|
sys.general.location.country = msg.extractPayloadString(2, 32);
|
|
52
105
|
msg.isProcessed = true;
|
|
53
106
|
break;
|
|
54
107
|
case 6:
|
|
108
|
+
if (isIntellicenterV3) {
|
|
109
|
+
const city = GeneralMessage.getTrimmed(msg, 2, 32);
|
|
110
|
+
if (city.length > 0) sys.general.location.city = city;
|
|
111
|
+
msg.isProcessed = true;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
55
114
|
sys.general.location.city = msg.extractPayloadString(2, 32);
|
|
56
115
|
msg.isProcessed = true;
|
|
57
116
|
break;
|
|
58
117
|
case 7:
|
|
118
|
+
if (isIntellicenterV3) {
|
|
119
|
+
const stateText = GeneralMessage.getTrimmed(msg, 2, 32);
|
|
120
|
+
if (stateText.length > 0) sys.general.location.state = stateText;
|
|
121
|
+
msg.isProcessed = true;
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
59
124
|
sys.general.location.state = msg.extractPayloadString(2, 32);
|
|
60
125
|
msg.isProcessed = true;
|
|
61
126
|
break;
|
|
File without changes
|
|
File without changes
|
|
@@ -1,175 +1,208 @@
|
|
|
1
|
-
/* nodejs-poolController. An application to control pool equipment.
|
|
2
|
-
Copyright (C) 2016, 2017, 2018, 2019, 2020, 2021, 2022.
|
|
3
|
-
Russell Goldin, tagyoureit. russ.goldin@gmail.com
|
|
4
|
-
|
|
5
|
-
This program is free software: you can redistribute it and/or modify
|
|
6
|
-
it under the terms of the GNU Affero General Public License as
|
|
7
|
-
published by the Free Software Foundation, either version 3 of the
|
|
8
|
-
License, or (at your option) any later version.
|
|
9
|
-
|
|
10
|
-
This program is distributed in the hope that it will be useful,
|
|
11
|
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
-
GNU Affero General Public License for more details.
|
|
14
|
-
|
|
15
|
-
You should have received a copy of the GNU Affero General Public License
|
|
16
|
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
-
*/
|
|
18
|
-
import { Inbound } from "../Messages";
|
|
19
|
-
import { sys } from "../../../Equipment";
|
|
20
|
-
import { state } from "../../../State";
|
|
21
|
-
import { ControllerType } from "../../../Constants";
|
|
22
|
-
export class OptionsMessage {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
case ControllerType.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
sys.
|
|
62
|
-
|
|
63
|
-
sys.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
1
|
+
/* nodejs-poolController. An application to control pool equipment.
|
|
2
|
+
Copyright (C) 2016, 2017, 2018, 2019, 2020, 2021, 2022.
|
|
3
|
+
Russell Goldin, tagyoureit. russ.goldin@gmail.com
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU Affero General Public License as
|
|
7
|
+
published by the Free Software Foundation, either version 3 of the
|
|
8
|
+
License, or (at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU Affero General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
import { Inbound } from "../Messages";
|
|
19
|
+
import { sys } from "../../../Equipment";
|
|
20
|
+
import { state } from "../../../State";
|
|
21
|
+
import { ControllerType } from "../../../Constants";
|
|
22
|
+
export class OptionsMessage {
|
|
23
|
+
private static decodeFreezeOverride(raw: number): number {
|
|
24
|
+
// v3.008 captures show this as a compact code where 0 => 30 min and 1 => 90 min.
|
|
25
|
+
return raw <= 3 ? (30 + (raw * 60)) : raw;
|
|
26
|
+
}
|
|
27
|
+
public static process(msg: Inbound): void {
|
|
28
|
+
switch (sys.controllerType) {
|
|
29
|
+
case ControllerType.IntelliCenter:
|
|
30
|
+
OptionsMessage.processIntelliCenter(msg);
|
|
31
|
+
break;
|
|
32
|
+
case ControllerType.IntelliCom:
|
|
33
|
+
case ControllerType.SunTouch:
|
|
34
|
+
case ControllerType.EasyTouch:
|
|
35
|
+
case ControllerType.IntelliTouch:
|
|
36
|
+
OptionsMessage.processIntelliTouch(msg);
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
private static processIntelliCenter(msg: Inbound) {
|
|
41
|
+
switch (msg.action) {
|
|
42
|
+
case 30:
|
|
43
|
+
switch (msg.extractPayloadByte(1)) {
|
|
44
|
+
case 0:
|
|
45
|
+
{
|
|
46
|
+
if ((msg.extractPayloadByte(13) & 32) === 32)
|
|
47
|
+
sys.general.options.clockSource = 'internet';
|
|
48
|
+
else if (sys.general.options.clockSource !== 'server')
|
|
49
|
+
sys.general.options.clockSource = 'manual';
|
|
50
|
+
sys.general.options.clockMode = (msg.extractPayloadByte(13) & 64) === 64 ? 24 : 12;
|
|
51
|
+
if (sys.general.options.clockSource !== 'server' || typeof sys.general.options.adjustDST === 'undefined') sys.general.options.adjustDST = (msg.extractPayloadByte(13) & 128) === 128;
|
|
52
|
+
// No pumpDelay
|
|
53
|
+
//[255, 0, 255][165, 63, 15, 16, 30, 40][0, 0, 1, 129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 149, 29, 35, 3, 0, 0, 92, 81, 91, 81, 3, 3, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0][4, 193]
|
|
54
|
+
// pumpDelay
|
|
55
|
+
//[255, 0, 255][165, 63, 15, 16, 30, 40][0, 0, 1, 129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 149, 29, 35, 3, 0, 0, 92, 81, 91, 81, 3, 3, 0, 0, 15, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0][4, 194]
|
|
56
|
+
sys.general.options.pumpDelay = msg.extractPayloadByte(29) === 1;
|
|
57
|
+
// No cooldownDelay
|
|
58
|
+
//[255, 0, 255][165, 63, 15, 16, 30, 40][0, 0, 1, 129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 149, 29, 35, 3, 0, 0, 92, 81, 91, 81, 3, 3, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0][4, 193]
|
|
59
|
+
// cooldownDelay
|
|
60
|
+
//[255, 0, 255][165, 63, 15, 16, 30, 40][0, 0, 1, 129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 149, 29, 35, 3, 0, 0, 92, 81, 91, 81, 3, 3, 0, 0, 15, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0][4, 194]
|
|
61
|
+
sys.general.options.cooldownDelay = msg.extractPayloadByte(30) === 1;
|
|
62
|
+
let manualPriorityByte = msg.extractPayloadByte(38, 255);
|
|
63
|
+
const isIntellicenterV3 = (sys.controllerType === ControllerType.IntelliCenter && sys.equipment.isIntellicenterV3);
|
|
64
|
+
if (isIntellicenterV3) {
|
|
65
|
+
const v3ManualPriorityByte = msg.extractPayloadByte(28, 255);
|
|
66
|
+
if (v3ManualPriorityByte === 0 || v3ManualPriorityByte === 1) manualPriorityByte = v3ManualPriorityByte;
|
|
67
|
+
const freezeCycleTime = msg.extractPayloadByte(26, 255);
|
|
68
|
+
if (freezeCycleTime !== 255) sys.general.options.freezeCycleTime = freezeCycleTime;
|
|
69
|
+
const freezeOverrideRaw = msg.extractPayloadByte(27, 255);
|
|
70
|
+
if (freezeOverrideRaw !== 255) sys.general.options.freezeOverride = OptionsMessage.decodeFreezeOverride(freezeOverrideRaw);
|
|
71
|
+
}
|
|
72
|
+
if (manualPriorityByte !== 255) sys.general.options.manualPriority = manualPriorityByte === 1;
|
|
73
|
+
sys.general.options.manualHeat = msg.extractPayloadByte(39) === 1;
|
|
74
|
+
let fnTranslateByte = (byte):number => { return (byte & 0x007F) * (((byte & 0x0080) > 0) ? -1 : 1); }
|
|
75
|
+
sys.equipment.tempSensors.setCalibration('water1', fnTranslateByte(msg.extractPayloadByte(3)));
|
|
76
|
+
sys.equipment.tempSensors.setCalibration('solar1', fnTranslateByte(msg.extractPayloadByte(4)));
|
|
77
|
+
sys.equipment.tempSensors.setCalibration('air', fnTranslateByte(msg.extractPayloadByte(5)));
|
|
78
|
+
sys.equipment.tempSensors.setCalibration('water2', fnTranslateByte(msg.extractPayloadByte(6)));
|
|
79
|
+
sys.equipment.tempSensors.setCalibration('solar2', fnTranslateByte(msg.extractPayloadByte(7)));
|
|
80
|
+
sys.equipment.tempSensors.setCalibration('water3', fnTranslateByte(msg.extractPayloadByte(8)));
|
|
81
|
+
sys.equipment.tempSensors.setCalibration('solar3', fnTranslateByte(msg.extractPayloadByte(9)));
|
|
82
|
+
sys.equipment.tempSensors.setCalibration('water4', fnTranslateByte(msg.extractPayloadByte(10)));
|
|
83
|
+
sys.equipment.tempSensors.setCalibration('solar4', fnTranslateByte(msg.extractPayloadByte(11)));
|
|
84
|
+
|
|
85
|
+
// When we complete our transition for the calibration make this go away.
|
|
86
|
+
//sys.general.options.waterTempAdj2 = (msg.extractPayloadByte(2) & 0x007F) * (((msg.extractPayloadByte(2) & 0x0080) > 0) ? -1 : 1);
|
|
87
|
+
//sys.general.options.waterTempAdj1 = (msg.extractPayloadByte(3) & 0x007F) * (((msg.extractPayloadByte(3) & 0x0080) > 0) ? -1 : 1);
|
|
88
|
+
//sys.general.options.solarTempAdj1 = (msg.extractPayloadByte(4) & 0x007F) * (((msg.extractPayloadByte(4) & 0x0080) > 0) ? -1 : 1);
|
|
89
|
+
//sys.general.options.airTempAdj = (msg.extractPayloadByte(5) & 0x007F) * (((msg.extractPayloadByte(5) & 0x0080) > 0) ? -1 : 1);
|
|
90
|
+
//sys.general.options.waterTempAdj2 = (msg.extractPayloadByte(6) & 0x007F) * (((msg.extractPayloadByte(6) & 0x0080) > 0) ? -1 : 1);
|
|
91
|
+
|
|
92
|
+
// Somewhere in here are the units.
|
|
93
|
+
|
|
94
|
+
// v3.004+: payload layout shifted by 1 byte vs v1.x (timestamp insertion earlier in the packet).
|
|
95
|
+
// Evidence: replay.21 Action 30 type 0 has [.., 85,100,94,103, 3,3 ..] at bytes 19-24.
|
|
96
|
+
const poolHeatNdx = isIntellicenterV3 ? 19 : 20;
|
|
97
|
+
const poolCoolNdx = isIntellicenterV3 ? 20 : 21;
|
|
98
|
+
const spaHeatNdx = isIntellicenterV3 ? 21 : 22;
|
|
99
|
+
const spaCoolNdx = isIntellicenterV3 ? 22 : 23;
|
|
100
|
+
const poolModeNdx = isIntellicenterV3 ? 23 : 24;
|
|
101
|
+
const spaModeNdx = isIntellicenterV3 ? 24 : 25;
|
|
102
|
+
|
|
103
|
+
let body = sys.bodies.getItemById(1, sys.equipment.maxBodies > 0);
|
|
104
|
+
body.heatMode = msg.extractPayloadByte(poolModeNdx);
|
|
105
|
+
body.heatSetpoint = msg.extractPayloadByte(poolHeatNdx);
|
|
106
|
+
body.coolSetpoint = msg.extractPayloadByte(poolCoolNdx);
|
|
107
|
+
// Keep runtime state in sync with config values so UIs (dashPanel/MQTT/etc) reflect
|
|
108
|
+
// authoritative OCP updates, including changes initiated by other panels (Wireless/OP).
|
|
109
|
+
let sbody = state.temps.bodies.getItemById(1, true);
|
|
110
|
+
sbody.heatMode = body.heatMode;
|
|
111
|
+
sbody.heatSetpoint = body.heatSetpoint;
|
|
112
|
+
sbody.coolSetpoint = body.coolSetpoint;
|
|
113
|
+
|
|
114
|
+
body = sys.bodies.getItemById(2, sys.equipment.maxBodies > 1);
|
|
115
|
+
body.heatMode = msg.extractPayloadByte(spaModeNdx);
|
|
116
|
+
body.heatSetpoint = msg.extractPayloadByte(spaHeatNdx);
|
|
117
|
+
body.coolSetpoint = msg.extractPayloadByte(spaCoolNdx);
|
|
118
|
+
sbody = state.temps.bodies.getItemById(2, true);
|
|
119
|
+
sbody.heatMode = body.heatMode;
|
|
120
|
+
sbody.heatSetpoint = body.heatSetpoint;
|
|
121
|
+
sbody.coolSetpoint = body.coolSetpoint;
|
|
122
|
+
|
|
123
|
+
//body = sys.bodies.getItemById(3, sys.equipment.maxBodies > 2);
|
|
124
|
+
//body.heatMode = msg.extractPayloadByte(26);
|
|
125
|
+
//body.heatSetpoint = msg.extractPayloadByte(21);
|
|
126
|
+
//body.manualHeat = sys.general.options.manualHeat;
|
|
127
|
+
//body = sys.bodies.getItemById(4, sys.equipment.maxBodies > 3);
|
|
128
|
+
//body.heatMode = msg.extractPayloadByte(27);
|
|
129
|
+
//body.heatSetpoint = msg.extractPayloadByte(23);
|
|
130
|
+
msg.isProcessed = true;
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
case 1: // Vacation mode
|
|
134
|
+
let yy = msg.extractPayloadByte(4) + 2000;
|
|
135
|
+
let mm = msg.extractPayloadByte(5);
|
|
136
|
+
let dd = msg.extractPayloadByte(6);
|
|
137
|
+
sys.general.options.vacation.startDate = new Date(yy, mm - 1, dd);
|
|
138
|
+
yy = msg.extractPayloadByte(7) + 2000;
|
|
139
|
+
mm = msg.extractPayloadByte(8);
|
|
140
|
+
dd = msg.extractPayloadByte(9);
|
|
141
|
+
sys.general.options.vacation.endDate = new Date(yy, mm - 1, dd);
|
|
142
|
+
sys.general.options.vacation.enabled = msg.extractPayloadByte(2) > 0;
|
|
143
|
+
sys.general.options.vacation.useTimeframe = msg.extractPayloadByte(3) > 0;
|
|
144
|
+
msg.isProcessed = true;
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
msg.isProcessed = true;
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
private static processIntelliTouch(msg: Inbound) {
|
|
152
|
+
switch (msg.action) {
|
|
153
|
+
case 30: {
|
|
154
|
+
// sample packet
|
|
155
|
+
// [165,33,15,16,30,16],[4,9,16,0,1,72,0,0,16,205,0,0,0,2,0,0],[2,88]
|
|
156
|
+
// this is (I believe) to assign circuits that require high speed mode with a dual speed pump
|
|
157
|
+
|
|
158
|
+
// We don't want the dual speed pump to even exist unless there are no circuit controlling it.
|
|
159
|
+
// It should not be showing up in our pumps list or emitting state unless the user has defined
|
|
160
|
+
// circuits to it on *Touch interfaces.
|
|
161
|
+
// RSG 1/5/23 - Intellitouch (and Dual Body) accept 8 high speed circuits
|
|
162
|
+
let maxCircuits = sys.controllerType === ControllerType.IntelliTouch ? 8 : 4;
|
|
163
|
+
let arrCircuits = [];
|
|
164
|
+
let pump = sys.pumps.getDualSpeed(true);
|
|
165
|
+
for (let i = 0; i < maxCircuits; i++) {
|
|
166
|
+
let val = msg.extractPayloadByte(i);
|
|
167
|
+
if (val > 0) arrCircuits.push(val);
|
|
168
|
+
else pump.circuits.removeItemById(i);
|
|
169
|
+
}
|
|
170
|
+
if (arrCircuits.length > 0) {
|
|
171
|
+
let pump = sys.pumps.getDualSpeed(true);
|
|
172
|
+
for (let j = 1; j <= arrCircuits.length; j++) pump.circuits.getItemById(j, true).circuit = arrCircuits[j-1];
|
|
173
|
+
}
|
|
174
|
+
else sys.pumps.removeItemById(10);
|
|
175
|
+
msg.isProcessed = true;
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
case 40:
|
|
179
|
+
case 168:
|
|
180
|
+
{
|
|
181
|
+
|
|
182
|
+
// [165,33,16,34,168,10],[0,0,0,254,0,0,0,0,0,0],[2,168 = manual heat mode off
|
|
183
|
+
// [165,33,16,34,168,10],[0,0,0,254,1,0,0,0,0,0],[2,169] = manual heat mode on
|
|
184
|
+
sys.general.options.manualHeat = msg.extractPayloadByte(4) === 1;
|
|
185
|
+
// From https://github.com/tagyoureit/nodejs-poolController/issues/362 = Intellitouch
|
|
186
|
+
// [0,0,0,0,1,x,0,0,0,0] x=0 Manual OP heat Off; x=1 Manual OP heat On
|
|
187
|
+
sys.general.options.manualPriority = msg.extractPayloadByte(5) === 1;
|
|
188
|
+
if ((msg.extractPayloadByte(3) & 0x01) === 1) {
|
|
189
|
+
// only support for 1 ic with EasyTouch
|
|
190
|
+
let chem = sys.chemControllers.getItemByAddress(144, true);
|
|
191
|
+
//let schem = state.chemControllers.getItemById(chem.id, true);
|
|
192
|
+
chem.ph.tank.capacity = chem.orp.tank.capacity = 6;
|
|
193
|
+
chem.ph.tank.units = chem.orp.tank.units = '';
|
|
194
|
+
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
if (sys.controllerType !== ControllerType.SunTouch) {
|
|
198
|
+
let chem = sys.chemControllers.getItemByAddress(144);
|
|
199
|
+
state.chemControllers.removeItemById(chem.id);
|
|
200
|
+
sys.chemControllers.removeItemById(chem.id);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
msg.isProcessed = true;
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
175
208
|
}
|