nodejs-poolcontroller 8.0.1 → 8.0.4
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/workflows/docker-publish-njsPC-linux.yml +50 -0
- package/Dockerfile +5 -3
- package/README.md +4 -1
- package/config/Config.ts +1 -1
- package/controller/Constants.ts +164 -67
- package/controller/Equipment.ts +78 -18
- package/controller/Lockouts.ts +15 -0
- package/controller/State.ts +281 -7
- package/controller/boards/EasyTouchBoard.ts +225 -101
- package/controller/boards/IntelliCenterBoard.ts +84 -23
- package/controller/boards/IntelliTouchBoard.ts +2 -4
- package/controller/boards/NixieBoard.ts +84 -27
- package/controller/boards/SunTouchBoard.ts +8 -2
- package/controller/boards/SystemBoard.ts +3262 -3242
- package/controller/comms/ScreenLogic.ts +47 -44
- package/controller/comms/messages/Messages.ts +4 -4
- package/controller/comms/messages/config/ChlorinatorMessage.ts +10 -3
- package/controller/comms/messages/config/ExternalMessage.ts +4 -1
- package/controller/comms/messages/config/PumpMessage.ts +8 -7
- package/controller/comms/messages/config/RemoteMessage.ts +48 -43
- package/controller/comms/messages/status/ChlorinatorStateMessage.ts +8 -2
- package/controller/comms/messages/status/EquipmentStateMessage.ts +9 -4
- package/controller/comms/messages/status/PumpStateMessage.ts +1 -1
- package/controller/nixie/NixieEquipment.ts +1 -1
- package/controller/nixie/bodies/Body.ts +1 -1
- package/controller/nixie/chemistry/ChemController.ts +37 -28
- package/controller/nixie/circuits/Circuit.ts +48 -7
- package/controller/nixie/heaters/Heater.ts +24 -5
- package/controller/nixie/pumps/Pump.ts +159 -97
- package/controller/nixie/schedules/Schedule.ts +207 -126
- package/defaultConfig.json +3 -3
- package/logger/DataLogger.ts +7 -7
- package/package.json +2 -2
- package/sendSocket.js +32 -0
- package/web/Server.ts +17 -11
- package/web/bindings/homeassistant.json +2 -2
- package/web/interfaces/mqttInterface.ts +18 -18
- package/web/services/config/Config.ts +34 -1
- package/web/services/state/State.ts +10 -3
- package/web/services/state/StateSocket.ts +7 -3
- package/web/services/utilities/Utilities.ts +3 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { clearTimeout, setTimeout } from 'timers';
|
|
2
2
|
import { conn } from '../../../controller/comms/Comms';
|
|
3
3
|
import { Outbound, Protocol, Response } from '../../../controller/comms/messages/Messages';
|
|
4
|
-
import { IChemical, IChemController, ChemController, ChemControllerCollection, ChemFlowSensor, Chemical, ChemicalChlor, ChemicalORP, ChemicalORPProbe, ChemicalPh, ChemicalPhProbe, ChemicalProbe, ChemicalPump, ChemicalTank, sys } from "../../../controller/Equipment";
|
|
4
|
+
import { IChemical, IChemController, Chlorinator, ChemController, ChemControllerCollection, ChemFlowSensor, Chemical, ChemicalChlor, ChemicalORP, ChemicalORPProbe, ChemicalPh, ChemicalPhProbe, ChemicalProbe, ChemicalPump, ChemicalTank, sys } from "../../../controller/Equipment";
|
|
5
5
|
import { logger } from '../../../logger/Logger';
|
|
6
6
|
import { InterfaceServerResponse, webApp } from "../../../web/Server";
|
|
7
7
|
import { Timestamp, utils } from '../../Constants';
|
|
@@ -21,6 +21,8 @@ export interface INixieChemical extends NixieEquipment {
|
|
|
21
21
|
chemController: INixieChemController;
|
|
22
22
|
chemical: IChemical;
|
|
23
23
|
}
|
|
24
|
+
|
|
25
|
+
//#region
|
|
24
26
|
export class NixieChemControllerCollection extends NixieEquipmentCollection<NixieChemControllerBase> {
|
|
25
27
|
public async manualDoseAsync(id: number, data: any) {
|
|
26
28
|
try {
|
|
@@ -208,6 +210,7 @@ export class NixieChemControllerBase extends NixieEquipment implements INixieChe
|
|
|
208
210
|
else if (!isOn) this.bodyOnTime = undefined;
|
|
209
211
|
return isOn;
|
|
210
212
|
}
|
|
213
|
+
public get activeBodyId(): number { return sys.board.bodies.getActiveBody(this.chem.body); }
|
|
211
214
|
public async setControllerAsync(data: any) { } // This is meant to be abstract override this value
|
|
212
215
|
public processAlarms(schem: any) { }
|
|
213
216
|
|
|
@@ -692,6 +695,7 @@ export class NixieChemController extends NixieChemControllerBase {
|
|
|
692
695
|
// to indicate this to the user.
|
|
693
696
|
schem.alarms.flow = schem.isBodyOn && !schem.flowDetected ? 1 : 0;
|
|
694
697
|
}
|
|
698
|
+
schem.activeBodyId = this.activeBodyId;
|
|
695
699
|
schem.ph.dailyVolumeDosed = schem.ph.calcDoseHistory();
|
|
696
700
|
schem.orp.dailyVolumeDosed = schem.orp.calcDoseHistory();
|
|
697
701
|
let chem = this.chem;
|
|
@@ -699,7 +703,6 @@ export class NixieChemController extends NixieChemControllerBase {
|
|
|
699
703
|
schem.ph.enabled = this.chem.ph.enabled;
|
|
700
704
|
let probeType = chem.orp.probe.type;
|
|
701
705
|
if (this.chem.orp.enabled) {
|
|
702
|
-
|
|
703
706
|
let useChlorinator = chem.orp.useChlorinator;
|
|
704
707
|
let pumpType = chem.orp.pump.type;
|
|
705
708
|
let currLevelPercent = schem.orp.tank.level / schem.orp.tank.capacity * 100;
|
|
@@ -710,7 +713,7 @@ export class NixieChemController extends NixieChemControllerBase {
|
|
|
710
713
|
else schem.alarms.orpTank = 0;
|
|
711
714
|
// Alright we need to determine whether we need to adjust the volume any so that we get at least 3 seconds out of the pump.
|
|
712
715
|
let padj = this.chem.orp.pump.type > 0 && !this.chem.orp.useChlorinator ? (this.chem.orp.pump.ratedFlow / 60) * 3 : 0;
|
|
713
|
-
if (this.chem.orp.maxDailyVolume <= schem.orp.dailyVolumeDosed && !this.chem.orp.useChlorinator) {
|
|
716
|
+
if (this.chem.orp.dosingMethod !== 0 && this.chem.orp.maxDailyVolume <= schem.orp.dailyVolumeDosed && !this.chem.orp.useChlorinator) {
|
|
714
717
|
schem.warnings.orpDailyLimitReached = 4;
|
|
715
718
|
schem.orp.dailyLimitReached = true;
|
|
716
719
|
}
|
|
@@ -722,7 +725,15 @@ export class NixieChemController extends NixieChemControllerBase {
|
|
|
722
725
|
if (probeType !== 0 && chem.orp.tolerance.enabled)
|
|
723
726
|
schem.alarms.orp = schem.orp.level < chem.orp.tolerance.low ? 16 : schem.orp.level > chem.orp.tolerance.high ? 8 : 0;
|
|
724
727
|
else schem.alarms.orp = 0;
|
|
725
|
-
|
|
728
|
+
let chlorErr = 0;
|
|
729
|
+
if (useChlorinator && schem.isBodyOn) {
|
|
730
|
+
let chlors = sys.chlorinators.getByBody(schem.activeBodyId);
|
|
731
|
+
let chlor = chlors.getItemByIndex(0);
|
|
732
|
+
let schlor = state.chlorinators.getItemById(chlor.id);
|
|
733
|
+
this.orp.chlor.chlorId = chlor.id;
|
|
734
|
+
if (schlor.status & 0xF0) chlorErr = 16;
|
|
735
|
+
}
|
|
736
|
+
schem.warnings.chlorinatorCommError = chlorErr;
|
|
726
737
|
schem.warnings.pHLockout = useChlorinator === false && probeType !== 0 && pumpType !== 0 && schem.ph.level >= chem.orp.phLockout ? 1 : 0;
|
|
727
738
|
}
|
|
728
739
|
else {
|
|
@@ -756,7 +767,7 @@ export class NixieChemController extends NixieChemControllerBase {
|
|
|
756
767
|
schem.warnings.pHDailyLimitReached = 0;
|
|
757
768
|
// Alright we need to determine whether we need to adjust the volume any so that we get at least 3 seconds out of the pump.
|
|
758
769
|
let padj = this.chem.ph.pump.type > 0 ? (this.chem.ph.pump.ratedFlow / 60) * 3 : 0;
|
|
759
|
-
if (this.chem.ph.maxDailyVolume <= schem.ph.dailyVolumeDosed + padj) {
|
|
770
|
+
if (this.chem.ph.dosingMethod !== 0 && this.chem.ph.maxDailyVolume <= schem.ph.dailyVolumeDosed + padj) {
|
|
760
771
|
schem.warnings.pHDailyLimitReached = 2;
|
|
761
772
|
schem.ph.dailyLimitReached = true;
|
|
762
773
|
}
|
|
@@ -773,7 +784,6 @@ export class NixieChemController extends NixieChemControllerBase {
|
|
|
773
784
|
else schem.alarms.pH = 0;
|
|
774
785
|
schem.ph.freezeProtect = (state.freeze && chem.ph.disableOnFreeze && schem.isBodyOn);
|
|
775
786
|
}
|
|
776
|
-
|
|
777
787
|
else {
|
|
778
788
|
schem.alarms.pHTank = 0;
|
|
779
789
|
schem.warnings.pHDailyLimitReached = 0;
|
|
@@ -1057,7 +1067,7 @@ class NixieChemical extends NixieChildEquipment implements INixieChemical {
|
|
|
1057
1067
|
schem.chlor.isDosing = schem.pump.isDosing = false;
|
|
1058
1068
|
if (!this.chemical.flowOnlyMixing || (schem.chemController.isBodyOn && this.chemController.flowDetected && !schem.freezeProtect)) {
|
|
1059
1069
|
if (this.chemType === 'orp' && typeof this.chemController.orp.orp.useChlorinator !== 'undefined' && this.chemController.orp.orp.useChlorinator && this.chemController.orp.orp.chlorDosingMethod > 0) {
|
|
1060
|
-
if (state.chlorinators.getItemById(
|
|
1070
|
+
if (state.chlorinators.getItemById(this.chemController.orp.chlor.chlorId).currentOutput !== 0) {
|
|
1061
1071
|
logger.debug(`Chem mixing ORP (chlorinator) paused waiting for chlor current output to be 0%. Mix time remaining: ${utils.formatDuration(schem.mixTimeRemaining)} `);
|
|
1062
1072
|
return;
|
|
1063
1073
|
}
|
|
@@ -1130,10 +1140,10 @@ export class NixieChemTank extends NixieChildEquipment {
|
|
|
1130
1140
|
try {
|
|
1131
1141
|
if (typeof data !== 'undefined') {
|
|
1132
1142
|
stank.level = typeof data.level !== 'undefined' ? parseFloat(data.level) : stank.level;
|
|
1133
|
-
stank.capacity = this.tank.capacity = typeof data.capacity !== 'undefined' ? parseFloat(data.capacity) :
|
|
1143
|
+
stank.capacity = this.tank.capacity = typeof data.capacity !== 'undefined' ? parseFloat(data.capacity) : this.tank.capacity;
|
|
1134
1144
|
stank.units = this.tank.units = typeof data.units !== 'undefined' ? sys.board.valueMaps.volumeUnits.encode(data.units) : this.tank.units;
|
|
1135
|
-
stank.alarmEmptyEnabled = this.tank.alarmEmptyEnabled = typeof data.alarmEmptyEnabled !== 'undefined' ? data.alarmEmptyEnabled :
|
|
1136
|
-
stank.alarmEmptyLevel = this.tank.alarmEmptyLevel = typeof data.alarmEmptyLevel !== 'undefined' ? data.alarmEmptyLevel :
|
|
1145
|
+
stank.alarmEmptyEnabled = this.tank.alarmEmptyEnabled = typeof data.alarmEmptyEnabled !== 'undefined' ? data.alarmEmptyEnabled : this.tank.alarmEmptyEnabled;
|
|
1146
|
+
stank.alarmEmptyLevel = this.tank.alarmEmptyLevel = typeof data.alarmEmptyLevel !== 'undefined' ? data.alarmEmptyLevel : this.tank.alarmEmptyLevel;
|
|
1137
1147
|
}
|
|
1138
1148
|
}
|
|
1139
1149
|
catch (err) { logger.error(`setTankAsync: ${err.message}`); return Promise.reject(err); }
|
|
@@ -1370,8 +1380,7 @@ export class NixieChemPump extends NixieChildEquipment {
|
|
|
1370
1380
|
await self.dose(schem);
|
|
1371
1381
|
}
|
|
1372
1382
|
catch (err) {
|
|
1373
|
-
logger.error(`self.dose error in finally
|
|
1374
|
-
logger.error(err);
|
|
1383
|
+
logger.error(`self.dose error in finally: ${err.message}`);
|
|
1375
1384
|
//return Promise.reject(err); // this isn't a promise we should be returning
|
|
1376
1385
|
}
|
|
1377
1386
|
}, 1000);
|
|
@@ -1383,8 +1392,7 @@ export class NixieChemPump extends NixieChildEquipment {
|
|
|
1383
1392
|
await this.chemical.cancelDosing(schem, 'completed');
|
|
1384
1393
|
}
|
|
1385
1394
|
catch (err) {
|
|
1386
|
-
logger.error(`this.chemical.cancelDosing error in finally
|
|
1387
|
-
logger.error(err);
|
|
1395
|
+
logger.error(`this.chemical.cancelDosing error in finally: ${err.message}`);
|
|
1388
1396
|
}
|
|
1389
1397
|
schem.pump.isDosing = this.isOn = false;
|
|
1390
1398
|
schem.manualDosing = false;
|
|
@@ -1416,6 +1424,7 @@ export class NixieChemPump extends NixieChildEquipment {
|
|
|
1416
1424
|
export class NixieChemChlor extends NixieChildEquipment {
|
|
1417
1425
|
public chlor: ChemicalChlor;
|
|
1418
1426
|
public isOn: boolean;
|
|
1427
|
+
public chlorId = 0;
|
|
1419
1428
|
public _lastOnStatus: number;
|
|
1420
1429
|
protected _dosingTimer: NodeJS.Timeout;
|
|
1421
1430
|
private _isStopping = false;
|
|
@@ -1427,7 +1436,7 @@ export class NixieChemChlor extends NixieChildEquipment {
|
|
|
1427
1436
|
if (typeof data.chlorDosingMethod !== 'undefined' && data.chlorDosingMethod === 0) {
|
|
1428
1437
|
if (schlor.chemical.dosingStatus === 0) { await this.chemical.cancelDosing(schlor.chemController.orp, 'dosing method changed'); }
|
|
1429
1438
|
if (schlor.chemical.dosingStatus === 1) { await this.chemical.cancelMixing(schlor.chemController.orp); }
|
|
1430
|
-
let chlor = sys.chlorinators.getItemById(
|
|
1439
|
+
let chlor = sys.chlorinators.getItemById(this.chlorId);
|
|
1431
1440
|
chlor.disabled = false;
|
|
1432
1441
|
chlor.isDosing = false;
|
|
1433
1442
|
}
|
|
@@ -1479,7 +1488,7 @@ export class NixieChemChlor extends NixieChildEquipment {
|
|
|
1479
1488
|
let isBodyOn = schem.chemController.flowDetected;
|
|
1480
1489
|
await this.chemical.initDose(schem);
|
|
1481
1490
|
let chemController = schem.getParent()
|
|
1482
|
-
let schlor = state.chlorinators.getItemById(
|
|
1491
|
+
let schlor = state.chlorinators.getItemById(this.chlorId);
|
|
1483
1492
|
if (!isBodyOn) {
|
|
1484
1493
|
// Make sure the chlor is off.
|
|
1485
1494
|
logger.info(`Chem chlor flow not detected. Body is not running.`);
|
|
@@ -1538,7 +1547,7 @@ export class NixieChemChlor extends NixieChildEquipment {
|
|
|
1538
1547
|
this._dosingTimer = setTimeout(async () => {
|
|
1539
1548
|
try { await self.dose(schem); }
|
|
1540
1549
|
catch (err) {
|
|
1541
|
-
logger.error(err);
|
|
1550
|
+
logger.error(`Chem dosing error: ${err.message}`);
|
|
1542
1551
|
// return Promise.reject(err); // should not be returning a promise in a finally
|
|
1543
1552
|
}
|
|
1544
1553
|
}, 1000);
|
|
@@ -1556,8 +1565,8 @@ export class NixieChemChlor extends NixieChildEquipment {
|
|
|
1556
1565
|
public async turnOff(schem: IChemicalState): Promise<ChlorinatorState> {
|
|
1557
1566
|
try {
|
|
1558
1567
|
//logger.info(`Turning off the chlorinator`);
|
|
1559
|
-
let chlor = sys.chlorinators.getItemById(
|
|
1560
|
-
let schlor = state.chlorinators.getItemById(
|
|
1568
|
+
let chlor = sys.chlorinators.getItemById(this.chlorId);
|
|
1569
|
+
let schlor = state.chlorinators.getItemById(chlor.id);
|
|
1561
1570
|
if (schlor.currentOutput === 0 && schlor.targetOutput === 0 && !schlor.superChlor && chlor.disabled && !chlor.isDosing) {
|
|
1562
1571
|
this.isOn = schem.chlor.isDosing = false;
|
|
1563
1572
|
return schlor;
|
|
@@ -1574,8 +1583,8 @@ export class NixieChemChlor extends NixieChildEquipment {
|
|
|
1574
1583
|
}
|
|
1575
1584
|
public async turnOn(schem: ChemicalState, latchTimeout?: number): Promise<ChlorinatorState> {
|
|
1576
1585
|
try {
|
|
1577
|
-
let chlor = sys.chlorinators.getItemById(
|
|
1578
|
-
let schlor = state.chlorinators.getItemById(
|
|
1586
|
+
let chlor = sys.chlorinators.getItemById(this.chlorId);
|
|
1587
|
+
let schlor = state.chlorinators.getItemById(chlor.id);
|
|
1579
1588
|
if (schlor.currentOutput === 100 && schlor.targetOutput === 100 && !schlor.superChlor && !chlor.disabled && chlor.isDosing) {
|
|
1580
1589
|
this.isOn = schem.chlor.isDosing = true;
|
|
1581
1590
|
return schlor;
|
|
@@ -1818,7 +1827,7 @@ export class NixieChemicalPh extends NixieChemical {
|
|
|
1818
1827
|
}
|
|
1819
1828
|
}
|
|
1820
1829
|
}
|
|
1821
|
-
catch (err) { logger.error(err); return Promise.reject(err); }
|
|
1830
|
+
catch (err) { logger.error(`Error checking for dosing: ${err.message}`); return Promise.reject(err); }
|
|
1822
1831
|
finally {
|
|
1823
1832
|
logger.debug(`End check ${sph.chemType} dosing status = ${sys.board.valueMaps.chemControllerDosingStatus.getName(sph.dosingStatus)}`);
|
|
1824
1833
|
}
|
|
@@ -1870,7 +1879,7 @@ export class NixieChemicalPh extends NixieChemical {
|
|
|
1870
1879
|
logger.verbose(`Chem acid manual calibration dose activate pump`);
|
|
1871
1880
|
await this.pump.dose(sph);
|
|
1872
1881
|
}
|
|
1873
|
-
catch (err) { logger.error(`calibrateDoseAsync: ${err.message}`);
|
|
1882
|
+
catch (err) { logger.error(`calibrateDoseAsync: ${err.message}`); return Promise.reject(err); }
|
|
1874
1883
|
}
|
|
1875
1884
|
public async manualDoseVolumeAsync(sph: ChemicalPhState, volume: number) {
|
|
1876
1885
|
try {
|
|
@@ -1903,7 +1912,7 @@ export class NixieChemicalPh extends NixieChemical {
|
|
|
1903
1912
|
await this.pump.dose(sph);
|
|
1904
1913
|
}
|
|
1905
1914
|
}
|
|
1906
|
-
catch (err) { logger.error(`manualDoseVolumeAsync: ${err.message}`);
|
|
1915
|
+
catch (err) { logger.error(`manualDoseVolumeAsync: ${err.message}`); return Promise.reject(err); }
|
|
1907
1916
|
}
|
|
1908
1917
|
public async initDose(sph: ChemicalPhState) {
|
|
1909
1918
|
try {
|
|
@@ -2024,7 +2033,7 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
2024
2033
|
await this.pump.dose(sorp);
|
|
2025
2034
|
}
|
|
2026
2035
|
}
|
|
2027
|
-
catch (err) { logger.error(`manualDoseVolumeAsync ORP: ${err.message}`);
|
|
2036
|
+
catch (err) { logger.error(`manualDoseVolumeAsync ORP: ${err.message}`); return Promise.reject(err); }
|
|
2028
2037
|
}
|
|
2029
2038
|
public async calibrateDoseAsync(sorp: ChemicalORPState, time: number) {
|
|
2030
2039
|
try {
|
|
@@ -2055,7 +2064,7 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
2055
2064
|
logger.verbose(`Chem acid manual dose activate pump ${this.pump.pump.ratedFlow}mL/min`);
|
|
2056
2065
|
await this.pump.dose(sorp);
|
|
2057
2066
|
}
|
|
2058
|
-
catch (err) { logger.error(`calibrateDoseAsync: ${err.message}`);
|
|
2067
|
+
catch (err) { logger.error(`calibrateDoseAsync: ${err.message}`); return Promise.reject(err); }
|
|
2059
2068
|
}
|
|
2060
2069
|
|
|
2061
2070
|
public async cancelDosing(sorp: ChemicalORPState, reason: string): Promise<void> {
|
|
@@ -2267,8 +2276,8 @@ export class NixieChemicalORP extends NixieChemical {
|
|
|
2267
2276
|
}
|
|
2268
2277
|
|
|
2269
2278
|
|
|
2270
|
-
let chlor = sys.chlorinators.getItemById(
|
|
2271
|
-
let schlor = state.chlorinators.getItemById(
|
|
2279
|
+
let chlor = sys.chlorinators.getItemById(this.chlor.chlorId); // Still haven't seen any systems with 2+ chlors
|
|
2280
|
+
let schlor = state.chlorinators.getItemById(chlor.id);
|
|
2272
2281
|
// If someone or something is superchloring the pool, let it be
|
|
2273
2282
|
if (schlor.superChlor) return;
|
|
2274
2283
|
// Let's have some fun trying to figure out a dynamic approach to chlor management
|
|
@@ -140,6 +140,9 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
140
140
|
let cstate = state.circuits.getItemById(circuit.id);
|
|
141
141
|
cstate.startDelay = false;
|
|
142
142
|
cstate.stopDelay = false;
|
|
143
|
+
cstate.name = circuit.name;
|
|
144
|
+
cstate.type = circuit.type;
|
|
145
|
+
cstate.showInFeatures = circuit.showInFeatures;
|
|
143
146
|
}
|
|
144
147
|
public async setServiceModeAsync() {
|
|
145
148
|
let cstate = state.circuits.getItemById(this.circuit.id);
|
|
@@ -155,20 +158,55 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
155
158
|
}
|
|
156
159
|
protected async setIntelliBriteThemeAsync(cstate: CircuitState, theme: any): Promise<InterfaceServerResponse> {
|
|
157
160
|
let arr = [];
|
|
158
|
-
if (cstate.isOn) arr.push({ isOn: false, timeout: 1000 });
|
|
159
161
|
let count = typeof theme !== 'undefined' && theme.sequence ? theme.sequence : 0;
|
|
160
|
-
|
|
162
|
+
|
|
163
|
+
// Removing this. No need to turn the light off first. We actually need it on to start the sequence for theme setting to work correctly when the light is starting from the off state.
|
|
164
|
+
// if (cstate.isOn) arr.push({ isOn: false, timeout: 1000 });
|
|
165
|
+
|
|
166
|
+
// Start the sequence of off/on after the light is on.
|
|
167
|
+
arr.push({ isOn: true, timeout: 100 });
|
|
161
168
|
for (let i = 0; i < count; i++) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
169
|
+
arr.push({ isOn: false, timeout: 100 });
|
|
170
|
+
arr.push({ isOn: true, timeout: 100 });
|
|
171
|
+
}
|
|
172
|
+
// Ensure light stays on long enough for the theme to stick (required for light group theme setting to function correctly).
|
|
173
|
+
// 2s was too short.
|
|
174
|
+
arr.push({ isOn: true, timeout: 3000 });
|
|
175
|
+
|
|
176
|
+
logger.debug(arr);
|
|
177
|
+
let res = await NixieEquipment.putDeviceService(this.circuit.connectionId, `/state/device/${this.circuit.deviceBinding}`, arr, 60000);
|
|
178
|
+
// Even though we ended with on we need to make sure that the relay stays on now that we are done.
|
|
179
|
+
if (!res.error) {
|
|
180
|
+
this._sequencing = false;
|
|
181
|
+
await this.setCircuitStateAsync(cstate, true, false);
|
|
182
|
+
}
|
|
183
|
+
return res;
|
|
184
|
+
}
|
|
185
|
+
protected async setWaterColorsThemeAsync(cstate: CircuitState, theme: any): Promise<InterfaceServerResponse> {
|
|
186
|
+
let ptheme = sys.board.valueMaps.lightThemes.findItem(cstate.lightingTheme) || { val: 0, sequence: 0 };
|
|
187
|
+
// First check to see if we are on. If we are not then we need to emit our status as if we are initializing and busy.
|
|
188
|
+
let arr = [];
|
|
189
|
+
if (ptheme.val === 0) {
|
|
190
|
+
// We don't know our previous theme so we are going to sync the lights to get a starting point.
|
|
191
|
+
arr.push({ isOn: true, timeout: 1000 }); // Turn on for 1 second
|
|
192
|
+
arr.push({ isOn: false, timeout: 5000 }); // Turn off for 5 seconds
|
|
193
|
+
arr.push({ isOn: true, timeout: 1000 });
|
|
194
|
+
ptheme = sys.board.valueMaps.lightThemes.findItem('eveningsea');
|
|
195
|
+
}
|
|
196
|
+
let count = theme.sequence - ptheme.sequence;
|
|
197
|
+
if (count < 0) count = count + 16;
|
|
198
|
+
for (let i = 0; i < count; i++) {
|
|
199
|
+
arr.push({ isOn: true, timeout: 200 });
|
|
200
|
+
arr.push({ isOn: false, timeout: 200 });
|
|
167
201
|
}
|
|
168
202
|
console.log(arr);
|
|
203
|
+
if (arr.length === 0) return new InterfaceServerResponse(200, 'Success');
|
|
169
204
|
let res = await NixieEquipment.putDeviceService(this.circuit.connectionId, `/state/device/${this.circuit.deviceBinding}`, arr, 60000);
|
|
170
205
|
// Even though we ended with on we need to make sure that the relay stays on now that we are done.
|
|
171
206
|
if (!res.error) {
|
|
207
|
+
cstate.lightingTheme = ptheme.val;
|
|
208
|
+
cstate.isOn = true; // At this point the relay will be off but we want the process
|
|
209
|
+
// to assume that the relay state is not actually changing.
|
|
172
210
|
this._sequencing = false;
|
|
173
211
|
await this.setCircuitStateAsync(cstate, true, false);
|
|
174
212
|
}
|
|
@@ -234,6 +272,9 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
234
272
|
case 'colorlogic':
|
|
235
273
|
res = await this.setColorLogicThemeAsync(cstate, theme);
|
|
236
274
|
break;
|
|
275
|
+
case 'watercolors':
|
|
276
|
+
res = await this.setWaterColorsThemeAsync(cstate, theme);
|
|
277
|
+
break;
|
|
237
278
|
}
|
|
238
279
|
cstate.action = 0;
|
|
239
280
|
// Make sure clients know that we are done.
|
|
@@ -287,11 +287,15 @@ export class NixieSolarHeater extends NixieHeaterBase {
|
|
|
287
287
|
if (typeof this._lastState === 'undefined' || target || this._lastState !== target) {
|
|
288
288
|
if (utils.isNullOrEmpty(this.heater.connectionId) || utils.isNullOrEmpty(this.heater.deviceBinding)) {
|
|
289
289
|
this._lastState = hstate.isOn = target;
|
|
290
|
+
hstate.isCooling = target && isCooling;
|
|
290
291
|
}
|
|
291
292
|
else {
|
|
292
293
|
let res = await NixieEquipment.putDeviceService(this.heater.connectionId, `/state/device/${this.heater.deviceBinding}`,
|
|
293
294
|
{ isOn: target, latch: target ? 10000 : undefined });
|
|
294
|
-
if (res.status.code === 200)
|
|
295
|
+
if (res.status.code === 200) {
|
|
296
|
+
this._lastState = hstate.isOn = target;
|
|
297
|
+
hstate.isCooling = target && isCooling;
|
|
298
|
+
}
|
|
295
299
|
else logger.error(`Nixie Error setting heater state: ${res.status.code} -${res.status.message} ${res.error.message}`);
|
|
296
300
|
}
|
|
297
301
|
if (target) {
|
|
@@ -578,6 +582,7 @@ export class NixieMastertemp extends NixieGasHeater {
|
|
|
578
582
|
// Set the polling interval to 3 seconds.
|
|
579
583
|
this.pollEquipmentAsync();
|
|
580
584
|
this.pollingInterval = 3000;
|
|
585
|
+
|
|
581
586
|
}
|
|
582
587
|
/* public getCooldownTime(): number {
|
|
583
588
|
// Delays are always in terms of seconds so convert the minute to seconds.
|
|
@@ -589,12 +594,26 @@ export class NixieMastertemp extends NixieGasHeater {
|
|
|
589
594
|
public async setHeaterStateAsync(hstate: HeaterState, isOn: boolean) {
|
|
590
595
|
try {
|
|
591
596
|
// Initialize the desired state.
|
|
597
|
+
this.isOn = isOn;
|
|
592
598
|
this.isCooling = false;
|
|
593
|
-
|
|
594
|
-
if (hstate.
|
|
595
|
-
|
|
599
|
+
let target = hstate.startupDelay === false && isOn;
|
|
600
|
+
if (target && typeof hstate.endTime !== 'undefined') {
|
|
601
|
+
// Calculate a short cycle time so that the gas heater does not cycle
|
|
602
|
+
// too often. For gas heaters this is 60 seconds. This gives enough time
|
|
603
|
+
// for the heater control circuit to make a full cycle.
|
|
604
|
+
if (new Date().getTime() - hstate.endTime.getTime() < this.heater.minCycleTime * 60000) {
|
|
605
|
+
logger.verbose(`${hstate.name} short cycle detected deferring turn on state`);
|
|
606
|
+
target = false;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
// Here we go we need to set the state.
|
|
610
|
+
if (hstate.isOn !== target) {
|
|
611
|
+
logger.info(`Nixie: Set Mastertemp ${hstate.id}-${hstate.name} to ${isOn}`);
|
|
612
|
+
}
|
|
613
|
+
if (typeof this._lastState === 'undefined' || target || this._lastState !== target) {
|
|
614
|
+
this._lastState = hstate.isOn = target;
|
|
615
|
+
if (target) this.lastHeatCycle = new Date();
|
|
596
616
|
}
|
|
597
|
-
if (isOn && !hstate.startupDelay) this.lastHeatCycle = new Date();
|
|
598
617
|
hstate.isOn = isOn;
|
|
599
618
|
} catch (err) { return logger.error(`Nixie Error setting heater state ${hstate.id}-${hstate.name}: ${err.message}`); }
|
|
600
619
|
}
|