nodejs-poolcontroller 7.5.1 → 7.7.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/.github/ISSUE_TEMPLATE/1-bug-report.yml +84 -0
- package/.github/ISSUE_TEMPLATE/2-docs.md +12 -0
- package/.github/ISSUE_TEMPLATE/3-proposal.md +28 -0
- package/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/Changelog +19 -0
- package/Dockerfile +3 -3
- package/README.md +13 -8
- package/app.ts +1 -1
- package/config/Config.ts +38 -2
- package/config/VersionCheck.ts +27 -12
- package/controller/Constants.ts +2 -1
- package/controller/Equipment.ts +193 -9
- package/controller/Errors.ts +10 -0
- package/controller/Lockouts.ts +503 -0
- package/controller/State.ts +269 -64
- package/controller/boards/AquaLinkBoard.ts +1000 -0
- package/controller/boards/BoardFactory.ts +4 -0
- package/controller/boards/EasyTouchBoard.ts +468 -144
- package/controller/boards/IntelliCenterBoard.ts +466 -307
- package/controller/boards/IntelliTouchBoard.ts +37 -5
- package/controller/boards/NixieBoard.ts +671 -141
- package/controller/boards/SystemBoard.ts +1397 -641
- package/controller/comms/Comms.ts +462 -362
- package/controller/comms/messages/Messages.ts +174 -30
- package/controller/comms/messages/config/ChlorinatorMessage.ts +6 -3
- package/controller/comms/messages/config/CircuitMessage.ts +1 -0
- package/controller/comms/messages/config/ExternalMessage.ts +10 -8
- package/controller/comms/messages/config/HeaterMessage.ts +141 -29
- package/controller/comms/messages/config/OptionsMessage.ts +9 -2
- package/controller/comms/messages/config/PumpMessage.ts +53 -35
- package/controller/comms/messages/config/ScheduleMessage.ts +33 -25
- package/controller/comms/messages/config/ValveMessage.ts +2 -2
- package/controller/comms/messages/status/ChlorinatorStateMessage.ts +38 -86
- package/controller/comms/messages/status/EquipmentStateMessage.ts +59 -23
- package/controller/comms/messages/status/HeaterStateMessage.ts +57 -3
- package/controller/comms/messages/status/IntelliChemStateMessage.ts +56 -8
- package/controller/comms/messages/status/PumpStateMessage.ts +23 -1
- package/controller/nixie/Nixie.ts +1 -1
- package/controller/nixie/bodies/Body.ts +3 -0
- package/controller/nixie/chemistry/ChemController.ts +164 -51
- package/controller/nixie/chemistry/Chlorinator.ts +137 -88
- package/controller/nixie/circuits/Circuit.ts +51 -19
- package/controller/nixie/heaters/Heater.ts +241 -31
- package/controller/nixie/pumps/Pump.ts +488 -206
- package/controller/nixie/schedules/Schedule.ts +91 -35
- package/controller/nixie/valves/Valve.ts +1 -1
- package/defaultConfig.json +20 -0
- package/package.json +21 -21
- package/web/Server.ts +94 -49
- package/web/bindings/aqualinkD.json +505 -0
- package/web/bindings/influxDB.json +71 -1
- package/web/bindings/mqtt.json +98 -39
- package/web/bindings/mqttAlt.json +59 -1
- package/web/interfaces/baseInterface.ts +1 -0
- package/web/interfaces/httpInterface.ts +23 -2
- package/web/interfaces/influxInterface.ts +45 -10
- package/web/interfaces/mqttInterface.ts +114 -54
- package/web/services/config/Config.ts +55 -132
- package/web/services/state/State.ts +81 -4
- package/web/services/state/StateSocket.ts +4 -4
- package/web/services/utilities/Utilities.ts +8 -6
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -52
- package/config copy.json +0 -300
- package/issue_template.md +0 -52
|
@@ -77,7 +77,6 @@ export class NixieChemControllerCollection extends NixieEquipmentCollection<Nixi
|
|
|
77
77
|
logger.info(`Initializing chemController ${cc.name}`);
|
|
78
78
|
// First check to make sure it isnt already there.
|
|
79
79
|
if (typeof this.find(elem => elem.id === cc.id) === 'undefined') {
|
|
80
|
-
|
|
81
80
|
let ncc = NixieChemControllerBase.create(this.controlPanel, cc);
|
|
82
81
|
this.push(ncc);
|
|
83
82
|
}
|
|
@@ -241,24 +240,28 @@ export class NixieIntelliChemController extends NixieChemControllerBase {
|
|
|
241
240
|
}
|
|
242
241
|
if (isNaN(pHSetpoint) || pHSetpoint > type.ph.max || pHSetpoint < type.ph.min) return Promise.reject(new InvalidEquipmentDataError(`Invalid pH setpoint ${pHSetpoint}`, 'ph.setpoint', pHSetpoint));
|
|
243
242
|
if (isNaN(orpSetpoint) || orpSetpoint > type.orp.max || orpSetpoint < type.orp.min) return Promise.reject(new InvalidEquipmentDataError(`Invalid orp setpoint`, 'orp.setpoint', orpSetpoint));
|
|
244
|
-
let phTolerance = typeof data.ph.tolerance !== 'undefined' ? data.ph.tolerance : chem.ph.tolerance;
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
if (
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
243
|
+
let phTolerance = typeof data.ph !== 'undefined' && typeof data.ph.tolerance !== 'undefined' ? data.ph.tolerance : chem.ph.tolerance;
|
|
244
|
+
if (typeof data.ph !== 'undefined') {
|
|
245
|
+
if (typeof data.ph.tolerance !== 'undefined') {
|
|
246
|
+
if (typeof data.ph.tolerance.enabled !== 'undefined') phTolerance.enabled = utils.makeBool(data.ph.tolerance.enabled);
|
|
247
|
+
if (typeof data.ph.tolerance.low !== 'undefined') phTolerance.low = parseFloat(data.ph.tolerance.low);
|
|
248
|
+
if (typeof data.ph.tolerance.high !== 'undefined') phTolerance.high = parseFloat(data.ph.tolerance.high);
|
|
249
|
+
if (isNaN(phTolerance.low)) phTolerance.low = type.ph.min;
|
|
250
|
+
if (isNaN(phTolerance.high)) phTolerance.high = type.ph.max;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
let phEnabled = typeof data.ph !== 'undefined' && typeof data.ph.enabled !== 'undefined' ? utils.makeBool(data.ph.enabled) : chem.ph.enabled;
|
|
254
|
+
let orpTolerance = typeof data.orp !== 'undefined' && typeof data.orp.tolerance !== 'undefined' ? data.orp.tolerance : chem.orp.tolerance;
|
|
255
|
+
if (typeof data.orp !== 'undefined') {
|
|
256
|
+
if (typeof data.orp.tolerance !== 'undefined') {
|
|
257
|
+
if (typeof data.orp.tolerance.enabled !== 'undefined') orpTolerance.enabled = utils.makeBool(data.orp.tolerance.enabled);
|
|
258
|
+
if (typeof data.orp.tolerance.low !== 'undefined') orpTolerance.low = parseFloat(data.orp.tolerance.low);
|
|
259
|
+
if (typeof data.orp.tolerance.high !== 'undefined') orpTolerance.high = parseFloat(data.orp.tolerance.high);
|
|
260
|
+
if (isNaN(orpTolerance.low)) orpTolerance.low = type.orp.min;
|
|
261
|
+
if (isNaN(orpTolerance.high)) orpTolerance.high = type.orp.max;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
let orpEnabled = typeof data.orp !== 'undefined' && typeof data.orp.enabled !== 'undefined' ? utils.makeBool(data.orp.enabled) : chem.orp.enabled;
|
|
262
265
|
let siCalcType = typeof data.siCalcType !== 'undefined' ? sys.board.valueMaps.siCalcTypes.encode(data.siCalcType, 0) : chem.siCalcType;
|
|
263
266
|
schem.siCalcType = chem.siCalcType = siCalcType;
|
|
264
267
|
schem.ph.tank.capacity = chem.ph.tank.capacity = 6;
|
|
@@ -288,6 +291,8 @@ export class NixieIntelliChemController extends NixieChemControllerBase {
|
|
|
288
291
|
chem.ph.tolerance.enabled = phTolerance.enabled;
|
|
289
292
|
chem.ph.tolerance.low = phTolerance.low;
|
|
290
293
|
chem.ph.tolerance.high = phTolerance.high;
|
|
294
|
+
schem.ph.tank.level = acidTankLevel;
|
|
295
|
+
schem.orp.tank.level = orpTankLevel;
|
|
291
296
|
chem.orp.tolerance.enabled = orpTolerance.enabled;
|
|
292
297
|
chem.orp.tolerance.low = orpTolerance.low;
|
|
293
298
|
chem.orp.tolerance.high = orpTolerance.high;
|
|
@@ -340,6 +345,7 @@ export class NixieIntelliChemController extends NixieChemControllerBase {
|
|
|
340
345
|
out.setPayloadByte(9, this.chem.cyanuricAcid);
|
|
341
346
|
out.setPayloadByte(10, Math.floor(this.chem.alkalinity / 256) || 0);
|
|
342
347
|
out.setPayloadByte(12, Math.round(this.chem.alkalinity % 256) || 0);
|
|
348
|
+
logger.verbose(`Nixie: ${this.chem.name} sending IntelliChem settings action 146`);
|
|
343
349
|
conn.queueSendMessage(out);
|
|
344
350
|
});
|
|
345
351
|
}
|
|
@@ -622,19 +628,14 @@ export class NixieChemController extends NixieChemControllerBase {
|
|
|
622
628
|
// Calculate all the alarms. These are only informational at this point.
|
|
623
629
|
let setupValid = true;
|
|
624
630
|
if (this.flowSensor.sensor.type === 0) {
|
|
625
|
-
|
|
631
|
+
// When there is no flow sensor we always use the body to determine flow. This means that the
|
|
632
|
+
// flow alarm can never be triggered.
|
|
633
|
+
schem.alarms.flow = 0;
|
|
626
634
|
}
|
|
627
635
|
else {
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
else {
|
|
632
|
-
// both flow and pressure sensors (type 2 & 4)
|
|
633
|
-
if (schem.isBodyOn && !schem.flowDetected || !schem.isBodyOn && schem.flowDetected) {
|
|
634
|
-
schem.alarms.flow = 1;
|
|
635
|
-
}
|
|
636
|
-
else schem.alarms.flow = 0;
|
|
637
|
-
}
|
|
636
|
+
// If the body is on and there is no flow detected then we need
|
|
637
|
+
// to indicate this to the user.
|
|
638
|
+
schem.alarms.flow = schem.isBodyOn && !schem.flowDetected ? 1 : 0;
|
|
638
639
|
}
|
|
639
640
|
schem.ph.dailyVolumeDosed = schem.ph.calcDoseHistory();
|
|
640
641
|
schem.orp.dailyVolumeDosed = schem.orp.calcDoseHistory();
|
|
@@ -666,7 +667,7 @@ export class NixieChemController extends NixieChemControllerBase {
|
|
|
666
667
|
if (probeType !== 0 && chem.orp.tolerance.enabled)
|
|
667
668
|
schem.alarms.orp = schem.orp.level < chem.orp.tolerance.low ? 16 : schem.orp.level > chem.orp.tolerance.high ? 8 : 0;
|
|
668
669
|
else schem.alarms.orp = 0;
|
|
669
|
-
schem.warnings.chlorinatorCommError = useChlorinator && state.chlorinators.getItemById(1).status & 0xF0 ? 16 : 0;
|
|
670
|
+
schem.warnings.chlorinatorCommError = useChlorinator && schem.isBodyOn && state.chlorinators.getItemById(1).status & 0xF0 ? 16 : 0;
|
|
670
671
|
schem.warnings.pHLockout = useChlorinator === false && probeType !== 0 && pumpType !== 0 && schem.ph.level >= chem.orp.phLockout ? 1 : 0;
|
|
671
672
|
}
|
|
672
673
|
else {
|
|
@@ -674,6 +675,7 @@ export class NixieChemController extends NixieChemControllerBase {
|
|
|
674
675
|
schem.warnings.chlorinatorCommError = 0;
|
|
675
676
|
schem.warnings.pHLockout = 0;
|
|
676
677
|
}
|
|
678
|
+
schem.orp.freezeProtect = (state.freeze && chem.orp.disableOnFreeze && schem.isBodyOn);
|
|
677
679
|
}
|
|
678
680
|
else {
|
|
679
681
|
schem.warnings.chlorinatorCommError = 0;
|
|
@@ -681,6 +683,7 @@ export class NixieChemController extends NixieChemControllerBase {
|
|
|
681
683
|
schem.warnings.orpDailyLimitReached = 0;
|
|
682
684
|
schem.alarms.orp = 0;
|
|
683
685
|
schem.warnings.pHLockout = 0;
|
|
686
|
+
schem.orp.freezeProtect = false;
|
|
684
687
|
}
|
|
685
688
|
if (this.chem.ph.enabled) {
|
|
686
689
|
let pumpType = chem.ph.pump.type;
|
|
@@ -709,11 +712,21 @@ export class NixieChemController extends NixieChemControllerBase {
|
|
|
709
712
|
else schem.alarms.pH = 0;
|
|
710
713
|
}
|
|
711
714
|
else schem.alarms.pH = 0;
|
|
715
|
+
schem.ph.freezeProtect = (state.freeze && chem.ph.disableOnFreeze && schem.isBodyOn);
|
|
712
716
|
}
|
|
717
|
+
else {
|
|
718
|
+
schem.alarms.pHTank = 0;
|
|
719
|
+
schem.warnings.pHDailyLimitReached = 0;
|
|
720
|
+
schem.alarms.pH = 0;
|
|
721
|
+
schem.ph.freezeProtect = false;
|
|
722
|
+
}
|
|
723
|
+
|
|
713
724
|
if (chem.lsiRange.enabled) {
|
|
714
725
|
schem.warnings.waterChemistry = schem.saturationIndex < chem.lsiRange.low ? 1 : schem.saturationIndex > chem.lsiRange.high ? 2 : 0;
|
|
715
726
|
}
|
|
716
727
|
else schem.warnings.waterChemistry = 0;
|
|
728
|
+
|
|
729
|
+
schem.alarms.freezeProtect = (schem.ph.freezeProtect || schem.orp.freezeProtect) ? sys.board.valueMaps.chemControllerAlarms.getValue('freezeprotect') : 0;
|
|
717
730
|
} catch (err) { logger.error(`Error processing chem controller ${this.chem.name} alarms: ${err.message}`); }
|
|
718
731
|
}
|
|
719
732
|
private async checkHardwareStatusAsync(connectionId: string, deviceBinding: string) {
|
|
@@ -752,6 +765,7 @@ export class NixieChemController extends NixieChemControllerBase {
|
|
|
752
765
|
}
|
|
753
766
|
else
|
|
754
767
|
schem.alarms.orpPumpFault = schem.alarms.chlorFault = 0;
|
|
768
|
+
|
|
755
769
|
}
|
|
756
770
|
else schem.alarms.orpPumpFault = schem.alarms.chlorFault = schem.alarms.orpProbeFault = 0;
|
|
757
771
|
if (chem.ph.enabled) {
|
|
@@ -869,7 +883,7 @@ class NixieChemical extends NixieChildEquipment {
|
|
|
869
883
|
chemical.maxDosingTime = typeof data.maxDosingTime !== 'undefined' ? parseInt(data.maxDosingTime, 10) : chemical.maxDosingTime;
|
|
870
884
|
chemical.maxDosingVolume = typeof data.maxDosingVolume !== 'undefined' ? parseInt(data.maxDosingVolume, 10) : chemical.maxDosingVolume;
|
|
871
885
|
chemical.startDelay = typeof data.startDelay !== 'undefined' ? parseFloat(data.startDelay) : chemical.startDelay;
|
|
872
|
-
chemical.maxDailyVolume = typeof data.maxDailyVolume !== 'undefined' ? parseInt(data.maxDailyVolume, 10) : chemical.maxDailyVolume;
|
|
886
|
+
chemical.maxDailyVolume = typeof data.maxDailyVolume !== 'undefined' ? typeof data.maxDailyVolume === 'number' ? data.maxDailyVolume : parseInt(data.maxDailyVolume, 10) : chemical.maxDailyVolume;
|
|
873
887
|
}
|
|
874
888
|
} catch (err) { logger.error(`setDosing: ${err.message}`); return Promise.reject(err); }
|
|
875
889
|
}
|
|
@@ -893,7 +907,7 @@ class NixieChemical extends NixieChildEquipment {
|
|
|
893
907
|
this._stoppingMix = true;
|
|
894
908
|
this.suspendPolling = true;
|
|
895
909
|
if (typeof this.currentMix !== 'undefined') logger.debug(`Stopping ${schem.chemType} mix and clearing the current mix object.`);
|
|
896
|
-
if (typeof this.chemController.orp.orp.useChlorinator !== 'undefined' && this.chemController.orp.orp.useChlorinator && this.chemController.orp.orp.
|
|
910
|
+
if (typeof this.chemController.orp.orp.useChlorinator !== 'undefined' && this.chemController.orp.orp.useChlorinator && this.chemController.orp.orp.chlorDosingMethod > 0)
|
|
897
911
|
schem.chlor.isDosing = false;
|
|
898
912
|
else
|
|
899
913
|
schem.pump.isDosing = false;
|
|
@@ -967,12 +981,20 @@ class NixieChemical extends NixieChildEquipment {
|
|
|
967
981
|
return;
|
|
968
982
|
}
|
|
969
983
|
this._processingMix = true;
|
|
984
|
+
if (!this.chemical.enabled) {
|
|
985
|
+
// The chemical is not enabled so we need to ditch the mixing if it is currently underway.
|
|
986
|
+
await this.stopMixing(schem);
|
|
987
|
+
return;
|
|
988
|
+
|
|
989
|
+
|
|
990
|
+
}
|
|
991
|
+
|
|
970
992
|
let dt = new Date().getTime();
|
|
971
993
|
await this.initMixChemicals(schem, mixingTime);
|
|
972
994
|
if (this._stoppingMix) return;
|
|
973
995
|
schem.chlor.isDosing = schem.pump.isDosing = false;
|
|
974
|
-
if (!this.chemical.flowOnlyMixing || (schem.chemController.isBodyOn && this.chemController.flowDetected)) {
|
|
975
|
-
if (this.chemType === 'orp' && typeof this.chemController.orp.orp.useChlorinator !== 'undefined' && this.chemController.orp.orp.useChlorinator && this.chemController.orp.orp.
|
|
996
|
+
if (!this.chemical.flowOnlyMixing || (schem.chemController.isBodyOn && this.chemController.flowDetected && !schem.freezeProtect)) {
|
|
997
|
+
if (this.chemType === 'orp' && typeof this.chemController.orp.orp.useChlorinator !== 'undefined' && this.chemController.orp.orp.useChlorinator && this.chemController.orp.orp.chlorDosingMethod > 0) {
|
|
976
998
|
if (state.chlorinators.getItemById(1).currentOutput !== 0) {
|
|
977
999
|
logger.debug(`Chem mixing ORP (chlorinator) paused waiting for chlor current output to be 0%. Mix time remaining: ${utils.formatDuration(schem.mixTimeRemaining)} `);
|
|
978
1000
|
return;
|
|
@@ -1015,7 +1037,7 @@ class NixieChemical extends NixieChildEquipment {
|
|
|
1015
1037
|
}
|
|
1016
1038
|
public async cancelDosing(schem: ChemicalState, reason: string): Promise<void> {
|
|
1017
1039
|
try {
|
|
1018
|
-
if (typeof this.chemController.orp.orp.useChlorinator !== 'undefined' && this.chemController.orp.orp.useChlorinator && this.chemController.orp.orp.
|
|
1040
|
+
if (typeof this.chemController.orp.orp.useChlorinator !== 'undefined' && this.chemController.orp.orp.useChlorinator && this.chemController.orp.orp.chlorDosingMethod > 0) {
|
|
1019
1041
|
if (!this.chlor.chlor.superChlor) await this.chlor.stopDosing(schem, reason);
|
|
1020
1042
|
// for chlor, we want 15 minute intervals
|
|
1021
1043
|
if (schem.doseHistory.length) {
|
|
@@ -1080,8 +1102,9 @@ export class NixieChemPump extends NixieChildEquipment {
|
|
|
1080
1102
|
public async setPumpAsync(spump: ChemicalPumpState, data: any): Promise<void> {
|
|
1081
1103
|
try {
|
|
1082
1104
|
if (typeof data !== 'undefined') {
|
|
1083
|
-
this.pump.enabled = typeof data.enabled !== 'undefined' ? data.enabled : this.pump.enabled;
|
|
1105
|
+
//this.pump.enabled = typeof data.enabled !== 'undefined' ? data.enabled : this.pump.enabled;
|
|
1084
1106
|
this.pump.type = typeof data.type !== 'undefined' ? data.type : this.pump.type;
|
|
1107
|
+
this.pump.enabled = this.pump.type !== 0;
|
|
1085
1108
|
this.pump.ratedFlow = typeof data.ratedFlow !== 'undefined' ? data.ratedFlow : this.pump.ratedFlow;
|
|
1086
1109
|
this.pump.connectionId = typeof data.connectionId !== 'undefined' ? data.connectionId : this.pump.connectionId;
|
|
1087
1110
|
this.pump.deviceBinding = typeof data.deviceBinding !== 'undefined' ? data.deviceBinding : this.pump.deviceBinding;
|
|
@@ -1141,7 +1164,7 @@ export class NixieChemPump extends NixieChildEquipment {
|
|
|
1141
1164
|
await this.chemical.initDose(schem);
|
|
1142
1165
|
let delay = 0;
|
|
1143
1166
|
// Check to see if we are in delay. The start delay for the configuration is in minutes.
|
|
1144
|
-
if (isBodyOn) {
|
|
1167
|
+
if (isBodyOn && !schem.freezeProtect) {
|
|
1145
1168
|
// The remaining delay = delay time - (current time - on time).
|
|
1146
1169
|
let timeElapsed = new Date().getTime() - this.chemical.chemController.bodyOnTime;
|
|
1147
1170
|
delay = Math.max(0, ((this.chemical.chemical.startDelay * 60) * 1000) - timeElapsed);
|
|
@@ -1165,6 +1188,12 @@ export class NixieChemPump extends NixieChildEquipment {
|
|
|
1165
1188
|
// the chlorinator to work more smoothly.
|
|
1166
1189
|
await this.chemical.cancelDosing(schem, 'no flow');
|
|
1167
1190
|
}
|
|
1191
|
+
else if (schem.freezeProtect) {
|
|
1192
|
+
logger.info(`Chem pump freeze protection`);
|
|
1193
|
+
// We originally thought that we could wait to turn the dosing on but instead we will cancel the dose. This will allow
|
|
1194
|
+
// the chlorinator to work more smoothly.
|
|
1195
|
+
await this.chemical.cancelDosing(schem, 'freeze');
|
|
1196
|
+
}
|
|
1168
1197
|
else if (schem.tank.level <= 0) {
|
|
1169
1198
|
logger.info(`Chem tank ran dry with ${schem.currentDose.volumeRemaining}mL remaining`);
|
|
1170
1199
|
await this.chemical.cancelDosing(schem, 'empty tank');
|
|
@@ -1373,7 +1402,7 @@ export class NixieChemChlor extends NixieChildEquipment {
|
|
|
1373
1402
|
try {
|
|
1374
1403
|
await this.turnOn(schem);
|
|
1375
1404
|
if (schlor.currentOutput !== 100) {
|
|
1376
|
-
logger.
|
|
1405
|
+
logger.silly(`Chlor dose not added because current output is not 100%`);
|
|
1377
1406
|
}
|
|
1378
1407
|
else {
|
|
1379
1408
|
if (typeof dose._lastLatch !== 'undefined') {
|
|
@@ -1424,7 +1453,7 @@ export class NixieChemChlor extends NixieChildEquipment {
|
|
|
1424
1453
|
}
|
|
1425
1454
|
public async turnOff(schem: ChemicalState): Promise<ChlorinatorState> {
|
|
1426
1455
|
try {
|
|
1427
|
-
logger.info(`Turning off the chlorinator`);
|
|
1456
|
+
//logger.info(`Turning off the chlorinator`);
|
|
1428
1457
|
let chlor = sys.chlorinators.getItemById(1);
|
|
1429
1458
|
let schlor = state.chlorinators.getItemById(1);
|
|
1430
1459
|
if (schlor.currentOutput === 0 && schlor.targetOutput === 0 && !schlor.superChlor && chlor.disabled && !chlor.isDosing) {
|
|
@@ -1470,6 +1499,15 @@ export class NixieChemicalPh extends NixieChemical {
|
|
|
1470
1499
|
super(controller, chemical);
|
|
1471
1500
|
this.chemType = 'acid';
|
|
1472
1501
|
this.probe = new NixieChemProbePh(this, chemical.probe);
|
|
1502
|
+
let sph = state.chemControllers.getItemById(controller.id).ph;
|
|
1503
|
+
if (!this.ph.enabled || !this.ph.pump.enabled) {
|
|
1504
|
+
this.ph.doserType = 0;
|
|
1505
|
+
sph.chemType = 'none';
|
|
1506
|
+
}
|
|
1507
|
+
else {
|
|
1508
|
+
this.ph.doserType = 1; // External Relay
|
|
1509
|
+
sph.chemType = (this.ph.phSupply === 0) ? 'base' : 'acid';
|
|
1510
|
+
}
|
|
1473
1511
|
}
|
|
1474
1512
|
public async setPhAsync(sph: ChemicalPhState, data: any) {
|
|
1475
1513
|
try {
|
|
@@ -1485,6 +1523,17 @@ export class NixieChemicalPh extends NixieChemical {
|
|
|
1485
1523
|
this.ph.acidType = typeof data.acidType !== 'undefined' ? data.acidType : this.ph.acidType;
|
|
1486
1524
|
this.ph.flowReadingsOnly = typeof data.flowReadingsOnly !== 'undefined' ? utils.makeBool(data.flowReadingsOnly) : this.ph.flowReadingsOnly;
|
|
1487
1525
|
sph.level = typeof data.level !== 'undefined' && !isNaN(parseFloat(data.level)) ? parseFloat(data.level) : sph.level;
|
|
1526
|
+
this.ph.disableOnFreeze = typeof data.disableOnFreeze !== 'undefined' ? utils.makeBool(data.disableOnFreeze) : this.ph.disableOnFreeze;
|
|
1527
|
+
if (!this.ph.disableOnFreeze) sph.freezeProtect = false;
|
|
1528
|
+
if (!this.ph.enabled || !this.ph.pump.enabled) {
|
|
1529
|
+
this.ph.doserType = 0;
|
|
1530
|
+
sph.chemType = 'none';
|
|
1531
|
+
}
|
|
1532
|
+
else {
|
|
1533
|
+
this.ph.doserType = 1; // External Relay
|
|
1534
|
+
sph.chemType = (this.ph.phSupply === 0) ? 'base' : 'acid';
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1488
1537
|
if (typeof data.tolerance !== 'undefined') {
|
|
1489
1538
|
if (typeof data.tolerance.enabled !== 'undefined') this.ph.tolerance.enabled = utils.makeBool(data.tolerance.enabled);
|
|
1490
1539
|
if (typeof data.tolerance.low === 'number') this.ph.tolerance.low = data.tolerance.low;
|
|
@@ -1525,6 +1574,10 @@ export class NixieChemicalPh extends NixieChemical {
|
|
|
1525
1574
|
logger.debug(`Begin check ${sph.chemType} dosing status = ${status}`);
|
|
1526
1575
|
let demand = sph.calcDemand(chem);
|
|
1527
1576
|
sph.demand = Math.max(demand, 0);
|
|
1577
|
+
if (!chem.ph.enabled) {
|
|
1578
|
+
await this.cancelDosing(sph, 'disabled');
|
|
1579
|
+
return;
|
|
1580
|
+
}
|
|
1528
1581
|
if (sph.suspendDosing) {
|
|
1529
1582
|
// Kill off the dosing and make sure the pump isn't running. Let's force the issue here.
|
|
1530
1583
|
await this.cancelDosing(sph, 'suspended');
|
|
@@ -1592,6 +1645,8 @@ export class NixieChemicalPh extends NixieChemical {
|
|
|
1592
1645
|
// Check the setpoint and the current level to see if we need to dose.
|
|
1593
1646
|
if (!sph.chemController.isBodyOn)
|
|
1594
1647
|
await this.cancelDosing(sph, 'body off');
|
|
1648
|
+
else if (sph.freezeProtect)
|
|
1649
|
+
await this.cancelDosing(sph, 'freeze');
|
|
1595
1650
|
else if (!sph.chemController.flowDetected)
|
|
1596
1651
|
await this.cancelDosing(sph, 'no flow');
|
|
1597
1652
|
else if (demand <= 0)
|
|
@@ -1740,6 +1795,23 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
1740
1795
|
this.orp = chemical;
|
|
1741
1796
|
this.probe = new NixieChemProbeORP(this, chemical.probe);
|
|
1742
1797
|
this.chlor = new NixieChemChlor(this, chemical.chlor);
|
|
1798
|
+
let sorp = state.chemControllers.getItemById(controller.id).orp;
|
|
1799
|
+
if (!this.orp.enabled) {
|
|
1800
|
+
this.orp.doserType = 0;
|
|
1801
|
+
sorp.chemType = 'none';
|
|
1802
|
+
}
|
|
1803
|
+
else if (sorp.useChlorinator) {
|
|
1804
|
+
this.orp.doserType = 2;
|
|
1805
|
+
sorp.chemType = 'chlorine';
|
|
1806
|
+
}
|
|
1807
|
+
else if (this.orp.pump.enabled) {
|
|
1808
|
+
this.orp.doserType = 1;
|
|
1809
|
+
sorp.chemType = 'chlorine';
|
|
1810
|
+
}
|
|
1811
|
+
else {
|
|
1812
|
+
this.orp.doserType = 0;
|
|
1813
|
+
sorp.chemType = 'none';
|
|
1814
|
+
}
|
|
1743
1815
|
}
|
|
1744
1816
|
public get logFilename() { return `chemDosage_orp.log`; }
|
|
1745
1817
|
public async setORPAsync(sorp: ChemicalORPState, data: any) {
|
|
@@ -1750,6 +1822,8 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
1750
1822
|
sorp.level = typeof data.level !== 'undefined' && !isNaN(parseFloat(data.level)) ? parseFloat(data.level) : sorp.level;
|
|
1751
1823
|
this.orp.phLockout = typeof data.phLockout !== 'undefined' && !isNaN(parseFloat(data.phLockout)) ? parseFloat(data.phLockout) : this.orp.phLockout;
|
|
1752
1824
|
this.orp.flowReadingsOnly = typeof data.flowReadingsOnly !== 'undefined' ? utils.makeBool(data.flowReadingsOnly) : this.orp.flowReadingsOnly;
|
|
1825
|
+
this.orp.disableOnFreeze = typeof data.disableOnFreeze !== 'undefined' ? utils.makeBool(data.disableOnFreeze) : this.orp.disableOnFreeze;
|
|
1826
|
+
if (!this.orp.disableOnFreeze) sorp.freezeProtect = false;
|
|
1753
1827
|
if (typeof data.chlorDosingMethod !== 'undefined') { this.orp.chlorDosingMethod = data.chlorDosingMethod; }
|
|
1754
1828
|
await this.setDosing(this.orp, data);
|
|
1755
1829
|
await this.setMixing(this.orp, data);
|
|
@@ -1757,6 +1831,23 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
1757
1831
|
await this.tank.setTankAsync(sorp.tank, data.tank);
|
|
1758
1832
|
await this.pump.setPumpAsync(sorp.pump, data.pump);
|
|
1759
1833
|
await this.chlor.setChlorAsync(sorp.chlor, data);
|
|
1834
|
+
if (!this.orp.enabled) {
|
|
1835
|
+
this.orp.doserType = 0;
|
|
1836
|
+
sorp.chemType = 'none';
|
|
1837
|
+
}
|
|
1838
|
+
else if (sorp.useChlorinator) {
|
|
1839
|
+
this.orp.doserType = 2;
|
|
1840
|
+
sorp.chemType = 'chlorine';
|
|
1841
|
+
}
|
|
1842
|
+
else if (this.orp.pump.enabled) {
|
|
1843
|
+
this.orp.doserType = 1;
|
|
1844
|
+
sorp.chemType = 'chlorine';
|
|
1845
|
+
}
|
|
1846
|
+
else {
|
|
1847
|
+
this.orp.doserType = 0;
|
|
1848
|
+
sorp.chemType = 'none';
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1760
1851
|
this.orp.setpoint = sorp.setpoint = typeof data.setpoint !== 'undefined' ? parseInt(data.setpoint, 10) : this.orp.setpoint;
|
|
1761
1852
|
if (typeof data.tolerance !== 'undefined') {
|
|
1762
1853
|
if (typeof data.tolerance.enabled !== 'undefined') this.orp.tolerance.enabled = utils.makeBool(data.tolerance.enabled);
|
|
@@ -1801,7 +1892,7 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
1801
1892
|
}
|
|
1802
1893
|
public async cancelDosing(sorp: ChemicalORPState, reason: string): Promise<void> {
|
|
1803
1894
|
try {
|
|
1804
|
-
if (typeof sorp.useChlorinator !== 'undefined' && sorp.useChlorinator && this.chemController.orp.orp.
|
|
1895
|
+
if (typeof sorp.useChlorinator !== 'undefined' && sorp.useChlorinator && this.chemController.orp.orp.chlorDosingMethod > 0) {
|
|
1805
1896
|
await this.chlor.stopDosing(sorp, reason);
|
|
1806
1897
|
// for chlor, we want 15 minute intervals
|
|
1807
1898
|
if (sorp.doseHistory.length) {
|
|
@@ -1850,7 +1941,7 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
1850
1941
|
this.currentMix.set({ time: schem.mixTimeRemaining, timeMixed: 0, isManual: true });
|
|
1851
1942
|
}
|
|
1852
1943
|
else
|
|
1853
|
-
if (typeof this.chemController.orp.orp.useChlorinator !== 'undefined' && this.chemController.orp.orp.useChlorinator && this.chemController.orp.orp.
|
|
1944
|
+
if (typeof this.chemController.orp.orp.useChlorinator !== 'undefined' && this.chemController.orp.orp.useChlorinator && this.chemController.orp.orp.chlorDosingMethod > 0) {
|
|
1854
1945
|
// if last dose was within 15 minutes, set mix time to 15 mins-(now-lastdose)
|
|
1855
1946
|
// if no dose in last 15, then we should be monitoring
|
|
1856
1947
|
await this.chlor.stopDosing(schem, 'mix override'); // ensure chlor has stopped
|
|
@@ -1872,7 +1963,7 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
1872
1963
|
}
|
|
1873
1964
|
}
|
|
1874
1965
|
else
|
|
1875
|
-
if (typeof this.chemController.orp.orp.useChlorinator !== 'undefined' && this.chemController.orp.orp.useChlorinator && this.chemController.orp.orp.
|
|
1966
|
+
if (typeof this.chemController.orp.orp.useChlorinator !== 'undefined' && this.chemController.orp.orp.useChlorinator && this.chemController.orp.orp.chlorDosingMethod > 0)
|
|
1876
1967
|
this.currentMix.set({ time: this.chlor.chlorInterval * 60, timeMixed: 0 });
|
|
1877
1968
|
else
|
|
1878
1969
|
this.currentMix.set({ time: this.chemical.mixingTime, timeMixed: 0 });
|
|
@@ -1888,6 +1979,11 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
1888
1979
|
}
|
|
1889
1980
|
public async checkDosing(chem: ChemController, sorp: ChemicalORPState): Promise<void> {
|
|
1890
1981
|
try {
|
|
1982
|
+
if (!chem.orp.enabled) {
|
|
1983
|
+
await this.cancelDosing(sorp, 'disabled');
|
|
1984
|
+
return;
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1891
1987
|
let status = sys.board.valueMaps.chemControllerDosingStatus.getName(sorp.dosingStatus);
|
|
1892
1988
|
if (!chem.orp.flowReadingsOnly || (chem.orp.flowReadingsOnly && sorp.chemController.flowDetected)) {
|
|
1893
1989
|
// demand in raw mV
|
|
@@ -1897,6 +1993,7 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
1897
1993
|
sorp.appendDemand(new Date().valueOf(), sorp.demand);
|
|
1898
1994
|
}
|
|
1899
1995
|
if (chem.orp.useChlorinator && chem.orp.chlorDosingMethod === 0) return; // if chlor is managing itself, don't even cancel/stop as it will set the flags on the chlor
|
|
1996
|
+
|
|
1900
1997
|
if (sorp.suspendDosing) {
|
|
1901
1998
|
// Kill off the dosing and make sure the pump isn't running. Let's force the issue here.
|
|
1902
1999
|
await this.cancelDosing(sorp, 'suspended');
|
|
@@ -1934,6 +2031,9 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
1934
2031
|
}
|
|
1935
2032
|
else await this.cancelDosing(sorp, 'empty tank');
|
|
1936
2033
|
}
|
|
2034
|
+
else if (sorp.freezeProtect) {
|
|
2035
|
+
await this.cancelDosing(sorp, 'freeze');
|
|
2036
|
+
}
|
|
1937
2037
|
else if (sorp.dailyLimitReached && !chem.orp.useChlorinator) {
|
|
1938
2038
|
await this.cancelDosing(sorp, 'daily limit');
|
|
1939
2039
|
}
|
|
@@ -2185,7 +2285,13 @@ export class NixieChemProbePh extends NixieChemProbe {
|
|
|
2185
2285
|
if (this.probe.type !== 1 || this.probe.deviceBinding !== data.deviceBinding) {
|
|
2186
2286
|
let disabledFeed = this.probe;
|
|
2187
2287
|
disabledFeed.remFeedEnabled = false;
|
|
2188
|
-
|
|
2288
|
+
try {
|
|
2289
|
+
// if remote REM server was not found this would error out
|
|
2290
|
+
await this.setRemoteREMFeed(disabledFeed);
|
|
2291
|
+
}
|
|
2292
|
+
catch (err){
|
|
2293
|
+
logger.silly(`Disabling remote REM connection for PH Probe returned error ${err.message}. Continuing.`)
|
|
2294
|
+
}
|
|
2189
2295
|
this.probe.remFeedId = undefined;
|
|
2190
2296
|
}
|
|
2191
2297
|
await this.setProbeAsync(this.probe, sprobe, data);
|
|
@@ -2194,6 +2300,7 @@ export class NixieChemProbePh extends NixieChemProbe {
|
|
|
2194
2300
|
sprobe.temperature = typeof data.temperature !== 'undefined' ? parseFloat(data.temperature) : sprobe.temperature;
|
|
2195
2301
|
sprobe.tempUnits = typeof data.tempUnits !== 'undefined' ? data.tempUnits : sprobe.tempUnits;
|
|
2196
2302
|
this.probe.feedBodyTemp = typeof data.feedBodyTemp !== 'undefined' ? utils.makeBool(data.feedBodyTemp) : utils.makeBool(this.probe.feedBodyTemp);
|
|
2303
|
+
//this.probe.connectionId = typeof data.connectionId !== 'undefined' ? data.connectionId : this.probe.connectionId;
|
|
2197
2304
|
await this.setRemoteREMFeed(data);
|
|
2198
2305
|
}
|
|
2199
2306
|
} catch (err) { logger.error(`setProbeAsync pH: ${err.message}`); return Promise.reject(err); }
|
|
@@ -2234,11 +2341,11 @@ export class NixieChemProbePh extends NixieChemProbe {
|
|
|
2234
2341
|
property: "pHLevel",
|
|
2235
2342
|
sendValue: 'all',
|
|
2236
2343
|
isActive: data.remFeedEnabled,
|
|
2237
|
-
sampling: 1,
|
|
2238
|
-
changesOnly: false,
|
|
2344
|
+
//sampling: 1,
|
|
2345
|
+
//changesOnly: false,
|
|
2239
2346
|
propertyDesc: '[chemController].pHLevel'
|
|
2240
2347
|
}
|
|
2241
|
-
let res = await NixieChemController.putDeviceService(this.probe.connectionId, '/config/
|
|
2348
|
+
let res = await NixieChemController.putDeviceService(this.probe.connectionId, '/config/verifyFeed', d);
|
|
2242
2349
|
if (res.status.code === 200) { this.probe.remFeedEnabled = data.remFeedEnabled; }
|
|
2243
2350
|
else { logger.warn(`setRemoteREMFeed: Cannot set remote feed. Message:${JSON.stringify(res.status)} for feed: ${JSON.stringify(d)}.`); }
|
|
2244
2351
|
}
|
|
@@ -2291,7 +2398,13 @@ export class NixieChemProbeORP extends NixieChemProbe {
|
|
|
2291
2398
|
if (this.probe.type !== 1 || this.probe.deviceBinding !== data.deviceBinding) {
|
|
2292
2399
|
let disabledFeed = this.probe;
|
|
2293
2400
|
disabledFeed.remFeedEnabled = false;
|
|
2294
|
-
|
|
2401
|
+
try {
|
|
2402
|
+
// if remote REM server was not found this would error out
|
|
2403
|
+
await this.setRemoteREMFeed(disabledFeed);
|
|
2404
|
+
}
|
|
2405
|
+
catch (err){
|
|
2406
|
+
logger.silly(`Disabling remote REM connection for ORP Probe returned error ${err.message}. Continuing.`)
|
|
2407
|
+
}
|
|
2295
2408
|
this.probe.remFeedId = undefined;
|
|
2296
2409
|
}
|
|
2297
2410
|
await this.setProbeAsync(this.probe, sprobe, data);
|
|
@@ -2317,11 +2430,11 @@ export class NixieChemProbeORP extends NixieChemProbe {
|
|
|
2317
2430
|
property: 'orpLevel',
|
|
2318
2431
|
sendValue: 'orp',
|
|
2319
2432
|
isActive: data.remFeedEnabled,
|
|
2320
|
-
sampling: 1,
|
|
2321
|
-
changesOnly: false,
|
|
2433
|
+
//sampling: 1,
|
|
2434
|
+
//changesOnly: false,
|
|
2322
2435
|
propertyDesc: '[chemController].orpLevel'
|
|
2323
2436
|
}
|
|
2324
|
-
let res = await NixieChemController.putDeviceService(this.probe.connectionId, '/config/
|
|
2437
|
+
let res = await NixieChemController.putDeviceService(this.probe.connectionId, '/config/verifyFeed', d);
|
|
2325
2438
|
if (res.status.code === 200) { this.probe.remFeedEnabled = data.remFeedEnabled; }
|
|
2326
2439
|
else {
|
|
2327
2440
|
logger.warn(`setRemoteREMFeed: Cannot set remote feed. Message:${JSON.stringify(res.status)} for feed: ${JSON.stringify(d)}.`);
|