nodejs-poolcontroller 7.3.0 → 7.6.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/bug_report.md +1 -1
- package/Changelog +23 -0
- package/README.md +5 -5
- package/app.ts +2 -0
- package/config/Config.ts +3 -0
- package/config/VersionCheck.ts +8 -4
- package/controller/Constants.ts +88 -0
- package/controller/Equipment.ts +246 -66
- package/controller/Errors.ts +24 -1
- package/controller/Lockouts.ts +423 -0
- package/controller/State.ts +314 -54
- package/controller/boards/EasyTouchBoard.ts +107 -59
- package/controller/boards/IntelliCenterBoard.ts +186 -125
- package/controller/boards/IntelliTouchBoard.ts +104 -30
- package/controller/boards/NixieBoard.ts +721 -159
- package/controller/boards/SystemBoard.ts +2370 -1108
- package/controller/comms/Comms.ts +85 -10
- package/controller/comms/messages/Messages.ts +10 -4
- package/controller/comms/messages/config/ChlorinatorMessage.ts +13 -4
- package/controller/comms/messages/config/CircuitGroupMessage.ts +6 -0
- package/controller/comms/messages/config/CoverMessage.ts +1 -0
- package/controller/comms/messages/config/EquipmentMessage.ts +4 -0
- package/controller/comms/messages/config/ExternalMessage.ts +44 -26
- package/controller/comms/messages/config/FeatureMessage.ts +8 -1
- package/controller/comms/messages/config/GeneralMessage.ts +8 -0
- package/controller/comms/messages/config/HeaterMessage.ts +15 -9
- package/controller/comms/messages/config/IntellichemMessage.ts +4 -1
- package/controller/comms/messages/config/OptionsMessage.ts +13 -1
- package/controller/comms/messages/config/PumpMessage.ts +4 -20
- package/controller/comms/messages/config/RemoteMessage.ts +4 -0
- package/controller/comms/messages/config/ScheduleMessage.ts +11 -0
- package/controller/comms/messages/config/SecurityMessage.ts +1 -0
- package/controller/comms/messages/config/ValveMessage.ts +13 -3
- package/controller/comms/messages/status/ChlorinatorStateMessage.ts +2 -3
- package/controller/comms/messages/status/EquipmentStateMessage.ts +78 -24
- package/controller/comms/messages/status/HeaterStateMessage.ts +42 -9
- package/controller/comms/messages/status/IntelliChemStateMessage.ts +37 -26
- package/controller/nixie/Nixie.ts +18 -16
- package/controller/nixie/bodies/Body.ts +4 -1
- package/controller/nixie/chemistry/ChemController.ts +80 -77
- package/controller/nixie/chemistry/Chlorinator.ts +9 -8
- package/controller/nixie/circuits/Circuit.ts +55 -6
- package/controller/nixie/heaters/Heater.ts +192 -32
- package/controller/nixie/pumps/Pump.ts +146 -84
- package/controller/nixie/schedules/Schedule.ts +3 -2
- package/controller/nixie/valves/Valve.ts +1 -1
- package/defaultConfig.json +32 -1
- package/issue_template.md +1 -1
- package/logger/DataLogger.ts +37 -22
- package/package.json +20 -18
- package/web/Server.ts +520 -29
- package/web/bindings/influxDB.json +96 -8
- package/web/bindings/mqtt.json +151 -40
- package/web/bindings/mqttAlt.json +114 -4
- package/web/interfaces/httpInterface.ts +2 -0
- package/web/interfaces/influxInterface.ts +36 -19
- package/web/interfaces/mqttInterface.ts +14 -3
- package/web/services/config/Config.ts +171 -44
- package/web/services/state/State.ts +49 -5
- package/web/services/state/StateSocket.ts +18 -1
|
@@ -6,9 +6,10 @@ import { logger } from '../../../logger/Logger';
|
|
|
6
6
|
import { InterfaceServerResponse, webApp } from "../../../web/Server";
|
|
7
7
|
import { Timestamp, utils } from '../../Constants';
|
|
8
8
|
import { EquipmentNotFoundError, EquipmentTimeoutError, InvalidEquipmentDataError, InvalidEquipmentIdError, InvalidOperationError } from '../../Errors';
|
|
9
|
-
import { ChemControllerState, ChemicalDoseState, ChemicalORPState, ChemicalPhState, ChemicalProbeORPState, ChemicalProbePHState, ChemicalProbeState, ChemicalPumpState, ChemicalState, ChemicalTankState, ChlorinatorState, state } from "../../State";
|
|
9
|
+
import { ChemControllerState, ChemicalChlorState, ChemicalDoseState, ChemicalORPState, ChemicalPhState, ChemicalProbeORPState, ChemicalProbePHState, ChemicalProbeState, ChemicalPumpState, ChemicalState, ChemicalTankState, ChlorinatorState, state } from "../../State";
|
|
10
10
|
import { ncp } from '../Nixie';
|
|
11
11
|
import { INixieControlPanel, NixieChildEquipment, NixieEquipment, NixieEquipmentCollection } from "../NixieEquipment";
|
|
12
|
+
import { NixieChlorinator } from './Chlorinator';
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
export class NixieChemControllerCollection extends NixieEquipmentCollection<NixieChemControllerBase> {
|
|
@@ -50,7 +51,7 @@ export class NixieChemControllerCollection extends NixieEquipmentCollection<Nixi
|
|
|
50
51
|
ncc = NixieChemControllerBase.create(this.controlPanel, chem);
|
|
51
52
|
this.push(ncc);
|
|
52
53
|
let ctype = sys.board.valueMaps.chemControllerTypes.transform(chem.type);
|
|
53
|
-
logger.info(`
|
|
54
|
+
logger.info(`Nixie Chem Controller was created at id #${chem.id} for type ${ctype.desc}`);
|
|
54
55
|
await ncc.setControllerAsync(data);
|
|
55
56
|
}
|
|
56
57
|
else {
|
|
@@ -72,9 +73,11 @@ export class NixieChemControllerCollection extends NixieEquipmentCollection<Nixi
|
|
|
72
73
|
for (let i = 0; i < controllers.length; i++) {
|
|
73
74
|
let cc = controllers.getItemByIndex(i);
|
|
74
75
|
if (cc.master === 1) {
|
|
76
|
+
let type = sys.board.valueMaps.chemControllerTypes.transform(cc.type);
|
|
75
77
|
logger.info(`Initializing chemController ${cc.name}`);
|
|
76
78
|
// First check to make sure it isnt already there.
|
|
77
79
|
if (typeof this.find(elem => elem.id === cc.id) === 'undefined') {
|
|
80
|
+
|
|
78
81
|
let ncc = NixieChemControllerBase.create(this.controlPanel, cc);
|
|
79
82
|
this.push(ncc);
|
|
80
83
|
}
|
|
@@ -98,6 +101,19 @@ export class NixieChemControllerCollection extends NixieEquipmentCollection<Nixi
|
|
|
98
101
|
|
|
99
102
|
} catch (err) { } // Don't bail if we have an error
|
|
100
103
|
}
|
|
104
|
+
public async deleteChlorAsync(chlor: NixieChlorinator) {
|
|
105
|
+
// if we delete the chlor, make sure it is removed from all REM Chem Controllers
|
|
106
|
+
try {
|
|
107
|
+
for (let i = this.length - 1; i >= 0; i--) {
|
|
108
|
+
try {
|
|
109
|
+
let ncc = this[i] as NixieChemControllerBase;;
|
|
110
|
+
ncc.orp.deleteChlorAsync(chlor);
|
|
111
|
+
} catch (err) { logger.error(`Error deleting chlor from Nixie Chem Controller ${err}`); return Promise.reject(err); }
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
}
|
|
115
|
+
catch (err) { logger.error(`ncp.deleteChlorAsync: ${err.message}`); return Promise.reject(err); }
|
|
116
|
+
}
|
|
101
117
|
// This is currently not used for anything.
|
|
102
118
|
/* public async searchIntelliChem(): Promise<number[]> {
|
|
103
119
|
let arr = [];
|
|
@@ -145,12 +161,10 @@ export class NixieChemControllerBase extends NixieEquipment {
|
|
|
145
161
|
public chem: ChemController;
|
|
146
162
|
public syncRemoteREMFeeds(servers) { }
|
|
147
163
|
public static create(ncp: INixieControlPanel, chem: ChemController): NixieChemControllerBase {
|
|
148
|
-
// RKS: 06-25-21 - Keeping the homegrown around for now but I don't really know why we care.
|
|
149
164
|
let type = sys.board.valueMaps.chemControllerTypes.transform(chem.type);
|
|
150
165
|
switch (type.name) {
|
|
151
166
|
case 'intellichem':
|
|
152
167
|
return new NixieIntelliChemController(ncp, chem);
|
|
153
|
-
case 'homegrown':
|
|
154
168
|
case 'rem':
|
|
155
169
|
return new NixieChemController(ncp, chem);
|
|
156
170
|
default:
|
|
@@ -194,7 +208,7 @@ export class NixieIntelliChemController extends NixieChemControllerBase {
|
|
|
194
208
|
}
|
|
195
209
|
}
|
|
196
210
|
catch (err) { logger.error(`Error polling IntelliChem Controller - ${err}`); return Promise.reject(err); }
|
|
197
|
-
finally { this.suspendPolling = false; if (!this.closing) this._pollTimer = setTimeout(
|
|
211
|
+
finally { this.suspendPolling = false; if (!this.closing) this._pollTimer = setTimeout(() => { self.pollEquipmentAsync(); }, this.pollingInterval || 10000); }
|
|
198
212
|
}
|
|
199
213
|
public async setControllerAsync(data: any) {
|
|
200
214
|
try {
|
|
@@ -203,7 +217,7 @@ export class NixieIntelliChemController extends NixieChemControllerBase {
|
|
|
203
217
|
let address = typeof data.address !== 'undefined' ? parseInt(data.address) : chem.address;
|
|
204
218
|
let name = typeof data.name !== 'undefined' ? data.name : chem.name || `IntelliChem - ${address - 143}`;
|
|
205
219
|
let type = sys.board.valueMaps.chemControllerTypes.transformByName('intellichem');
|
|
206
|
-
// So now we are down to the nitty gritty setting the data for the REM
|
|
220
|
+
// So now we are down to the nitty gritty setting the data for the REM Chem controller.
|
|
207
221
|
let calciumHardness = typeof data.calciumHardness !== 'undefined' ? parseInt(data.calciumHardness, 10) : chem.calciumHardness;
|
|
208
222
|
let cyanuricAcid = typeof data.cyanuricAcid !== 'undefined' ? parseInt(data.cyanuricAcid, 10) : chem.cyanuricAcid;
|
|
209
223
|
let alkalinity = typeof data.alkalinity !== 'undefined' ? parseInt(data.alkalinity, 10) : chem.alkalinity;
|
|
@@ -543,6 +557,7 @@ export class NixieChemController extends NixieChemControllerBase {
|
|
|
543
557
|
else if (typeof ret.obj.state === 'boolean') v = ret.obj.state;
|
|
544
558
|
else if (typeof ret.obj.state === 'number') v = utils.makeBool(ret.obj.state);
|
|
545
559
|
else if (typeof ret.obj.state.val === 'number') v = utils.makeBool(ret.obj.state.val);
|
|
560
|
+
else if (typeof ret.obj.state.value === 'number') v = utils.makeBool(ret.obj.state.value);
|
|
546
561
|
else v = false;
|
|
547
562
|
this.flowDetected = schem.flowDetected = v;
|
|
548
563
|
}
|
|
@@ -584,7 +599,6 @@ export class NixieChemController extends NixieChemControllerBase {
|
|
|
584
599
|
await this.checkFlowAsync(schem);
|
|
585
600
|
await this.validateSetupAsync(this.chem, schem);
|
|
586
601
|
if (this.chem.ph.enabled) await this.ph.probe.setTempCompensationAsync(schem.ph.probe);
|
|
587
|
-
// We are not processing Homegrown at this point.
|
|
588
602
|
// Check each piece of equipment to make sure it is doing its thing.
|
|
589
603
|
schem.calculateSaturationIndex();
|
|
590
604
|
this.processAlarms(schem);
|
|
@@ -596,15 +610,10 @@ export class NixieChemController extends NixieChemControllerBase {
|
|
|
596
610
|
}
|
|
597
611
|
this._ispolling = false;
|
|
598
612
|
}
|
|
599
|
-
catch (err) { this._ispolling = false; logger.error(`Error polling Chem Controller - ${err}`);
|
|
613
|
+
catch (err) { this._ispolling = false; logger.error(`Error polling Chem Controller - ${err}`); }
|
|
600
614
|
finally {
|
|
601
615
|
if (!this.closing && !this._ispolling)
|
|
602
|
-
this._pollTimer = setTimeout(
|
|
603
|
-
try { await self.pollEquipmentAsync() } catch (err) {
|
|
604
|
-
//return Promise.reject(err);
|
|
605
|
-
logger.error(err);
|
|
606
|
-
}
|
|
607
|
-
}, this.pollingInterval || 10000);
|
|
616
|
+
this._pollTimer = setTimeout(() => { self.pollEquipmentAsync(); }, this.pollingInterval || 10000);
|
|
608
617
|
logger.verbose(`End polling Chem Controller ${this.id}`);
|
|
609
618
|
}
|
|
610
619
|
}
|
|
@@ -963,10 +972,9 @@ class NixieChemical extends NixieChildEquipment {
|
|
|
963
972
|
if (this._stoppingMix) return;
|
|
964
973
|
schem.chlor.isDosing = schem.pump.isDosing = false;
|
|
965
974
|
if (!this.chemical.flowOnlyMixing || (schem.chemController.isBodyOn && this.chemController.flowDetected)) {
|
|
966
|
-
if (this.chemType === 'orp' && typeof this.chemController.orp.orp.useChlorinator !== 'undefined' && this.chemController.orp.orp.useChlorinator && this.chemController.orp.orp.dosingMethod > 0){
|
|
967
|
-
await this.chlor.stopDosing(schem, 'mixing');
|
|
975
|
+
if (this.chemType === 'orp' && typeof this.chemController.orp.orp.useChlorinator !== 'undefined' && this.chemController.orp.orp.useChlorinator && this.chemController.orp.orp.dosingMethod > 0) {
|
|
968
976
|
if (state.chlorinators.getItemById(1).currentOutput !== 0) {
|
|
969
|
-
logger.debug(`Chem mixing ORP (chlorinator) paused
|
|
977
|
+
logger.debug(`Chem mixing ORP (chlorinator) paused waiting for chlor current output to be 0%. Mix time remaining: ${utils.formatDuration(schem.mixTimeRemaining)} `);
|
|
970
978
|
return;
|
|
971
979
|
}
|
|
972
980
|
}
|
|
@@ -1283,20 +1291,17 @@ export class NixieChemChlor extends NixieChildEquipment {
|
|
|
1283
1291
|
public chlorInterval = 15;
|
|
1284
1292
|
constructor(chemical: NixieChemical, chlor: ChemicalChlor) { super(chemical); this.chlor = chlor; }
|
|
1285
1293
|
public get chemical(): NixieChemical { return this.getParent() as NixieChemical; }
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
}
|
|
1298
|
-
} catch (err) { logger.error(`setChlorAsync: ${err.message}`); return Promise.reject(err); }
|
|
1299
|
-
} */
|
|
1294
|
+
public async setChlorAsync(schlor: ChemicalChlorState, data: any) {
|
|
1295
|
+
try {
|
|
1296
|
+
if (typeof data.chlorDosingMethod !== 'undefined' && data.chlorDosingMethod === 0) {
|
|
1297
|
+
if (schlor.chemical.dosingStatus === 0) { await this.chemical.cancelDosing(schlor.chemController.orp, 'dosing method changed'); }
|
|
1298
|
+
if (schlor.chemical.dosingStatus === 1) { await this.chemical.cancelMixing(schlor.chemController.orp); }
|
|
1299
|
+
let chlor = sys.chlorinators.getItemById(1);
|
|
1300
|
+
chlor.disabled = false;
|
|
1301
|
+
chlor.isDosing = false;
|
|
1302
|
+
}
|
|
1303
|
+
} catch (err) { logger.error(`setChlorAsync: ${err.message}`); return Promise.reject(err); }
|
|
1304
|
+
}
|
|
1300
1305
|
public async stopDosing(schem: ChemicalState, reason: string): Promise<void> {
|
|
1301
1306
|
try {
|
|
1302
1307
|
if (this._dosingTimer) {
|
|
@@ -1368,7 +1373,7 @@ export class NixieChemChlor extends NixieChildEquipment {
|
|
|
1368
1373
|
try {
|
|
1369
1374
|
await this.turnOn(schem);
|
|
1370
1375
|
if (schlor.currentOutput !== 100) {
|
|
1371
|
-
logger.
|
|
1376
|
+
logger.warn(`Chlor dose not added because current output is not 100%`);
|
|
1372
1377
|
}
|
|
1373
1378
|
else {
|
|
1374
1379
|
if (typeof dose._lastLatch !== 'undefined') {
|
|
@@ -1419,18 +1424,15 @@ export class NixieChemChlor extends NixieChildEquipment {
|
|
|
1419
1424
|
}
|
|
1420
1425
|
public async turnOff(schem: ChemicalState): Promise<ChlorinatorState> {
|
|
1421
1426
|
try {
|
|
1427
|
+
logger.info(`Turning off the chlorinator`);
|
|
1422
1428
|
let chlor = sys.chlorinators.getItemById(1);
|
|
1423
1429
|
let schlor = state.chlorinators.getItemById(1);
|
|
1424
|
-
if (schlor.currentOutput === 0 && schlor.targetOutput === 0 && !schlor.superChlor && chlor.disabled &&
|
|
1430
|
+
if (schlor.currentOutput === 0 && schlor.targetOutput === 0 && !schlor.superChlor && chlor.disabled && !chlor.isDosing) {
|
|
1425
1431
|
this.isOn = schem.chlor.isDosing = false;
|
|
1426
1432
|
return schlor;
|
|
1427
1433
|
}
|
|
1428
1434
|
let cstate = await sys.board.chlorinator.setChlorAsync({
|
|
1429
1435
|
id: 1,
|
|
1430
|
-
poolSetpoint: 0,
|
|
1431
|
-
spaSetpoint: 0,
|
|
1432
|
-
superChlor: false,
|
|
1433
|
-
superChlorHours: 0,
|
|
1434
1436
|
disabled: true,
|
|
1435
1437
|
isDosing: false
|
|
1436
1438
|
})
|
|
@@ -1443,20 +1445,12 @@ export class NixieChemChlor extends NixieChildEquipment {
|
|
|
1443
1445
|
try {
|
|
1444
1446
|
let chlor = sys.chlorinators.getItemById(1);
|
|
1445
1447
|
let schlor = state.chlorinators.getItemById(1);
|
|
1446
|
-
|
|
1447
|
-
let poolSetpoint: number = 0, spaSetpoint: number = 0;
|
|
1448
|
-
if (chem.body === 0 || chem.body === 32) poolSetpoint = 100;
|
|
1449
|
-
if (chem.body === 1 || chem.body === 32) spaSetpoint = 100;
|
|
1450
|
-
if (schlor.currentOutput === 100 && schlor.targetOutput === 100 && !schlor.superChlor && !chlor.disabled && schlor.poolSetpoint === poolSetpoint && schlor.spaSetpoint === spaSetpoint && chlor.isDosing) {
|
|
1448
|
+
if (schlor.currentOutput === 100 && schlor.targetOutput === 100 && !schlor.superChlor && !chlor.disabled && chlor.isDosing) {
|
|
1451
1449
|
this.isOn = schem.chlor.isDosing = true;
|
|
1452
1450
|
return schlor;
|
|
1453
1451
|
}
|
|
1454
1452
|
let cstate = await sys.board.chlorinator.setChlorAsync({
|
|
1455
1453
|
id: 1,
|
|
1456
|
-
poolSetpoint,
|
|
1457
|
-
spaSetpoint,
|
|
1458
|
-
superChlor: false,
|
|
1459
|
-
superChlorHours: 0,
|
|
1460
1454
|
disabled: false,
|
|
1461
1455
|
isDosing: true
|
|
1462
1456
|
})
|
|
@@ -1512,7 +1506,7 @@ export class NixieChemicalPh extends NixieChemical {
|
|
|
1512
1506
|
let sorp = sph.chemController.orp;
|
|
1513
1507
|
for (let i = 0; i < chlors.length; i++) {
|
|
1514
1508
|
let chlor = chlors.getItemByIndex(i);
|
|
1515
|
-
if (!chlor.disabled) await sys.board.chlorinator.setChlorAsync({ id: chlor.id, disabled: true });
|
|
1509
|
+
if (!chlor.disabled) await sys.board.chlorinator.setChlorAsync({ id: chlor.id, disabled: true, isDosing: false });
|
|
1516
1510
|
}
|
|
1517
1511
|
// If we are currently dosing ORP then we need to stop that because pH is currently dosing.
|
|
1518
1512
|
if (sorp.pump.isDosing || sorp.chlor.isDosing) await this.chemController.orp.cancelDosing(sorp, 'pH priority');
|
|
@@ -1756,24 +1750,13 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
1756
1750
|
sorp.level = typeof data.level !== 'undefined' && !isNaN(parseFloat(data.level)) ? parseFloat(data.level) : sorp.level;
|
|
1757
1751
|
this.orp.phLockout = typeof data.phLockout !== 'undefined' && !isNaN(parseFloat(data.phLockout)) ? parseFloat(data.phLockout) : this.orp.phLockout;
|
|
1758
1752
|
this.orp.flowReadingsOnly = typeof data.flowReadingsOnly !== 'undefined' ? utils.makeBool(data.flowReadingsOnly) : this.orp.flowReadingsOnly;
|
|
1759
|
-
|
|
1760
|
-
// if dynamically calculating the chlor dose, set the chlor body assoc
|
|
1761
|
-
// to the same as REM chem (dP will lock this out)
|
|
1762
|
-
let schlor = state.chlorinators.getItemById(1);
|
|
1763
|
-
/* if (this.orp.chlorDosingMethod > 0) {
|
|
1764
|
-
let chlor = sys.chlorinators.getItemById(1);
|
|
1765
|
-
chlor.body = this.chemController.chem.body;
|
|
1766
|
-
schlor.lockSetpoints = true;
|
|
1767
|
-
}
|
|
1768
|
-
else {
|
|
1769
|
-
schlor.lockSetpoints = false;
|
|
1770
|
-
} */
|
|
1753
|
+
if (typeof data.chlorDosingMethod !== 'undefined') { this.orp.chlorDosingMethod = data.chlorDosingMethod; }
|
|
1771
1754
|
await this.setDosing(this.orp, data);
|
|
1772
1755
|
await this.setMixing(this.orp, data);
|
|
1773
1756
|
await this.probe.setProbeORPAsync(sorp.probe, data.probe);
|
|
1774
1757
|
await this.tank.setTankAsync(sorp.tank, data.tank);
|
|
1775
1758
|
await this.pump.setPumpAsync(sorp.pump, data.pump);
|
|
1776
|
-
|
|
1759
|
+
await this.chlor.setChlorAsync(sorp.chlor, data);
|
|
1777
1760
|
this.orp.setpoint = sorp.setpoint = typeof data.setpoint !== 'undefined' ? parseInt(data.setpoint, 10) : this.orp.setpoint;
|
|
1778
1761
|
if (typeof data.tolerance !== 'undefined') {
|
|
1779
1762
|
if (typeof data.tolerance.enabled !== 'undefined') this.orp.tolerance.enabled = utils.makeBool(data.tolerance.enabled);
|
|
@@ -1812,7 +1795,7 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
1812
1795
|
if (sorp.tank.level > 0) {
|
|
1813
1796
|
logger.verbose(`Chem orp dose activate pump ${this.pump.pump.ratedFlow}mL/min`);
|
|
1814
1797
|
await this.pump.dose(sorp);
|
|
1815
|
-
}
|
|
1798
|
+
}
|
|
1816
1799
|
}
|
|
1817
1800
|
catch (err) { logger.error(`manualDoseAsync ORP: ${err.message}`); logger.error(err); return Promise.reject(err); }
|
|
1818
1801
|
}
|
|
@@ -1824,12 +1807,17 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
1824
1807
|
if (sorp.doseHistory.length) {
|
|
1825
1808
|
// if last dose was within 15 minutes, set mix time to 15 mins-lastdose
|
|
1826
1809
|
// if no dose in last 15, then we should be monitoring
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1810
|
+
if (new Date().getTime() - sorp.doseHistory[0].end.getTime() < this.chlor.chlorInterval * 60 * 1000){
|
|
1811
|
+
let lastDoseTime = sorp.doseHistory[0].timeDosed;
|
|
1812
|
+
let mixTime = Math.min(Math.max(this.chlor.chlorInterval * 60 - lastDoseTime, 0), this.chlor.chlorInterval * 60);
|
|
1813
|
+
// if (mixTime === 0) return; // due to delays with setting chlor, let the checkDosing pick up the cycle again with the chlor already on.
|
|
1814
|
+
if (sorp.dosingStatus === 0) await this.mixChemicals(sorp, mixTime);
|
|
1815
|
+
}
|
|
1830
1816
|
}
|
|
1831
|
-
else
|
|
1817
|
+
else{
|
|
1832
1818
|
if (sorp.dosingStatus === 0) await this.mixChemicals(sorp);
|
|
1819
|
+
}
|
|
1820
|
+
return;
|
|
1833
1821
|
}
|
|
1834
1822
|
else {
|
|
1835
1823
|
// Just stop the pump for now but we will do some logging later.
|
|
@@ -1871,6 +1859,7 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
1871
1859
|
// if no dose in last 15, then we should be monitoring
|
|
1872
1860
|
let lastDoseTime = schem.doseHistory[0].timeDosed;
|
|
1873
1861
|
let mixTime = Math.min(Math.max(this.chlor.chlorInterval * 60 - lastDoseTime, 0), this.chlor.chlorInterval * 60);
|
|
1862
|
+
// if (mixTime === 0) return; // due to delays in the setting the chlor, if we had a full dose last time let the chlor continue
|
|
1874
1863
|
this.currentMix.set({ time: this.chlor.chlorInterval, timeMixed: Math.max(0, mixTime - schem.mixTimeRemaining) });
|
|
1875
1864
|
}
|
|
1876
1865
|
else
|
|
@@ -1899,14 +1888,15 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
1899
1888
|
}
|
|
1900
1889
|
public async checkDosing(chem: ChemController, sorp: ChemicalORPState): Promise<void> {
|
|
1901
1890
|
try {
|
|
1902
|
-
let status = sys.board.valueMaps.chemControllerDosingStatus.getName(sorp.dosingStatus);
|
|
1903
|
-
if (!chem.orp.flowReadingsOnly || (chem.orp.flowReadingsOnly && sorp.chemController.flowDetected)){
|
|
1891
|
+
let status = sys.board.valueMaps.chemControllerDosingStatus.getName(sorp.dosingStatus);
|
|
1892
|
+
if (!chem.orp.flowReadingsOnly || (chem.orp.flowReadingsOnly && sorp.chemController.flowDetected)) {
|
|
1904
1893
|
// demand in raw mV
|
|
1905
1894
|
sorp.demand = this.orp.setpoint - sorp.level;
|
|
1906
1895
|
// log the demand. We'll store the last 100 data points.
|
|
1907
1896
|
// With 1s intervals, this will only be 1m 40s. Likely should consider more... and def time to move this to an external file.
|
|
1908
1897
|
sorp.appendDemand(new Date().valueOf(), sorp.demand);
|
|
1909
1898
|
}
|
|
1899
|
+
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
|
|
1910
1900
|
if (sorp.suspendDosing) {
|
|
1911
1901
|
// Kill off the dosing and make sure the pump isn't running. Let's force the issue here.
|
|
1912
1902
|
await this.cancelDosing(sorp, 'suspended');
|
|
@@ -1991,7 +1981,7 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
1991
1981
|
return;
|
|
1992
1982
|
}
|
|
1993
1983
|
// Old fashion method; let the setpoints on chlor be the master
|
|
1994
|
-
if (chem.orp.chlorDosingMethod === 0) return;
|
|
1984
|
+
// if (chem.orp.chlorDosingMethod === 0) return;
|
|
1995
1985
|
// if there is a current pending dose, finish it out
|
|
1996
1986
|
if (typeof sorp.currentDose === 'undefined') {
|
|
1997
1987
|
if (sorp.dosingStatus === 0) { // 0 is dosing
|
|
@@ -2049,7 +2039,6 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
2049
2039
|
percentOfTime = 1;
|
|
2050
2040
|
}
|
|
2051
2041
|
else if (sorp.demand < -20) {
|
|
2052
|
-
logger.info(`Chlor % of time should be 0%`)
|
|
2053
2042
|
await this.cancelDosing(sorp, 'demand < -20');
|
|
2054
2043
|
}
|
|
2055
2044
|
else {
|
|
@@ -2083,16 +2072,16 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
2083
2072
|
// convert the % of time back to an amount of chlorine over 15 minutes;
|
|
2084
2073
|
let time = this.chlor.chlorInterval * 60 * percentOfTime;
|
|
2085
2074
|
let dose = model.chlorinePerSec * time;
|
|
2086
|
-
|
|
2087
|
-
|
|
2075
|
+
|
|
2088
2076
|
if (dose > 0) {
|
|
2077
|
+
logger.info(`Chem chlor calculated dosing at ${Math.round(percentOfTime * 10000) / 100}% and will dose ${Math.round(dose * 1000000) / 1000000}Lbs of chlorine over the next ${utils.formatDuration(time)}.`)
|
|
2089
2078
|
sorp.startDose(new Date(), 'auto', dose, 0, time, 0);
|
|
2090
2079
|
await this.chlor.dose(sorp);
|
|
2091
2080
|
return;
|
|
2092
2081
|
}
|
|
2093
2082
|
|
|
2094
2083
|
// if none of the other conditions are true, mix
|
|
2095
|
-
await this.mixChemicals(sorp, this.chlor.chlorInterval * 60);
|
|
2084
|
+
// await this.mixChemicals(sorp, this.chlor.chlorInterval * 60);
|
|
2096
2085
|
|
|
2097
2086
|
}
|
|
2098
2087
|
else if (this.orp.setpoint > sorp.level) {
|
|
@@ -2156,6 +2145,14 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
2156
2145
|
}
|
|
2157
2146
|
catch (err) { logger.error(`checkDosing ORP: ${err.message}`); return Promise.reject(err); }
|
|
2158
2147
|
}
|
|
2148
|
+
public async deleteChlorAsync(chlor: NixieChlorinator) {
|
|
2149
|
+
logger.info(`Removing chlor ${chlor.id} from Chem Controller ${this.getParent().id}`);
|
|
2150
|
+
let schem = state.chemControllers.getItemById(this.getParent().id);
|
|
2151
|
+
this.orp.useChlorinator = false;
|
|
2152
|
+
schem.orp.useChlorinator = false;
|
|
2153
|
+
if (schem.orp.dosingStatus === 0) { await this.cancelDosing(schem.orp, 'deleting chlorinator'); }
|
|
2154
|
+
if (schem.orp.dosingStatus === 1) { await this.cancelMixing(schem.orp); }
|
|
2155
|
+
}
|
|
2159
2156
|
}
|
|
2160
2157
|
class NixieChemProbe extends NixieChildEquipment {
|
|
2161
2158
|
constructor(parent: NixieChemical) { super(parent); }
|
|
@@ -2209,7 +2206,7 @@ export class NixieChemProbePh extends NixieChemProbe {
|
|
|
2209
2206
|
// Set the current body so that it references the temperature of the current running body.
|
|
2210
2207
|
let body = sys.board.bodies.getBodyState(this.chemical.chemController.chem.body);
|
|
2211
2208
|
if (typeof body !== 'undefined' && body.isOn) {
|
|
2212
|
-
let units = sys.board.valueMaps.tempUnits.transform(
|
|
2209
|
+
let units = sys.board.valueMaps.tempUnits.transform(state.temps.units);
|
|
2213
2210
|
let obj = {};
|
|
2214
2211
|
obj[`temp${units.name.toUpperCase()}`] = body.temp;
|
|
2215
2212
|
sprobe.tempUnits = units.val;
|
|
@@ -2235,7 +2232,7 @@ export class NixieChemProbePh extends NixieChemProbe {
|
|
|
2235
2232
|
deviceBinding: this.probe.deviceBinding,
|
|
2236
2233
|
eventName: "chemController",
|
|
2237
2234
|
property: "pHLevel",
|
|
2238
|
-
sendValue: '
|
|
2235
|
+
sendValue: 'all',
|
|
2239
2236
|
isActive: data.remFeedEnabled,
|
|
2240
2237
|
sampling: 1,
|
|
2241
2238
|
changesOnly: false,
|
|
@@ -2243,7 +2240,7 @@ export class NixieChemProbePh extends NixieChemProbe {
|
|
|
2243
2240
|
}
|
|
2244
2241
|
let res = await NixieChemController.putDeviceService(this.probe.connectionId, '/config/feed', d);
|
|
2245
2242
|
if (res.status.code === 200) { this.probe.remFeedEnabled = data.remFeedEnabled; }
|
|
2246
|
-
else { logger.warn(`setRemoteREMFeed: Cannot set remote feed. Message:${JSON.stringify(res.status)} for feed: ${JSON.stringify(d)}.`);
|
|
2243
|
+
else { logger.warn(`setRemoteREMFeed: Cannot set remote feed. Message:${JSON.stringify(res.status)} for feed: ${JSON.stringify(d)}.`); }
|
|
2247
2244
|
}
|
|
2248
2245
|
catch (err) { logger.error(`setRemoteREMFeed: ${err.message}`); return Promise.reject(err); }
|
|
2249
2246
|
}
|
|
@@ -2326,9 +2323,15 @@ export class NixieChemProbeORP extends NixieChemProbe {
|
|
|
2326
2323
|
}
|
|
2327
2324
|
let res = await NixieChemController.putDeviceService(this.probe.connectionId, '/config/feed', d);
|
|
2328
2325
|
if (res.status.code === 200) { this.probe.remFeedEnabled = data.remFeedEnabled; }
|
|
2329
|
-
else {
|
|
2326
|
+
else {
|
|
2327
|
+
logger.warn(`setRemoteREMFeed: Cannot set remote feed. Message:${JSON.stringify(res.status)} for feed: ${JSON.stringify(d)}.`);
|
|
2328
|
+
// return Promise.reject(new InvalidOperationError(`Nixie could not set remote REM feed for the ORP probe.`, this.probe.dataName));
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
catch (err) {
|
|
2332
|
+
logger.error(`setRemoteREMFeed: ${err.message}`);
|
|
2333
|
+
//return Promise.reject(err); // don't muck up chem controller if we can't set the feeds.
|
|
2330
2334
|
}
|
|
2331
|
-
catch (err) { logger.error(`setRemoteREMFeed: ${err.message}`); return Promise.reject(err); }
|
|
2332
2335
|
}
|
|
2333
2336
|
public syncRemoteREMFeeds(chem: ChemController, servers) {
|
|
2334
2337
|
// match any feeds and store the id/statusf
|
|
@@ -9,6 +9,7 @@ import { setTimeout, clearTimeout } from 'timers';
|
|
|
9
9
|
import { webApp, InterfaceServerResponse } from "../../../web/Server";
|
|
10
10
|
import { Outbound, Protocol, Response } from '../../comms/messages/Messages';
|
|
11
11
|
import { conn } from '../../comms/Comms';
|
|
12
|
+
import { ncp } from '../Nixie';
|
|
12
13
|
|
|
13
14
|
export class NixieChlorinatorCollection extends NixieEquipmentCollection<NixieChlorinator> {
|
|
14
15
|
public async deleteChlorinatorAsync(id: number) {
|
|
@@ -18,6 +19,7 @@ export class NixieChlorinatorCollection extends NixieEquipmentCollection<NixieCh
|
|
|
18
19
|
for (let i = this.length - 1; i >= 0; i--) {
|
|
19
20
|
let c = this[i];
|
|
20
21
|
if (c.id === id) {
|
|
22
|
+
await ncp.chemControllers.deleteChlorAsync(c as NixieChlorinator);
|
|
21
23
|
await c.closeAsync();
|
|
22
24
|
this.splice(i, 1);
|
|
23
25
|
}
|
|
@@ -75,7 +77,6 @@ export class NixieChlorinator extends NixieEquipment {
|
|
|
75
77
|
private _pollTimer: NodeJS.Timeout = null;
|
|
76
78
|
private superChlorinating: boolean = false;
|
|
77
79
|
private superChlorStart: number = 0;
|
|
78
|
-
private chlorinating: boolean = false;
|
|
79
80
|
public chlor: Chlorinator;
|
|
80
81
|
public bodyOnTime: number;
|
|
81
82
|
protected _suspendPolling: number = 0;
|
|
@@ -101,7 +102,7 @@ export class NixieChlorinator extends NixieEquipment {
|
|
|
101
102
|
let superChlorHours = typeof data.superChlorHours !== 'undefined' ? parseInt(data.superChlorHours, 10) : chlor.superChlorHours;
|
|
102
103
|
let disabled = typeof data.disabled !== 'undefined' ? utils.makeBool(data.disabled) : chlor.disabled;
|
|
103
104
|
let isDosing = typeof data.isDosing !== 'undefined' ? utils.makeBool(data.isDosing) : chlor.isDosing;
|
|
104
|
-
let model = typeof data.model !== 'undefined' ? data.model : chlor.model;
|
|
105
|
+
let model = typeof data.model !== 'undefined' ? data.model : chlor.model || 0;
|
|
105
106
|
if (typeof body === 'undefined') return Promise.reject(new InvalidEquipmentDataError(`Invalid body assignment`, 'chlorinator', data.body || chlor.body));
|
|
106
107
|
if (isNaN(poolSetpoint)) poolSetpoint = 0;
|
|
107
108
|
if (isNaN(spaSetpoint)) spaSetpoint = 0;
|
|
@@ -113,9 +114,8 @@ export class NixieChlorinator extends NixieEquipment {
|
|
|
113
114
|
schlor.superChlor = chlor.superChlor = superChlor;
|
|
114
115
|
schlor.superChlorHours = chlor.superChlorHours = superChlorHours;
|
|
115
116
|
schlor.type = chlor.type = chlorType;
|
|
116
|
-
chlor.body = body;
|
|
117
117
|
chlor.model = model;
|
|
118
|
-
schlor.body = chlor.body;
|
|
118
|
+
schlor.body = chlor.body = body.val;
|
|
119
119
|
chlor.disabled = disabled;
|
|
120
120
|
chlor.isDosing = isDosing;
|
|
121
121
|
schlor.name = chlor.name = data.name || chlor.name || `Chlorinator ${chlor.id}`;
|
|
@@ -178,7 +178,7 @@ export class NixieChlorinator extends NixieEquipment {
|
|
|
178
178
|
// Comms failure will be handeled by the message processor.
|
|
179
179
|
logger.error(`Chlorinator ${this.chlor.name} comms failure: ${err.message}`);
|
|
180
180
|
}
|
|
181
|
-
finally { if(!this.closing) this._pollTimer = setTimeout(
|
|
181
|
+
finally { if(!this.closing) this._pollTimer = setTimeout(() => {self.pollEquipment();}, this.pollingInterval); }
|
|
182
182
|
}
|
|
183
183
|
public async takeControl(): Promise<boolean> {
|
|
184
184
|
try {
|
|
@@ -230,7 +230,7 @@ export class NixieChlorinator extends NixieEquipment {
|
|
|
230
230
|
let setpoint = 0;
|
|
231
231
|
if (typeof body !== 'undefined') {
|
|
232
232
|
setpoint = (body.id === 1) ? this.chlor.poolSetpoint : this.chlor.spaSetpoint;
|
|
233
|
-
if (this.chlor.superChlor === true) setpoint = 100;
|
|
233
|
+
if (this.chlor.superChlor === true || this.chlor.isDosing) setpoint = 100;
|
|
234
234
|
if (this.chlor.disabled === true) setpoint = 0; // Our target should be 0 because we have other things going on. For instance,
|
|
235
235
|
// we may be dosing acid which will cause the disabled flag to be true.
|
|
236
236
|
}
|
|
@@ -251,7 +251,6 @@ export class NixieChlorinator extends NixieEquipment {
|
|
|
251
251
|
onAbort: () => {},
|
|
252
252
|
onComplete: (err) => {
|
|
253
253
|
if (err) {
|
|
254
|
-
this.chlorinating = false;
|
|
255
254
|
cstate.currentOutput = 0;
|
|
256
255
|
cstate.status = 128;
|
|
257
256
|
resolve(false);
|
|
@@ -260,7 +259,6 @@ export class NixieChlorinator extends NixieEquipment {
|
|
|
260
259
|
// The action:17 message originated from us so we will not see it in the
|
|
261
260
|
// ChlorinatorStateMessage module.
|
|
262
261
|
cstate.currentOutput = setpoint;
|
|
263
|
-
this.chlorinating = true;
|
|
264
262
|
if (!this.superChlorinating && cstate.superChlor) {
|
|
265
263
|
cstate.superChlorRemaining = cstate.superChlorHours * 3600;
|
|
266
264
|
this.superChlorStart = Math.floor(new Date().getTime() / 1000) * 1000;
|
|
@@ -274,6 +272,8 @@ export class NixieChlorinator extends NixieEquipment {
|
|
|
274
272
|
}
|
|
275
273
|
}
|
|
276
274
|
});
|
|
275
|
+
// #338
|
|
276
|
+
if (setpoint === 16) { out.appendPayloadByte(0); }
|
|
277
277
|
conn.queueSendMessage(out);
|
|
278
278
|
});
|
|
279
279
|
|
|
@@ -306,6 +306,7 @@ export class NixieChlorinator extends NixieEquipment {
|
|
|
306
306
|
conn.queueSendMessage(out);
|
|
307
307
|
});
|
|
308
308
|
}
|
|
309
|
+
else return Promise.resolve(false);
|
|
309
310
|
} catch (err) { logger.error(`Communication error with Chlorinator ${this.chlor.name} : ${err.message}`); return Promise.reject(err);}
|
|
310
311
|
|
|
311
312
|
}
|
|
@@ -56,6 +56,12 @@ export class NixieCircuitCollection extends NixieEquipmentCollection<NixieCircui
|
|
|
56
56
|
}
|
|
57
57
|
catch (err) { logger.error(`setCircuitAsync: ${err.message}`); return Promise.reject(err); }
|
|
58
58
|
}
|
|
59
|
+
public async checkCircuitEggTimerExpirationAsync(cstate: ICircuitState) {
|
|
60
|
+
try {
|
|
61
|
+
let c: NixieCircuit = this.find(elem => elem.id === cstate.id) as NixieCircuit;
|
|
62
|
+
await c.checkCircuitEggTimerExpirationAsync(cstate);
|
|
63
|
+
} catch (err) { logger.error(`NCP: Error synching circuit states: ${err}`); }
|
|
64
|
+
}
|
|
59
65
|
public async initAsync(circuits: CircuitCollection) {
|
|
60
66
|
try {
|
|
61
67
|
for (let i = 0; i < circuits.length; i++) {
|
|
@@ -112,6 +118,10 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
112
118
|
constructor(ncp: INixieControlPanel, circuit: Circuit) {
|
|
113
119
|
super(ncp);
|
|
114
120
|
this.circuit = circuit;
|
|
121
|
+
// Clear out the delays.
|
|
122
|
+
let cstate = state.circuits.getItemById(circuit.id);
|
|
123
|
+
cstate.startDelay = false;
|
|
124
|
+
cstate.stopDelay = false;
|
|
115
125
|
}
|
|
116
126
|
public get id(): number { return typeof this.circuit !== 'undefined' ? this.circuit.id : -1; }
|
|
117
127
|
public get eggTimerOff(): Timestamp { return typeof this.timeOn !== 'undefined' && !this.circuit.dontStop ? this.timeOn.clone().addMinutes(this.circuit.eggTimer) : undefined; }
|
|
@@ -126,18 +136,40 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
126
136
|
this._sequencing = true;
|
|
127
137
|
let arr = [];
|
|
128
138
|
let t = typeof timeout === 'undefined' ? 100 : timeout;
|
|
129
|
-
arr.push({ isOn:
|
|
139
|
+
arr.push({ isOn: false, timeout: t }); // This may not be needed but we always need to start from off.
|
|
130
140
|
//[{ isOn: true, timeout: 1000 }, { isOn: false, timeout: 1000 }]
|
|
131
141
|
for (let i = 0; i < count; i++) {
|
|
132
|
-
arr.push({ isOn: false, timeout: t });
|
|
133
142
|
arr.push({ isOn: true, timeout: t });
|
|
143
|
+
if(i < count - 1) arr.push({ isOn: false, timeout: t });
|
|
134
144
|
}
|
|
145
|
+
// The documentation for IntelliBrite is incorrect. The sequence below will give us Party mode.
|
|
146
|
+
// Party mode:2
|
|
147
|
+
// Start: Off
|
|
148
|
+
// On
|
|
149
|
+
// Off
|
|
150
|
+
// On
|
|
151
|
+
// According to the docs this is the sequence they lay out.
|
|
152
|
+
// Party mode:2
|
|
153
|
+
// Start: On
|
|
154
|
+
// Off
|
|
155
|
+
// On
|
|
156
|
+
// Off
|
|
157
|
+
// On
|
|
158
|
+
|
|
135
159
|
let res = await NixieEquipment.putDeviceService(this.circuit.connectionId, `/state/device/${this.circuit.deviceBinding}`, arr, 60000);
|
|
136
160
|
return res;
|
|
137
161
|
} catch (err) { logger.error(`Nixie: Error sending circuit sequence ${this.id}: ${count}`); }
|
|
138
162
|
finally { this._sequencing = false; }
|
|
139
163
|
}
|
|
140
|
-
public async
|
|
164
|
+
public async setThemeAsync(cstate: ICircuitState, theme: number): Promise<InterfaceServerResponse> {
|
|
165
|
+
try {
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
return new InterfaceServerResponse(200, 'Sucess');
|
|
170
|
+
} catch (err) { logger.error(`Nixie: Error setting light theme ${cstate.id}-${cstate.name} to ${theme}`); }
|
|
171
|
+
}
|
|
172
|
+
public async setCircuitStateAsync(cstate: ICircuitState, val: boolean, scheduled: boolean = false): Promise<InterfaceServerResponse> {
|
|
141
173
|
try {
|
|
142
174
|
if (val !== cstate.isOn) {
|
|
143
175
|
logger.info(`NCP: Setting Circuit ${cstate.name} to ${val}`);
|
|
@@ -149,20 +181,35 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
149
181
|
// Check to see if we should be on by poking the schedules.
|
|
150
182
|
}
|
|
151
183
|
if (utils.isNullOrEmpty(this.circuit.connectionId) || utils.isNullOrEmpty(this.circuit.deviceBinding)) {
|
|
184
|
+
sys.board.circuits.setEndTime(sys.circuits.getInterfaceById(cstate.id), cstate, val);
|
|
152
185
|
cstate.isOn = val;
|
|
153
186
|
return new InterfaceServerResponse(200, 'Success');
|
|
154
187
|
}
|
|
155
188
|
if (this._sequencing) return new InterfaceServerResponse(200, 'Success');
|
|
156
189
|
let res = await NixieEquipment.putDeviceService(this.circuit.connectionId, `/state/device/${this.circuit.deviceBinding}`, { isOn: val, latch: val ? 10000 : undefined });
|
|
157
190
|
if (res.status.code === 200) {
|
|
158
|
-
cstate.
|
|
191
|
+
sys.board.circuits.setEndTime(sys.circuits.getInterfaceById(cstate.id), cstate, val);
|
|
159
192
|
// Set this up so we can process our egg timer.
|
|
160
|
-
if (!cstate.isOn && val) { this.timeOn = new Timestamp(); }
|
|
161
|
-
else if (!val) this.timeOn = undefined;
|
|
193
|
+
//if (!cstate.isOn && val) { cstate.startTime = this.timeOn = new Timestamp(); }
|
|
194
|
+
//else if (!val) cstate.startTime = this.timeOn = undefined;
|
|
195
|
+
cstate.isOn = val;
|
|
162
196
|
}
|
|
163
197
|
return res;
|
|
164
198
|
} catch (err) { logger.error(`Nixie: Error setting circuit state ${cstate.id}-${cstate.name} to ${val}`); }
|
|
165
199
|
}
|
|
200
|
+
public async checkCircuitEggTimerExpirationAsync(cstate: ICircuitState) {
|
|
201
|
+
// if circuit end time is past current time, either the schedule is finished
|
|
202
|
+
// (this should already be turned off) or the egg timer has expired
|
|
203
|
+
try {
|
|
204
|
+
if (!cstate.isActive || !cstate.isOn) return;
|
|
205
|
+
if (typeof cstate.endTime !== 'undefined') {
|
|
206
|
+
if (cstate.endTime.toDate() < new Timestamp().toDate()) {
|
|
207
|
+
await sys.board.circuits.setCircuitStateAsync(cstate.id, false);
|
|
208
|
+
cstate.emitEquipmentChange();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
} catch (err) { logger.error(`Error syncing circuit: ${err}`); }
|
|
212
|
+
}
|
|
166
213
|
private async checkHardwareStatusAsync(connectionId: string, deviceBinding: string) {
|
|
167
214
|
try {
|
|
168
215
|
let dev = await NixieEquipment.getDeviceService(connectionId, `/status/device/${deviceBinding}`);
|
|
@@ -187,6 +234,8 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
187
234
|
public async closeAsync() {
|
|
188
235
|
try {
|
|
189
236
|
let cstate = state.circuits.getItemById(this.circuit.id);
|
|
237
|
+
cstate.stopDelay = false;
|
|
238
|
+
cstate.startDelay = false;
|
|
190
239
|
await this.setCircuitStateAsync(cstate, false);
|
|
191
240
|
cstate.emitEquipmentChange();
|
|
192
241
|
}
|