nodejs-poolcontroller 8.0.4 → 8.1.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/Changelog +15 -0
- package/README.md +5 -1
- package/controller/Equipment.ts +15 -79
- package/controller/State.ts +5 -71
- package/controller/boards/NixieBoard.ts +1 -0
- package/controller/boards/SystemBoard.ts +1 -1
- package/controller/comms/Comms.ts +3 -0
- package/controller/comms/ScreenLogic.ts +83 -84
- package/controller/nixie/chemistry/ChemController.ts +64 -31
- package/controller/nixie/circuits/Circuit.ts +65 -30
- package/package.json +1 -1
- package/web/services/config/Config.ts +2 -1
package/Changelog
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 8.1.0
|
|
4
|
+
1. Support for dual chlorinators with REM chem controllers. It is now possible to have two separate chlorinators controlled in 'dynamic' mode by two separate REM chems. Note: In order for REM chem to control each chlorinator, each needs to be on a dedicated RS-485 port (not shared with an OCP or any other chlorinator).
|
|
5
|
+
|
|
6
|
+
## 8.0.1-8.0.5
|
|
7
|
+
1. Bug fixes including:
|
|
8
|
+
a. schedule end time errors
|
|
9
|
+
b. manual priority
|
|
10
|
+
c. screenlogic recurring schedules
|
|
11
|
+
d. VF pump message sequences
|
|
12
|
+
e. intellibrite themes
|
|
13
|
+
f. schedules are evaluated by bodies first and then everything else
|
|
14
|
+
g. solar stop/start delta logic
|
|
15
|
+
2. Jandy WaterColors support
|
|
16
|
+
3. Initial docker support (github docker actions)
|
|
17
|
+
|
|
3
18
|
## 8.0.0
|
|
4
19
|
1. Refactor comms code to Async
|
|
5
20
|
2. Update dependencies and Node >16
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
```diff
|
|
2
2
|
- INTELLICENTER USERS: Do not upgrade Intellicenter to 2.006. Rollback to 1.064 to use this application.
|
|
3
3
|
```
|
|
4
|
-
# nodejs-poolController - Version 8.
|
|
4
|
+
# nodejs-poolController - Version 8.1
|
|
5
5
|
|
|
6
6
|
## What is nodejs-poolController
|
|
7
7
|
|
|
@@ -26,6 +26,10 @@ Equipment supported
|
|
|
26
26
|
## Latest Changes
|
|
27
27
|
See [Changelog](https://github.com/tagyoureit/nodejs-poolController/blob/master/Changelog)
|
|
28
28
|
|
|
29
|
+
## What's new in 8.1?
|
|
30
|
+
|
|
31
|
+
Support for dual chlorinators with REM chem controllers. It is now possible to have two separate chlorinators controlled in 'dynamic' mode by two separate REM chems. Note: In order for REM chem to control each chlorinator, each needs to be on a dedicated RS-485 port (not shared with an OCP or any other chlorinator).
|
|
32
|
+
|
|
29
33
|
## What's new in 8.0?
|
|
30
34
|
|
|
31
35
|
Screenlogic can now be used as a direct connection point. If you feel that integrating an RS-485 adapter is a bit too much, then this is an option for you. The preferred method is still RS-485 as it is more fully featured.
|
package/controller/Equipment.ts
CHANGED
|
@@ -1678,6 +1678,10 @@ export class Chlorinator extends EqItem {
|
|
|
1678
1678
|
public set ignoreSaltReading(val: boolean) { this.setDataVal('ignoreSaltReading', val); }
|
|
1679
1679
|
public get model() { return this.data.model; }
|
|
1680
1680
|
public set model(val: number | any) { this.setDataVal('model', sys.board.valueMaps.chlorinatorModel.encode(val)); }
|
|
1681
|
+
public get ratedLbs(): number {
|
|
1682
|
+
let model = sys.board.valueMaps.chlorinatorModel.get(this.model);
|
|
1683
|
+
return typeof model.chlorinePerSec !== 'undefined' ? model.chlorinePerSec : 0;
|
|
1684
|
+
}
|
|
1681
1685
|
}
|
|
1682
1686
|
export class ValveCollection extends EqItemCollection<Valve> {
|
|
1683
1687
|
constructor(data: any, name?: string) { super(data, name || "valves"); }
|
|
@@ -2207,80 +2211,6 @@ export interface IChemController {
|
|
|
2207
2211
|
}
|
|
2208
2212
|
export class ChemController extends EqItem implements IChemController {
|
|
2209
2213
|
public initData() {
|
|
2210
|
-
//var chemController = {
|
|
2211
|
-
// id: 'number', // Id of the controller
|
|
2212
|
-
// name: 'string', // Name assigned to the controller
|
|
2213
|
-
// type: 'valueMap', // intellichem, rem -- There is an unknown but that should probably go away.
|
|
2214
|
-
// body: 'valueMap', // Body assigned to the chem controller.
|
|
2215
|
-
// address: 'number', // Address for IntelliChem controller only.
|
|
2216
|
-
// isActive: 'booean',
|
|
2217
|
-
// isVirtual: 'boolean', // False if controlled by OCP.
|
|
2218
|
-
// calciumHardness: 'number',
|
|
2219
|
-
// cyanuricAcid: 'number',
|
|
2220
|
-
// alkalinity: 'number',
|
|
2221
|
-
// HMIAdvancedDisplay: 'boolean', // This is related to IntelliChem and determines what is displayed on the controller.
|
|
2222
|
-
// ph: { // pH chemical structure
|
|
2223
|
-
// chemType: 'string', // Constant ph
|
|
2224
|
-
// enabled: 'boolean', // Allows disabling the functions without deleting the settings.
|
|
2225
|
-
// dosingMethod: 'valueMap', // manual, volume, volumeTime.
|
|
2226
|
-
// // manual = The dosing pump is not triggered.
|
|
2227
|
-
// // volume = Time is not considered as a limit to the dosing.
|
|
2228
|
-
// // time = The only limit to the dose is the amount of time.
|
|
2229
|
-
// // volumeTime = Limit the dose by volume or time whichever is sooner.
|
|
2230
|
-
// maxDosingTime: 'number', // The maximum amount of time a dose can occur before mixing.
|
|
2231
|
-
// maxDosingVolume: 'number', // The maximum volume for a dose in mL.
|
|
2232
|
-
// mixingTime: 'number', // Amount of time between in seconds doses that the pump must run before adding another dose.
|
|
2233
|
-
// startDelay: 'number', // The number of seconds that the pump must be running prior to considering a dose.
|
|
2234
|
-
// setpoint: 'number', // Target setpoint for pH
|
|
2235
|
-
// phSupply: 'valueMap', // base or acid.
|
|
2236
|
-
// pump: {
|
|
2237
|
-
// type: 'valueMap', // none, relay, ezo-pmp
|
|
2238
|
-
// connectionId: 'uuid', // Unique identifier for njspc external connections.
|
|
2239
|
-
// deviceBinding: 'string', // Binding value for REM to tell it what device is involved.
|
|
2240
|
-
// ratedFlow: 'number', // The standard flow rate for the pump in mL/min.
|
|
2241
|
-
// },
|
|
2242
|
-
// tank: {
|
|
2243
|
-
// capacity: 'number', // Capacity of the tank in the units provided.
|
|
2244
|
-
// units: 'valueMap' // gal, mL, cL, L, oz, pt, qt.
|
|
2245
|
-
// },
|
|
2246
|
-
// probe: {
|
|
2247
|
-
// connectionId: 'uuid', // A unique identifier that has been generated for connections in njspc.
|
|
2248
|
-
// deviceBinding: 'string', // A mapping value that is used by REM to determine which device is used.
|
|
2249
|
-
// type: 'valueMap' // none, ezo-ph, other.
|
|
2250
|
-
// }
|
|
2251
|
-
|
|
2252
|
-
// },
|
|
2253
|
-
// orp: { // ORP chemical structure
|
|
2254
|
-
// chemType: 'string', // Constant orp
|
|
2255
|
-
// enabled: 'boolean', // Allows disabling the functions without deleting the settings.
|
|
2256
|
-
// dosingMethod: 'valueMap', // manual, volume, volumeTime.
|
|
2257
|
-
// // manual = The dosing pump is not triggered.
|
|
2258
|
-
// // volume = Time is not considered as a limit to the dosing.
|
|
2259
|
-
// // time = The only limit to the dose is the amount of time.
|
|
2260
|
-
// // volumeTime = Limit the dose by volume or time whichever is sooner.
|
|
2261
|
-
// maxDosingTime: 'number', // The maximum amount of time a dose can occur before mixing.
|
|
2262
|
-
// maxDosingVolume: 'number', // The maximum volume for a dose in mL.
|
|
2263
|
-
// mixingTime: 'number', // Amount of time between in seconds doses that the pump must run before adding another dose.
|
|
2264
|
-
// startDelay: 'number', // The number of seconds that the pump must be running prior to considering a dose.
|
|
2265
|
-
// setpoint: 'number', // Target setpoint for ORP
|
|
2266
|
-
// useChlorinator: 'boolean', // Indicates whether the chlorinator will be used for dosing.
|
|
2267
|
-
// pump: {
|
|
2268
|
-
// type: 'valueMap', // none, relay, ezo-pmp
|
|
2269
|
-
// connectionId: 'uuid', // Unique identifier for njspc external connections.
|
|
2270
|
-
// deviceBinding: 'string', // Binding value for REM to tell it what device is involved.
|
|
2271
|
-
// ratedFlow: 'number', // The standard flow rate for the pump in mL/min.
|
|
2272
|
-
// },
|
|
2273
|
-
// tank: {
|
|
2274
|
-
// capacity: 'number', // Capacity of the tank in the units provided.
|
|
2275
|
-
// units: 'valueMap' // gal, mL, cL, L, oz, pt, qt.
|
|
2276
|
-
// },
|
|
2277
|
-
// probe: {
|
|
2278
|
-
// connectionId: 'uuid', // A unique identifier that has been generated for connections in njspc.
|
|
2279
|
-
// deviceBinding: 'string', // A mapping value that is used by REM to determine which device is used.
|
|
2280
|
-
// type: 'valueMap' // none, ezo-orp, other.
|
|
2281
|
-
// }
|
|
2282
|
-
// }
|
|
2283
|
-
//}
|
|
2284
2214
|
if (typeof this.data.lsiRange === 'undefined') this.data.lsiRange = { low: -.5, high: .5, enabled: true };
|
|
2285
2215
|
if (typeof this.data.borates === 'undefined') this.data.borates = 0;
|
|
2286
2216
|
if (typeof this.data.siCalcType === 'undefined') this.data.siCalcType = 0;
|
|
@@ -2299,8 +2229,6 @@ export class ChemController extends EqItem implements IChemController {
|
|
|
2299
2229
|
public set address(val: number) { this.setDataVal('address', val); }
|
|
2300
2230
|
public get isActive(): boolean { return this.data.isActive; }
|
|
2301
2231
|
public set isActive(val: boolean) { this.setDataVal('isActive', val); }
|
|
2302
|
-
// public get isVirtual(): boolean { return this.data.isVirtual; }
|
|
2303
|
-
// public set isVirtual(val: boolean) { this.setDataVal('isVirtual', val); }
|
|
2304
2232
|
public get calciumHardness(): number { return this.data.calciumHardness; }
|
|
2305
2233
|
public set calciumHardness(val: number) { this.setDataVal('calciumHardness', val); }
|
|
2306
2234
|
public get cyanuricAcid(): number { return this.data.cyanuricAcid; }
|
|
@@ -2460,7 +2388,7 @@ export class Chemical extends ChildEqItem implements IChemical {
|
|
|
2460
2388
|
public set startDelay(val: number) { this.setDataVal('startDelay', val); }
|
|
2461
2389
|
public get pump(): ChemicalPump { return new ChemicalPump(this.data, 'pump', this); }
|
|
2462
2390
|
public get tank(): ChemicalTank { return new ChemicalTank(this.data, 'tank', this); }
|
|
2463
|
-
public get chlor():
|
|
2391
|
+
// public get chlor(): Chlorinator { return new ChemicalChlor(this.data, 'chlor', this); }
|
|
2464
2392
|
public get setpoint(): number { return this.data.setpoint; }
|
|
2465
2393
|
public set setpoint(val: number) { this.setDataVal('setpoint', val); }
|
|
2466
2394
|
public get tolerance(): AlarmSetting { return new AlarmSetting(this.data, 'tolerance', this); }
|
|
@@ -2518,6 +2446,14 @@ export class ChemicalORP extends Chemical {
|
|
|
2518
2446
|
}
|
|
2519
2447
|
public get useChlorinator(): boolean { return utils.makeBool(this.data.useChlorinator); }
|
|
2520
2448
|
public set useChlorinator(val: boolean) { this.setDataVal('useChlorinator', val); }
|
|
2449
|
+
public get chlorId(): number {
|
|
2450
|
+
if (typeof this.data.chlorId === 'undefined'){
|
|
2451
|
+
// default to 1st chlorinator if not set; this is a backwards compatibility item when upgrading to 8.1
|
|
2452
|
+
return sys.chlorinators.getItemByIndex(0).id;
|
|
2453
|
+
}
|
|
2454
|
+
return this.data.chlorId;
|
|
2455
|
+
}
|
|
2456
|
+
public set chlorId(val: number) { this.setDataVal('chlorId', val); }
|
|
2521
2457
|
public get phLockout(): number { return this.data.phLockout; }
|
|
2522
2458
|
public set phLockout(val: number) { this.setDataVal('phLockout', val); }
|
|
2523
2459
|
public get probe(): ChemicalORPProbe { return new ChemicalORPProbe(this.data, 'probe', this); }
|
|
@@ -2661,7 +2597,7 @@ export class ChemicalTank extends ChildEqItem {
|
|
|
2661
2597
|
return tank;
|
|
2662
2598
|
}
|
|
2663
2599
|
}
|
|
2664
|
-
export class ChemicalChlor extends ChildEqItem {
|
|
2600
|
+
/* export class ChemicalChlor extends ChildEqItem {
|
|
2665
2601
|
// This whole class is a reference to the first chlorinator.
|
|
2666
2602
|
// This may not follow a best practice
|
|
2667
2603
|
// and certainly won't work for multiple chlors
|
|
@@ -2695,7 +2631,7 @@ export class ChemicalChlor extends ChildEqItem {
|
|
|
2695
2631
|
chlor.model = sys.board.valueMaps.chlorinatorModel.transform(this.model);
|
|
2696
2632
|
return chlor;
|
|
2697
2633
|
}
|
|
2698
|
-
}
|
|
2634
|
+
} */
|
|
2699
2635
|
export class AlarmSetting extends ChildEqItem {
|
|
2700
2636
|
public dataName = 'AlarmSettingConfig';
|
|
2701
2637
|
public initData() {
|
package/controller/State.ts
CHANGED
|
@@ -1089,7 +1089,9 @@ export class ScheduleStateCollection extends EqStateCollection<ScheduleState> {
|
|
|
1089
1089
|
let ssched = this.getItemByIndex(i);
|
|
1090
1090
|
let st = ssched.scheduleTime;
|
|
1091
1091
|
let sched = sys.schedules.getItemById(ssched.id);
|
|
1092
|
-
|
|
1092
|
+
// rsg st.startTime is null when the schedule has No Days <-- WRONG. ssched.scheduleDays should be checked.
|
|
1093
|
+
// original fix #879; updated fix #1033
|
|
1094
|
+
if (!sched.isActive || ssched.disabled || ssched.scheduleDays === 0) {
|
|
1093
1095
|
continue;
|
|
1094
1096
|
}
|
|
1095
1097
|
st.calcSchedule(state.time, sys.schedules.getItemById(ssched.id));
|
|
@@ -2656,74 +2658,6 @@ export class ChemControllerState extends EqState implements IChemControllerState
|
|
|
2656
2658
|
if (typeof this.data.siCalcType === 'undefined') {
|
|
2657
2659
|
this.data.siCalcType = sys.board.valueMaps.siCalcTypes.transform(0);
|
|
2658
2660
|
}
|
|
2659
|
-
//var chemControllerState = {
|
|
2660
|
-
// lastComm: 'number', // The unix time the chem controller sent its status.
|
|
2661
|
-
// id: 'number', // Id of the chemController.
|
|
2662
|
-
// type: 'valueMap', // intellichem, rem.
|
|
2663
|
-
// address: 'number', // Assigned address if IntelliChem.
|
|
2664
|
-
// name: 'string', // Name assigned to the controller.
|
|
2665
|
-
// status: 'valueMap', // ok, nocomms, setupError
|
|
2666
|
-
// body: 'valueMap', // Body that the chemController is assigned to.
|
|
2667
|
-
// flowDetected: 'boolean', // True if there is currently sufficient flow to read and dose.
|
|
2668
|
-
// flowDelay: 'boolean', // True of the controller is currently under a flow delay.
|
|
2669
|
-
// firmware: 'string', // Firmware version from IntelliChem (this should be in config)
|
|
2670
|
-
// saturationIndex: 'number', // Calculated LSI for the body.
|
|
2671
|
-
// isActive: 'boolean',
|
|
2672
|
-
// alarms: {}, // This has not changed although additional alarms will be added.
|
|
2673
|
-
// warnings: {}, // This has not changed although additional warnings will be added.
|
|
2674
|
-
// chemistryStatus: 'valueMap', // Current water quality status.
|
|
2675
|
-
// ph: {
|
|
2676
|
-
// chemType: 'string', // Constant ph.
|
|
2677
|
-
// dosingTimeRemaining: 'number', // The number of seconds remaining for the current dose.
|
|
2678
|
-
// dosingVolumeRemaining: 'number', // Remaining volume for the current dose in mL.
|
|
2679
|
-
// mixTimeRemaining: 'number', // The number of seconds remaining in the current mix cycle.
|
|
2680
|
-
// dosingStatus: 'valueMap', // dosing, monitoring, mixing.
|
|
2681
|
-
// level: 'number', // The current pH level.
|
|
2682
|
-
// lockout: 'boolean', // True if an attempt to dose was thwarted by error.
|
|
2683
|
-
// manualDosing: 'boolean', // True if the pump is running outside of a dosing command.
|
|
2684
|
-
// dailyLimitReached: 'boolean', // True if the calculated daily limit has been reached based upon body volume.
|
|
2685
|
-
// pump: {
|
|
2686
|
-
// type: 'valueMap', // The defined pump type.
|
|
2687
|
-
// isDosing: 'boolean', // True if the pump is running.
|
|
2688
|
-
// },
|
|
2689
|
-
// tank: {
|
|
2690
|
-
// level: 'number', // The current level for the tank.
|
|
2691
|
-
// capacity: 'number', // Total capacity for the tank.
|
|
2692
|
-
// units: 'valueMap', // nounits, gal, mL, cL, L, oz, pt, qt.
|
|
2693
|
-
// },
|
|
2694
|
-
// probe: {
|
|
2695
|
-
// level: 'number', // Current ph level as measured by the probe.
|
|
2696
|
-
// temperature: 'number', // The temperature used to calculate the adjusted probe level.
|
|
2697
|
-
// tempUnits: 'valueMap' // Units for the temperature C or F.
|
|
2698
|
-
// }
|
|
2699
|
-
// },
|
|
2700
|
-
// orp: {
|
|
2701
|
-
// chemType: 'string', // Constant orp.
|
|
2702
|
-
// dosingTimeRemaining: 'number', // The number of seconds remaining for the current dose.
|
|
2703
|
-
// dosingVolumeRemaining: 'number', // Remaining volume for the current dose in mL.
|
|
2704
|
-
// mixTimeRemaining: 'number', // The number of seconds remaining in the current mix cycle.
|
|
2705
|
-
// dosingStatus: 'valueMap', // dosing, monitoring, mixing.
|
|
2706
|
-
// level: 'number', // The current ORP level.
|
|
2707
|
-
// lockout: 'boolean', // True if an attempt to dose was thwarted by error.
|
|
2708
|
-
// manualDosing: 'boolean', // True if the pump is running outside of a dosing command.
|
|
2709
|
-
// dailyLimitReached: 'boolean', // True if the calculated daily limit has been reached based upon body volume.
|
|
2710
|
-
// pump: {
|
|
2711
|
-
// type: 'valueMap', // The defined pump type.
|
|
2712
|
-
// isDosing: 'boolean', // True if the pump is running.
|
|
2713
|
-
// },
|
|
2714
|
-
// tank: {
|
|
2715
|
-
// level: 'number', // The current level for the tank.
|
|
2716
|
-
// capacity: 'number', // Total capacity for the tank.
|
|
2717
|
-
// units: 'valueMap', // nounits, gal, mL, cL, L, oz, pt, qt.
|
|
2718
|
-
// },
|
|
2719
|
-
// probe: {
|
|
2720
|
-
// level: 'number', // Current ORP level as measured by the probe.
|
|
2721
|
-
// temperature: 'number', // The temperature used to calculate the adjusted probe level.
|
|
2722
|
-
// tempUnits: 'valueMap' // Units for the temperature C or F.
|
|
2723
|
-
// }
|
|
2724
|
-
// }
|
|
2725
|
-
//}
|
|
2726
|
-
|
|
2727
2661
|
}
|
|
2728
2662
|
public dataName: string = 'chemController';
|
|
2729
2663
|
public get lastComm(): number { return this.data.lastComm || 0; }
|
|
@@ -3173,8 +3107,8 @@ export class ChemicalORPState extends ChemicalState {
|
|
|
3173
3107
|
public get chemType() { return 'orp'; }
|
|
3174
3108
|
public set chemType(val) { this.setDataVal('chemType', val); }
|
|
3175
3109
|
public get probe() { return new ChemicalProbeORPState(this.data, 'probe', this); }
|
|
3176
|
-
public get useChlorinator(): boolean { return utils.makeBool(this.data.useChlorinator); }
|
|
3177
|
-
public set useChlorinator(val: boolean) { this.setDataVal('useChlorinator', val); }
|
|
3110
|
+
// public get useChlorinator(): boolean { return utils.makeBool(this.data.useChlorinator); }
|
|
3111
|
+
// public set useChlorinator(val: boolean) { this.setDataVal('useChlorinator', val); }
|
|
3178
3112
|
public get suspendDosing(): boolean {
|
|
3179
3113
|
let cc = this.chemController;
|
|
3180
3114
|
return cc.alarms.comms !== 0 || cc.alarms.orpProbeFault !== 0 || cc.alarms.orpPumpFault !== 0 || cc.alarms.bodyFault !== 0;
|
|
@@ -73,6 +73,7 @@ export class NixieBoard extends SystemBoard {
|
|
|
73
73
|
[14, { name: 'colorlogic', desc: 'ColorLogic', isLight: true, theme: 'colorlogic' }],
|
|
74
74
|
[15, { name: 'spadrain', desc: 'Spa Drain' }],
|
|
75
75
|
[16, { name: 'pooltone', desc: 'Pool Tone', isLight: true, theme: 'pooltone' }],
|
|
76
|
+
[17, { name: 'watercolors', desc: 'WaterColors', isLight: true, theme: 'watercolors' }],
|
|
76
77
|
]);
|
|
77
78
|
this.valueMaps.pumpTypes = new byteValueMap([
|
|
78
79
|
[1, { name: 'ss', desc: 'Single Speed', maxCircuits: 8, hasAddress: false, hasBody: false, maxRelays: 1, relays: [{ id: 1, name: 'Pump On/Off' }]}],
|
|
@@ -3631,7 +3631,7 @@ export class ScheduleCommands extends BoardCommands {
|
|
|
3631
3631
|
if (heatSetpoint < 0 || heatSetpoint > 104) return Promise.reject(new InvalidEquipmentDataError(`Invalid heat setpoint: ${heatSetpoint}`, 'Schedule', heatSetpoint));
|
|
3632
3632
|
if (sys.board.circuits.getCircuitReferences(true, true, false, true).find(elem => elem.id === circuit) === undefined)
|
|
3633
3633
|
return Promise.reject(new InvalidEquipmentDataError(`Invalid circuit reference: ${circuit}`, 'Schedule', circuit));
|
|
3634
|
-
if (schedType === 128 && schedDays === 0) return Promise.reject(new InvalidEquipmentDataError(`Invalid schedule days: ${schedDays}. You must supply days that the schedule is to run.`, 'Schedule', schedDays));
|
|
3634
|
+
if (schedType === 128 && schedDays === 0) return Promise.reject(new InvalidEquipmentDataError(`Invalid schedule days: ${schedDays}. You must supply days that the schedule is to run.`, 'Schedule', schedDays)); // rsg 2024.11.22 - some controllers allow no days.
|
|
3635
3635
|
|
|
3636
3636
|
// If we made it to here we are valid and the schedula and it state should exist.
|
|
3637
3637
|
sched = sys.schedules.getItemById(id, true);
|
|
@@ -668,6 +668,9 @@ export class RS485Port {
|
|
|
668
668
|
let opts: SerialPortOpenOptions<AutoDetectTypes> = { path: portPath, autoOpen: false, baudRate: 9600 };
|
|
669
669
|
sp = new SerialPortMock(opts);
|
|
670
670
|
}
|
|
671
|
+
else if (this._cfg.type === 'screenlogic') {
|
|
672
|
+
return await sl.openAsync();
|
|
673
|
+
}
|
|
671
674
|
else {
|
|
672
675
|
this.mock = false;
|
|
673
676
|
let opts: SerialPortOpenOptions<AutoDetectTypes> = extend(true, { path: this._cfg.rs485Port }, this._cfg.portSettings);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ControllerType, Timestamp, Utils, utils } from '../../controller/Constants';
|
|
2
|
-
import { LightGroup, LightGroupCircuit, sys, Valve, Body, Pump, PumpCircuit, Remote} from '../../controller/Equipment';
|
|
2
|
+
import { LightGroup, LightGroupCircuit, sys, Valve, Body, Pump, PumpCircuit, Remote } from '../../controller/Equipment';
|
|
3
3
|
import { CircuitState, state, ValveState } from '../../controller/State';
|
|
4
4
|
import { RemoteLogin, UnitConnection, FindUnits, SLEquipmentStateData, SLIntellichlorData, SLPumpStatusData, SLScheduleData, SLSystemTimeData, HeatModes, SLControllerConfigData, SLEquipmentConfigurationData, HeaterConfig, Valves, SLChemData, SLGetCustomNamesData } from 'node-screenlogic';
|
|
5
5
|
import * as Screenlogic from 'node-screenlogic';
|
|
@@ -87,7 +87,7 @@ export class ScreenLogicComms {
|
|
|
87
87
|
logger.screenlogic(msg);
|
|
88
88
|
})
|
|
89
89
|
let ver = await this._client.getVersionAsync();
|
|
90
|
-
logger.info(`Screenlogic: connect to ${systemName} ${ver} at ${unit.ipAddr}:${unit.port}`);
|
|
90
|
+
logger.info(`Screenlogic: connect to ${systemName} ${ver.version} at ${unit.ipAddr}:${unit.port}`);
|
|
91
91
|
|
|
92
92
|
let addClient = await this._client.addClientAsync();
|
|
93
93
|
logger.silly(`Screenlogic:Add client result: ${addClient}`);
|
|
@@ -912,21 +912,21 @@ class Controller {
|
|
|
912
912
|
}
|
|
913
913
|
], */
|
|
914
914
|
}
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
915
|
+
public static decodeHighSpeed(highSpeed: number[]) {
|
|
916
|
+
let maxCircuits = sys.controllerType === ControllerType.IntelliTouch ? 8 : 4;
|
|
917
|
+
let arrCircuits = [];
|
|
918
|
+
let pump = sys.pumps.find(x => { return x.master !== 1 && x.type === 65 });
|
|
919
|
+
for (let i = 0; i < maxCircuits && i < highSpeed.length; i++) {
|
|
920
|
+
let val = highSpeed[i];
|
|
921
|
+
if (val > 0) arrCircuits.push(val);
|
|
922
|
+
else if (typeof pump !== 'undefined') pump.circuits.removeItemById(i);
|
|
923
|
+
}
|
|
924
|
+
if (arrCircuits.length > 0) {
|
|
925
|
+
let pump = sys.pumps.getDualSpeed(true);
|
|
926
|
+
for (let j = 1; j <= arrCircuits.length; j++) pump.circuits.getItemById(j, true).circuit = arrCircuits[j - 1];
|
|
927
|
+
}
|
|
928
|
+
else if (typeof pump !== 'undefined') sys.pumps.removeItemById(pump.id);
|
|
929
|
+
}
|
|
930
930
|
public static decodeRemote(remoteDataArray) {
|
|
931
931
|
if (sys.controllerType === ControllerType.EasyTouch) {
|
|
932
932
|
|
|
@@ -980,11 +980,11 @@ class Controller {
|
|
|
980
980
|
remote6.button3 = remote.button8;
|
|
981
981
|
remote6.button4 = remote.button9;
|
|
982
982
|
if (!remote5.button1 && !remote5.button2 && !remote5.button3 && !remote5.button4) remote5.isActive = false;
|
|
983
|
-
|
|
984
|
-
|
|
983
|
+
else remote5.isActive = true;
|
|
984
|
+
|
|
985
985
|
if (!remote6.button1 && !remote6.button2 && !remote6.button3 && !remote6.button4) remote6.isActive = false;
|
|
986
|
-
|
|
987
|
-
|
|
986
|
+
else remote6.isActive = true;
|
|
987
|
+
|
|
988
988
|
}
|
|
989
989
|
else {
|
|
990
990
|
remote5.isActive = remote6.isActive = false;
|
|
@@ -1066,43 +1066,43 @@ class Controller {
|
|
|
1066
1066
|
}
|
|
1067
1067
|
|
|
1068
1068
|
}
|
|
1069
|
-
public static async decodePumpAsync(pDataArr: any
|
|
1070
|
-
pDataArr.forEach(async (pData, idx)=>{
|
|
1069
|
+
public static async decodePumpAsync(pDataArr: any) {
|
|
1070
|
+
pDataArr.forEach(async (pData, idx) => {
|
|
1071
1071
|
await sys.board.pumps.setPumpAsync(pData, false);
|
|
1072
1072
|
})
|
|
1073
1073
|
}
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
}
|
|
1074
|
+
public static async decodePumpStatusAsync(id: number, slpump: SLPumpStatusData) {
|
|
1075
|
+
/* {
|
|
1076
|
+
pumpCircuits: [
|
|
1077
|
+
{ circuitId: 6,speed: 2000,isRPMs: true, },
|
|
1078
|
+
{ circuitId: 8, speed:2700,isRPMs: true, },
|
|
1079
|
+
{ circuitId: 2,speed: 2710,isRPMs: true, },
|
|
1080
|
+
{ circuitId: 2,speed:1000, isRPMs: true,},
|
|
1081
|
+
{ circuitId: 5,speed:2830, isRPMs: true,},
|
|
1082
|
+
{ circuitId: 0,speed: 30,isRPMs: false,},
|
|
1083
|
+
{ circuitId: 0,speed: 30,isRPMs: false,},
|
|
1084
|
+
{ circuitId: 0,speed: 30,isRPMs: false,},
|
|
1085
|
+
],
|
|
1086
|
+
pumpType: 4,
|
|
1087
|
+
isRunning: false,
|
|
1088
|
+
pumpWatts: 0,
|
|
1089
|
+
pumpRPMs: 0,
|
|
1090
|
+
pumpUnknown1: 0,
|
|
1091
|
+
pumpGPMs: 0,
|
|
1092
|
+
pumpUnknown2: 255,
|
|
1093
|
+
}
|
|
1094
|
+
*/
|
|
1095
|
+
// RKS: 05-07-23 - This process of getting the pump by its id is flawed. We need to pull this information by its address.
|
|
1096
|
+
//let pstate = state.pumps.getItemById(id);
|
|
1097
|
+
let pstate = state.pumps.find(x => x.address === 95 + id);
|
|
1098
|
+
if (typeof pstate !== 'undefined') {
|
|
1099
|
+
pstate.watts = slpump.pumpWatts;
|
|
1100
|
+
pstate.rpm = slpump.pumpRPMs;
|
|
1101
|
+
pstate.flow = slpump.pumpGPMs === 255 ? 0 : slpump.pumpGPMs;
|
|
1102
|
+
pstate.command = (pstate.rpm > 0 || pstate.watts > 0) ? 10 : 0;
|
|
1103
|
+
state.emitEquipmentChanges();
|
|
1105
1104
|
}
|
|
1105
|
+
}
|
|
1106
1106
|
public static async decodeSchedules(slrecurring: SLScheduleData, slrunonce: SLScheduleData) {
|
|
1107
1107
|
/* reccuring schedules: [{"scheduleId":1,"circuitId":6,"startTime":"1800","stopTime":"0700","dayMask":127,"flags":0,"heatCmd":4,"heatSetPoint":70,"days":["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]},
|
|
1108
1108
|
|
|
@@ -1111,18 +1111,17 @@ class Controller {
|
|
|
1111
1111
|
Run once schedules: [{"scheduleId":12,"circuitId":6,"startTime":"0800","stopTime":"1100","dayMask":1,"flags":1,"heatCmd":4,"heatSetPoint":70,"days":["Mon"]},{"scheduleId":13,"circuitId":6,"startTime":"0800","stopTime":"1100","dayMask":1,"flags":1,"heatCmd":4,"heatSetPoint":70,"days":["Mon"]}] */
|
|
1112
1112
|
|
|
1113
1113
|
for (let i = 0; i < slrecurring.data.length; i++) {
|
|
1114
|
-
let slsched = slrecurring[i];
|
|
1115
|
-
let data = {
|
|
1116
|
-
id: slsched.scheduleId,
|
|
1117
|
-
circuit: slsched.circuitId,
|
|
1118
|
-
startTime: Math.floor(slsched.startTime / 100) * 60 + slsched.startTime % 100,
|
|
1119
|
-
endTime: Math.floor(slsched.stopTime / 100) * 60 + slsched.stopTime % 100,
|
|
1120
|
-
scheduleDays: slsched.dayMask,
|
|
1121
|
-
changeHeatSetPoint: slsched.heatCmd > 0,
|
|
1122
|
-
heatSetPoint: slsched.heatSetPoint,
|
|
1123
|
-
schedType: 128 // recurring
|
|
1124
|
-
}
|
|
1114
|
+
let slsched = slrecurring.data[i];
|
|
1125
1115
|
try {
|
|
1116
|
+
let data = {
|
|
1117
|
+
circuit: slsched.circuitId,
|
|
1118
|
+
startTime: Math.floor(parseInt(slsched.startTime, 10) / 100) * 60 + parseInt(slsched.startTime, 10) % 100,
|
|
1119
|
+
endTime: Math.floor(parseInt(slsched.stopTime, 10) / 100) * 60 + parseInt(slsched.stopTime, 10) % 100,
|
|
1120
|
+
scheduleDays: slsched.dayMask,
|
|
1121
|
+
changeHeatSetPoint: slsched.heatCmd > 0,
|
|
1122
|
+
heatSetPoint: slsched.heatSetPoint,
|
|
1123
|
+
schedType: 128 // recurring
|
|
1124
|
+
}
|
|
1126
1125
|
await sys.board.schedules.setScheduleAsync(data, false)
|
|
1127
1126
|
} catch (err) {
|
|
1128
1127
|
logger.error(`Error setting schedule ${slsched.scheduleId}. ${err.message}`);
|
|
@@ -1130,18 +1129,18 @@ class Controller {
|
|
|
1130
1129
|
}
|
|
1131
1130
|
for (let i = 0; i < slrunonce.data.length; i++) {
|
|
1132
1131
|
let slsched = slrunonce.data[i];
|
|
1133
|
-
let data = {
|
|
1134
|
-
id: slsched.scheduleId,
|
|
1135
|
-
circuit: slsched.circuitId,
|
|
1136
|
-
// start and stop come in as military time string
|
|
1137
|
-
startTime: parseInt(slsched.startTime, 10),
|
|
1138
|
-
endTime: parseInt(slsched.stopTime, 10),
|
|
1139
|
-
scheduleDays: slsched.dayMask,
|
|
1140
|
-
changeHeatSetPoint: slsched.heatCmd > 0,
|
|
1141
|
-
heatSetPoint: slsched.heatSetPoint,
|
|
1142
|
-
schedType: 0 // runonce
|
|
1143
|
-
}
|
|
1144
1132
|
try {
|
|
1133
|
+
let data = {
|
|
1134
|
+
id: slsched.scheduleId,
|
|
1135
|
+
circuit: slsched.circuitId,
|
|
1136
|
+
// start and stop come in as military time string
|
|
1137
|
+
startTime: parseInt(slsched.startTime, 10),
|
|
1138
|
+
endTime: parseInt(slsched.stopTime, 10),
|
|
1139
|
+
scheduleDays: slsched.dayMask,
|
|
1140
|
+
changeHeatSetPoint: slsched.heatCmd > 0,
|
|
1141
|
+
heatSetPoint: slsched.heatSetPoint,
|
|
1142
|
+
schedType: 0 // runonce
|
|
1143
|
+
}
|
|
1145
1144
|
await sys.board.schedules.setScheduleAsync(data, false);
|
|
1146
1145
|
sys.board.system.setTZ();
|
|
1147
1146
|
} catch (err) {
|
|
@@ -1607,23 +1606,23 @@ export class SLController extends SLCommands {
|
|
|
1607
1606
|
const spaCommand: Remote = sys.remotes.getItemById(8).get();
|
|
1608
1607
|
let alarm = 0;
|
|
1609
1608
|
|
|
1610
|
-
switch (eq){
|
|
1609
|
+
switch (eq) {
|
|
1611
1610
|
case 'misc': {
|
|
1612
|
-
|
|
1611
|
+
misc = extend({}, true, misc, obj);
|
|
1613
1612
|
break;
|
|
1614
1613
|
}
|
|
1615
1614
|
case 'lightGroup': {
|
|
1616
|
-
|
|
1615
|
+
lightGroup = extend({}, true, lightGroup, obj);
|
|
1617
1616
|
break;
|
|
1618
1617
|
}
|
|
1619
|
-
case 'pump':{
|
|
1620
|
-
let idx = pumps.findIndex(el=>{console.log(el.id);return el.id === obj.id;})
|
|
1618
|
+
case 'pump': {
|
|
1619
|
+
let idx = pumps.findIndex(el => { console.log(el.id); return el.id === obj.id; })
|
|
1621
1620
|
if (idx >= 0) pumps = extend({}, true, pumps[idx], obj);
|
|
1622
1621
|
else return Promise.reject(`Screenlogic: No pump found by that id: ${obj}`);
|
|
1623
1622
|
break;
|
|
1624
1623
|
}
|
|
1625
1624
|
case 'heater': {
|
|
1626
|
-
let idx = heaters.findIndex(el=>{console.log(el.id);return el.id === obj.id;})
|
|
1625
|
+
let idx = heaters.findIndex(el => { console.log(el.id); return el.id === obj.id; })
|
|
1627
1626
|
if (idx >= 0) heaters = extend({}, true, heaters[idx], obj);
|
|
1628
1627
|
else return Promise.reject(`Screenlogic: No pump found by that id: ${obj}`);
|
|
1629
1628
|
break;
|
|
@@ -1646,7 +1645,7 @@ export class SLController extends SLCommands {
|
|
|
1646
1645
|
// await this._unit.equipment.setEquipmentConfigurationAsync(data);
|
|
1647
1646
|
}
|
|
1648
1647
|
|
|
1649
|
-
public async setSystemTime(){
|
|
1648
|
+
public async setSystemTime() {
|
|
1650
1649
|
try {
|
|
1651
1650
|
let sysTime = await this._unit.equipment.setSystemTimeAsync(state.time.toDate(), sys.general.options.adjustDST);
|
|
1652
1651
|
logger.silly(`Screenlogic:set time result: ${sysTime}`);
|
|
@@ -1654,7 +1653,7 @@ export class SLController extends SLCommands {
|
|
|
1654
1653
|
return Promise.reject(new InvalidOperationError('Unable to set system time.', error.message));
|
|
1655
1654
|
}
|
|
1656
1655
|
}
|
|
1657
|
-
public async setCustomName(idx: number, name: string){
|
|
1656
|
+
public async setCustomName(idx: number, name: string) {
|
|
1658
1657
|
try {
|
|
1659
1658
|
let ack = await this._unit.equipment.setCustomNameAsync(idx, name);
|
|
1660
1659
|
logger.silly(`Screenlogic:set custom name result: ${JSON.stringify(ack)}`);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { clearTimeout, setTimeout } from 'timers';
|
|
2
2
|
import { conn } from '../../../controller/comms/Comms';
|
|
3
3
|
import { Outbound, Protocol, Response } from '../../../controller/comms/messages/Messages';
|
|
4
|
-
import { IChemical, IChemController, Chlorinator, ChemController, ChemControllerCollection, ChemFlowSensor, Chemical,
|
|
4
|
+
import { IChemical, IChemController, Chlorinator, ChemController, ChemControllerCollection, ChemFlowSensor, Chemical, ChemicalORP, ChemicalORPProbe, ChemicalPh, ChemicalPhProbe, ChemicalProbe, ChemicalPump, ChemicalTank, sys } from "../../../controller/Equipment";
|
|
5
5
|
import { logger } from '../../../logger/Logger';
|
|
6
6
|
import { InterfaceServerResponse, webApp } from "../../../web/Server";
|
|
7
7
|
import { Timestamp, utils } from '../../Constants';
|
|
@@ -727,11 +727,16 @@ export class NixieChemController extends NixieChemControllerBase {
|
|
|
727
727
|
else schem.alarms.orp = 0;
|
|
728
728
|
let chlorErr = 0;
|
|
729
729
|
if (useChlorinator && schem.isBodyOn) {
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
730
|
+
const chlorCollection = sys.chlorinators.getByBody(schem.activeBodyId);
|
|
731
|
+
if (chlorCollection.length > 0) {
|
|
732
|
+
for (let chlor of chlorCollection.toArray()) {
|
|
733
|
+
let schlor = state.chlorinators.getItemById(chlor.id);
|
|
734
|
+
if (schlor.status & 0xF0) {
|
|
735
|
+
chlorErr = 16;
|
|
736
|
+
break;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
735
740
|
}
|
|
736
741
|
schem.warnings.chlorinatorCommError = chlorErr;
|
|
737
742
|
schem.warnings.pHLockout = useChlorinator === false && probeType !== 0 && pumpType !== 0 && schem.ph.level >= chem.orp.phLockout ? 1 : 0;
|
|
@@ -1067,7 +1072,7 @@ class NixieChemical extends NixieChildEquipment implements INixieChemical {
|
|
|
1067
1072
|
schem.chlor.isDosing = schem.pump.isDosing = false;
|
|
1068
1073
|
if (!this.chemical.flowOnlyMixing || (schem.chemController.isBodyOn && this.chemController.flowDetected && !schem.freezeProtect)) {
|
|
1069
1074
|
if (this.chemType === 'orp' && typeof this.chemController.orp.orp.useChlorinator !== 'undefined' && this.chemController.orp.orp.useChlorinator && this.chemController.orp.orp.chlorDosingMethod > 0) {
|
|
1070
|
-
if (state.chlorinators.getItemById(this.
|
|
1075
|
+
if (state.chlorinators.getItemById(this.chlor.id).currentOutput !== 0) {
|
|
1071
1076
|
logger.debug(`Chem mixing ORP (chlorinator) paused waiting for chlor current output to be 0%. Mix time remaining: ${utils.formatDuration(schem.mixTimeRemaining)} `);
|
|
1072
1077
|
return;
|
|
1073
1078
|
}
|
|
@@ -1422,24 +1427,25 @@ export class NixieChemPump extends NixieChildEquipment {
|
|
|
1422
1427
|
}
|
|
1423
1428
|
}
|
|
1424
1429
|
export class NixieChemChlor extends NixieChildEquipment {
|
|
1425
|
-
public chlor:
|
|
1426
|
-
public isOn: boolean;
|
|
1427
|
-
public chlorId = 0;
|
|
1430
|
+
public get chlor(): Chlorinator { return sys.chlorinators.getItemById((this.getParent() as NixieChemicalORP).orp.chlorId); }
|
|
1431
|
+
public isOn: boolean; // can this just be chlor.isOn?
|
|
1428
1432
|
public _lastOnStatus: number;
|
|
1429
1433
|
protected _dosingTimer: NodeJS.Timeout;
|
|
1430
1434
|
private _isStopping = false;
|
|
1431
1435
|
public chlorInterval = 15;
|
|
1432
|
-
constructor(chemical: NixieChemical, chlor: ChemicalChlor) { super(chemical); this.chlor = chlor; }
|
|
1436
|
+
// constructor(chemical: NixieChemical, chlor: ChemicalChlor) { super(chemical); this.chlor = chlor; }
|
|
1437
|
+
constructor(chemical: NixieChemical) { super(chemical); }
|
|
1433
1438
|
public get chemical(): NixieChemical { return this.getParent() as NixieChemical; }
|
|
1434
1439
|
public async setChlorAsync(schlor: ChemicalChlorState, data: any) {
|
|
1435
1440
|
try {
|
|
1436
1441
|
if (typeof data.chlorDosingMethod !== 'undefined' && data.chlorDosingMethod === 0) {
|
|
1437
1442
|
if (schlor.chemical.dosingStatus === 0) { await this.chemical.cancelDosing(schlor.chemController.orp, 'dosing method changed'); }
|
|
1438
1443
|
if (schlor.chemical.dosingStatus === 1) { await this.chemical.cancelMixing(schlor.chemController.orp); }
|
|
1439
|
-
let chlor = sys.chlorinators.getItemById(this.chlorId);
|
|
1444
|
+
let chlor = sys.chlorinators.getItemById((this.getParent() as NixieChemicalORP).orp.chlorId);
|
|
1440
1445
|
chlor.disabled = false;
|
|
1441
1446
|
chlor.isDosing = false;
|
|
1442
1447
|
}
|
|
1448
|
+
let c = sys.chlorinators.toArray
|
|
1443
1449
|
} catch (err) { logger.error(`setChlorAsync: ${err.message}`); return Promise.reject(err); }
|
|
1444
1450
|
}
|
|
1445
1451
|
public async stopDosing(schem: IChemicalState, reason: string): Promise<void> {
|
|
@@ -1479,7 +1485,8 @@ export class NixieChemChlor extends NixieChildEquipment {
|
|
|
1479
1485
|
await this.chemical.cancelDosing(schem, 'undefined dose');
|
|
1480
1486
|
return;
|
|
1481
1487
|
}
|
|
1482
|
-
|
|
1488
|
+
let chlor = sys.chlorinators.getItemById((this.getParent() as NixieChemicalORP).orp.chlorId);
|
|
1489
|
+
if (chlor.ratedLbs === 0) {
|
|
1483
1490
|
// We aren't going to do anything.
|
|
1484
1491
|
logger.verbose(`Chem dose ignore chlor because it doesn't have a dosing rating.`);
|
|
1485
1492
|
}
|
|
@@ -1488,7 +1495,7 @@ export class NixieChemChlor extends NixieChildEquipment {
|
|
|
1488
1495
|
let isBodyOn = schem.chemController.flowDetected;
|
|
1489
1496
|
await this.chemical.initDose(schem);
|
|
1490
1497
|
let chemController = schem.getParent()
|
|
1491
|
-
let schlor = state.chlorinators.getItemById(
|
|
1498
|
+
let schlor = state.chlorinators.getItemById(chlor.id);
|
|
1492
1499
|
if (!isBodyOn) {
|
|
1493
1500
|
// Make sure the chlor is off.
|
|
1494
1501
|
logger.info(`Chem chlor flow not detected. Body is not running.`);
|
|
@@ -1501,7 +1508,7 @@ export class NixieChemChlor extends NixieChildEquipment {
|
|
|
1501
1508
|
if (chem.ph.dosePriority)
|
|
1502
1509
|
await this.chemical.cancelDosing(schem, 'ph dose priority');
|
|
1503
1510
|
}
|
|
1504
|
-
else if (
|
|
1511
|
+
else if (chlor.superChlor) {
|
|
1505
1512
|
// if superchlor is active, it may be to boost the ORP and we should respect that
|
|
1506
1513
|
await this.chemical.cancelDosing(schem, 'superchlor');
|
|
1507
1514
|
}
|
|
@@ -1518,7 +1525,7 @@ export class NixieChemChlor extends NixieChildEquipment {
|
|
|
1518
1525
|
else {
|
|
1519
1526
|
if (typeof dose._lastLatch !== 'undefined') {
|
|
1520
1527
|
let time = new Date().getTime() - (dose._lastLatch || new Date().getTime());
|
|
1521
|
-
let vol =
|
|
1528
|
+
let vol = chlor.ratedLbs * time / 1000;
|
|
1522
1529
|
schem.appendDose(vol, time);
|
|
1523
1530
|
}
|
|
1524
1531
|
logger.info(`Chem Controller ${dose.chem} chlorinated ${Math.round(dose.volumeDosed * 1000000) / 1000000}lbs of ${Math.round(dose.volume * 1000000) / 1000000}lbs - ${utils.formatDuration(dose.timeRemaining)} remaining`);
|
|
@@ -1565,14 +1572,15 @@ export class NixieChemChlor extends NixieChildEquipment {
|
|
|
1565
1572
|
public async turnOff(schem: IChemicalState): Promise<ChlorinatorState> {
|
|
1566
1573
|
try {
|
|
1567
1574
|
//logger.info(`Turning off the chlorinator`);
|
|
1568
|
-
let
|
|
1575
|
+
let chemORP = this.getParent() as NixieChemicalORP;
|
|
1576
|
+
let chlor = sys.chlorinators.getItemById(chemORP.orp.chlorId);
|
|
1569
1577
|
let schlor = state.chlorinators.getItemById(chlor.id);
|
|
1570
1578
|
if (schlor.currentOutput === 0 && schlor.targetOutput === 0 && !schlor.superChlor && chlor.disabled && !chlor.isDosing) {
|
|
1571
1579
|
this.isOn = schem.chlor.isDosing = false;
|
|
1572
1580
|
return schlor;
|
|
1573
1581
|
}
|
|
1574
1582
|
let cstate = await sys.board.chlorinator.setChlorAsync({
|
|
1575
|
-
id:
|
|
1583
|
+
id: chlor.id,
|
|
1576
1584
|
disabled: true,
|
|
1577
1585
|
isDosing: false
|
|
1578
1586
|
})
|
|
@@ -1583,14 +1591,15 @@ export class NixieChemChlor extends NixieChildEquipment {
|
|
|
1583
1591
|
}
|
|
1584
1592
|
public async turnOn(schem: ChemicalState, latchTimeout?: number): Promise<ChlorinatorState> {
|
|
1585
1593
|
try {
|
|
1586
|
-
let
|
|
1594
|
+
let chemORP = this.getParent() as NixieChemicalORP;
|
|
1595
|
+
let chlor = sys.chlorinators.getItemById(chemORP.orp.chlorId);
|
|
1587
1596
|
let schlor = state.chlorinators.getItemById(chlor.id);
|
|
1588
1597
|
if (schlor.currentOutput === 100 && schlor.targetOutput === 100 && !schlor.superChlor && !chlor.disabled && chlor.isDosing) {
|
|
1589
1598
|
this.isOn = schem.chlor.isDosing = true;
|
|
1590
1599
|
return schlor;
|
|
1591
1600
|
}
|
|
1592
1601
|
let cstate = await sys.board.chlorinator.setChlorAsync({
|
|
1593
|
-
id:
|
|
1602
|
+
id: chlor.id,
|
|
1594
1603
|
disabled: false,
|
|
1595
1604
|
isDosing: true
|
|
1596
1605
|
})
|
|
@@ -1939,13 +1948,14 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
1939
1948
|
this.chemType = 'orp';
|
|
1940
1949
|
this.orp = chemical;
|
|
1941
1950
|
this.probe = new NixieChemProbeORP(this, chemical.probe);
|
|
1942
|
-
this.chlor = new NixieChemChlor(this, chemical.chlor);
|
|
1951
|
+
// this.chlor = new NixieChemChlor(this, chemical.chlor);
|
|
1952
|
+
this.chlor = new NixieChemChlor(this);
|
|
1943
1953
|
let sorp = state.chemControllers.getItemById(controller.id).orp;
|
|
1944
1954
|
if (!this.orp.enabled) {
|
|
1945
1955
|
this.orp.doserType = 0;
|
|
1946
1956
|
sorp.chemType = 'none';
|
|
1947
1957
|
}
|
|
1948
|
-
else if (
|
|
1958
|
+
else if (this.orp.useChlorinator) {
|
|
1949
1959
|
this.orp.doserType = 2;
|
|
1950
1960
|
sorp.chemType = 'chlorine';
|
|
1951
1961
|
}
|
|
@@ -1962,14 +1972,38 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
1962
1972
|
public async setORPAsync(sorp: ChemicalORPState, data: any) {
|
|
1963
1973
|
try {
|
|
1964
1974
|
if (typeof data !== 'undefined') {
|
|
1965
|
-
|
|
1975
|
+
this.orp.useChlorinator = typeof data.useChlorinator !== 'undefined' ? utils.makeBool(data.useChlorinator) : this.orp.useChlorinator;
|
|
1976
|
+
if (this.orp.useChlorinator) {
|
|
1977
|
+
if (typeof data.chlorId === 'undefined') {
|
|
1978
|
+
return Promise.reject(new InvalidEquipmentDataError(`Chlorinator ID must be provided when useChlorinator is true`, 'chemController', data.chlorId));
|
|
1979
|
+
}
|
|
1980
|
+
let chlor = sys.chlorinators.getItemById(data.chlorId);
|
|
1981
|
+
if (typeof chlor === 'undefined') {
|
|
1982
|
+
return Promise.reject(new InvalidEquipmentDataError(`Chlorinator with ID ${data.chlorId} not found`, 'chemController', data.chlorId));
|
|
1983
|
+
}
|
|
1984
|
+
if (chlor.body !== this.chemController.chem.body && chlor.body !== 32) {
|
|
1985
|
+
return Promise.reject(new InvalidEquipmentDataError(`Chlorinator body does not match the chem controller body`, 'chemController', data.chlorId));
|
|
1986
|
+
}
|
|
1987
|
+
let assignedChemController = sys.chemControllers.get().find((cc: ChemController) =>
|
|
1988
|
+
{
|
|
1989
|
+
return cc.orp.chlorId === data.chlorId && cc.id !== this.chemController.id;
|
|
1990
|
+
});
|
|
1991
|
+
if (assignedChemController) {
|
|
1992
|
+
return Promise.reject(new InvalidEquipmentDataError(`Chlorinator is already assigned to another chem controller`, 'chemController', data.chlorId));
|
|
1993
|
+
}
|
|
1994
|
+
this.orp.chlorId = data.chlorId;
|
|
1995
|
+
if (typeof data.chlorDosingMethod !== 'undefined') { this.orp.chlorDosingMethod = data.chlorDosingMethod; }
|
|
1996
|
+
} else {
|
|
1997
|
+
this.orp.chlorId = undefined;
|
|
1998
|
+
this.orp.chlorDosingMethod = undefined;
|
|
1999
|
+
}
|
|
1966
2000
|
sorp.enabled = this.orp.enabled = typeof data.enabled !== 'undefined' ? utils.makeBool(data.enabled) : this.orp.enabled;
|
|
1967
2001
|
sorp.level = typeof data.level !== 'undefined' && !isNaN(parseFloat(data.level)) ? parseFloat(data.level) : sorp.level;
|
|
1968
2002
|
this.orp.phLockout = typeof data.phLockout !== 'undefined' && !isNaN(parseFloat(data.phLockout)) ? parseFloat(data.phLockout) : this.orp.phLockout;
|
|
1969
2003
|
this.orp.flowReadingsOnly = typeof data.flowReadingsOnly !== 'undefined' ? utils.makeBool(data.flowReadingsOnly) : this.orp.flowReadingsOnly;
|
|
1970
2004
|
this.orp.disableOnFreeze = typeof data.disableOnFreeze !== 'undefined' ? utils.makeBool(data.disableOnFreeze) : this.orp.disableOnFreeze;
|
|
1971
2005
|
if (!this.orp.disableOnFreeze) sorp.freezeProtect = false;
|
|
1972
|
-
|
|
2006
|
+
|
|
1973
2007
|
await this.setDosing(this.orp, data);
|
|
1974
2008
|
await this.setMixing(this.orp, data);
|
|
1975
2009
|
await this.probe.setProbeORPAsync(sorp.probe, data.probe);
|
|
@@ -1980,7 +2014,7 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
1980
2014
|
this.orp.doserType = 0;
|
|
1981
2015
|
sorp.chemType = 'none';
|
|
1982
2016
|
}
|
|
1983
|
-
else if (
|
|
2017
|
+
else if (this.orp.useChlorinator) {
|
|
1984
2018
|
this.orp.doserType = 2;
|
|
1985
2019
|
sorp.chemType = 'chlorine';
|
|
1986
2020
|
}
|
|
@@ -2069,7 +2103,7 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
2069
2103
|
|
|
2070
2104
|
public async cancelDosing(sorp: ChemicalORPState, reason: string): Promise<void> {
|
|
2071
2105
|
try {
|
|
2072
|
-
if (typeof
|
|
2106
|
+
if (typeof this.orp.useChlorinator !== 'undefined' && this.orp.useChlorinator && this.chemController.orp.orp.chlorDosingMethod > 0) {
|
|
2073
2107
|
await this.chlor.stopDosing(sorp, reason);
|
|
2074
2108
|
// for chlor, we want 15 minute intervals
|
|
2075
2109
|
if (sorp.doseHistory.length) {
|
|
@@ -2104,7 +2138,7 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
2104
2138
|
if (typeof mixingTime !== 'undefined') {
|
|
2105
2139
|
// This is a manual mix so we need to make sure the pump is not dosing.
|
|
2106
2140
|
logger.info(`Clearing any possible ${schem.chemType} dosing or existing mix for mixingTime: ${mixingTime}`);
|
|
2107
|
-
if (
|
|
2141
|
+
if (this.orp.useChlorinator) await this.chlor.stopDosing(schem, 'mix override');
|
|
2108
2142
|
else await this.pump.stopDosing(schem, 'mix override');
|
|
2109
2143
|
await this.stopMixing(schem);
|
|
2110
2144
|
}
|
|
@@ -2274,9 +2308,8 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
2274
2308
|
return;
|
|
2275
2309
|
}
|
|
2276
2310
|
}
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
let chlor = sys.chlorinators.getItemById(this.chlor.chlorId); // Still haven't seen any systems with 2+ chlors
|
|
2311
|
+
let chlor = this.chlor.chlor; // Still haven't seen any systems with 2+ chlors.
|
|
2312
|
+
// 2024.12.25 RSG - Oh really? See https://github.com/tagyoureit/nodejs-poolController/discussions/896
|
|
2280
2313
|
let schlor = state.chlorinators.getItemById(chlor.id);
|
|
2281
2314
|
// If someone or something is superchloring the pool, let it be
|
|
2282
2315
|
if (schlor.superChlor) return;
|
|
@@ -2429,7 +2462,7 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
2429
2462
|
logger.info(`Removing chlor ${chlor.id} from Chem Controller ${this.getParent().id}`);
|
|
2430
2463
|
let schem = state.chemControllers.getItemById(this.getParent().id);
|
|
2431
2464
|
this.orp.useChlorinator = false;
|
|
2432
|
-
schem.orp.useChlorinator = false;
|
|
2465
|
+
// schem.orp.useChlorinator = false;
|
|
2433
2466
|
if (schem.orp.dosingStatus === 0) { await this.cancelDosing(schem.orp, 'deleting chlorinator'); }
|
|
2434
2467
|
if (schem.orp.dosingStatus === 1) { await this.cancelMixing(schem.orp); }
|
|
2435
2468
|
}
|
|
@@ -45,7 +45,7 @@ export class NixieCircuitCollection extends NixieEquipmentCollection<NixieCircui
|
|
|
45
45
|
} catch (err) { return logger.error(`NCP: setServiceModeAsync: ${err.message}`); }
|
|
46
46
|
}
|
|
47
47
|
public async setLightThemeAsync(id: number, theme: any) {
|
|
48
|
-
|
|
48
|
+
let c: NixieCircuit = this.find(elem => elem.id === id) as NixieCircuit;
|
|
49
49
|
if (typeof c === 'undefined') return Promise.reject(new Error(`NCP: Circuit ${id} could not be found to set light theme ${theme.name}.`));
|
|
50
50
|
await c.setLightThemeAsync(theme);
|
|
51
51
|
} catch(err) { return logger.error(`NCP: sendOnOffSequence: ${err.message}`); }
|
|
@@ -75,10 +75,10 @@ export class NixieCircuitCollection extends NixieEquipmentCollection<NixieCircui
|
|
|
75
75
|
catch (err) { logger.error(`setCircuitAsync: ${err.message}`); return Promise.reject(err); }
|
|
76
76
|
}
|
|
77
77
|
public async checkCircuitEggTimerExpirationAsync(cstate: ICircuitState) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
try {
|
|
79
|
+
let c: NixieCircuit = this.find(elem => elem.id === cstate.id) as NixieCircuit;
|
|
80
|
+
await c.checkCircuitEggTimerExpirationAsync(cstate);
|
|
81
|
+
} catch (err) { logger.error(`NCP: Error synching circuit states: ${err}`); }
|
|
82
82
|
}
|
|
83
83
|
public async initAsync(circuits: CircuitCollection) {
|
|
84
84
|
try {
|
|
@@ -159,21 +159,21 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
159
159
|
protected async setIntelliBriteThemeAsync(cstate: CircuitState, theme: any): Promise<InterfaceServerResponse> {
|
|
160
160
|
let arr = [];
|
|
161
161
|
let count = typeof theme !== 'undefined' && theme.sequence ? theme.sequence : 0;
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
162
|
+
|
|
163
|
+
// Removing this. No need to turn the light off first. We actually need it on to start the sequence for theme setting to work correctly when the light is starting from the off state.
|
|
164
|
+
// if (cstate.isOn) arr.push({ isOn: false, timeout: 1000 });
|
|
165
|
+
|
|
166
|
+
// Start the sequence of off/on after the light is on.
|
|
167
167
|
arr.push({ isOn: true, timeout: 100 });
|
|
168
168
|
for (let i = 0; i < count; i++) {
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
arr.push({ isOn: false, timeout: 100 });
|
|
170
|
+
arr.push({ isOn: true, timeout: 100 });
|
|
171
171
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
172
|
+
// Ensure light stays on long enough for the theme to stick (required for light group theme setting to function correctly).
|
|
173
|
+
// 2s was too short.
|
|
174
|
+
arr.push({ isOn: true, timeout: 3000 });
|
|
175
|
+
|
|
176
|
+
logger.debug(arr);
|
|
177
177
|
let res = await NixieEquipment.putDeviceService(this.circuit.connectionId, `/state/device/${this.circuit.deviceBinding}`, arr, 60000);
|
|
178
178
|
// Even though we ended with on we need to make sure that the relay stays on now that we are done.
|
|
179
179
|
if (!res.error) {
|
|
@@ -182,7 +182,7 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
182
182
|
}
|
|
183
183
|
return res;
|
|
184
184
|
}
|
|
185
|
-
protected async
|
|
185
|
+
protected async setPoolToneThemeAsync(cstate: CircuitState, theme: any): Promise<InterfaceServerResponse> {
|
|
186
186
|
let ptheme = sys.board.valueMaps.lightThemes.findItem(cstate.lightingTheme) || { val: 0, sequence: 0 };
|
|
187
187
|
// First check to see if we are on. If we are not then we need to emit our status as if we are initializing and busy.
|
|
188
188
|
let arr = [];
|
|
@@ -196,7 +196,40 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
196
196
|
let count = theme.sequence - ptheme.sequence;
|
|
197
197
|
if (count < 0) count = count + 16;
|
|
198
198
|
for (let i = 0; i < count; i++) {
|
|
199
|
-
arr.push({ isOn: true, timeout: 200 });
|
|
199
|
+
arr.push({ isOn: true, timeout: 200 });
|
|
200
|
+
arr.push({ isOn: false, timeout: 200 });
|
|
201
|
+
}
|
|
202
|
+
console.log(arr);
|
|
203
|
+
if (arr.length === 0) return new InterfaceServerResponse(200, 'Success');
|
|
204
|
+
let res = await NixieEquipment.putDeviceService(this.circuit.connectionId, `/state/device/${this.circuit.deviceBinding}`, arr, 60000);
|
|
205
|
+
// Even though we ended with on we need to make sure that the relay stays on now that we are done.
|
|
206
|
+
if (!res.error) {
|
|
207
|
+
cstate.lightingTheme = ptheme.val;
|
|
208
|
+
cstate.isOn = true; // At this point the relay will be off but we want the process
|
|
209
|
+
// to assume that the relay state is not actually changing.
|
|
210
|
+
this._sequencing = false;
|
|
211
|
+
await this.setCircuitStateAsync(cstate, true, false);
|
|
212
|
+
}
|
|
213
|
+
return res;
|
|
214
|
+
}
|
|
215
|
+
protected async setWaterColorsThemeAsync(cstate: CircuitState, theme: any): Promise<InterfaceServerResponse> {
|
|
216
|
+
// RSG 2024.12.24 - This logic was aligned with the Pool Tone themes. I haven't checked if that
|
|
217
|
+
// logic is correct, but made a copy and adjusted for the watercolors themes.
|
|
218
|
+
|
|
219
|
+
let ptheme = sys.board.valueMaps.lightThemes.findItem(cstate.lightingTheme) || { val: 0, sequence: 0 };
|
|
220
|
+
// First check to see if we are on. If we are not then we need to emit our status as if we are initializing and busy.
|
|
221
|
+
let arr = [];
|
|
222
|
+
if (ptheme.val === 0) {
|
|
223
|
+
// We don't know our previous theme so we are going to sync the lights to get a starting point.
|
|
224
|
+
arr.push({ isOn: true, timeout: 1000 }); // Turn on for 1 second
|
|
225
|
+
arr.push({ isOn: false, timeout: 5000 }); // Turn off for 5 seconds
|
|
226
|
+
arr.push({ isOn: true, timeout: 1000 });
|
|
227
|
+
ptheme = sys.board.valueMaps.lightThemes.findItem('alpinewhite');
|
|
228
|
+
}
|
|
229
|
+
let count = theme.sequence - ptheme.sequence;
|
|
230
|
+
if (count < 0) count = count + 14;
|
|
231
|
+
for (let i = 0; i < count; i++) {
|
|
232
|
+
arr.push({ isOn: true, timeout: 200 });
|
|
200
233
|
arr.push({ isOn: false, timeout: 200 });
|
|
201
234
|
}
|
|
202
235
|
console.log(arr);
|
|
@@ -206,7 +239,7 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
206
239
|
if (!res.error) {
|
|
207
240
|
cstate.lightingTheme = ptheme.val;
|
|
208
241
|
cstate.isOn = true; // At this point the relay will be off but we want the process
|
|
209
|
-
|
|
242
|
+
// to assume that the relay state is not actually changing.
|
|
210
243
|
this._sequencing = false;
|
|
211
244
|
await this.setCircuitStateAsync(cstate, true, false);
|
|
212
245
|
}
|
|
@@ -243,7 +276,7 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
243
276
|
if (!res.error) {
|
|
244
277
|
cstate.lightingTheme = ptheme.val;
|
|
245
278
|
cstate.isOn = true; // At this point the relay will be off but we want the process
|
|
246
|
-
|
|
279
|
+
// to assume that the relay state is not actually changing.
|
|
247
280
|
this._sequencing = false;
|
|
248
281
|
await this.setCircuitStateAsync(cstate, true, false);
|
|
249
282
|
}
|
|
@@ -264,7 +297,6 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
264
297
|
switch (type.name) {
|
|
265
298
|
case 'colorcascade':
|
|
266
299
|
case 'globrite':
|
|
267
|
-
case 'pooltone':
|
|
268
300
|
case 'magicstream':
|
|
269
301
|
case 'intellibrite':
|
|
270
302
|
res = await this.setIntelliBriteThemeAsync(cstate, theme);
|
|
@@ -275,6 +307,9 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
275
307
|
case 'watercolors':
|
|
276
308
|
res = await this.setWaterColorsThemeAsync(cstate, theme);
|
|
277
309
|
break;
|
|
310
|
+
case 'pooltone':
|
|
311
|
+
res = await this.setPoolToneThemeAsync(cstate, theme);
|
|
312
|
+
break;
|
|
278
313
|
}
|
|
279
314
|
cstate.action = 0;
|
|
280
315
|
// Make sure clients know that we are done.
|
|
@@ -285,11 +320,11 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
285
320
|
}
|
|
286
321
|
public async sendOnOffSequenceAsync(count: number | { isOn: boolean, timeout: number }[], timeout?: number): Promise<InterfaceServerResponse> {
|
|
287
322
|
try {
|
|
288
|
-
|
|
323
|
+
|
|
289
324
|
this._sequencing = true;
|
|
290
325
|
let arr = [];
|
|
291
326
|
let cstate = state.circuits.getItemById(this.circuit.id);
|
|
292
|
-
|
|
327
|
+
|
|
293
328
|
if (typeof count === 'number') {
|
|
294
329
|
if (cstate.isOn) arr.push({ isOn: false, timeout: 1000 });
|
|
295
330
|
let t = typeof timeout === 'undefined' ? 100 : timeout;
|
|
@@ -339,21 +374,21 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
339
374
|
// Check to see if we should be on by poking the schedules.
|
|
340
375
|
}
|
|
341
376
|
if (utils.isNullOrEmpty(this.circuit.connectionId) || utils.isNullOrEmpty(this.circuit.deviceBinding)) {
|
|
342
|
-
if (val && val !== cstate.isOn){
|
|
377
|
+
if (val && val !== cstate.isOn) {
|
|
343
378
|
sys.board.circuits.setEndTime(sys.circuits.getInterfaceById(cstate.id), cstate, val);
|
|
344
379
|
}
|
|
345
|
-
else if (!val){
|
|
380
|
+
else if (!val) {
|
|
346
381
|
if (cstate.manualPriorityActive) delayMgr.cancelManualPriorityDelay(cstate.id);
|
|
347
382
|
cstate.manualPriorityActive = false; // if the delay was previously cancelled, still need to turn this off
|
|
348
|
-
}
|
|
349
|
-
cstate.isOn = val;
|
|
383
|
+
}
|
|
384
|
+
cstate.isOn = val;
|
|
350
385
|
return new InterfaceServerResponse(200, 'Success');
|
|
351
386
|
}
|
|
352
387
|
if (this._sequencing) return new InterfaceServerResponse(200, 'Success');
|
|
353
388
|
let res = await NixieEquipment.putDeviceService(this.circuit.connectionId, `/state/device/${this.circuit.deviceBinding}`, { isOn: val, latch: val ? 10000 : undefined });
|
|
354
389
|
if (res.status.code === 200) {
|
|
355
390
|
// Set this up so we can process our egg timer.
|
|
356
|
-
if (val && val !== cstate.isOn){
|
|
391
|
+
if (val && val !== cstate.isOn) {
|
|
357
392
|
sys.board.circuits.setEndTime(sys.circuits.getInterfaceById(cstate.id), cstate, val);
|
|
358
393
|
switch (sys.board.valueMaps.circuitFunctions.getName(this.circuit.type)) {
|
|
359
394
|
case 'colorlogic':
|
|
@@ -385,7 +420,7 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
385
420
|
break;
|
|
386
421
|
}
|
|
387
422
|
}
|
|
388
|
-
else if (!val){
|
|
423
|
+
else if (!val) {
|
|
389
424
|
delayMgr.cancelManualPriorityDelays();
|
|
390
425
|
cstate.manualPriorityActive = false; // if the delay was previously cancelled, still need to turn this off
|
|
391
426
|
}
|
package/package.json
CHANGED
|
@@ -301,7 +301,8 @@ export class ConfigRoute {
|
|
|
301
301
|
// waterFlow: sys.board.valueMaps.chemControllerWaterFlow.toArray(), // remove
|
|
302
302
|
controllers: sys.chemControllers.get(),
|
|
303
303
|
maxChemControllers: sys.equipment.maxChemControllers,
|
|
304
|
-
doserTypes: sys.board.valueMaps.chemDoserTypes.toArray()
|
|
304
|
+
doserTypes: sys.board.valueMaps.chemDoserTypes.toArray(),
|
|
305
|
+
chlorinators: sys.chlorinators.get(),
|
|
305
306
|
};
|
|
306
307
|
return res.status(200).send(opts);
|
|
307
308
|
}
|