nodejs-poolcontroller 8.0.0 → 8.0.2
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/.docker/Dockerfile.armv6 +29 -0
- package/.docker/Dockerfile.armv7 +29 -0
- package/.docker/Dockerfile.linux +62 -0
- package/.docker/Dockerfile.windows +43 -0
- package/.docker/docker-compose.yml +47 -0
- package/.docker/ecosystem.config.js +35 -0
- package/.github/workflows/docker-publish-njsPC-linux.yml +81 -0
- package/.github/workflows/docker-publish-njsPC-windows.yml +41 -0
- package/Dockerfile +4 -3
- package/README.md +4 -1
- package/config/Config.ts +1 -1
- package/controller/Constants.ts +164 -67
- package/controller/Equipment.ts +79 -18
- package/controller/Lockouts.ts +15 -0
- package/controller/State.ts +280 -7
- package/controller/boards/EasyTouchBoard.ts +226 -102
- package/controller/boards/IntelliCenterBoard.ts +67 -18
- 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 +3259 -3242
- package/controller/comms/ScreenLogic.ts +60 -57
- 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/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 +36 -0
- package/controller/nixie/heaters/Heater.ts +24 -5
- package/controller/nixie/pumps/Pump.ts +155 -97
- package/controller/nixie/schedules/Schedule.ts +207 -126
- package/defaultConfig.json +4 -3
- package/logger/DataLogger.ts +7 -7
- package/package.json +3 -3
- 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
package/controller/Constants.ts
CHANGED
|
@@ -18,10 +18,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
18
18
|
import { EventEmitter } from 'events';
|
|
19
19
|
import { logger } from "../logger/Logger";
|
|
20
20
|
import * as util from 'util';
|
|
21
|
-
|
|
22
|
-
constructor() {
|
|
23
|
-
this.
|
|
24
|
-
this.
|
|
21
|
+
class HeliotropeContext {
|
|
22
|
+
constructor(longitude: number, latitude: number, zenith: number) {
|
|
23
|
+
this._zenith = typeof zenith !== 'undefined' ? zenith : 90 + 50 / 60;
|
|
24
|
+
this._longitude = longitude;
|
|
25
|
+
this._latitude = latitude;
|
|
25
26
|
}
|
|
26
27
|
private dMath = {
|
|
27
28
|
sin: function (deg) { return Math.sin(deg * (Math.PI / 180)); },
|
|
@@ -31,42 +32,14 @@ export class Heliotrope {
|
|
|
31
32
|
acos: function (x) { return (180 / Math.PI) * Math.acos(x); },
|
|
32
33
|
atan: function (x) { return (180 / Math.PI) * Math.atan(x); }
|
|
33
34
|
}
|
|
34
|
-
public isCalculated: boolean = false;
|
|
35
|
-
public isValid: boolean = false;
|
|
36
|
-
public get date() { return this.dt; }
|
|
37
|
-
public set date(dt: Date) {
|
|
38
|
-
if (typeof this.dt === 'undefined' ||
|
|
39
|
-
this.dt.getFullYear() !== dt.getFullYear() ||
|
|
40
|
-
this.dt.getMonth() !== dt.getMonth() ||
|
|
41
|
-
this.dt.getDate() !== dt.getDate()) {
|
|
42
|
-
this.isCalculated = false;
|
|
43
|
-
// Always store a copy since we don't want to create instances where the change doesn't get reflected. This
|
|
44
|
-
// also could hold onto references that we don't want held for garbage cleanup.
|
|
45
|
-
this.dt = typeof dt !== 'undefined' && typeof dt.getMonth === 'function' ? new Date(dt.getFullYear(), dt.getMonth(), dt.getDate(),
|
|
46
|
-
dt.getHours(), dt.getMinutes(), dt.getSeconds(), dt.getMilliseconds()) : undefined;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
public get longitude() { return this._longitude; }
|
|
50
|
-
public set longitude(lon: number) {
|
|
51
|
-
if (this._longitude !== lon) this.isCalculated = false;
|
|
52
|
-
this._longitude = lon;
|
|
53
|
-
}
|
|
54
|
-
public get latitude() { return this._latitude; }
|
|
55
|
-
public set latitude(lat: number) {
|
|
56
|
-
if (this._latitude !== lat) this.isCalculated = false;
|
|
57
|
-
this._latitude = lat;
|
|
58
|
-
}
|
|
59
|
-
public get zenith() { return this._zenith; }
|
|
60
|
-
public set zenith(zen: number) {
|
|
61
|
-
if (this._zenith !== zen) this.isCalculated = false;
|
|
62
|
-
this._zenith = zen;
|
|
63
|
-
}
|
|
64
35
|
private dt: Date;
|
|
65
36
|
private _longitude: number;
|
|
66
37
|
private _latitude: number;
|
|
67
38
|
private _zenith: number;
|
|
68
|
-
|
|
69
|
-
|
|
39
|
+
public get longitude() { return this._longitude; }
|
|
40
|
+
public get latitude() { return this._latitude; }
|
|
41
|
+
public get zenith() { return this._zenith; }
|
|
42
|
+
public get isValid(): boolean { return typeof this._longitude === 'number' && typeof this._latitude === 'number'; }
|
|
70
43
|
private get longitudeHours(): number { return this.longitude / 15.0; }
|
|
71
44
|
private get doy(): number { return Math.ceil((this.dt.getTime() - new Date(this.dt.getFullYear(), 0, 1).getTime()) / 8.64e7); }
|
|
72
45
|
private get sunriseApproxTime(): number { return this.doy + ((6.0 - this.longitudeHours) / 24.0); }
|
|
@@ -125,57 +98,175 @@ export class Heliotrope {
|
|
|
125
98
|
dtLocal.setFullYear(this.dt.getFullYear(), this.dt.getMonth(), this.dt.getDate());
|
|
126
99
|
return dtLocal;
|
|
127
100
|
}
|
|
128
|
-
public
|
|
129
|
-
let times = this.
|
|
101
|
+
public calculate(dt: Date): { dt: Date, sunrise: Date, sunset: Date } {
|
|
102
|
+
let times = { dt: this.dt = dt, sunrise: undefined, sunset: undefined };
|
|
130
103
|
if (this.isValid) {
|
|
131
|
-
let time = new Date().getTime();
|
|
132
|
-
if (time >= times.sunset.getTime() && time < times.sunrise.getTime()) return true;
|
|
133
|
-
}
|
|
134
|
-
return false;
|
|
135
|
-
}
|
|
136
|
-
public calculate() {
|
|
137
|
-
if (typeof this.dt !== 'undefined'
|
|
138
|
-
&& typeof this._latitude !== 'undefined'
|
|
139
|
-
&& typeof this._longitude !== 'undefined'
|
|
140
|
-
&& typeof this._zenith !== 'undefined') {
|
|
141
104
|
let sunriseLocal = this.sunriseLocalTime;
|
|
142
105
|
let sunsetLocal = this.sunsetLocalTime;
|
|
143
106
|
if (typeof sunriseLocal !== 'undefined') {
|
|
144
107
|
sunriseLocal = (sunriseLocal - this.longitudeHours);
|
|
145
108
|
while (sunriseLocal >= 24) sunriseLocal -= 24;
|
|
146
109
|
while (sunriseLocal < 0) sunriseLocal += 24;
|
|
147
|
-
|
|
110
|
+
times.sunrise = this.toLocalTime(sunriseLocal);
|
|
148
111
|
}
|
|
149
|
-
else
|
|
112
|
+
else times.sunrise = undefined;
|
|
150
113
|
if (typeof sunsetLocal !== 'undefined') {
|
|
151
114
|
sunsetLocal = (sunsetLocal - this.longitudeHours);
|
|
152
115
|
while (sunsetLocal >= 24) sunsetLocal -= 24;
|
|
153
116
|
while (sunsetLocal < 0) sunsetLocal += 24;
|
|
154
|
-
|
|
117
|
+
times.sunset = this.toLocalTime(sunsetLocal);
|
|
155
118
|
}
|
|
156
|
-
else
|
|
157
|
-
logger.verbose(`sunriseLocal:${sunriseLocal} sunsetLocal:${sunsetLocal} Calculating Heliotrope Valid`);
|
|
158
|
-
this.isValid = typeof this._dtSunrise !== 'undefined' && typeof this._dtSunset !== 'undefined';
|
|
159
|
-
this.isCalculated = true;
|
|
119
|
+
else times.sunset = undefined;
|
|
160
120
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
121
|
+
return times;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
}
|
|
125
|
+
export class Heliotrope {
|
|
126
|
+
constructor() {
|
|
127
|
+
this.isCalculated = false;
|
|
128
|
+
this._zenith = 90 + 50 / 60;
|
|
129
|
+
}
|
|
130
|
+
public isCalculated: boolean = false;
|
|
131
|
+
public get isValid(): boolean { return typeof this.dt !== 'undefined' && typeof this.dt.getMonth === 'function' && typeof this._longitude === 'number' && typeof this._latitude === 'number'; }
|
|
132
|
+
public get date() { return this.dt; }
|
|
133
|
+
public set date(dt: Date) {
|
|
134
|
+
if (typeof this.dt === 'undefined' ||
|
|
135
|
+
this.dt.getFullYear() !== dt.getFullYear() ||
|
|
136
|
+
this.dt.getMonth() !== dt.getMonth() ||
|
|
137
|
+
this.dt.getDate() !== dt.getDate()) {
|
|
166
138
|
this.isCalculated = false;
|
|
139
|
+
// Always store a copy since we don't want to create instances where the change doesn't get reflected. This
|
|
140
|
+
// also could hold onto references that we don't want held for garbage cleanup.
|
|
141
|
+
this.dt = typeof dt !== 'undefined' && typeof dt.getMonth === 'function' ? new Date(dt.getFullYear(), dt.getMonth(), dt.getDate(),
|
|
142
|
+
dt.getHours(), dt.getMinutes(), dt.getSeconds(), dt.getMilliseconds()) : undefined;
|
|
167
143
|
}
|
|
168
|
-
|
|
144
|
+
}
|
|
145
|
+
public get longitude() { return this._longitude; }
|
|
146
|
+
public set longitude(lon: number) {
|
|
147
|
+
if (this._longitude !== lon) {
|
|
148
|
+
this.isCalculated = false;
|
|
149
|
+
}
|
|
150
|
+
this._longitude = lon;
|
|
151
|
+
}
|
|
152
|
+
public get latitude() { return this._latitude; }
|
|
153
|
+
public set latitude(lat: number) {
|
|
154
|
+
if (this._latitude !== lat) {
|
|
155
|
+
this.isCalculated = false;
|
|
156
|
+
}
|
|
157
|
+
this._latitude = lat;
|
|
158
|
+
}
|
|
159
|
+
public get zenith() { return this._zenith; }
|
|
160
|
+
public set zenith(zen: number) {
|
|
161
|
+
if (this._zenith !== zen) this.isCalculated = false;
|
|
162
|
+
this._zenith = zen;
|
|
163
|
+
}
|
|
164
|
+
private dt: Date;
|
|
165
|
+
private _longitude: number;
|
|
166
|
+
private _latitude: number;
|
|
167
|
+
private _zenith: number;
|
|
168
|
+
private _dtSunrise: Date;
|
|
169
|
+
private _dtSunset: Date;
|
|
170
|
+
private _dtNextSunrise: Date;
|
|
171
|
+
private _dtNextSunset: Date;
|
|
172
|
+
private _dtPrevSunrise: Date;
|
|
173
|
+
private _dtPrevSunset: Date;
|
|
174
|
+
public get isNight(): boolean {
|
|
175
|
+
let times = this.calculatedTimes;
|
|
176
|
+
if (this.isValid) {
|
|
177
|
+
let time = new Date().getTime();
|
|
178
|
+
if (time >= times.sunset.getTime()) // We are after sunset.
|
|
179
|
+
return time < times.nextSunrise.getTime(); // It is night so long as we are less than the next sunrise.
|
|
180
|
+
// Normally this would be updated on 1 min after midnight so it should never be true.
|
|
181
|
+
else
|
|
182
|
+
return time < times.sunrise.getTime(); // If the Heliotrope is updated then we need to declare pre-sunrise to be night.
|
|
183
|
+
// This is the normal condition where it would be night since at 1 min after midnight the sunrise/sunset
|
|
184
|
+
// will get updated. So it will be before sunrise that it will still be night.
|
|
185
|
+
}
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
public calculate(dt: Date): { isValid: boolean, dt: Date, sunrise: Date, sunset: Date, nextSunrise: Date, nextSunset: Date, prevSunrise: Date, prevSunset: Date } {
|
|
189
|
+
let ctx = new HeliotropeContext(this.longitude, this.latitude, this.zenith);
|
|
190
|
+
let ret = { isValid: ctx.isValid, dt: dt, sunrise: undefined, sunset: undefined, nextSunrise: undefined, nextSunset: undefined, prevSunrise: undefined, prevSunset: undefined };
|
|
191
|
+
if (ctx.isValid) {
|
|
192
|
+
let tToday = ctx.calculate(dt);
|
|
193
|
+
let tTom = ctx.calculate(new Date(dt.getTime() + 86400000));
|
|
194
|
+
let tYesterday = ctx.calculate(new Date(dt.getTime() - 86400000));
|
|
195
|
+
ret.sunrise = tToday.sunrise;
|
|
196
|
+
ret.sunset = tToday.sunset;
|
|
197
|
+
ret.nextSunrise = tTom.sunrise;
|
|
198
|
+
ret.nextSunset = tTom.sunset;
|
|
199
|
+
ret.prevSunrise = tYesterday.sunrise;
|
|
200
|
+
ret.prevSunset = tYesterday.sunset;
|
|
201
|
+
}
|
|
202
|
+
return ret;
|
|
203
|
+
}
|
|
204
|
+
private calcInternal() {
|
|
205
|
+
if (this.isValid) {
|
|
206
|
+
let times = this.calculate(this.dt);
|
|
207
|
+
this._dtSunrise = times.sunrise;
|
|
208
|
+
this._dtSunset = times.sunset;
|
|
209
|
+
this._dtNextSunrise = times.nextSunrise;
|
|
210
|
+
this._dtNextSunset = times.nextSunset;
|
|
211
|
+
this._dtPrevSunrise = times.prevSunrise;
|
|
212
|
+
this._dtPrevSunset = times.prevSunset;
|
|
213
|
+
this.isCalculated = true;
|
|
214
|
+
logger.verbose(`Calculated Heliotrope: sunrise:${Timestamp.toISOLocal(this._dtSunrise)} sunset:${Timestamp.toISOLocal(this._dtSunset)}`);
|
|
215
|
+
}
|
|
216
|
+
else
|
|
217
|
+
logger.warn(`dt:${this.dt} lat:${this._latitude} lon:${this._longitude} Not enough information to calculate Heliotrope. See https://github.com/tagyoureit/nodejs-poolController/issues/245`);
|
|
169
218
|
}
|
|
170
219
|
public get sunrise(): Date {
|
|
171
|
-
if (!this.isCalculated) this.
|
|
220
|
+
if (!this.isCalculated) this.calcInternal();
|
|
172
221
|
return this._dtSunrise;
|
|
173
222
|
}
|
|
174
223
|
public get sunset(): Date {
|
|
175
|
-
if (!this.isCalculated) this.
|
|
224
|
+
if (!this.isCalculated) this.calcInternal();
|
|
176
225
|
return this._dtSunset;
|
|
177
226
|
}
|
|
178
|
-
public get
|
|
227
|
+
public get nextSunrise(): Date {
|
|
228
|
+
if (!this.isCalculated) this.calcInternal();
|
|
229
|
+
return this._dtNextSunrise;
|
|
230
|
+
}
|
|
231
|
+
public get nextSunset(): Date {
|
|
232
|
+
if (!this.isCalculated) this.calcInternal();
|
|
233
|
+
return this._dtNextSunset;
|
|
234
|
+
}
|
|
235
|
+
public get prevSunrise(): Date {
|
|
236
|
+
if (!this.isCalculated) this.calcInternal();
|
|
237
|
+
return this._dtPrevSunrise;
|
|
238
|
+
}
|
|
239
|
+
public get prevSunset(): Date {
|
|
240
|
+
if (!this.isCalculated) this.calcInternal();
|
|
241
|
+
return this._dtPrevSunset;
|
|
242
|
+
}
|
|
243
|
+
public get calculatedTimes(): { sunrise?: Date, sunset?: Date, nextSunrise?: Date, nextSunset?: Date, prevSunrise?: Date, prevSunset: Date, isValid: boolean } { return { sunrise: this.sunrise, sunset: this.sunset, nextSunrise: this.nextSunrise, nextSunset: this.nextSunset, prevSunrise: this.prevSunrise, prevSunset: this.prevSunset, isValid: this.isValid }; }
|
|
244
|
+
public calcAdjustedTimes(dt: Date, hours = 0, min = 0): { sunrise?: Date, sunset?: Date, nextSunrise?: Date, nextSunset?: Date, prevSunrise?: Date, prevSunset: Date, isValid: boolean } {
|
|
245
|
+
if (this.dt.getFullYear() === dt.getFullYear() && this.dt.getMonth() === dt.getMonth() && this.dt.getDate() === dt.getDate()) return this.getAdjustedTimes(hours, min);
|
|
246
|
+
let ms = (hours * 3600000) + (min * 60000);
|
|
247
|
+
let times = this.calculate(dt);
|
|
248
|
+
return {
|
|
249
|
+
sunrise: new Date(times.sunrise.getTime() + ms),
|
|
250
|
+
sunset: new Date(times.sunset.getTime() + ms),
|
|
251
|
+
nextSunrise: new Date(times.nextSunrise.getTime() + ms),
|
|
252
|
+
nextSunset: new Date(times.nextSunset.getTime() + ms),
|
|
253
|
+
prevSunrise: new Date(times.prevSunrise.getTime() + ms),
|
|
254
|
+
prevSunset: new Date(times.prevSunset.getTime() + ms),
|
|
255
|
+
isValid: this.isValid
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
public getAdjustedTimes(hours = 0, min = 0): { sunrise?: Date, sunset?: Date, nextSunrise?: Date, nextSunset?: Date, prevSunrise?: Date, prevSunset: Date, isValid: boolean } {
|
|
259
|
+
let ms = (hours * 3600000) + (min * 60000);
|
|
260
|
+
return {
|
|
261
|
+
sunrise: new Date(this.sunrise.getTime() + ms),
|
|
262
|
+
sunset: new Date(this.sunset.getTime() + ms),
|
|
263
|
+
nextSunrise: new Date(this.nextSunrise.getTime() + ms),
|
|
264
|
+
nextSunset: new Date(this.nextSunset.getTime() + ms),
|
|
265
|
+
prevSunrise: new Date(this.prevSunrise.getTime() + ms),
|
|
266
|
+
prevSunset: new Date(this.prevSunset.getTime() + ms),
|
|
267
|
+
isValid: this.isValid
|
|
268
|
+
}
|
|
269
|
+
}
|
|
179
270
|
}
|
|
180
271
|
export class Timestamp {
|
|
181
272
|
private static dateTextISO = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*))(?:Z|(\+|-)([\d|:]*))?$/;
|
|
@@ -185,11 +276,15 @@ export class Timestamp {
|
|
|
185
276
|
constructor(dt?: Date | string) {
|
|
186
277
|
if (typeof dt === 'string') this._dt = new Date(dt);
|
|
187
278
|
else this._dt = dt || new Date();
|
|
279
|
+
if (!this.isValid) this._dt = new Date();
|
|
188
280
|
this.emitter = new EventEmitter();
|
|
189
281
|
}
|
|
190
282
|
private _isUpdating: boolean = false;
|
|
191
283
|
public static get now(): Timestamp { return new Timestamp(); }
|
|
192
|
-
public toDate() { return this._dt; }
|
|
284
|
+
public toDate(): Date { return this._dt; }
|
|
285
|
+
public get isValid() {
|
|
286
|
+
return this._dt instanceof Date && !isNaN(this._dt.getTime());
|
|
287
|
+
}
|
|
193
288
|
public set isUpdating(val: boolean) { this._isUpdating = val; }
|
|
194
289
|
public get isUpdating(): boolean { return this._isUpdating; }
|
|
195
290
|
public get hours(): number { return this._dt.getHours(); }
|
|
@@ -221,7 +316,8 @@ export class Timestamp {
|
|
|
221
316
|
public set fullYear(val: number) { this._dt.setFullYear(val); }
|
|
222
317
|
public get year(): number { return this._dt.getFullYear(); }
|
|
223
318
|
public set year(val: number) {
|
|
224
|
-
let
|
|
319
|
+
let dt = new Date();
|
|
320
|
+
let y = val < 100 ? (Math.floor(dt.getFullYear() / 100) * 100) + val : val;
|
|
225
321
|
if (y !== this.year) {
|
|
226
322
|
this._dt.setFullYear(y);
|
|
227
323
|
this.emitter.emit('change');
|
|
@@ -244,7 +340,8 @@ export class Timestamp {
|
|
|
244
340
|
public getDay(): number { return this._dt.getDay(); }
|
|
245
341
|
public getTime() { return this._dt.getTime(); }
|
|
246
342
|
public format(): string { return Timestamp.toISOLocal(this._dt); }
|
|
247
|
-
public static toISOLocal(dt): string {
|
|
343
|
+
public static toISOLocal(dt: Date): string {
|
|
344
|
+
if (typeof dt === 'undefined' || typeof dt.getTime !== 'function' || isNaN(dt.getTime())) return '';
|
|
248
345
|
let tzo = dt.getTimezoneOffset();
|
|
249
346
|
var pad = function (n) {
|
|
250
347
|
var t = Math.floor(Math.abs(n));
|
package/controller/Equipment.ts
CHANGED
|
@@ -75,10 +75,11 @@ interface IPoolSystem {
|
|
|
75
75
|
export class PoolSystem implements IPoolSystem {
|
|
76
76
|
public _hasChanged: boolean = false;
|
|
77
77
|
public isReady: boolean = false;
|
|
78
|
+
private _startOCPTimer: NodeJS.Timeout;
|
|
78
79
|
constructor() {
|
|
79
80
|
this.cfgPath = path.posix.join(process.cwd(), '/data/poolConfig.json');
|
|
80
81
|
}
|
|
81
|
-
public getAvailableControllerTypes(include:string[] = ['easytouch', 'intellitouch', 'intellicenter', 'nixie']) {
|
|
82
|
+
public getAvailableControllerTypes(include:string[] = ['easytouch', 'intellitouch', 'intellicenter', 'suntouch', 'nixie']) {
|
|
82
83
|
let arr = [];
|
|
83
84
|
if (include.indexOf('easytouch')>=0) arr.push({
|
|
84
85
|
type: 'easytouch', name: 'EasyTouch',
|
|
@@ -124,7 +125,14 @@ export class PoolSystem implements IPoolSystem {
|
|
|
124
125
|
{ val: 7, name: 'i10D', part: '523029Z', desc: 'IntelliCenter i10D', bodies: 2, valves: 2, circuits: 11, shared: false, dual: true, chlorinators: 2, chemControllers: 2 },
|
|
125
126
|
]
|
|
126
127
|
});
|
|
127
|
-
if (include.indexOf('
|
|
128
|
+
if (include.indexOf('suntouch') >= 0) arr.push({
|
|
129
|
+
type: 'suntouch', name: 'SunTouch',
|
|
130
|
+
models: [
|
|
131
|
+
{ val: 41, name: 'stshared', part: '520820', desc: 'Pool and Spa controller', bodies: 2, valves: 4, circuits: 5, single: false, shared: true, dual: false, features: 4, chlorinators: 1, chemControllers: 1 },
|
|
132
|
+
{ val: 40, name: 'stsingle', part: '520819', desc: 'Pool or Spa controller', bodies: 2, valves: 4, circuits: 5, single: true, shared: true, dual: false, features: 4, chlorinators: 1, chemControllers: 1 }
|
|
133
|
+
]
|
|
134
|
+
})
|
|
135
|
+
if (include.indexOf('nixie') >= 0) arr.push({
|
|
128
136
|
type: 'nixie', name: 'Nixie', canChange: true,
|
|
129
137
|
models: [
|
|
130
138
|
{ val: 0, name: 'nxp', part: 'NXP', desc: 'Nixie Single Body', bodies: 1, shared: false, dual: false },
|
|
@@ -143,7 +151,9 @@ export class PoolSystem implements IPoolSystem {
|
|
|
143
151
|
if (this.controllerType === 'unknown' || typeof this.controllerType === 'undefined') {
|
|
144
152
|
// Delay for 7.5 seconds to give any OCPs a chance to start emitting messages.
|
|
145
153
|
logger.info(`Listening for any installed OCPs`);
|
|
146
|
-
|
|
154
|
+
if (this._startOCPTimer) clearTimeout(this._startOCPTimer);
|
|
155
|
+
this._startOCPTimer = null;
|
|
156
|
+
this._startOCPTimer = setTimeout(() => { self.initNixieController(); }, 7500);
|
|
147
157
|
}
|
|
148
158
|
else
|
|
149
159
|
this.initNixieController();
|
|
@@ -217,15 +227,40 @@ export class PoolSystem implements IPoolSystem {
|
|
|
217
227
|
}
|
|
218
228
|
|
|
219
229
|
public resetSystem() {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
230
|
+
logger.info(`Resetting System to initial defaults`);
|
|
231
|
+
(async () => {
|
|
232
|
+
await this.board.closeAsync();
|
|
233
|
+
logger.info(`Closed ${this.controllerType} board`);
|
|
234
|
+
this.controllerType = ControllerType.Unknown;
|
|
235
|
+
})();
|
|
236
|
+
|
|
237
|
+
/*
|
|
238
|
+
let self = this;
|
|
239
|
+
if (this.controllerType === ControllerType.Nixie) {
|
|
240
|
+
(async () => {
|
|
241
|
+
await this.board.closeAsync();
|
|
242
|
+
this.board = BoardFactory.fromControllerType(ControllerType.Nixie, this);
|
|
243
|
+
let board = sys.board as NixieBoard;
|
|
244
|
+
await board.initNixieBoard();
|
|
245
|
+
})();
|
|
246
|
+
state.status = 0;
|
|
247
|
+
|
|
248
|
+
logger.info(`Listening for any installed OCPs`);
|
|
249
|
+
setTimeout(() => { self.initNixieController(); }, 7500);
|
|
250
|
+
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
conn.pauseAll();
|
|
254
|
+
this.resetData();
|
|
255
|
+
state.resetData();
|
|
256
|
+
this.data.controllerType === 'unknown';
|
|
257
|
+
state.equipment.controllerType = ControllerType.Unknown;
|
|
258
|
+
this.controllerType = ControllerType.Unknown;
|
|
259
|
+
state.status = 0;
|
|
260
|
+
this.board = BoardFactory.fromControllerType(ControllerType.Unknown, this);
|
|
261
|
+
setTimeout(function () { state.status = 0; conn.resumeAll(); }, 0);
|
|
262
|
+
}
|
|
263
|
+
*/
|
|
229
264
|
}
|
|
230
265
|
public get anslq25ControllerType(): ControllerType { return this.data.anslq25.controllerType as ControllerType; }
|
|
231
266
|
public set anslq25ControllerType(val: ControllerType) {
|
|
@@ -250,11 +285,17 @@ export class PoolSystem implements IPoolSystem {
|
|
|
250
285
|
// Only go in here if there is a change to the controller type.
|
|
251
286
|
this.resetData(); // Clear the configuration data.
|
|
252
287
|
state.resetData(); // Clear the state data.
|
|
288
|
+
state.status = 0; // We are performing a re-initialize.
|
|
253
289
|
this.data.controllerType = val;
|
|
254
290
|
EquipmentStateMessage.initDefaults();
|
|
291
|
+
|
|
255
292
|
// We are actually changing the config so lets clear out all the data.
|
|
256
293
|
this.board = BoardFactory.fromControllerType(val, this);
|
|
257
|
-
if (this.data.controllerType === ControllerType.Unknown)
|
|
294
|
+
if (this.data.controllerType === ControllerType.Unknown) {
|
|
295
|
+
if (this._startOCPTimer) clearTimeout(this._startOCPTimer);
|
|
296
|
+
this._startOCPTimer = null;
|
|
297
|
+
this._startOCPTimer = setTimeout(() => { self.initNixieController(); }, 7500);
|
|
298
|
+
}
|
|
258
299
|
}
|
|
259
300
|
}
|
|
260
301
|
public resetData() {
|
|
@@ -1144,6 +1185,8 @@ export class Schedule extends EqItem {
|
|
|
1144
1185
|
if (typeof this.data.startTimeType === 'undefined') this.data.startTimeType = 0;
|
|
1145
1186
|
if (typeof this.data.endTimeType === 'undefined') this.data.endTimeType = 0;
|
|
1146
1187
|
if (typeof this.data.display === 'undefined') this.data.display = 0;
|
|
1188
|
+
if (typeof this.data.startTimeOffset === 'undefined') this.data.startTimeOffset = 0;
|
|
1189
|
+
if (typeof this.data.endTimeOffset === 'undefined') this.data.endTimeOffset = 0;
|
|
1147
1190
|
}
|
|
1148
1191
|
|
|
1149
1192
|
// todo: investigate schedules having startDate and _startDate
|
|
@@ -1155,6 +1198,11 @@ export class Schedule extends EqItem {
|
|
|
1155
1198
|
public set startTime(val: number) { this.setDataVal('startTime', val); }
|
|
1156
1199
|
public get endTime(): number { return this.data.endTime; }
|
|
1157
1200
|
public set endTime(val: number) { this.setDataVal('endTime', val); }
|
|
1201
|
+
public get startTimeOffset(): number { return this.data.startTimeOffset || 0; }
|
|
1202
|
+
public set startTimeOffset(val: number) { this.setDataVal('startTimeOffset', val); }
|
|
1203
|
+
public get endTimeOffset(): number { return this.data.endTimeOffset || 0; }
|
|
1204
|
+
public set endTimeOffset(val: number) { this.setDataVal('endTimeOffset', val); }
|
|
1205
|
+
|
|
1158
1206
|
public get scheduleDays(): number { return this.data.scheduleDays; }
|
|
1159
1207
|
public set scheduleDays(val: number) { this.setDataVal('scheduleDays', val); }
|
|
1160
1208
|
public get circuit(): number { return this.data.circuit; }
|
|
@@ -1177,7 +1225,10 @@ export class Schedule extends EqItem {
|
|
|
1177
1225
|
public set startDay(val: number) { if (typeof this._startDate === 'undefined') this._startDate = new Date(); this._startDate.setDate(val); this._saveStartDate(); }
|
|
1178
1226
|
public get startYear(): number { if (typeof this._startDate === 'undefined') this._startDate = new Date(); return this._startDate.getFullYear(); }
|
|
1179
1227
|
public set startYear(val: number) { if (typeof this._startDate === 'undefined') this._startDate = new Date(); this._startDate.setFullYear(val < 100 ? val + 2000 : val); this._saveStartDate(); }
|
|
1180
|
-
public get startDate(): Date {
|
|
1228
|
+
public get startDate(): Date {
|
|
1229
|
+
this._startDate = typeof this._startDate === 'undefined' ? new Date(this.data.startDate) : this._startDate;
|
|
1230
|
+
return typeof this._startDate === 'undefined' || isNaN(this._startDate.getTime()) ? new Date() : this._startDate;
|
|
1231
|
+
}
|
|
1181
1232
|
public set startDate(val: Date) { this._startDate = val; }
|
|
1182
1233
|
public get scheduleType(): number | any { return this.data.scheduleType; }
|
|
1183
1234
|
public set scheduleType(val: number | any) { this.setDataVal('scheduleType', sys.board.valueMaps.scheduleTypes.encode(val)); }
|
|
@@ -1390,14 +1441,22 @@ export class PumpCollection extends EqItemCollection<Pump> {
|
|
|
1390
1441
|
constructor(data: any, name?: string) { super(data, name || "pumps"); }
|
|
1391
1442
|
public createItem(data: any): Pump { return new Pump(data); }
|
|
1392
1443
|
public getDualSpeed(add?: boolean): Pump {
|
|
1393
|
-
|
|
1444
|
+
let ds = sys.board.valueMaps.pumpTypes.getValue('ds');
|
|
1445
|
+
let pump = this.find(x => x.type === ds);
|
|
1446
|
+
return typeof pump !== 'undefined' ? pump : this.getItemById(10, add, { id: 10, type: ds, name: 'Two Speed', master: 0 });
|
|
1394
1447
|
}
|
|
1395
|
-
public
|
|
1448
|
+
public removePumpByAddress(address: number) {
|
|
1396
1449
|
let pmp = this.find(elem => elem.address === address);
|
|
1397
|
-
if (typeof pmp !== 'undefined') return this.
|
|
1450
|
+
if (typeof pmp !== 'undefined') return this.removeItemById(pmp.id);
|
|
1451
|
+
return pmp;
|
|
1452
|
+
}
|
|
1453
|
+
public getPumpByAddress(address: number, add?: boolean, data?: any) : Pump {
|
|
1454
|
+
let pmp = this.find(elem => elem.address === address);
|
|
1455
|
+
if (typeof pmp !== 'undefined') return pmp;
|
|
1398
1456
|
if (typeof add !== 'undefined' && add) return this.add(data || { id: this.data.length + 1, address: address });
|
|
1399
|
-
return this.createItem(data || { id: this.
|
|
1457
|
+
return this.createItem(data || { id: this.getNextEquipmentId(), address: address });
|
|
1400
1458
|
}
|
|
1459
|
+
public getNextEquipmentId(range?: EquipmentIdRange, exclude?: number[]): number { return super.getNextEquipmentId(typeof range === 'undefined' ? sys.board.equipmentIds.pumps : range, exclude); }
|
|
1401
1460
|
}
|
|
1402
1461
|
export class Pump extends EqItem {
|
|
1403
1462
|
public dataName = 'pumpConfig';
|
|
@@ -2439,6 +2498,7 @@ export class ChemicalPh extends Chemical {
|
|
|
2439
2498
|
public getExtended() {
|
|
2440
2499
|
let chem = super.getExtended();
|
|
2441
2500
|
chem.probe = this.probe.getExtended();
|
|
2501
|
+
chem.tank = this.tank.getExtended();
|
|
2442
2502
|
chem.phSupply = sys.board.valueMaps.phSupplyTypes.transform(this.phSupply);
|
|
2443
2503
|
chem.doserType = sys.board.valueMaps.phDoserTypes.transform(this.doserType);
|
|
2444
2504
|
return chem;
|
|
@@ -2469,6 +2529,7 @@ export class ChemicalORP extends Chemical {
|
|
|
2469
2529
|
public getExtended() {
|
|
2470
2530
|
let chem = super.getExtended();
|
|
2471
2531
|
chem.probe = this.probe.getExtended();
|
|
2532
|
+
chem.tank = this.tank.getExtended();
|
|
2472
2533
|
chem.doserType = sys.board.valueMaps.orpDoserTypes.transform(this.doserType);
|
|
2473
2534
|
return chem;
|
|
2474
2535
|
}
|
package/controller/Lockouts.ts
CHANGED
|
@@ -135,6 +135,21 @@ export class ManualPriorityDelay extends EquipmentDelay {
|
|
|
135
135
|
logger.info(`Manual Operation Priority cancelled for ${this.circuitState.name}`);
|
|
136
136
|
this._delayTimer = undefined;
|
|
137
137
|
this.circuitState.manualPriorityActive = false;
|
|
138
|
+
// Rip through all the schedules and clear the manual priority.
|
|
139
|
+
let sscheds = state.schedules.getActiveSchedules();
|
|
140
|
+
let circIds = [];
|
|
141
|
+
for (let i = 0; i < sscheds.length; i++) {
|
|
142
|
+
let ssched = sscheds[i];
|
|
143
|
+
ssched.manualPriorityActive = false;
|
|
144
|
+
if (!circIds.includes(ssched.circuit)) circIds.push(ssched.circuit);
|
|
145
|
+
}
|
|
146
|
+
for (let i = 0; i < circIds.length; i++) {
|
|
147
|
+
let circ = sys.circuits.getInterfaceById(circIds[i]);
|
|
148
|
+
if (!circ.isActive) continue;
|
|
149
|
+
let cstate = state.circuits.getInterfaceById(circ.id);
|
|
150
|
+
sys.board.circuits.setEndTime(circ, cstate, cstate.isOn, true);
|
|
151
|
+
}
|
|
152
|
+
|
|
138
153
|
delayMgr.deleteDelay(this.id);
|
|
139
154
|
}
|
|
140
155
|
public clearDelay() {
|