nodejs-poolcontroller 7.2.0 → 7.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
- package/Changelog +13 -0
- package/Dockerfile +1 -0
- package/README.md +5 -5
- package/app.ts +11 -0
- package/config/Config.ts +3 -0
- package/config/VersionCheck.ts +8 -4
- package/controller/Constants.ts +165 -9
- package/controller/Equipment.ts +186 -65
- package/controller/Errors.ts +22 -1
- package/controller/State.ts +273 -57
- package/controller/boards/EasyTouchBoard.ts +194 -95
- package/controller/boards/IntelliCenterBoard.ts +115 -42
- package/controller/boards/IntelliTouchBoard.ts +104 -30
- package/controller/boards/NixieBoard.ts +155 -53
- package/controller/boards/SystemBoard.ts +1529 -514
- package/controller/comms/Comms.ts +219 -42
- package/controller/comms/messages/Messages.ts +16 -4
- package/controller/comms/messages/config/ChlorinatorMessage.ts +13 -3
- package/controller/comms/messages/config/CircuitGroupMessage.ts +6 -0
- package/controller/comms/messages/config/CircuitMessage.ts +1 -1
- package/controller/comms/messages/config/CoverMessage.ts +1 -0
- package/controller/comms/messages/config/EquipmentMessage.ts +4 -0
- package/controller/comms/messages/config/ExternalMessage.ts +43 -25
- 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 +15 -9
- package/controller/comms/messages/config/IntellichemMessage.ts +4 -1
- package/controller/comms/messages/config/OptionsMessage.ts +13 -1
- 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 +11 -0
- package/controller/comms/messages/config/SecurityMessage.ts +1 -0
- package/controller/comms/messages/config/ValveMessage.ts +12 -2
- package/controller/comms/messages/status/ChlorinatorStateMessage.ts +14 -6
- package/controller/comms/messages/status/EquipmentStateMessage.ts +78 -24
- package/controller/comms/messages/status/HeaterStateMessage.ts +25 -5
- package/controller/comms/messages/status/IntelliChemStateMessage.ts +55 -26
- package/controller/nixie/Nixie.ts +18 -16
- package/controller/nixie/NixieEquipment.ts +6 -6
- package/controller/nixie/bodies/Body.ts +7 -4
- package/controller/nixie/bodies/Filter.ts +7 -4
- package/controller/nixie/chemistry/ChemController.ts +800 -283
- package/controller/nixie/chemistry/Chlorinator.ts +22 -14
- package/controller/nixie/circuits/Circuit.ts +42 -7
- package/controller/nixie/heaters/Heater.ts +303 -30
- package/controller/nixie/pumps/Pump.ts +57 -30
- package/controller/nixie/schedules/Schedule.ts +10 -7
- package/controller/nixie/valves/Valve.ts +7 -5
- package/defaultConfig.json +32 -1
- package/issue_template.md +1 -1
- package/logger/DataLogger.ts +37 -22
- package/package.json +20 -18
- package/web/Server.ts +529 -31
- package/web/bindings/influxDB.json +157 -5
- package/web/bindings/mqtt.json +112 -13
- package/web/bindings/mqttAlt.json +109 -11
- package/web/interfaces/baseInterface.ts +2 -1
- package/web/interfaces/httpInterface.ts +2 -0
- package/web/interfaces/influxInterface.ts +103 -54
- package/web/interfaces/mqttInterface.ts +16 -5
- package/web/services/config/Config.ts +179 -43
- package/web/services/state/State.ts +51 -5
- package/web/services/state/StateSocket.ts +19 -2
|
@@ -38,6 +38,12 @@ export class IntelliCenterBoard extends SystemBoard {
|
|
|
38
38
|
this.equipmentIds.features.start = 129;
|
|
39
39
|
this.equipmentIds.circuitGroups.start = 193;
|
|
40
40
|
this.equipmentIds.virtualCircuits.start = 237;
|
|
41
|
+
this.valueMaps.panelModes = new byteValueMap([
|
|
42
|
+
[0, { val: 0, name: 'auto', desc: 'Auto' }],
|
|
43
|
+
[1, { val: 1, name: 'service', desc: 'Service' }],
|
|
44
|
+
[8, { val: 8, name: 'freeze', desc: 'Freeze' }],
|
|
45
|
+
[255, { name: 'error', desc: 'System Error' }]
|
|
46
|
+
]);
|
|
41
47
|
this.valueMaps.circuitFunctions = new byteValueMap([
|
|
42
48
|
[0, { name: 'generic', desc: 'Generic' }],
|
|
43
49
|
[1, { name: 'spillway', desc: 'Spillway' }],
|
|
@@ -59,12 +65,12 @@ export class IntelliCenterBoard extends SystemBoard {
|
|
|
59
65
|
[2, { name: 'ds', desc: 'Two Speed', maxCircuits: 8, hasAddress: false, hasBody:true }],
|
|
60
66
|
[3, { name: 'vs', desc: 'Intelliflo VS', maxPrimingTime: 6, minSpeed: 450, maxSpeed: 3450, maxCircuits: 8, hasAddress: true }],
|
|
61
67
|
[4, { name: 'vsf', desc: 'Intelliflo VSF', minSpeed: 450, maxSpeed: 3450, minFlow: 15, maxFlow: 130, maxCircuits: 8, hasAddress: true }],
|
|
62
|
-
[5, { name: 'vf', desc: 'Intelliflo VF', minFlow: 15, maxFlow: 130, maxCircuits: 8, hasAddress: true }],
|
|
68
|
+
[5, { name: 'vf', desc: 'Intelliflo VF', maxPrimingTime: 6, minFlow: 15, maxFlow: 130, maxCircuits: 8, hasAddress: true }],
|
|
63
69
|
[100, {name: 'sf', desc: 'SuperFlo VS', hasAddress: false, maxCircuits: 8, maxRelays: 4, equipmentMaster: 1}]
|
|
64
70
|
]);
|
|
65
71
|
// RSG - same as systemBoard definition; can delete.
|
|
66
72
|
this.valueMaps.heatModes = new byteValueMap([
|
|
67
|
-
[
|
|
73
|
+
[1, { name: 'off', desc: 'Off' }],
|
|
68
74
|
[3, { name: 'heater', desc: 'Heater' }],
|
|
69
75
|
[5, { name: 'solar', desc: 'Solar Only' }],
|
|
70
76
|
[12, { name: 'solarpref', desc: 'Solar Preferred' }]
|
|
@@ -129,8 +135,8 @@ export class IntelliCenterBoard extends SystemBoard {
|
|
|
129
135
|
[6, { name: 'i10x', part: '522997Z', desc: 'i10x Expansion Module', circuits: 10 }],
|
|
130
136
|
[7, { name: 'i10D', part: '523029Z', desc: 'i10D Personality Card', bodies: 2, valves: 2, circuits: 11, shared: false, dual: true, chlorinators: 1, chemControllers: 1 }], // We have witnessed this in the wild
|
|
131
137
|
[8, { name: 'Valve Exp', part: '522440', desc: 'Valve Expansion Module', valves: 6 }],
|
|
132
|
-
[9, { name: '
|
|
133
|
-
[10, { name: '
|
|
138
|
+
[9, { name: 'A/D Module', part: '522039', desc: 'A/D Cover Module', covers: 2 }], // Finally have a user with one of these
|
|
139
|
+
[10, { name: 'iChlor Mux', part: '522719', desc: 'iChlor MUX Card', chlorinators: 3 }], // This is a guess
|
|
134
140
|
[255, {name: 'i5x', part: '522033', desc: 'i5x Expansion Module', circuits: 5}] // This does not actually map to a known value at this point but we do know it will be > 6.
|
|
135
141
|
]);
|
|
136
142
|
|
|
@@ -207,8 +213,9 @@ export class IntelliCenterBoard extends SystemBoard {
|
|
|
207
213
|
[1, { name: 'heater', desc: 'Heater' }],
|
|
208
214
|
[2, { name: 'solar', desc: 'Solar' }],
|
|
209
215
|
[3, { name: 'cooling', desc: 'Cooling' }],
|
|
216
|
+
[6, { name: 'mtheat', desc: 'Heater' }],
|
|
210
217
|
[4, { name: 'hpheat', desc: 'Heating' }],
|
|
211
|
-
[8, { name: 'hpcool', desc: 'Cooling'}]
|
|
218
|
+
[8, { name: 'hpcool', desc: 'Cooling' }]
|
|
212
219
|
]);
|
|
213
220
|
this.valueMaps.scheduleTypes = new byteValueMap([
|
|
214
221
|
[0, { name: 'runonce', desc: 'Run Once', startDate: true, startTime: true, endTime: true, days: false, heatSource: true, heatSetpoint: true }],
|
|
@@ -572,7 +579,7 @@ class IntelliCenterConfigRequest extends ConfigRequest {
|
|
|
572
579
|
if (typeof items !== 'undefined') this.items.push(...items);
|
|
573
580
|
this.oncomplete = oncomplete;
|
|
574
581
|
}
|
|
575
|
-
|
|
582
|
+
declare category: ConfigCategories;
|
|
576
583
|
}
|
|
577
584
|
class IntelliCenterConfigQueue extends ConfigQueue {
|
|
578
585
|
public _processing: boolean = false;
|
|
@@ -1388,7 +1395,20 @@ class IntelliCenterSystemCommands extends SystemCommands {
|
|
|
1388
1395
|
}
|
|
1389
1396
|
}
|
|
1390
1397
|
class IntelliCenterCircuitCommands extends CircuitCommands {
|
|
1391
|
-
|
|
1398
|
+
declare board: IntelliCenterBoard;
|
|
1399
|
+
// Need to override this as IntelliCenter manages all the egg timers for all circuit types.
|
|
1400
|
+
public async checkEggTimerExpirationAsync() {
|
|
1401
|
+
try {
|
|
1402
|
+
for (let i = 0; i < sys.circuits.length; i++) {
|
|
1403
|
+
let c = sys.circuits.getItemByIndex(i);
|
|
1404
|
+
let cstate = state.circuits.getItemByIndex(i);
|
|
1405
|
+
if (!cstate.isActive || !cstate.isOn) continue;
|
|
1406
|
+
if (c.master === 1) {
|
|
1407
|
+
await ncp.circuits.checkCircuitEggTimerExpirationAsync(cstate);
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
} catch (err) { logger.error(`checkEggTimerExpiration: Error synchronizing circuit relays ${err.message}`); }
|
|
1411
|
+
}
|
|
1392
1412
|
public async setCircuitAsync(data: any): Promise<ICircuit> {
|
|
1393
1413
|
let id = parseInt(data.id, 10);
|
|
1394
1414
|
let circuit = sys.circuits.getItemById(id, false);
|
|
@@ -1405,7 +1425,7 @@ class IntelliCenterCircuitCommands extends CircuitCommands {
|
|
|
1405
1425
|
let eggHrs = Math.floor(eggTimer / 60);
|
|
1406
1426
|
let eggMins = eggTimer - (eggHrs * 60);
|
|
1407
1427
|
let type = typeof data.type !== 'undefined' ? parseInt(data.type, 10) : circuit.type;
|
|
1408
|
-
let theme = typeof data.lightingTheme !== 'undefined' ? data.
|
|
1428
|
+
let theme = typeof data.lightingTheme !== 'undefined' ? data.lightingTheme : circuit.lightingTheme;
|
|
1409
1429
|
if (circuit.type === 9) theme = typeof data.level !== 'undefined' ? data.level : circuit.level;
|
|
1410
1430
|
if (typeof theme === 'undefined') theme = 0;
|
|
1411
1431
|
let out = Outbound.create({
|
|
@@ -1419,14 +1439,24 @@ class IntelliCenterCircuitCommands extends CircuitCommands {
|
|
|
1419
1439
|
onComplete: (err, msg) => {
|
|
1420
1440
|
if (err) reject(err);
|
|
1421
1441
|
else {
|
|
1442
|
+
let scircuit = state.circuits.getItemById(circuit.id, true);
|
|
1422
1443
|
circuit.eggTimer = eggTimer;
|
|
1423
1444
|
circuit.dontStop = data.dontStop;
|
|
1424
1445
|
circuit.freeze = (typeof data.freeze !== 'undefined' ? utils.makeBool(data.freeze) : circuit.freeze);
|
|
1425
1446
|
circuit.showInFeatures = (typeof data.showInFeatures !== 'undefined' ? utils.makeBool(data.showInFeatures) : circuit.showInFeatures);
|
|
1426
|
-
if (type === 9) circuit.level = theme;
|
|
1427
|
-
else
|
|
1428
|
-
|
|
1429
|
-
|
|
1447
|
+
if (type === 9) scircuit.level = circuit.level = theme;
|
|
1448
|
+
else {
|
|
1449
|
+
let t = sys.board.valueMaps.circuitFunctions.transform(type);
|
|
1450
|
+
if (t.isLight == true) scircuit.lightingTheme = circuit.lightingTheme = theme;
|
|
1451
|
+
else {
|
|
1452
|
+
scircuit.lightingTheme = undefined;
|
|
1453
|
+
circuit.lightingTheme = 0;
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
scircuit.name = circuit.name = typeof data.name !== 'undefined' ? data.name.toString().substring(0, 16) : circuit.name;
|
|
1457
|
+
scircuit.type = circuit.type = type;
|
|
1458
|
+
scircuit.isActive = circuit.isActive = true;
|
|
1459
|
+
circuit.master = 0;
|
|
1430
1460
|
resolve(circuit);
|
|
1431
1461
|
}
|
|
1432
1462
|
}
|
|
@@ -2055,6 +2085,14 @@ class IntelliCenterCircuitCommands extends CircuitCommands {
|
|
|
2055
2085
|
// NOT SURE IF COINCIDENTAL: The ICP seems to respond immediately after action 2.
|
|
2056
2086
|
// 7. ICP Sends 168[15,0,... new options, 0,0,0,0]
|
|
2057
2087
|
// 8. OCP responds ACK(168)
|
|
2088
|
+
// i10D turn on pool
|
|
2089
|
+
// OCP
|
|
2090
|
+
// Schedule on
|
|
2091
|
+
// [255, 0, 255][165, 1, 15, 16, 168, 36][15, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 1][5, 226]
|
|
2092
|
+
// No schedules
|
|
2093
|
+
// [255, 0, 255][165, 1, 15, 16, 168, 36][15, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 1, 0][5, 195]
|
|
2094
|
+
// njsPC
|
|
2095
|
+
// [255, 0, 255][165, 1, 15, 33, 168, 36][15, 0, 0, 33, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0][5, 216]
|
|
2058
2096
|
|
|
2059
2097
|
// The previous sequence is just additional noise on the bus. There is no need for it. We just
|
|
2060
2098
|
// need to send the set circuit message. It will reliably work 100% of the time but the ICP
|
|
@@ -2064,6 +2102,9 @@ class IntelliCenterCircuitCommands extends CircuitCommands {
|
|
|
2064
2102
|
//if (b) b = await this.getConfigAsync([15, 0]);
|
|
2065
2103
|
return new Promise<ICircuitState>((resolve, reject) => {
|
|
2066
2104
|
let out = this.createCircuitStateMessage(id, val);
|
|
2105
|
+
//if (sys.equipment.dual && id === 6) out.setPayloadByte(35, 1);
|
|
2106
|
+
out.setPayloadByte(34, 1);
|
|
2107
|
+
out.source = 16;
|
|
2067
2108
|
out.onComplete = async (err, msg: Inbound) => {
|
|
2068
2109
|
if (err) reject(err);
|
|
2069
2110
|
else {
|
|
@@ -2297,7 +2338,19 @@ class IntelliCenterCircuitCommands extends CircuitCommands {
|
|
|
2297
2338
|
let ndx = Math.floor(ordinal / 8);
|
|
2298
2339
|
let byte = out.payload[ndx + 15];
|
|
2299
2340
|
let bit = ordinal - (ndx * 8);
|
|
2300
|
-
|
|
2341
|
+
// Lets determine if this schedule should be on.
|
|
2342
|
+
if (sched.circuit === id) {
|
|
2343
|
+
if (isOn) {
|
|
2344
|
+
let dt = state.time.toDate();
|
|
2345
|
+
let dow = dt.getDay();
|
|
2346
|
+
// Convert the dow to the bit value.
|
|
2347
|
+
let sd = sys.board.valueMaps.scheduleDays.toArray().find(elem => elem.dow === dow);
|
|
2348
|
+
let dayVal = sd.bitVal || sd.val; // The bitval allows mask overrides.
|
|
2349
|
+
let ts = dt.getHours() * 60 + dt.getMinutes();
|
|
2350
|
+
if ((sched.scheduleDays & dayVal) > 0 && ts >= sched.startTime && ts <= sched.endTime) byte = byte | (1 << bit);
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
else if (sched.isOn) byte = byte | (1 << bit);
|
|
2301
2354
|
out.payload[ndx + 15] = byte;
|
|
2302
2355
|
}
|
|
2303
2356
|
return out;
|
|
@@ -2340,7 +2393,7 @@ class IntelliCenterCircuitCommands extends CircuitCommands {
|
|
|
2340
2393
|
}
|
|
2341
2394
|
}
|
|
2342
2395
|
class IntelliCenterFeatureCommands extends FeatureCommands {
|
|
2343
|
-
|
|
2396
|
+
declare board: IntelliCenterBoard;
|
|
2344
2397
|
public async setFeatureStateAsync(id, val): Promise<ICircuitState> { return sys.board.circuits.setCircuitStateAsync(id, val); }
|
|
2345
2398
|
public async toggleFeatureStateAsync(id): Promise<ICircuitState> { return sys.board.circuits.toggleCircuitStateAsync(id); }
|
|
2346
2399
|
public syncGroupStates() { } // Do nothing and let IntelliCenter do it.
|
|
@@ -2427,12 +2480,10 @@ class IntelliCenterChlorinatorCommands extends ChlorinatorCommands {
|
|
|
2427
2480
|
public async setChlorAsync(obj: any): Promise<ChlorinatorState> {
|
|
2428
2481
|
let id = parseInt(obj.id, 10);
|
|
2429
2482
|
let isAdd = false;
|
|
2430
|
-
let isVirtual = false;
|
|
2431
|
-
if (id <= 0 || isNaN(id)) id = 1;
|
|
2432
2483
|
let chlor = sys.chlorinators.getItemById(id);
|
|
2433
|
-
if (id
|
|
2484
|
+
if (id <= 0 || isNaN(id)) {
|
|
2434
2485
|
isAdd = true;
|
|
2435
|
-
chlor.master = utils.makeBool(obj.
|
|
2486
|
+
chlor.master = utils.makeBool(obj.master) ? 1 : 0;
|
|
2436
2487
|
// Calculate an id for the chlorinator. The messed up part is that if a chlorinator is not attached to the OCP, its address
|
|
2437
2488
|
// cannot be set by the MUX. This will have to wait.
|
|
2438
2489
|
id = 1;
|
|
@@ -2441,13 +2492,22 @@ class IntelliCenterChlorinatorCommands extends ChlorinatorCommands {
|
|
|
2441
2492
|
//let chlor = extend(true, {}, sys.chlorinators.getItemById(id).get(), obj);
|
|
2442
2493
|
// If this is a virtual chlorinator then go to the base class and handle it from there.
|
|
2443
2494
|
if (chlor.master === 1) return super.setChlorAsync(obj);
|
|
2444
|
-
|
|
2445
|
-
let
|
|
2446
|
-
let spaSetpoint = parseInt(obj.spaSetpoint, 10);
|
|
2495
|
+
if (typeof chlor.master === 'undefined') chlor.master = 0;
|
|
2496
|
+
let name = obj.name || chlor.name || 'IntelliChlor' + id;
|
|
2447
2497
|
let superChlorHours = parseInt(obj.superChlorHours, 10);
|
|
2448
2498
|
if (typeof obj.superChlorinate !== 'undefined') obj.superChlor = utils.makeBool(obj.superChlorinate);
|
|
2449
2499
|
let superChlorinate = typeof obj.superChlor === 'undefined' ? undefined : utils.makeBool(obj.superChlor);
|
|
2500
|
+
let isDosing = typeof obj.isDosing !== 'undefined' ? utils.makeBool(obj.isDosing) : chlor.isDosing;
|
|
2450
2501
|
let disabled = typeof obj.disabled !== 'undefined' ? utils.makeBool(obj.disabled) : chlor.disabled;
|
|
2502
|
+
// This should never never never modify the setpoints based upon the disabled or isDosing flags.
|
|
2503
|
+
//let poolSetpoint = isDosing ? 100 : disabled ? 0 : parseInt(obj.poolSetpoint, 10);
|
|
2504
|
+
//let spaSetpoint = isDosing ? 100 : disabled ? 0 : parseInt(obj.spaSetpoint, 10);
|
|
2505
|
+
let poolSetpoint = typeof obj.poolSetpoint !== 'undefined' ? parseInt(obj.poolSetpoint, 10) : chlor.poolSetpoint;
|
|
2506
|
+
let spaSetpoint = typeof obj.spaSetpoint !== 'undefined' ? parseInt(obj.spaSetpoint, 10) : chlor.spaSetpoint;
|
|
2507
|
+
if (poolSetpoint === 0) console.log(obj);
|
|
2508
|
+
|
|
2509
|
+
let model = typeof obj.model !== 'undefined' ? obj.model : chlor.model;
|
|
2510
|
+
let chlorType = typeof obj.type !== 'undefined' ? sys.board.valueMaps.chlorinatorType.encode(obj.type) : chlor.type || 0;
|
|
2451
2511
|
if (isAdd) {
|
|
2452
2512
|
if (isNaN(poolSetpoint)) poolSetpoint = 50;
|
|
2453
2513
|
if (isNaN(spaSetpoint)) spaSetpoint = 10;
|
|
@@ -2455,8 +2515,8 @@ class IntelliCenterChlorinatorCommands extends ChlorinatorCommands {
|
|
|
2455
2515
|
if (typeof superChlorinate === 'undefined') superChlorinate = false;
|
|
2456
2516
|
}
|
|
2457
2517
|
else {
|
|
2458
|
-
if (isNaN(poolSetpoint)) poolSetpoint = chlor.poolSetpoint;
|
|
2459
|
-
if (isNaN(spaSetpoint)) spaSetpoint = chlor.spaSetpoint;
|
|
2518
|
+
if (isNaN(poolSetpoint)) poolSetpoint = chlor.poolSetpoint || 0;
|
|
2519
|
+
if (isNaN(spaSetpoint)) spaSetpoint = chlor.spaSetpoint || 0;
|
|
2460
2520
|
if (isNaN(superChlorHours)) superChlorHours = chlor.superChlorHours;
|
|
2461
2521
|
if (typeof superChlorinate === 'undefined') superChlorinate = utils.makeBool(chlor.superChlor);
|
|
2462
2522
|
}
|
|
@@ -2471,7 +2531,10 @@ class IntelliCenterChlorinatorCommands extends ChlorinatorCommands {
|
|
|
2471
2531
|
return new Promise<ChlorinatorState>((resolve, reject) => {
|
|
2472
2532
|
let out = Outbound.create({
|
|
2473
2533
|
action: 168,
|
|
2474
|
-
payload: [7, 0, id - 1, body.val, 1,
|
|
2534
|
+
payload: [7, 0, id - 1, body.val, 1,
|
|
2535
|
+
disabled ? 0 : isDosing ? 100 : poolSetpoint,
|
|
2536
|
+
disabled ? 0 : isDosing ? 100 : spaSetpoint,
|
|
2537
|
+
superChlorinate ? 1 : 0, superChlorHours, 0, 1],
|
|
2475
2538
|
response: IntelliCenterBoard.getAckResponse(168),
|
|
2476
2539
|
retries: 5,
|
|
2477
2540
|
onComplete: (err, msg) => {
|
|
@@ -2480,6 +2543,10 @@ class IntelliCenterChlorinatorCommands extends ChlorinatorCommands {
|
|
|
2480
2543
|
let schlor = state.chlorinators.getItemById(id, true);
|
|
2481
2544
|
let cchlor = sys.chlorinators.getItemById(id, true);
|
|
2482
2545
|
chlor.disabled = disabled;
|
|
2546
|
+
chlor.model = model;
|
|
2547
|
+
schlor.type = chlor.type = chlorType;
|
|
2548
|
+
chlor.name = schlor.name = name;
|
|
2549
|
+
chlor.isDosing = isDosing;
|
|
2483
2550
|
schlor.isActive = cchlor.isActive = true;
|
|
2484
2551
|
schlor.poolSetpoint = cchlor.poolSetpoint = poolSetpoint;
|
|
2485
2552
|
schlor.spaSetpoint = cchlor.spaSetpoint = spaSetpoint;
|
|
@@ -2495,21 +2562,22 @@ class IntelliCenterChlorinatorCommands extends ChlorinatorCommands {
|
|
|
2495
2562
|
}
|
|
2496
2563
|
public async deleteChlorAsync(obj: any): Promise<ChlorinatorState> {
|
|
2497
2564
|
let id = parseInt(obj.id, 10);
|
|
2498
|
-
if (isNaN(id)) obj.id
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
let
|
|
2565
|
+
if (isNaN(id)) return Promise.reject(new InvalidEquipmentDataError(`Chlorinator id is not valid: ${obj.id}`, 'chlorinator', obj.id));
|
|
2566
|
+
let chlor = sys.chlorinators.getItemById(id);
|
|
2567
|
+
if (chlor.master === 1) return await super.deleteChlorAsync(obj);
|
|
2568
|
+
let schlor = state.chlorinators.getItemById(id);
|
|
2502
2569
|
// Verify the data.
|
|
2503
2570
|
return new Promise<ChlorinatorState>((resolve, reject) => {
|
|
2504
2571
|
let out = Outbound.create({
|
|
2505
2572
|
action: 168,
|
|
2506
|
-
payload: [7, 0, id - 1,
|
|
2573
|
+
payload: [7, 0, id - 1, schlor.body || 0, 0, schlor.poolSetpoint || 0, schlor.spaSetpoint || 0, 0, schlor.superChlorHours || 0, 0, 0],
|
|
2507
2574
|
response: IntelliCenterBoard.getAckResponse(168),
|
|
2508
2575
|
retries: 5,
|
|
2509
2576
|
onComplete: (err, msg) => {
|
|
2510
2577
|
if (err) reject(err);
|
|
2511
2578
|
else {
|
|
2512
|
-
|
|
2579
|
+
ncp.chlorinators.deleteChlorinatorAsync(id).then(()=>{});
|
|
2580
|
+
schlor = state.chlorinators.getItemById(id, true);
|
|
2513
2581
|
state.chlorinators.removeItemById(id);
|
|
2514
2582
|
sys.chlorinators.removeItemById(id);
|
|
2515
2583
|
resolve(schlor);
|
|
@@ -2598,7 +2666,7 @@ class IntelliCenterPumpCommands extends PumpCommands {
|
|
|
2598
2666
|
let id = (typeof data.id === 'undefined' || data.id <= 0) ? sys.pumps.getNextEquipmentId(sys.board.equipmentIds.pumps) : parseInt(data.id, 10);
|
|
2599
2667
|
if (isNaN(id)) return Promise.reject(new Error(`Invalid pump id: ${data.id}`));
|
|
2600
2668
|
let pump = sys.pumps.getItemById(id, false);
|
|
2601
|
-
if (data.master > 0 || pump.master > 0
|
|
2669
|
+
if (data.master > 0 || pump.master > 0) return await super.setPumpAsync(data);
|
|
2602
2670
|
|
|
2603
2671
|
// 0 6 10 11 12 15
|
|
2604
2672
|
//[255, 0, 255][165, 63, 15, 16, 168, 34][4, 0, 0, 3, 0, 96, 194, 1, 122, 13, 15, 130, 1, 196, 9, 128, 2, 255, 5, 0, 251, 128, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0][11, 218]
|
|
@@ -3177,6 +3245,8 @@ class IntelliCenterScheduleCommands extends ScheduleCommands {
|
|
|
3177
3245
|
out.retries = 5;
|
|
3178
3246
|
out.onComplete = (err, msg) => {
|
|
3179
3247
|
if (!err) {
|
|
3248
|
+
sched = sys.schedules.getItemById(id, true);
|
|
3249
|
+
ssched = state.schedules.getItemById(id, true);
|
|
3180
3250
|
sched.circuit = ssched.circuit = circuit;
|
|
3181
3251
|
sched.scheduleDays = ssched.scheduleDays = schedDays;
|
|
3182
3252
|
sched.scheduleType = ssched.scheduleType = schedType;
|
|
@@ -3273,14 +3343,14 @@ class IntelliCenterHeaterCommands extends HeaterCommands {
|
|
|
3273
3343
|
conn.queueSendMessage(out);
|
|
3274
3344
|
}
|
|
3275
3345
|
public async setHeaterAsync(obj: any): Promise<Heater> {
|
|
3276
|
-
if (
|
|
3346
|
+
if (obj.master === 1 || parseInt(obj.id, 10) > 255) return super.setHeaterAsync(obj);
|
|
3277
3347
|
return new Promise<Heater>((resolve, reject) => {
|
|
3278
3348
|
let id = typeof obj.id === 'undefined' ? -1 : parseInt(obj.id, 10);
|
|
3279
3349
|
if (isNaN(id)) return reject(new InvalidEquipmentIdError('Heater Id is not valid.', obj.id, 'Heater'));
|
|
3280
3350
|
let heater: Heater;
|
|
3281
3351
|
if (id <= 0) {
|
|
3282
3352
|
// We are adding a heater. In this case all heaters are virtual.
|
|
3283
|
-
let vheaters = sys.heaters.filter(h => h.
|
|
3353
|
+
let vheaters = sys.heaters.filter(h => h.master === 1);
|
|
3284
3354
|
id = vheaters.length + 1;
|
|
3285
3355
|
}
|
|
3286
3356
|
heater = sys.heaters.getItemById(id, false);
|
|
@@ -3388,7 +3458,6 @@ class IntelliCenterHeaterCommands extends HeaterCommands {
|
|
|
3388
3458
|
heater.economyTime = economyTime;
|
|
3389
3459
|
heater.startTempDelta = startTempDelta;
|
|
3390
3460
|
heater.stopTempDelta = stopTempDelta;
|
|
3391
|
-
hstate.isVirtual = heater.isVirtual = false;
|
|
3392
3461
|
heater.cooldownDelay = cooldownDelay;
|
|
3393
3462
|
sys.board.heaters.updateHeaterServices();
|
|
3394
3463
|
sys.board.heaters.syncHeaterStates();
|
|
@@ -3401,7 +3470,7 @@ class IntelliCenterHeaterCommands extends HeaterCommands {
|
|
|
3401
3470
|
});
|
|
3402
3471
|
}
|
|
3403
3472
|
public async deleteHeaterAsync(obj): Promise<Heater> {
|
|
3404
|
-
if (
|
|
3473
|
+
if (obj.master === 1 || parseInt(obj.id, 10) > 255) return await super.deleteHeaterAsync(obj);
|
|
3405
3474
|
return new Promise<Heater>((resolve, reject) => {
|
|
3406
3475
|
let id = parseInt(obj.id, 10);
|
|
3407
3476
|
if (isNaN(id)) return Promise.reject(new InvalidEquipmentIdError('Cannot delete. Heater Id is not valid.', obj.id, 'Heater'));
|
|
@@ -3443,6 +3512,8 @@ class IntelliCenterHeaterCommands extends HeaterCommands {
|
|
|
3443
3512
|
let heatPumpInstalled = htypes.heatpump > 0;
|
|
3444
3513
|
let gasHeaterInstalled = htypes.gas > 0;
|
|
3445
3514
|
let ultratempInstalled = htypes.ultratemp > 0;
|
|
3515
|
+
let mastertempInstalled = htypes.mastertemp > 0;
|
|
3516
|
+
|
|
3446
3517
|
|
|
3447
3518
|
// RKS: 09-26-20 This is a hack to maintain backward compatability with fw versions 1.04 and below. Ultratemp is not
|
|
3448
3519
|
// supported on 1.04 and below.
|
|
@@ -3466,9 +3537,10 @@ class IntelliCenterHeaterCommands extends HeaterCommands {
|
|
|
3466
3537
|
// 3 = Solar Heater
|
|
3467
3538
|
// 4 = Solar Preferred
|
|
3468
3539
|
// 5 = Heat Pump
|
|
3469
|
-
|
|
3540
|
+
|
|
3470
3541
|
if (sys.heaters.length > 0) sys.board.valueMaps.heatSources = new byteValueMap([[1, { name: 'off', desc: 'Off' }]]);
|
|
3471
3542
|
if (gasHeaterInstalled) sys.board.valueMaps.heatSources.merge([[2, { name: 'heater', desc: 'Heater' }]]);
|
|
3543
|
+
if (mastertempInstalled) sys.board.valueMaps.heatSources.merge([[11, { name: 'mtheater', desc: 'MasterTemp' }]]);
|
|
3472
3544
|
if (solarInstalled && (gasHeaterInstalled || heatPumpInstalled)) sys.board.valueMaps.heatSources.merge([[3, { name: 'solar', desc: 'Solar Only', hasCoolSetpoint: htypes.hasCoolSetpoint }], [4, { name: 'solarpref', desc: 'Solar Preferred', hasCoolSetpoint: htypes.hasCoolSetpoint }]]);
|
|
3473
3545
|
else if (solarInstalled) sys.board.valueMaps.heatSources.merge([[3, { name: 'solar', desc: 'Solar', hasCoolsetpoint: htypes.hasCoolSetpoint }]]);
|
|
3474
3546
|
if (heatPumpInstalled && (gasHeaterInstalled || solarInstalled)) sys.board.valueMaps.heatSources.merge([[9, { name: 'heatpump', desc: 'Heatpump Only' }], [25, { name: 'heatpumppref', desc: 'Heat Pump Pref' }]]);
|
|
@@ -3479,11 +3551,12 @@ class IntelliCenterHeaterCommands extends HeaterCommands {
|
|
|
3479
3551
|
|
|
3480
3552
|
sys.board.valueMaps.heatModes = new byteValueMap([[1, { name: 'off', desc: 'Off' }]]);
|
|
3481
3553
|
if (gasHeaterInstalled) sys.board.valueMaps.heatModes.merge([[2, { name: 'heater', desc: 'Heater' }]]);
|
|
3482
|
-
if (
|
|
3554
|
+
if (mastertempInstalled) sys.board.valueMaps.heatModes.merge([11, { name: 'mtheater', desc: 'MasterTemp' }]);
|
|
3555
|
+
if (solarInstalled && (gasHeaterInstalled || heatPumpInstalled || mastertempInstalled)) sys.board.valueMaps.heatModes.merge([[3, { name: 'solar', desc: 'Solar Only' }], [4, { name: 'solarpref', desc: 'Solar Preferred' }]]);
|
|
3483
3556
|
else if (solarInstalled) sys.board.valueMaps.heatModes.merge([[3, { name: 'solar', desc: 'Solar' }]]);
|
|
3484
|
-
if (ultratempInstalled && (gasHeaterInstalled || heatPumpInstalled)) sys.board.valueMaps.heatModes.merge([[5, { name: 'ultratemp', desc: 'UltraTemp Only'}], [6, { name: 'ultratemppref', desc: 'UltraTemp Pref' }]]);
|
|
3557
|
+
if (ultratempInstalled && (gasHeaterInstalled || heatPumpInstalled || mastertempInstalled)) sys.board.valueMaps.heatModes.merge([[5, { name: 'ultratemp', desc: 'UltraTemp Only' }], [6, { name: 'ultratemppref', desc: 'UltraTemp Pref' }]]);
|
|
3485
3558
|
else if (ultratempInstalled) sys.board.valueMaps.heatModes.merge([[5, { name: 'ultratemp', desc: 'UltraTemp' }]]);
|
|
3486
|
-
if (heatPumpInstalled && (gasHeaterInstalled || solarInstalled)) sys.board.valueMaps.heatModes.merge([[9, { name: 'heatpump', desc: 'Heatpump Only' }], [25, { name: 'heatpumppref', desc: 'Heat Pump Preferred' }]]);
|
|
3559
|
+
if (heatPumpInstalled && (gasHeaterInstalled || solarInstalled || mastertempInstalled)) sys.board.valueMaps.heatModes.merge([[9, { name: 'heatpump', desc: 'Heatpump Only' }], [25, { name: 'heatpumppref', desc: 'Heat Pump Preferred' }]]);
|
|
3487
3560
|
else if (heatPumpInstalled) sys.board.valueMaps.heatModes.merge([[9, { name: 'heatpump', desc: 'Heat Pump' }]]);
|
|
3488
3561
|
}
|
|
3489
3562
|
else {
|
|
@@ -3515,7 +3588,7 @@ class IntelliCenterHeaterCommands extends HeaterCommands {
|
|
|
3515
3588
|
}
|
|
3516
3589
|
class IntelliCenterValveCommands extends ValveCommands {
|
|
3517
3590
|
public async setValveAsync(obj?: any): Promise<Valve> {
|
|
3518
|
-
if (obj.
|
|
3591
|
+
if (obj.master === 1) return super.setValveAsync(obj);
|
|
3519
3592
|
let id = parseInt(obj.id, 10);
|
|
3520
3593
|
if (isNaN(id)) return Promise.reject(new InvalidEquipmentIdError('Valve Id has not been defined', obj.id, 'Valve'));
|
|
3521
3594
|
let valve = sys.valves.getItemById(id);
|
|
@@ -3565,7 +3638,7 @@ export class IntelliCenterChemControllerCommands extends ChemControllerCommands
|
|
|
3565
3638
|
// Now lets do all our validation to the incoming chem controller data.
|
|
3566
3639
|
let name = typeof data.name !== 'undefined' ? data.name : chem.name || `IntelliChem - ${address - 143}`;
|
|
3567
3640
|
let type = sys.board.valueMaps.chemControllerTypes.transformByName('intellichem');
|
|
3568
|
-
// So now we are down to the nitty gritty setting the data for the REM
|
|
3641
|
+
// So now we are down to the nitty gritty setting the data for the REM Chem controller.
|
|
3569
3642
|
let calciumHardness = typeof data.calciumHardness !== 'undefined' ? parseInt(data.calciumHardness, 10) : chem.calciumHardness;
|
|
3570
3643
|
let cyanuricAcid = typeof data.cyanuricAcid !== 'undefined' ? parseInt(data.cyanuricAcid, 10) : chem.cyanuricAcid;
|
|
3571
3644
|
let alkalinity = typeof data.alkalinity !== 'undefined' ? parseInt(data.alkalinity, 10) : chem.alkalinity;
|
|
@@ -3647,7 +3720,7 @@ export class IntelliCenterChemControllerCommands extends ChemControllerCommands
|
|
|
3647
3720
|
chem.orp.tolerance.high = orpTolerance.high;
|
|
3648
3721
|
chem.ph.setpoint = pHSetpoint;
|
|
3649
3722
|
chem.orp.setpoint = orpSetpoint;
|
|
3650
|
-
chem.siCalcType = siCalcType;
|
|
3723
|
+
schem.siCalcType = chem.siCalcType = siCalcType;
|
|
3651
3724
|
chem.address = schem.address = address;
|
|
3652
3725
|
chem.name = schem.name = name;
|
|
3653
3726
|
chem.flowSensor.enabled = false;
|
|
@@ -14,16 +14,17 @@ GNU Affero General Public License for more details.
|
|
|
14
14
|
You should have received a copy of the GNU Affero General Public License
|
|
15
15
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
16
|
*/
|
|
17
|
-
import {byteValueMap} from './SystemBoard';
|
|
18
|
-
import {logger} from '../../logger/Logger';
|
|
17
|
+
import { byteValueMap } from './SystemBoard';
|
|
18
|
+
import { logger } from '../../logger/Logger';
|
|
19
19
|
import { EasyTouchBoard, TouchConfigQueue, GetTouchConfigCategories, TouchCircuitCommands } from './EasyTouchBoard';
|
|
20
20
|
import { state, ICircuitGroupState } from '../State';
|
|
21
|
-
import { PoolSystem, sys, ExpansionPanel,
|
|
22
|
-
|
|
21
|
+
import { PoolSystem, sys, ExpansionPanel, Equipment } from '../Equipment';
|
|
22
|
+
|
|
23
|
+
import { conn } from '../comms/Comms';
|
|
24
|
+
import { InvalidEquipmentDataError } from '../Errors';
|
|
23
25
|
|
|
24
|
-
import {conn} from '../comms/Comms';
|
|
25
26
|
export class IntelliTouchBoard extends EasyTouchBoard {
|
|
26
|
-
constructor
|
|
27
|
+
constructor(system: PoolSystem) {
|
|
27
28
|
super(system);
|
|
28
29
|
this.equipmentIds.features.start = 41;
|
|
29
30
|
this.equipmentIds.features.end = 50;
|
|
@@ -32,10 +33,11 @@ export class IntelliTouchBoard extends EasyTouchBoard {
|
|
|
32
33
|
[0, { name: 'IT5', part: 'i5+3', desc: 'IntelliTouch i5+3', circuits: 6, shared: true }],
|
|
33
34
|
[1, { name: 'IT7', part: 'i7+3', desc: 'IntelliTouch i7+3', circuits: 8, shared: true }],
|
|
34
35
|
[2, { name: 'IT9', part: 'i9+3', desc: 'IntelliTouch i9+3', circuits: 10, shared: true }],
|
|
35
|
-
[3, { name: 'IT5S', part: 'i5+3S', desc: 'IntelliTouch i5+3S', circuits: 5, shared: false }],
|
|
36
|
-
[4, { name: 'IT9S', part: 'i9+3S', desc: 'IntelliTouch i9+3S', circuits: 9, shared: false }],
|
|
36
|
+
[3, { name: 'IT5S', part: 'i5+3S', desc: 'IntelliTouch i5+3S', circuits: 5, shared: false, bodies: 1, intakeReturnValves: false }],
|
|
37
|
+
[4, { name: 'IT9S', part: 'i9+3S', desc: 'IntelliTouch i9+3S', circuits: 9, shared: false, bodies: 1, intakeReturnValves: false }],
|
|
37
38
|
[5, { name: 'IT10D', part: 'i10D', desc: 'IntelliTouch i10D', circuits: 10, shared: false, dual: true }],
|
|
38
|
-
[32, { name: '
|
|
39
|
+
[32, { name: 'IT5X', part: 'i5X', desc: 'IntelliTouch i5X', circuits: 5 }],
|
|
40
|
+
[33, { name: 'IT10X', part: 'i10X', desc: 'IntelliTouch i10X', circuits: 10 }]
|
|
39
41
|
]);
|
|
40
42
|
}
|
|
41
43
|
public initExpansionModules(byte1: number, byte2: number) {
|
|
@@ -48,25 +50,28 @@ export class IntelliTouchBoard extends EasyTouchBoard {
|
|
|
48
50
|
mod.type = byte1;
|
|
49
51
|
mod.part = mt.part;
|
|
50
52
|
let eq = sys.equipment;
|
|
53
|
+
let bd = sys.board;
|
|
51
54
|
let md = mod.get();
|
|
52
55
|
|
|
53
56
|
eq.maxBodies = md.bodies = typeof mt.bodies !== 'undefined' ? mt.bodies : mt.shared || mt.dual ? 2 : 1;
|
|
54
57
|
eq.maxCircuits = md.circuits = typeof mt.circuits !== 'undefined' ? mt.circuits : 6;
|
|
55
|
-
eq.maxFeatures = md.features = typeof mt.features !== 'undefined' ? mt.features :
|
|
58
|
+
eq.maxFeatures = md.features = typeof mt.features !== 'undefined' ? mt.features : 8;
|
|
56
59
|
eq.maxValves = md.valves = typeof mt.valves !== 'undefined' ? mt.valves : mt.shared ? 4 : 2;
|
|
57
60
|
eq.maxPumps = md.maxPumps = typeof mt.pumps !== 'undefined' ? mt.pumps : 8;
|
|
58
61
|
eq.shared = mt.shared;
|
|
59
62
|
eq.dual = typeof mt.dual !== 'undefined' ? mt.dual : false;
|
|
63
|
+
eq.intakeReturnValves = md.intakeReturnValves = typeof mt.intakeReturnValves !== 'undefined' ? mt.intakeReturnValves : false;
|
|
60
64
|
eq.maxChlorinators = md.chlorinators = 1;
|
|
61
65
|
eq.maxChemControllers = md.chemControllers = 1;
|
|
62
66
|
eq.maxCustomNames = 20;
|
|
63
67
|
eq.maxCircuitGroups = 10; // Not sure why this is 10 other than to allow for those that we are in control of.
|
|
64
68
|
|
|
65
69
|
// Calculate out the invalid ids.
|
|
66
|
-
sys.board.equipmentIds.invalidIds.set([]);
|
|
67
|
-
if (!eq.shared) sys.board.equipmentIds.invalidIds.merge([1]);
|
|
70
|
+
// sys.board.equipmentIds.invalidIds.set([]);
|
|
68
71
|
// Add in all the invalid ids from the base personality board.
|
|
69
72
|
sys.board.equipmentIds.invalidIds.set([16, 17, 18]); // These appear to alway be invalid in IntelliTouch.
|
|
73
|
+
// RGS 10-7-21: Since single bodies have hi-temp/lo-temp we will always want ID 1.
|
|
74
|
+
// if (!eq.shared) sys.board.equipmentIds.invalidIds.merge([1]);
|
|
70
75
|
//if (eq.maxCircuits < 9) sys.board.equipmentIds.invalidIds.merge([9]);
|
|
71
76
|
for (let i = 7; i <= 10; i++) {
|
|
72
77
|
// This will add all the invalid ids between 7 and 10 that are omitted for IntelliTouch models.
|
|
@@ -74,26 +79,42 @@ export class IntelliTouchBoard extends EasyTouchBoard {
|
|
|
74
79
|
if (i > eq.maxCircuits) sys.board.equipmentIds.invalidIds.merge([i]);
|
|
75
80
|
}
|
|
76
81
|
// This code should be repeated if we ever see a panel with more than one expansion panel.
|
|
77
|
-
let
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
let emd = pnl.modules.getItemById(1, true).get();
|
|
87
|
-
eq.maxCircuits += emd.circuits = typeof emt.circuits !== 'undefined' ? emt.circuits : 0;
|
|
82
|
+
let pnl1: ExpansionPanel;
|
|
83
|
+
if ((byte2 & 0x40) === 64) {
|
|
84
|
+
// 64 indicates one expansion panel; SL defaults to i10x but it could also be i5x until we know better
|
|
85
|
+
pnl1 = sys.equipment.expansions.getItemById(1, true);
|
|
86
|
+
pnl1.type = 32;
|
|
87
|
+
let emt = this.valueMaps.expansionBoards.transform(pnl1.type);
|
|
88
|
+
pnl1.name = emt.desc;
|
|
89
|
+
pnl1.isActive = true;
|
|
90
|
+
eq.maxCircuits += emt.circuits;
|
|
88
91
|
}
|
|
89
|
-
else
|
|
90
|
-
|
|
92
|
+
else sys.equipment.expansions.removeItemById(1);
|
|
93
|
+
let pnl2: ExpansionPanel;
|
|
94
|
+
if ((byte2 & 0x80) === 128) {
|
|
95
|
+
// SL defaults to i5x but it could also be i10x until we know better
|
|
96
|
+
pnl2 = sys.equipment.expansions.getItemById(2, true);
|
|
97
|
+
pnl2.type = 32;
|
|
98
|
+
let emt = this.valueMaps.expansionBoards.transform(pnl2.type);
|
|
99
|
+
pnl2.name = emt.desc;
|
|
100
|
+
pnl2.isActive = true;
|
|
101
|
+
eq.maxCircuits += emt.circuits;
|
|
102
|
+
}
|
|
103
|
+
else sys.equipment.expansions.removeItemById(2);
|
|
104
|
+
let pnl3: ExpansionPanel;
|
|
105
|
+
if ((byte2 & 0xC0) === 192) {
|
|
106
|
+
// SL defaults to i5x but it could also be i10x until we know better
|
|
107
|
+
pnl3 = sys.equipment.expansions.getItemById(3, true);
|
|
108
|
+
pnl3.type = 32;
|
|
109
|
+
let emt = this.valueMaps.expansionBoards.transform(pnl3.type);
|
|
110
|
+
pnl3.name = emt.desc;
|
|
111
|
+
pnl3.isActive = true;
|
|
112
|
+
eq.maxCircuits += emt.circuits;
|
|
113
|
+
}
|
|
114
|
+
else sys.equipment.expansions.removeItemById(3);
|
|
91
115
|
if (byte1 !== 14) sys.board.equipmentIds.invalidIds.merge([10, 19]);
|
|
92
116
|
state.equipment.model = sys.equipment.model = mt.desc;
|
|
93
117
|
state.equipment.controllerType = 'intellitouch';
|
|
94
|
-
// The code above should be repeated if we ever see a panel with more than one expansion panel.
|
|
95
|
-
sys.equipment.expansions.getItemById(2, true).isActive = false;
|
|
96
|
-
sys.equipment.expansions.getItemById(3, true).isActive = false;
|
|
97
118
|
sys.equipment.shared ? sys.board.equipmentIds.circuits.start = 1 : sys.board.equipmentIds.circuits.start = 2;
|
|
98
119
|
this.initBodyDefaults();
|
|
99
120
|
this.initHeaterDefaults();
|
|
@@ -117,6 +138,59 @@ export class IntelliTouchBoard extends EasyTouchBoard {
|
|
|
117
138
|
state.emitControllerChange();
|
|
118
139
|
}
|
|
119
140
|
public circuits: ITTouchCircuitCommands = new ITTouchCircuitCommands(this);
|
|
141
|
+
public async setControllerType(obj): Promise<Equipment> {
|
|
142
|
+
try {
|
|
143
|
+
if (obj.controllerType !== sys.controllerType) {
|
|
144
|
+
return Promise.reject(new InvalidEquipmentDataError(`You may not change the controller type data for ${sys.controllerType} controllers`, 'controllerType', obj.controllerType));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
let mod = sys.equipment.modules.getItemById(0);
|
|
148
|
+
let mt = this.valueMaps.expansionBoards.get(mod.type);
|
|
149
|
+
let _circuits = mt.circuits;
|
|
150
|
+
let pnl1 = sys.equipment.expansions.getItemById(1);
|
|
151
|
+
if (typeof obj.expansion1 !== 'undefined' && obj.expansion1 !== pnl1.type) {
|
|
152
|
+
let emt = this.valueMaps.expansionBoards.transform(obj.expansion1);
|
|
153
|
+
logger.info(`Changing expansion 1 to ${emt.desc}.`);
|
|
154
|
+
pnl1.type = emt.val;
|
|
155
|
+
pnl1.name = emt.desc;
|
|
156
|
+
pnl1.isActive = true;
|
|
157
|
+
}
|
|
158
|
+
let pnl2 = sys.equipment.expansions.getItemById(2);
|
|
159
|
+
if (typeof obj.expansion2 !== 'undefined' && obj.expansion2 !== pnl2.type) {
|
|
160
|
+
let emt = this.valueMaps.expansionBoards.transform(obj.expansion2);
|
|
161
|
+
logger.info(`Changing expansion 2 to ${emt.desc}.`);
|
|
162
|
+
pnl2.type = emt.val;
|
|
163
|
+
pnl2.name = emt.desc;
|
|
164
|
+
pnl2.isActive = true;
|
|
165
|
+
}
|
|
166
|
+
let pnl3 = sys.equipment.expansions.getItemById(3);
|
|
167
|
+
if (typeof obj.expansion3 !== 'undefined' && obj.expansion3 !== pnl3.type) {
|
|
168
|
+
let emt = this.valueMaps.expansionBoards.transform(obj.expansion3);
|
|
169
|
+
logger.info(`Changing expansion 3 to ${emt.desc}.`);
|
|
170
|
+
pnl3.type = emt.val;
|
|
171
|
+
pnl3.name = emt.desc;
|
|
172
|
+
pnl3.isActive = true;
|
|
173
|
+
}
|
|
174
|
+
let prevMaxCircuits = sys.equipment.maxCircuits;
|
|
175
|
+
if (pnl1.isActive) _circuits += this.valueMaps.expansionBoards.get(pnl1.type).circuits;
|
|
176
|
+
if (pnl2.isActive) _circuits += this.valueMaps.expansionBoards.get(pnl2.type).circuits;
|
|
177
|
+
if (pnl3.isActive) _circuits += this.valueMaps.expansionBoards.get(pnl3.type).circuits;
|
|
178
|
+
if (_circuits < prevMaxCircuits) {
|
|
179
|
+
// if we downsize expansions, remove circuits
|
|
180
|
+
for (let i = _circuits + 1; i <= prevMaxCircuits; i++) {
|
|
181
|
+
sys.circuits.removeItemById(i);
|
|
182
|
+
state.circuits.removeItemById(i);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
else if (_circuits > prevMaxCircuits) {
|
|
186
|
+
this._configQueue.queueChanges();
|
|
187
|
+
}
|
|
188
|
+
sys.equipment.maxCircuits = _circuits;
|
|
189
|
+
return sys.equipment;
|
|
190
|
+
} catch (err) {
|
|
191
|
+
logger.error(`Error setting expansion panels: ${err.message}`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
120
194
|
}
|
|
121
195
|
class ITTouchConfigQueue extends TouchConfigQueue {
|
|
122
196
|
public queueChanges() {
|
|
@@ -148,7 +222,7 @@ class ITTouchConfigQueue extends TouchConfigQueue {
|
|
|
148
222
|
}
|
|
149
223
|
if (this.remainingItems > 0) {
|
|
150
224
|
var self = this;
|
|
151
|
-
setTimeout(() => {self.processNext();}, 50);
|
|
225
|
+
setTimeout(() => { self.processNext(); }, 50);
|
|
152
226
|
} else state.status = 1;
|
|
153
227
|
state.emitControllerChange();
|
|
154
228
|
}
|
|
@@ -164,5 +238,5 @@ class ITTouchCircuitCommands extends TouchCircuitCommands {
|
|
|
164
238
|
}
|
|
165
239
|
catch (err) { reject(err); }
|
|
166
240
|
});
|
|
167
|
-
}
|
|
241
|
+
}
|
|
168
242
|
}
|