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
package/controller/State.ts
CHANGED
|
@@ -7,7 +7,7 @@ published by the Free Software Foundation, either version 3 of the
|
|
|
7
7
|
License, or (at your option) any later version.
|
|
8
8
|
|
|
9
9
|
This program is distributed in the hope that it will be useful,
|
|
10
|
-
but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of1
|
|
11
11
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
12
|
GNU Affero General Public License for more details.
|
|
13
13
|
|
|
@@ -26,7 +26,7 @@ import { sys, Chemical, ChemController } from './Equipment';
|
|
|
26
26
|
import { versionCheck } from '../config/VersionCheck';
|
|
27
27
|
import { EquipmentStateMessage } from './comms/messages/status/EquipmentStateMessage';
|
|
28
28
|
import { DataLogger, DataLoggerEntry, IDataLoggerEntry } from '../logger/DataLogger';
|
|
29
|
-
|
|
29
|
+
import { delayMgr } from './Lockouts';
|
|
30
30
|
|
|
31
31
|
export class State implements IState {
|
|
32
32
|
statePath: string;
|
|
@@ -36,6 +36,7 @@ export class State implements IState {
|
|
|
36
36
|
private _isDirty: boolean;
|
|
37
37
|
private _timerDirty: NodeJS.Timeout;
|
|
38
38
|
protected _dt: Timestamp;
|
|
39
|
+
protected _startTime: Timestamp;
|
|
39
40
|
protected _controllerType: ControllerType;
|
|
40
41
|
protected onchange = (obj, fn) => {
|
|
41
42
|
const handler = {
|
|
@@ -139,6 +140,7 @@ export class State implements IState {
|
|
|
139
140
|
_state.filters = this.filters.getExtended();
|
|
140
141
|
_state.schedules = this.schedules.getExtended();
|
|
141
142
|
_state.chemControllers = this.chemControllers.getExtended();
|
|
143
|
+
_state.delays = delayMgr.serialize();
|
|
142
144
|
return _state;
|
|
143
145
|
}
|
|
144
146
|
else {
|
|
@@ -152,7 +154,6 @@ export class State implements IState {
|
|
|
152
154
|
return extend(true, [], this.data[section] || []);
|
|
153
155
|
else
|
|
154
156
|
return extend(true, {}, this.data[section] || {});
|
|
155
|
-
|
|
156
157
|
}
|
|
157
158
|
}
|
|
158
159
|
public async stopAsync() {
|
|
@@ -191,6 +192,8 @@ export class State implements IState {
|
|
|
191
192
|
public get controllerState() {
|
|
192
193
|
var self = this;
|
|
193
194
|
return {
|
|
195
|
+
systemUnits: sys.board.valueMaps.systemUnits.transform(sys.general.options.units),
|
|
196
|
+
startTime: self.data.startTime || '',
|
|
194
197
|
time: self.data.time || '',
|
|
195
198
|
// body: self.data.body || {},
|
|
196
199
|
valve: self.data.valve || 0,
|
|
@@ -200,7 +203,6 @@ export class State implements IState {
|
|
|
200
203
|
batteryVoltage: self.data.batteryVoltage || 0,
|
|
201
204
|
status: self.data.status || {},
|
|
202
205
|
mode: self.data.mode || {},
|
|
203
|
-
// freeze: self.data.freeze || false,
|
|
204
206
|
appVersion: sys.appVersion || '',
|
|
205
207
|
appVersionState: self.appVersion.get(true) || {},
|
|
206
208
|
clockMode: sys.board.valueMaps.clockModes.transform(sys.general.options.clockMode) || {},
|
|
@@ -209,7 +211,9 @@ export class State implements IState {
|
|
|
209
211
|
model: sys.equipment.model,
|
|
210
212
|
sunrise: self.data.sunrise || '',
|
|
211
213
|
sunset: self.data.sunset || '',
|
|
212
|
-
alias: sys.general.alias
|
|
214
|
+
alias: sys.general.alias,
|
|
215
|
+
freeze: utils.makeBool(self.data.freeze),
|
|
216
|
+
valveMode: self.data.valveMode || {},
|
|
213
217
|
};
|
|
214
218
|
}
|
|
215
219
|
public emitAllEquipmentChanges() {
|
|
@@ -284,6 +288,14 @@ export class State implements IState {
|
|
|
284
288
|
this.hasChanged = true;
|
|
285
289
|
}
|
|
286
290
|
}
|
|
291
|
+
public get valveMode(): number { return typeof this.data.valveMode !== 'undefined' ? this.data.valveMode.val : 0; }
|
|
292
|
+
public set valveMode(val: number) {
|
|
293
|
+
let m = sys.board.valueMaps.valveModes.transform(val);
|
|
294
|
+
if (m.val !== this.valveMode) {
|
|
295
|
+
this.data.valveMode = m;
|
|
296
|
+
this.hasChanged = true;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
287
299
|
public get freeze(): boolean { return this.data.freeze === true; }
|
|
288
300
|
public set freeze(val: boolean) {
|
|
289
301
|
if (this.data.freeze !== val) {
|
|
@@ -305,7 +317,6 @@ export class State implements IState {
|
|
|
305
317
|
this.hasChanged = true;
|
|
306
318
|
}
|
|
307
319
|
}
|
|
308
|
-
|
|
309
320
|
}
|
|
310
321
|
public get valve(): number { return this.data.valve; }
|
|
311
322
|
public set valve(val: number) {
|
|
@@ -330,14 +341,30 @@ export class State implements IState {
|
|
|
330
341
|
public get isInitialized(): boolean { return typeof (this.data.status) !== 'undefined' && this.data.status.val !== 0; }
|
|
331
342
|
public init() {
|
|
332
343
|
console.log(`Init state for Pool Controller`);
|
|
333
|
-
var
|
|
334
|
-
|
|
344
|
+
var sdata = this.loadFile(this.statePath, {});
|
|
345
|
+
sdata = extend(true, { mode: { val: -1 }, temps: { units: { val: 0, name: 'F', desc: 'Fahrenheit' } } }, sdata);
|
|
346
|
+
if (typeof sdata.temps !== 'undefined' && typeof sdata.temps.bodies !== 'undefined') {
|
|
347
|
+
EqStateCollection.removeNullIds(sdata.temps.bodies);
|
|
348
|
+
}
|
|
349
|
+
EqStateCollection.removeNullIds(sdata.schedules);
|
|
350
|
+
EqStateCollection.removeNullIds(sdata.features);
|
|
351
|
+
EqStateCollection.removeNullIds(sdata.circuits);
|
|
352
|
+
EqStateCollection.removeNullIds(sdata.pumps);
|
|
353
|
+
EqStateCollection.removeNullIds(sdata.chlorinators);
|
|
354
|
+
EqStateCollection.removeNullIds(sdata.valves);
|
|
355
|
+
EqStateCollection.removeNullIds(sdata.heaters);
|
|
356
|
+
EqStateCollection.removeNullIds(sdata.covers);
|
|
357
|
+
EqStateCollection.removeNullIds(sdata.circuitGroups);
|
|
358
|
+
EqStateCollection.removeNullIds(sdata.lightGroups);
|
|
359
|
+
EqStateCollection.removeNullIds(sdata.remotes);
|
|
360
|
+
EqStateCollection.removeNullIds(sdata.chemControllers);
|
|
361
|
+
EqStateCollection.removeNullIds(sdata.filters);
|
|
335
362
|
var self = this;
|
|
336
|
-
let pnlTime = typeof
|
|
363
|
+
let pnlTime = typeof sdata.time !== 'undefined' ? new Date(sdata.time) : new Date();
|
|
337
364
|
if (isNaN(pnlTime.getTime())) pnlTime = new Date();
|
|
338
365
|
this._dt = new Timestamp(pnlTime);
|
|
339
366
|
this._dt.milliseconds = 0;
|
|
340
|
-
this.data =
|
|
367
|
+
this.data = sdata;
|
|
341
368
|
//this.onchange(state, function () { self.dirty = true; });
|
|
342
369
|
this._dt.emitter.on('change', function () {
|
|
343
370
|
self.data.time = self._dt.format();
|
|
@@ -370,6 +397,7 @@ export class State implements IState {
|
|
|
370
397
|
this.comms = new CommsState();
|
|
371
398
|
this.heliotrope = new Heliotrope();
|
|
372
399
|
this.appVersion = new AppVersionState(this.data, 'appVersion');
|
|
400
|
+
this.data.startTime = Timestamp.toISOLocal(new Date());
|
|
373
401
|
versionCheck.checkGitLocal();
|
|
374
402
|
}
|
|
375
403
|
public resetData() {
|
|
@@ -467,11 +495,15 @@ export interface ICircuitState {
|
|
|
467
495
|
name: string;
|
|
468
496
|
nameId?: number;
|
|
469
497
|
isOn: boolean;
|
|
498
|
+
startTime?: Timestamp;
|
|
470
499
|
endTime: Timestamp;
|
|
471
500
|
lightingTheme?: number;
|
|
472
501
|
emitEquipmentChange();
|
|
473
502
|
get(bCopy?: boolean);
|
|
474
503
|
showInFeatures?: boolean;
|
|
504
|
+
isActive?: boolean;
|
|
505
|
+
startDelay?: boolean;
|
|
506
|
+
stopDelay?: boolean;
|
|
475
507
|
}
|
|
476
508
|
|
|
477
509
|
interface IEqStateCreator<T> { ctor(data: any, name: string, parent?): T; }
|
|
@@ -571,6 +603,20 @@ class EqStateCollection<T> {
|
|
|
571
603
|
if (typeof (data[name]) === 'undefined') data[name] = [];
|
|
572
604
|
this.data = data[name];
|
|
573
605
|
}
|
|
606
|
+
public static removeNullIds(data: any) {
|
|
607
|
+
if (typeof data !== 'undefined' && Array.isArray(data) && typeof data.length === 'number') {
|
|
608
|
+
for (let i = data.length - 1; i >= 0; i--) {
|
|
609
|
+
if (typeof data[i].id !== 'number') {
|
|
610
|
+
console.log(`Removing ${data[i].id}-${data[i].name}`);
|
|
611
|
+
data.splice(i, 1);
|
|
612
|
+
}
|
|
613
|
+
else if (typeof data[i].id === 'undefined' || isNaN(data[i].id)) {
|
|
614
|
+
console.log(`Removing isNaN ${data[i].id}-${data[i].name}`);
|
|
615
|
+
data.splice(i, 1);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
574
620
|
public getItemById(id: number, add?: boolean, data?: any): T {
|
|
575
621
|
for (let i = 0; i < this.data.length; i++)
|
|
576
622
|
if (typeof this.data[i].id !== 'undefined' && this.data[i].id === id) {
|
|
@@ -827,7 +873,10 @@ export class PumpStateCollection extends EqStateCollection<PumpState> {
|
|
|
827
873
|
}
|
|
828
874
|
public cleanupState() {
|
|
829
875
|
for (let i = this.data.length - 1; i >= 0; i--) {
|
|
830
|
-
if (
|
|
876
|
+
if (isNaN(this.data[i].id)) this.data.splice(i, 1);
|
|
877
|
+
else {
|
|
878
|
+
if (typeof sys.pumps.find(elem => elem.id === this.data[i].id) === 'undefined') this.removeItemById(this.data[i].id);
|
|
879
|
+
}
|
|
831
880
|
}
|
|
832
881
|
let cfg = sys.pumps.toArray();
|
|
833
882
|
for (let i = 0; i < cfg.length; i++) {
|
|
@@ -842,6 +891,13 @@ export class PumpStateCollection extends EqStateCollection<PumpState> {
|
|
|
842
891
|
}
|
|
843
892
|
export class PumpState extends EqState {
|
|
844
893
|
public dataName: string = 'pump';
|
|
894
|
+
public initData() {
|
|
895
|
+
if (typeof this.data.status === 'undefined') {
|
|
896
|
+
this.data.status = { name: 'ok', desc: 'Ok', val: 0 };
|
|
897
|
+
}
|
|
898
|
+
if (typeof this.data.pumpOnDelay === 'undefined') this.data.pumpOnDelay = false;
|
|
899
|
+
}
|
|
900
|
+
private _pumpOnDelayTimer: NodeJS.Timeout;
|
|
845
901
|
private _threshold = 0.05;
|
|
846
902
|
private exceedsThreshold(origVal: number, newVal: number) {
|
|
847
903
|
return Math.abs((newVal - origVal) / origVal) > this._threshold;
|
|
@@ -875,7 +931,7 @@ export class PumpState extends EqState {
|
|
|
875
931
|
// quick fix for #172
|
|
876
932
|
if (this.status !== val) {
|
|
877
933
|
if (sys.board.valueMaps.pumpTypes.getName(this.type) === 'vsf' && val === 0) {
|
|
878
|
-
this.data.status = { name: 'ok', desc: 'Ok', val };
|
|
934
|
+
this.data.status = { name: 'ok', desc: 'Ok', val: 0 };
|
|
879
935
|
}
|
|
880
936
|
else this.data.status = sys.board.valueMaps.pumpStatus.transform(val);
|
|
881
937
|
this.hasChanged = true;
|
|
@@ -901,6 +957,23 @@ export class PumpState extends EqState {
|
|
|
901
957
|
}
|
|
902
958
|
public get time(): number { return this.data.time; }
|
|
903
959
|
public set time(val: number) { this.setDataVal('time', val, false); }
|
|
960
|
+
public get pumpOnDelay() { return this.data.pumpOnDelay; }
|
|
961
|
+
public set pumpOnDelay(val: boolean) {
|
|
962
|
+
if (val === false) {
|
|
963
|
+
if (typeof this._pumpOnDelayTimer !== 'undefined') clearTimeout(this._pumpOnDelayTimer);
|
|
964
|
+
this._pumpOnDelayTimer = undefined;
|
|
965
|
+
}
|
|
966
|
+
this.setDataVal('pumpOnDelay', val);
|
|
967
|
+
}
|
|
968
|
+
public setPumpOnDelayTimeout(delay: number) {
|
|
969
|
+
this.pumpOnDelay = true;
|
|
970
|
+
logger.info(`Pump ON Delay ${this.name} for ${delay / 1000} seconds`);
|
|
971
|
+
this._pumpOnDelayTimer = setTimeout(() => {
|
|
972
|
+
logger.info(`Pump ON Delay ${this.name} expired`);
|
|
973
|
+
this.pumpOnDelay = false;
|
|
974
|
+
}, delay);
|
|
975
|
+
}
|
|
976
|
+
|
|
904
977
|
public getExtended() {
|
|
905
978
|
let pump = this.get(true);
|
|
906
979
|
let cpump = sys.pumps.getItemById(pump.id);
|
|
@@ -957,6 +1030,7 @@ export class ScheduleState extends EqState {
|
|
|
957
1030
|
public get startDate(): Date { return this._startDate; }
|
|
958
1031
|
public set startDate(val: Date) { this._startDate = val; this._saveStartDate(); }
|
|
959
1032
|
private _saveStartDate() {
|
|
1033
|
+
if (typeof this._startDate === 'undefined') this._startDate = new Date();
|
|
960
1034
|
this.startDate.setHours(0, 0, 0, 0);
|
|
961
1035
|
this.setDataVal('startDate', Timestamp.toISOLocal(this.startDate));
|
|
962
1036
|
}
|
|
@@ -1061,7 +1135,10 @@ export class CircuitGroupStateCollection extends EqStateCollection<CircuitGroupS
|
|
|
1061
1135
|
}
|
|
1062
1136
|
public cleanupState() {
|
|
1063
1137
|
for (let i = this.data.length - 1; i >= 0; i--) {
|
|
1064
|
-
if (
|
|
1138
|
+
if (isNaN(this.data[i].id)) this.data.splice(i, 1);
|
|
1139
|
+
else {
|
|
1140
|
+
if (typeof sys.circuitGroups.find(elem => elem.id === this.data[i].id) === 'undefined') this.removeItemById(this.data[i].id);
|
|
1141
|
+
}
|
|
1065
1142
|
}
|
|
1066
1143
|
let cfg = sys.circuitGroups.toArray();
|
|
1067
1144
|
for (let i = 0; i < cfg.length; i++) {
|
|
@@ -1121,12 +1198,23 @@ export class CircuitGroupState extends EqState implements ICircuitGroupState, IC
|
|
|
1121
1198
|
state._dirtyList.removeEqState(this);
|
|
1122
1199
|
}
|
|
1123
1200
|
}
|
|
1201
|
+
public get(bcopy?: boolean): any {
|
|
1202
|
+
let d = super.get(bcopy);
|
|
1203
|
+
let cg = sys.circuitGroups.getItemById(this.id);
|
|
1204
|
+
if (!cg.isActive) d.isActive = false;
|
|
1205
|
+
else d.isActive = undefined;
|
|
1206
|
+
return d;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1124
1209
|
}
|
|
1125
1210
|
export class LightGroupStateCollection extends EqStateCollection<LightGroupState> {
|
|
1126
1211
|
public createItem(data: any): LightGroupState { return new LightGroupState(data); }
|
|
1127
1212
|
public cleanupState() {
|
|
1128
1213
|
for (let i = this.data.length - 1; i >= 0; i--) {
|
|
1129
|
-
if (
|
|
1214
|
+
if (isNaN(this.data[i].id)) this.data.splice(i, 1);
|
|
1215
|
+
else {
|
|
1216
|
+
if (typeof sys.lightGroups.find(elem => elem.id === this.data[i].id) === 'undefined') this.removeItemById(this.data[i].id);
|
|
1217
|
+
}
|
|
1130
1218
|
}
|
|
1131
1219
|
let cfg = sys.lightGroups.toArray();
|
|
1132
1220
|
for (let i = 0; i < cfg.length; i++) {
|
|
@@ -1205,10 +1293,24 @@ export class BodyTempStateCollection extends EqStateCollection<BodyTempState> {
|
|
|
1205
1293
|
}
|
|
1206
1294
|
return undefined;
|
|
1207
1295
|
}
|
|
1296
|
+
public getBodyByCircuitId(circuitId: number) {
|
|
1297
|
+
let b = this.data.find(x => x.circuit === circuitId);
|
|
1298
|
+
if (typeof b === 'undefined') {
|
|
1299
|
+
let circ = sys.circuits.getItemById(circuitId);
|
|
1300
|
+
// Find our body by circuit function.
|
|
1301
|
+
let cfn = sys.board.valueMaps.circuitFunctions.get(circ.type);
|
|
1302
|
+
if (typeof cfn.body !== 'undefined') b = this.data.find(x => x.id === cfn.body);
|
|
1303
|
+
}
|
|
1304
|
+
return typeof b !== 'undefined' ? this.createItem(b) : undefined;
|
|
1305
|
+
}
|
|
1208
1306
|
public cleanupState() {
|
|
1209
1307
|
for (let i = this.data.length - 1; i >= 0; i--) {
|
|
1210
|
-
if (
|
|
1308
|
+
if (isNaN(this.data[i].id)) this.data.splice(i, 1);
|
|
1309
|
+
else {
|
|
1310
|
+
if (typeof sys.bodies.find(elem => elem.id === this.data[i].id) === 'undefined') this.removeItemById(this.data[i].id);
|
|
1311
|
+
}
|
|
1211
1312
|
}
|
|
1313
|
+
this.sortById();
|
|
1212
1314
|
}
|
|
1213
1315
|
|
|
1214
1316
|
}
|
|
@@ -1227,6 +1329,10 @@ export class BodyTempState extends EqState {
|
|
|
1227
1329
|
public dataName = 'bodyTempState';
|
|
1228
1330
|
public initData() {
|
|
1229
1331
|
if (typeof this.data.heaterOptions === 'undefined') this.data.heaterOptions = { total: 0 };
|
|
1332
|
+
if (typeof this.data.isCovered === 'undefined') this.data.isCovered = false;
|
|
1333
|
+
if (typeof this.heaterCooldownDelay === 'undefined') this.data.heaterCooldownDelay = false;
|
|
1334
|
+
if (typeof this.data.startDelay === 'undefined') this.data.startDelay = false;
|
|
1335
|
+
if (typeof this.data.stopDelay === 'undefined') this.data.stopDelay = false;
|
|
1230
1336
|
}
|
|
1231
1337
|
public get id(): number { return this.data.id; }
|
|
1232
1338
|
public set id(val: number) { this.setDataVal('id', val); }
|
|
@@ -1265,6 +1371,19 @@ export class BodyTempState extends EqState {
|
|
|
1265
1371
|
public set coolSetpoint(val: number) { this.setDataVal('coolSetpoint', val); }
|
|
1266
1372
|
public get isOn(): boolean { return this.data.isOn; }
|
|
1267
1373
|
public set isOn(val: boolean) { this.setDataVal('isOn', val); }
|
|
1374
|
+
public get startDelay(): boolean { return this.data.startDelay; }
|
|
1375
|
+
public set startDelay(val: boolean) { this.setDataVal('startDelay', val); }
|
|
1376
|
+
public get stopDelay(): boolean { return this.data.stopDelay; }
|
|
1377
|
+
public set stopDelay(val: boolean) { this.setDataVal('stopDelay', val); }
|
|
1378
|
+
|
|
1379
|
+
public get isCovered(): boolean { return this.data.isCovered; }
|
|
1380
|
+
public set isCovered(val: boolean) { this.setDataVal('isCovered', val); }
|
|
1381
|
+
// RKS: Heater cooldown delays force the current valve and body configuration until the
|
|
1382
|
+
// heater cooldown expires. This occurs at the pool level but it is triggered by the heater attached
|
|
1383
|
+
// to the body. Unfortunately, I think we can only detect this condition in Nixie as there really isn't an
|
|
1384
|
+
// indicator with Pentair OCPs. This is triggered in NixieBoard and managed by the delayMgr.
|
|
1385
|
+
public get heaterCooldownDelay(): boolean { return this.data.heaterCooldownDelay; }
|
|
1386
|
+
public set heaterCooldownDelay(val: boolean) { this.setDataVal('heaterCooldownDelay', val); }
|
|
1268
1387
|
public emitData(name: string, data: any) { webApp.emitToClients('body', this.data); }
|
|
1269
1388
|
// RKS: This is a very interesting object because we have a varied object. Type safety rules should not apply
|
|
1270
1389
|
// here as the heater types are specific to the installed equipment. The reason is because it has no meaning without the body and the calculation of it should
|
|
@@ -1331,7 +1450,13 @@ export class HeaterStateCollection extends EqStateCollection<HeaterState> {
|
|
|
1331
1450
|
public createItem(data: any): HeaterState { return new HeaterState(data); }
|
|
1332
1451
|
public cleanupState() {
|
|
1333
1452
|
for (let i = this.data.length - 1; i >= 0; i--) {
|
|
1334
|
-
if (
|
|
1453
|
+
if (isNaN(this.data[i].id)) {
|
|
1454
|
+
logger.info(`Removed Invalid Heater ${this.data[i].id}-${this.data[i].name}`);
|
|
1455
|
+
this.data.splice(i, 1);
|
|
1456
|
+
}
|
|
1457
|
+
else {
|
|
1458
|
+
if (typeof sys.heaters.find(elem => elem.id === this.data[i].id) === 'undefined') this.removeItemById(this.data[i].id);
|
|
1459
|
+
}
|
|
1335
1460
|
}
|
|
1336
1461
|
let cfg = sys.heaters.toArray();
|
|
1337
1462
|
for (let i = 0; i < cfg.length; i++) {
|
|
@@ -1344,16 +1469,36 @@ export class HeaterStateCollection extends EqStateCollection<HeaterState> {
|
|
|
1344
1469
|
}
|
|
1345
1470
|
export class HeaterState extends EqState {
|
|
1346
1471
|
public dataName: string = 'heater';
|
|
1472
|
+
public initData() {
|
|
1473
|
+
if (typeof this.data.startupDelay === 'undefined') this.data.startupDelay = false;
|
|
1474
|
+
if (typeof this.data.shutdownDelay === 'undefined') this.data.shutdownDelay = false;
|
|
1475
|
+
}
|
|
1347
1476
|
public get id(): number { return this.data.id; }
|
|
1348
1477
|
public set id(val: number) { this.data.id = val; }
|
|
1349
1478
|
public get name(): string { return this.data.name; }
|
|
1350
1479
|
public set name(val: string) { this.setDataVal('name', val); }
|
|
1351
1480
|
public get isOn(): boolean { return this.data.isOn; }
|
|
1352
|
-
public set isOn(val: boolean) {
|
|
1481
|
+
public set isOn(val: boolean) {
|
|
1482
|
+
if (val !== this.data.isOn) {
|
|
1483
|
+
if (val) this.startTime = new Timestamp();
|
|
1484
|
+
else this.endTime = new Timestamp();
|
|
1485
|
+
}
|
|
1486
|
+
this.setDataVal('isOn', val);
|
|
1487
|
+
}
|
|
1488
|
+
public get startTime(): Timestamp {
|
|
1489
|
+
if (typeof this.data.startTime === 'undefined') return undefined;
|
|
1490
|
+
return new Timestamp(this.data.startTime);
|
|
1491
|
+
}
|
|
1492
|
+
public set startTime(val: Timestamp) { typeof val !== 'undefined' ? this.setDataVal('startTime', Timestamp.toISOLocal(val.toDate())) : this.setDataVal('startTime', undefined); }
|
|
1493
|
+
|
|
1494
|
+
public get endTime(): Timestamp {
|
|
1495
|
+
if (typeof this.data.endTime === 'undefined') return undefined;
|
|
1496
|
+
return new Timestamp(this.data.endTime);
|
|
1497
|
+
}
|
|
1498
|
+
public set endTime(val: Timestamp) { typeof val !== 'undefined' ? this.setDataVal('endTime', Timestamp.toISOLocal(val.toDate())) : this.setDataVal('endTime', undefined); }
|
|
1499
|
+
|
|
1353
1500
|
public get isCooling(): boolean { return this.data.isCooling; }
|
|
1354
1501
|
public set isCooling(val: boolean) { this.setDataVal('isCooling', val); }
|
|
1355
|
-
//public get isVirtual(): boolean { return this.data.isVirtual; }
|
|
1356
|
-
//public set isVirtual(val: boolean) { this.setDataVal('isVirtual', val); }
|
|
1357
1502
|
public get type(): number | any { return typeof this.data.type !== 'undefined' ? this.data.type.val : 0; }
|
|
1358
1503
|
public set type(val: number | any) {
|
|
1359
1504
|
if (this.type !== val) {
|
|
@@ -1368,6 +1513,13 @@ export class HeaterState extends EqState {
|
|
|
1368
1513
|
this.hasChanged = true;
|
|
1369
1514
|
}
|
|
1370
1515
|
}
|
|
1516
|
+
public get startupDelay(): boolean { return this.data.startupDelay; }
|
|
1517
|
+
public set startupDelay(val: boolean) { this.setDataVal('startupDelay', val); }
|
|
1518
|
+
public get shutdownDelay(): boolean { return this.data.shutdownDelay; }
|
|
1519
|
+
public set shutdownDelay(val: boolean) { this.setDataVal('shutdownDelay', val); }
|
|
1520
|
+
public get bodyId(): number { return this.data.bodyId || 0 }
|
|
1521
|
+
public set bodyId(val: number) { this.setDataVal('bodyId', val); }
|
|
1522
|
+
|
|
1371
1523
|
}
|
|
1372
1524
|
export class FeatureStateCollection extends EqStateCollection<FeatureState> {
|
|
1373
1525
|
public createItem(data: any): FeatureState { return new FeatureState(data); }
|
|
@@ -1375,7 +1527,10 @@ export class FeatureStateCollection extends EqStateCollection<FeatureState> {
|
|
|
1375
1527
|
public async toggleFeatureStateAsync(id: number) { return sys.board.features.toggleFeatureStateAsync(id); }
|
|
1376
1528
|
public cleanupState() {
|
|
1377
1529
|
for (let i = this.data.length - 1; i >= 0; i--) {
|
|
1378
|
-
if (
|
|
1530
|
+
if (isNaN(this.data[i].id)) this.data.splice(i, 1);
|
|
1531
|
+
else {
|
|
1532
|
+
if (typeof sys.features.find(elem => elem.id === this.data[i].id) === 'undefined') this.removeItemById(this.data[i].id);
|
|
1533
|
+
}
|
|
1379
1534
|
}
|
|
1380
1535
|
let cfg = sys.features.toArray();
|
|
1381
1536
|
for (let i = 0; i < cfg.length; i++) {
|
|
@@ -1391,6 +1546,9 @@ export class FeatureStateCollection extends EqStateCollection<FeatureState> {
|
|
|
1391
1546
|
|
|
1392
1547
|
export class FeatureState extends EqState implements ICircuitState {
|
|
1393
1548
|
public dataName: string = 'feature';
|
|
1549
|
+
public initData() {
|
|
1550
|
+
if (typeof this.data.freezeProtect === 'undefined') this.data.freezeProtect = false;
|
|
1551
|
+
}
|
|
1394
1552
|
public get id(): number { return this.data.id; }
|
|
1395
1553
|
public set id(val: number) { this.data.id = val; }
|
|
1396
1554
|
public get name(): string { return this.data.name; }
|
|
@@ -1413,6 +1571,12 @@ export class FeatureState extends EqState implements ICircuitState {
|
|
|
1413
1571
|
return new Timestamp(this.data.endTime);
|
|
1414
1572
|
}
|
|
1415
1573
|
public set endTime(val: Timestamp) { typeof val !== 'undefined' ? this.setDataVal('endTime', Timestamp.toISOLocal(val.toDate())) : this.setDataVal('endTime', undefined); }
|
|
1574
|
+
// This property will be set if the system has turn this feature on for freeze protection reasons. We have no way of knowing when Pentair does this but
|
|
1575
|
+
// need to know (so we can shut it off) if we have done this.
|
|
1576
|
+
public get freezeProtect(): boolean { return this.data.freezeProtect; }
|
|
1577
|
+
public set freezeProtect(val: boolean) { this.setDataVal('freezeProtect', val); }
|
|
1578
|
+
public get isActive(): boolean { return this.data.isActive; }
|
|
1579
|
+
public set isActive(val: boolean) { this.setDataVal('isActive', val); }
|
|
1416
1580
|
}
|
|
1417
1581
|
export class VirtualCircuitState extends EqState implements ICircuitState {
|
|
1418
1582
|
public dataName: string = 'virtualCircuit';
|
|
@@ -1436,6 +1600,8 @@ export class VirtualCircuitState extends EqState implements ICircuitState {
|
|
|
1436
1600
|
return new Timestamp(this.data.endTime);
|
|
1437
1601
|
}
|
|
1438
1602
|
public set endTime(val: Timestamp) { typeof val !== 'undefined' ? this.setDataVal('endTime', Timestamp.toISOLocal(val.toDate())) : this.setDataVal('endTime', undefined); }
|
|
1603
|
+
public get isActive(): boolean { return this.data.isActive; }
|
|
1604
|
+
public set isActive(val: boolean) { this.setDataVal('isActive', val); }
|
|
1439
1605
|
}
|
|
1440
1606
|
export class VirtualCircuitStateCollection extends EqStateCollection<VirtualCircuitState> {
|
|
1441
1607
|
public createItem(data: any): VirtualCircuitState { return new VirtualCircuitState(data); }
|
|
@@ -1460,7 +1626,10 @@ export class CircuitStateCollection extends EqStateCollection<CircuitState> {
|
|
|
1460
1626
|
}
|
|
1461
1627
|
public cleanupState() {
|
|
1462
1628
|
for (let i = this.data.length - 1; i >= 0; i--) {
|
|
1463
|
-
if (
|
|
1629
|
+
if (isNaN(this.data[i].id)) this.data.splice(i, 1);
|
|
1630
|
+
else {
|
|
1631
|
+
if (typeof sys.circuits.find(elem => elem.id === this.data[i].id) === 'undefined') this.removeItemById(this.data[i].id);
|
|
1632
|
+
}
|
|
1464
1633
|
}
|
|
1465
1634
|
let cfg = sys.circuits.toArray();
|
|
1466
1635
|
for (let i = 0; i < cfg.length; i++) {
|
|
@@ -1476,6 +1645,9 @@ export class CircuitStateCollection extends EqStateCollection<CircuitState> {
|
|
|
1476
1645
|
}
|
|
1477
1646
|
export class CircuitState extends EqState implements ICircuitState {
|
|
1478
1647
|
public dataName = 'circuit';
|
|
1648
|
+
public initData() {
|
|
1649
|
+
if (typeof this.data.freezeProtect === 'undefined') this.data.freezeProtect = false;
|
|
1650
|
+
}
|
|
1479
1651
|
public get id(): number { return this.data.id; }
|
|
1480
1652
|
public set id(val: number) { this.data.id = val; }
|
|
1481
1653
|
public get name(): string { return this.data.name; }
|
|
@@ -1485,7 +1657,11 @@ export class CircuitState extends EqState implements ICircuitState {
|
|
|
1485
1657
|
public get showInFeatures(): boolean { return this.data.showInFeatures; }
|
|
1486
1658
|
public set showInFeatures(val: boolean) { this.setDataVal('showInFeatures', val); }
|
|
1487
1659
|
public get isOn(): boolean { return this.data.isOn; }
|
|
1488
|
-
public set isOn(val: boolean) {
|
|
1660
|
+
public set isOn(val: boolean) {
|
|
1661
|
+
if (val && !this.data.isOn) this.startTime = new Timestamp();
|
|
1662
|
+
else if (!val) this.startTime = undefined;
|
|
1663
|
+
this.setDataVal('isOn', val);
|
|
1664
|
+
}
|
|
1489
1665
|
public get type() { return typeof (this.data.type) !== 'undefined' ? this.data.type.val : -1; }
|
|
1490
1666
|
public set type(val: number) {
|
|
1491
1667
|
if (this.type !== val) {
|
|
@@ -1493,10 +1669,12 @@ export class CircuitState extends EqState implements ICircuitState {
|
|
|
1493
1669
|
this.hasChanged = true;
|
|
1494
1670
|
}
|
|
1495
1671
|
}
|
|
1496
|
-
public get lightingTheme(): number { return typeof
|
|
1672
|
+
public get lightingTheme(): number { return typeof this.data.lightingTheme !== 'undefined' ? this.data.lightingTheme.val : 255; }
|
|
1497
1673
|
public set lightingTheme(val: number) {
|
|
1498
1674
|
if (this.lightingTheme !== val) {
|
|
1499
|
-
this
|
|
1675
|
+
// Force this to undefined when we are a circuit without a theme.
|
|
1676
|
+
if (typeof val === 'undefined') this.data.lightingTheme = undefined;
|
|
1677
|
+
else this.data.lightingTheme = sys.board.valueMaps.lightThemes.transform(val);
|
|
1500
1678
|
this.hasChanged = true;
|
|
1501
1679
|
}
|
|
1502
1680
|
}
|
|
@@ -1509,17 +1687,42 @@ export class CircuitState extends EqState implements ICircuitState {
|
|
|
1509
1687
|
this.hasChanged = true;
|
|
1510
1688
|
}
|
|
1511
1689
|
}
|
|
1690
|
+
public get startTime(): Timestamp {
|
|
1691
|
+
if (typeof this.data.startTime === 'undefined') return undefined;
|
|
1692
|
+
return new Timestamp(this.data.startTime);
|
|
1693
|
+
}
|
|
1694
|
+
public set startTime(val: Timestamp) { typeof val !== 'undefined' ? this.setDataVal('startTime', Timestamp.toISOLocal(val.toDate())) : this.setDataVal('startTime', undefined); }
|
|
1695
|
+
|
|
1512
1696
|
public get endTime(): Timestamp {
|
|
1513
1697
|
if (typeof this.data.endTime === 'undefined') return undefined;
|
|
1514
1698
|
return new Timestamp(this.data.endTime);
|
|
1515
1699
|
}
|
|
1516
1700
|
public set endTime(val: Timestamp) { typeof val !== 'undefined' ? this.setDataVal('endTime', Timestamp.toISOLocal(val.toDate())) : this.setDataVal('endTime', undefined); }
|
|
1701
|
+
// This property will be set if the system has turn this circuit on for freeze protection reasons. We have no way of knowing when Pentair does this but
|
|
1702
|
+
// need to know (so we can shut it off) if we have done this.
|
|
1703
|
+
public get freezeProtect(): boolean { return this.data.freezeProtect; }
|
|
1704
|
+
public set freezeProtect(val: boolean) { this.setDataVal('freezeProtect', val); }
|
|
1705
|
+
public get isActive(): boolean { return this.data.isActive; }
|
|
1706
|
+
public set isActive(val: boolean) { this.setDataVal('isActive', val); }
|
|
1707
|
+
// The properties below are for delays and lockouts. Manual or scheduled
|
|
1708
|
+
// actions cannot be performed when the flags below are set.
|
|
1709
|
+
public get startDelay(): boolean { return this.data.startDelay; }
|
|
1710
|
+
public set startDelay(val: boolean) { this.setDataVal('startDelay', val); }
|
|
1711
|
+
public get stopDelay(): boolean { return this.data.stopDelay; }
|
|
1712
|
+
public set stopDelay(val: boolean) { this.setDataVal('stopDelay', val); }
|
|
1713
|
+
public get lockoutOn(): boolean { return this.data.lockoutOn; }
|
|
1714
|
+
public set lockoutOn(val: boolean) { this.setDataVal('lockoutOn', val); }
|
|
1715
|
+
public get lockoutOff(): boolean { return this.data.lockoutOff; }
|
|
1716
|
+
public set lockoutOff(val: boolean) { this.setDataVal('lockoutOff', val); }
|
|
1517
1717
|
}
|
|
1518
1718
|
export class ValveStateCollection extends EqStateCollection<ValveState> {
|
|
1519
1719
|
public createItem(data: any): ValveState { return new ValveState(data); }
|
|
1520
1720
|
public cleanupState() {
|
|
1521
1721
|
for (let i = this.data.length - 1; i >= 0; i--) {
|
|
1522
|
-
if (
|
|
1722
|
+
if (isNaN(this.data[i].id)) this.data.splice(i, 1);
|
|
1723
|
+
else {
|
|
1724
|
+
if (typeof sys.valves.find(elem => elem.id === this.data[i].id) === 'undefined') this.removeItemById(this.data[i].id);
|
|
1725
|
+
}
|
|
1523
1726
|
}
|
|
1524
1727
|
let cfg = sys.valves.toArray();
|
|
1525
1728
|
for (let i = 0; i < cfg.length; i++) {
|
|
@@ -1558,7 +1761,7 @@ export class ValveState extends EqState {
|
|
|
1558
1761
|
if (valve.circuit !== 256) vstate.circuit = state.circuits.getInterfaceById(valve.circuit).get(true);
|
|
1559
1762
|
vstate.isIntake = utils.makeBool(valve.isIntake);
|
|
1560
1763
|
vstate.isReturn = utils.makeBool(valve.isReturn);
|
|
1561
|
-
vstate.isVirtual = utils.makeBool(valve.isVirtual);
|
|
1764
|
+
// vstate.isVirtual = utils.makeBool(valve.isVirtual);
|
|
1562
1765
|
vstate.isActive = utils.makeBool(valve.isActive);
|
|
1563
1766
|
vstate.pinId = valve.pinId;
|
|
1564
1767
|
return vstate;
|
|
@@ -1576,12 +1779,15 @@ export class CoverStateCollection extends EqStateCollection<CoverState> {
|
|
|
1576
1779
|
}
|
|
1577
1780
|
export class CoverState extends EqState {
|
|
1578
1781
|
public dataName: string = 'cover';
|
|
1782
|
+
public initData() {
|
|
1783
|
+
if (typeof this.data.isClosed === 'undefined') this.data.isClosed = false;
|
|
1784
|
+
}
|
|
1579
1785
|
public get id(): number { return this.data.id; }
|
|
1580
1786
|
public set id(val: number) { this.data.id = val; }
|
|
1581
1787
|
public get name(): string { return this.data.name; }
|
|
1582
1788
|
public set name(val: string) { this.setDataVal('name', val); }
|
|
1583
|
-
public get
|
|
1584
|
-
public set
|
|
1789
|
+
public get isClosed(): boolean { return this.data.isClosed; }
|
|
1790
|
+
public set isClosed(val: boolean) { this.setDataVal('isClosed', val); }
|
|
1585
1791
|
}
|
|
1586
1792
|
export class ChlorinatorStateCollection extends EqStateCollection<ChlorinatorState> {
|
|
1587
1793
|
public createItem(data: any): ChlorinatorState { return new ChlorinatorState(data); }
|
|
@@ -1589,7 +1795,10 @@ export class ChlorinatorStateCollection extends EqStateCollection<ChlorinatorSta
|
|
|
1589
1795
|
public lastDispatchSuperChlor: number = 0;
|
|
1590
1796
|
public cleanupState() {
|
|
1591
1797
|
for (let i = this.data.length - 1; i >= 0; i--) {
|
|
1592
|
-
if (
|
|
1798
|
+
if (isNaN(this.data[i].id)) this.data.splice(i, 1);
|
|
1799
|
+
else {
|
|
1800
|
+
if (typeof sys.chlorinators.find(elem => elem.id === this.data[i].id) === 'undefined') this.removeItemById(this.data[i].id);
|
|
1801
|
+
}
|
|
1593
1802
|
}
|
|
1594
1803
|
let cfg = sys.chlorinators.toArray();
|
|
1595
1804
|
for (let i = 0; i < cfg.length; i++) {
|
|
@@ -1642,16 +1851,6 @@ export class ChlorinatorState extends EqState {
|
|
|
1642
1851
|
this.hasChanged = true;
|
|
1643
1852
|
}
|
|
1644
1853
|
}
|
|
1645
|
-
//public get virtualControllerStatus(): number {
|
|
1646
|
-
// return typeof (this.data.virtualControllerStatus) !== 'undefined' ? this.data.virtualControllerStatus.val : -1;
|
|
1647
|
-
//}
|
|
1648
|
-
//public set virtualControllerStatus(val: number) {
|
|
1649
|
-
// if (this.virtualControllerStatus !== val) {
|
|
1650
|
-
// this.data.virtualControllerStatus = sys.board.valueMaps.virtualControllerStatus.transform(val);
|
|
1651
|
-
// this.hasChanged = true;
|
|
1652
|
-
|
|
1653
|
-
// }
|
|
1654
|
-
//}
|
|
1655
1854
|
public get type(): number { return typeof (this.data.type) !== 'undefined' ? this.data.type.val : -1; }
|
|
1656
1855
|
public set type(val: number) {
|
|
1657
1856
|
if (this.type !== val) {
|
|
@@ -1738,12 +1937,21 @@ export class ChlorinatorState extends EqState {
|
|
|
1738
1937
|
else
|
|
1739
1938
|
this.setDataVal('superChlor', false);
|
|
1740
1939
|
}
|
|
1940
|
+
public getExtended(): any {
|
|
1941
|
+
let schlor = this.get(true);
|
|
1942
|
+
let chlor = sys.chlorinators.getItemById(this.id, false);
|
|
1943
|
+
schlor.lockSetpoints = chlor.disabled || chlor.isDosing;
|
|
1944
|
+
return schlor;
|
|
1945
|
+
}
|
|
1741
1946
|
}
|
|
1742
1947
|
export class ChemControllerStateCollection extends EqStateCollection<ChemControllerState> {
|
|
1743
1948
|
public createItem(data: any): ChemControllerState { return new ChemControllerState(data); }
|
|
1744
1949
|
public cleanupState() {
|
|
1745
1950
|
for (let i = this.data.length - 1; i >= 0; i--) {
|
|
1746
|
-
if (
|
|
1951
|
+
if (isNaN(this.data[i].id)) this.data.splice(i, 1);
|
|
1952
|
+
else {
|
|
1953
|
+
if (typeof sys.chemControllers.find(elem => elem.id === this.data[i].id) === 'undefined') this.removeItemById(this.data[i].id);
|
|
1954
|
+
}
|
|
1747
1955
|
}
|
|
1748
1956
|
// Make sure we have at least the items that exist in the config.
|
|
1749
1957
|
let cfg = sys.chemControllers.toArray();
|
|
@@ -1783,7 +1991,7 @@ export class ChemControllerState extends EqState {
|
|
|
1783
1991
|
//var chemControllerState = {
|
|
1784
1992
|
// lastComm: 'number', // The unix time the chem controller sent its status.
|
|
1785
1993
|
// id: 'number', // Id of the chemController.
|
|
1786
|
-
// type: 'valueMap', // intellichem,
|
|
1994
|
+
// type: 'valueMap', // intellichem, rem.
|
|
1787
1995
|
// address: 'number', // Assigned address if IntelliChem.
|
|
1788
1996
|
// name: 'string', // Name assigned to the controller.
|
|
1789
1997
|
// status: 'valueMap', // ok, nocomms, setupError
|
|
@@ -2006,14 +2214,15 @@ export class ChemControllerState extends EqState {
|
|
|
2006
2214
|
export class ChemicalState extends ChildEqState {
|
|
2007
2215
|
public initData() {
|
|
2008
2216
|
if (typeof this.data.probe === 'undefined') this.data.probe = {};
|
|
2009
|
-
if (typeof this.data.tank
|
|
2217
|
+
if (typeof this.data.tank === 'undefined') this.data.tank = { capacity: 0, level: 0, units: 0 };
|
|
2218
|
+
if (typeof this.data.pump === 'undefined') this.data.pump = { isDosing: false };
|
|
2010
2219
|
if (typeof this.data.dosingTimeRemaining === 'undefined') this.data.dosingTimeRemaining = 0;
|
|
2011
2220
|
if (typeof this.data.delayTimeRemaining === 'undefined') this.data.delayTimeRemaining = 0;
|
|
2012
2221
|
if (typeof this.data.dosingVolumeRemaining === 'undefined') this.data.dosingVolumeRemaining = 0;
|
|
2013
2222
|
if (typeof this.data.doseVolume === 'undefined') this.data.doseVolume = 0;
|
|
2014
2223
|
if (typeof this.data.doseTime === 'undefined') this.data.doseTime = 0;
|
|
2015
2224
|
if (typeof this.data.lockout === 'undefined') this.data.lockout = false;
|
|
2016
|
-
if (typeof this.data.level
|
|
2225
|
+
if (typeof this.data.level === 'undefined') this.data.level = 0;
|
|
2017
2226
|
if (typeof this.data.mixTimeRemaining === 'undefined') this.data.mixTimeRemaining = 0;
|
|
2018
2227
|
if (typeof this.data.dailyLimitReached === 'undefined') this.data.dailyLimitReached = false;
|
|
2019
2228
|
if (typeof this.data.manualDosing === 'undefined') this.data.manualDosing = false;
|
|
@@ -2021,7 +2230,6 @@ export class ChemicalState extends ChildEqState {
|
|
|
2021
2230
|
if (typeof this.data.flowDelay === 'undefined') this.data.flowDelay = false;
|
|
2022
2231
|
if (typeof this.data.dosingStatus === 'undefined') this.dosingStatus = 2;
|
|
2023
2232
|
if (typeof this.data.enabled === 'undefined') this.data.enabled = true;
|
|
2024
|
-
if (typeof this.data.level === 'undefined') this.data.level = 0;
|
|
2025
2233
|
}
|
|
2026
2234
|
public getConfig(): Chemical { return; }
|
|
2027
2235
|
public calcDoseHistory(): number {
|
|
@@ -2185,7 +2393,7 @@ export class ChemicalState extends ChildEqState {
|
|
|
2185
2393
|
}
|
|
2186
2394
|
export class ChemicalPhState extends ChemicalState {
|
|
2187
2395
|
public initData() {
|
|
2188
|
-
if (typeof this.data.chemType === 'undefined') this.data.chemType === 'acid';
|
|
2396
|
+
// if (typeof this.data.chemType === 'undefined') this.data.chemType === 'acid'; // RSG 10-23-21 - Only a getter; don't need to set this.
|
|
2189
2397
|
super.initData();
|
|
2190
2398
|
}
|
|
2191
2399
|
public getConfig() {
|
|
@@ -2390,14 +2598,16 @@ export class ChemicalDoseState extends DataLoggerEntry {
|
|
|
2390
2598
|
public _isManual: boolean;
|
|
2391
2599
|
|
|
2392
2600
|
constructor(entry?: string | object) {
|
|
2393
|
-
super(
|
|
2601
|
+
super();
|
|
2602
|
+
if (typeof entry === 'object') entry = JSON.stringify(entry);
|
|
2603
|
+
if (typeof entry === 'string') this.parse(entry);
|
|
2394
2604
|
// Javascript is idiotic in that the initialization of variables
|
|
2395
2605
|
// do not happen before the assignment so some of the values can be undefined.
|
|
2396
2606
|
if (typeof this.volumeDosed === 'undefined' || !this.volumeDosed) this.volumeDosed = 0;
|
|
2397
2607
|
if (typeof this.volume === 'undefined' || !this.volume) this.volume = 0;
|
|
2398
2608
|
if (typeof this._isManual === 'undefined') this._isManual = this.method === 'manual';
|
|
2399
2609
|
if (typeof this.timeDosed === 'undefined' || !this.timeDosed) this.timeDosed = 0;
|
|
2400
|
-
if (typeof this._timeDosed === 'undefined') this.timeDosed * 1000;
|
|
2610
|
+
if (typeof this._timeDosed === 'undefined') this._timeDosed = this.timeDosed * 1000;
|
|
2401
2611
|
if (typeof this.time === 'undefined' || !this.time) this.time = 0;
|
|
2402
2612
|
}
|
|
2403
2613
|
public id: number;
|
|
@@ -2414,10 +2624,40 @@ export class ChemicalDoseState extends DataLoggerEntry {
|
|
|
2414
2624
|
public time: number;
|
|
2415
2625
|
public timeDosed: number;
|
|
2416
2626
|
|
|
2417
|
-
public createInstance(entry?: string): ChemicalDoseState { return new ChemicalDoseState(entry); }
|
|
2627
|
+
public static createInstance(entry?: string): ChemicalDoseState { return new ChemicalDoseState(entry); }
|
|
2418
2628
|
public save() { DataLogger.writeEnd(`chemDosage_${this.chem}.log`, this); }
|
|
2419
2629
|
public get timeRemaining(): number { return Math.floor(Math.max(0, this.time - (this._timeDosed / 1000))); }
|
|
2420
2630
|
public get volumeRemaining(): number { return Math.max(0, this.volume - this.volumeDosed); }
|
|
2631
|
+
public parse(entry: string) {
|
|
2632
|
+
// let obj = typeof entry !== 'undefined' ? JSON.parse(entry, this.dateParser) : {};
|
|
2633
|
+
let obj = typeof entry !== 'undefined' ? JSON.parse(entry) : {};
|
|
2634
|
+
for (const prop in obj) {obj[prop] = this.dateParser(prop, obj[prop])}
|
|
2635
|
+
if (typeof obj.setpoint !== 'undefined') this.setpoint = obj.setpoint;
|
|
2636
|
+
if (typeof obj.method !== 'undefined') this.method = obj.method;
|
|
2637
|
+
if (typeof obj.start !== 'undefined') this.start = obj.start;
|
|
2638
|
+
if (typeof obj.end !== 'undefined') this.end = obj.end;
|
|
2639
|
+
if (typeof obj.chem !== 'undefined') this.chem = obj.chem;
|
|
2640
|
+
if (typeof obj.demand !== 'undefined') this.demand = obj.demand;
|
|
2641
|
+
if (typeof obj.id !== 'undefined') this.id = obj.id;
|
|
2642
|
+
if (typeof obj.level !== 'undefined') this.level = obj.level;
|
|
2643
|
+
if (typeof obj.volume !== 'undefined') this.volume = obj.volume;
|
|
2644
|
+
if (typeof obj.status !== 'undefined') this.status = obj.status;
|
|
2645
|
+
if (typeof obj.volumeDosed !== 'undefined') this.volumeDosed = obj.volumeDosed;
|
|
2646
|
+
if (typeof obj.time !== 'undefined') this.time = obj.time;
|
|
2647
|
+
if (typeof obj.timeDosed !== 'undefined') this.timeDosed = obj.timeDosed;
|
|
2648
|
+
// this.setProperties(obj);
|
|
2649
|
+
}
|
|
2650
|
+
protected setProperties(data: any) {
|
|
2651
|
+
let op = Object.getOwnPropertyNames(Object.getPrototypeOf(this));
|
|
2652
|
+
for (let i in op) {
|
|
2653
|
+
let prop = op[i];
|
|
2654
|
+
if (typeof this[prop] === 'function') continue;
|
|
2655
|
+
if (typeof data[prop] !== 'undefined') {
|
|
2656
|
+
if (typeof this[prop] === null || typeof data[prop] === null) continue;
|
|
2657
|
+
this[prop] = data[prop];
|
|
2658
|
+
}
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2421
2661
|
}
|
|
2422
2662
|
|
|
2423
2663
|
export class ChemicalDemandState extends ChildEqState {
|
|
@@ -2665,15 +2905,35 @@ export class FilterState extends EqState {
|
|
|
2665
2905
|
this.hasChanged = true;
|
|
2666
2906
|
}
|
|
2667
2907
|
}
|
|
2668
|
-
public get
|
|
2669
|
-
public set
|
|
2670
|
-
|
|
2671
|
-
|
|
2908
|
+
public get pressureUnits(): number { return this.data.pressureUnits; }
|
|
2909
|
+
public set pressureUnits(val: number) {
|
|
2910
|
+
if (this.pressureUnits !== val) {
|
|
2911
|
+
this.setDataVal('pressureUnits', sys.board.valueMaps.pressureUnits.transform(val));
|
|
2912
|
+
}
|
|
2913
|
+
}
|
|
2914
|
+
public get pressure(): number { return this.data.pressure; }
|
|
2915
|
+
public set pressure(val: number) { this.setDataVal('pressure', val); }
|
|
2916
|
+
public get refPressure(): number { return this.data.refPressure; }
|
|
2917
|
+
public set refPressure(val: number) {
|
|
2918
|
+
if (val !== this.refPressure) {
|
|
2919
|
+
this.setDataVal('refPressure', val);
|
|
2920
|
+
this.calcCleanPercentage();
|
|
2921
|
+
}
|
|
2922
|
+
else { this.setDataVal('refPressure', val); }
|
|
2923
|
+
}
|
|
2924
|
+
public get cleanPercentage(): number { return this.data.cleanPercentage; }
|
|
2925
|
+
public set cleanPercentage(val: number) { this.setDataVal('cleanPercentage', val); }
|
|
2672
2926
|
public get lastCleanDate(): Timestamp { return this.data.lastCleanDate; }
|
|
2673
2927
|
public set lastCleanDate(val: Timestamp) { this.setDataVal('lastCleanDate', val); }
|
|
2674
|
-
public get needsCleaning(): number { return this.data.needsCleaning; }
|
|
2675
|
-
public set needsCleaning(val: number) { this.setDataVal('needsCleaning', val); }
|
|
2676
2928
|
public get isOn(): boolean { return utils.makeBool(this.data.isOn); }
|
|
2677
2929
|
public set isOn(val: boolean) { this.setDataVal('isOn', val); }
|
|
2930
|
+
public calcCleanPercentage() {
|
|
2931
|
+
if (typeof this.refPressure === 'undefined') return;
|
|
2932
|
+
let filter = sys.filters.find(elem => elem.id == this.id);
|
|
2933
|
+
// 8 to 10
|
|
2934
|
+
let cp = filter.cleanPressure || 0;
|
|
2935
|
+
let dp = filter.dirtyPressure || 1;
|
|
2936
|
+
this.cleanPercentage = (cp - dp != 0) ? Math.round(Math.max(0, (1 - (this.refPressure - cp) / (dp - cp)) * 100) * 100)/100 : 0;
|
|
2937
|
+
}
|
|
2678
2938
|
}
|
|
2679
2939
|
export var state = new State();
|