nodejs-poolcontroller 7.5.1 → 7.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/1-bug-report.yml +84 -0
- package/.github/ISSUE_TEMPLATE/2-docs.md +12 -0
- package/.github/ISSUE_TEMPLATE/3-proposal.md +28 -0
- package/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/Changelog +19 -0
- package/Dockerfile +3 -3
- package/README.md +13 -8
- package/app.ts +1 -1
- package/config/Config.ts +38 -2
- package/config/VersionCheck.ts +27 -12
- package/controller/Constants.ts +2 -1
- package/controller/Equipment.ts +193 -9
- package/controller/Errors.ts +10 -0
- package/controller/Lockouts.ts +503 -0
- package/controller/State.ts +269 -64
- package/controller/boards/AquaLinkBoard.ts +1000 -0
- package/controller/boards/BoardFactory.ts +4 -0
- package/controller/boards/EasyTouchBoard.ts +468 -144
- package/controller/boards/IntelliCenterBoard.ts +466 -307
- package/controller/boards/IntelliTouchBoard.ts +37 -5
- package/controller/boards/NixieBoard.ts +671 -141
- package/controller/boards/SystemBoard.ts +1397 -641
- package/controller/comms/Comms.ts +462 -362
- package/controller/comms/messages/Messages.ts +174 -30
- package/controller/comms/messages/config/ChlorinatorMessage.ts +6 -3
- package/controller/comms/messages/config/CircuitMessage.ts +1 -0
- package/controller/comms/messages/config/ExternalMessage.ts +10 -8
- package/controller/comms/messages/config/HeaterMessage.ts +141 -29
- package/controller/comms/messages/config/OptionsMessage.ts +9 -2
- package/controller/comms/messages/config/PumpMessage.ts +53 -35
- package/controller/comms/messages/config/ScheduleMessage.ts +33 -25
- package/controller/comms/messages/config/ValveMessage.ts +2 -2
- package/controller/comms/messages/status/ChlorinatorStateMessage.ts +38 -86
- package/controller/comms/messages/status/EquipmentStateMessage.ts +59 -23
- package/controller/comms/messages/status/HeaterStateMessage.ts +57 -3
- package/controller/comms/messages/status/IntelliChemStateMessage.ts +56 -8
- package/controller/comms/messages/status/PumpStateMessage.ts +23 -1
- package/controller/nixie/Nixie.ts +1 -1
- package/controller/nixie/bodies/Body.ts +3 -0
- package/controller/nixie/chemistry/ChemController.ts +164 -51
- package/controller/nixie/chemistry/Chlorinator.ts +137 -88
- package/controller/nixie/circuits/Circuit.ts +51 -19
- package/controller/nixie/heaters/Heater.ts +241 -31
- package/controller/nixie/pumps/Pump.ts +488 -206
- package/controller/nixie/schedules/Schedule.ts +91 -35
- package/controller/nixie/valves/Valve.ts +1 -1
- package/defaultConfig.json +20 -0
- package/package.json +21 -21
- package/web/Server.ts +94 -49
- package/web/bindings/aqualinkD.json +505 -0
- package/web/bindings/influxDB.json +71 -1
- package/web/bindings/mqtt.json +98 -39
- package/web/bindings/mqttAlt.json +59 -1
- package/web/interfaces/baseInterface.ts +1 -0
- package/web/interfaces/httpInterface.ts +23 -2
- package/web/interfaces/influxInterface.ts +45 -10
- package/web/interfaces/mqttInterface.ts +114 -54
- package/web/services/config/Config.ts +55 -132
- package/web/services/state/State.ts +81 -4
- package/web/services/state/StateSocket.ts +4 -4
- package/web/services/utilities/Utilities.ts +8 -6
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -52
- package/config copy.json +0 -300
- package/issue_template.md +0 -52
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { InvalidEquipmentDataError, InvalidEquipmentIdError, InvalidOperationError } from '../../Errors';
|
|
2
|
-
import { utils, Timestamp } from '../../Constants';
|
|
2
|
+
import { utils, Timestamp, ControllerType } from '../../Constants';
|
|
3
3
|
import { logger } from '../../../logger/Logger';
|
|
4
4
|
|
|
5
5
|
import { NixieEquipment, NixieChildEquipment, NixieEquipmentCollection, INixieControlPanel } from "../NixieEquipment";
|
|
@@ -87,7 +87,11 @@ export class NixieChlorinator extends NixieEquipment {
|
|
|
87
87
|
}
|
|
88
88
|
public get id(): number { return typeof this.chlor !== 'undefined' ? this.chlor.id : -1; }
|
|
89
89
|
public get suspendPolling(): boolean { return this._suspendPolling > 0; }
|
|
90
|
-
public set suspendPolling(val: boolean) { this._suspendPolling = Math.max(0, this._suspendPolling + (val ? 1 : -1));
|
|
90
|
+
public set suspendPolling(val: boolean) { this._suspendPolling = Math.max(0, this._suspendPolling + (val ? 1 : -1)); }
|
|
91
|
+
public get superChlorRemaining(): number {
|
|
92
|
+
if (typeof this.superChlorStart === 'undefined' || this.superChlorStart === 0 || !this.chlor.superChlor) return 0;
|
|
93
|
+
return Math.max(Math.floor(((this.chlor.superChlorHours * 3600 * 1000) - (new Date().getTime() - this.superChlorStart)) / 1000), 0);
|
|
94
|
+
}
|
|
91
95
|
public async setChlorinatorAsync(data: any) {
|
|
92
96
|
try {
|
|
93
97
|
let chlor = this.chlor;
|
|
@@ -97,15 +101,20 @@ export class NixieChlorinator extends NixieEquipment {
|
|
|
97
101
|
let poolSetpoint = typeof data.poolSetpoint !== 'undefined' ? parseInt(data.poolSetpoint, 10) : chlor.poolSetpoint;
|
|
98
102
|
let spaSetpoint = typeof data.spaSetpoint !== 'undefined' ? parseInt(data.spaSetpoint, 10) : chlor.spaSetpoint;
|
|
99
103
|
let body = sys.board.bodies.mapBodyAssociation(typeof data.body === 'undefined' ? chlor.body : data.body);
|
|
100
|
-
let superChlor = typeof data.superChlor !== 'undefined' ? utils.makeBool(data.superChlor) : chlor.superChlor;
|
|
104
|
+
let superChlor = typeof data.superChlor !== 'undefined' ? utils.makeBool(data.superChlor) : typeof data.superChlorinate !== 'undefined' ? utils.makeBool(data.superChlorinate) : chlor.superChlor;
|
|
101
105
|
let chlorType = typeof data.type !== 'undefined' ? sys.board.valueMaps.chlorinatorType.encode(data.type) : chlor.type || 0;
|
|
102
106
|
let superChlorHours = typeof data.superChlorHours !== 'undefined' ? parseInt(data.superChlorHours, 10) : chlor.superChlorHours;
|
|
103
107
|
let disabled = typeof data.disabled !== 'undefined' ? utils.makeBool(data.disabled) : chlor.disabled;
|
|
104
108
|
let isDosing = typeof data.isDosing !== 'undefined' ? utils.makeBool(data.isDosing) : chlor.isDosing;
|
|
105
|
-
let model = typeof data.model !== 'undefined' ? data.model : chlor.model || 0;
|
|
106
|
-
|
|
109
|
+
let model = typeof data.model !== 'undefined' ? sys.board.valueMaps.chlorinatorModel.encode(data.model) : chlor.model || 0;
|
|
110
|
+
let portId = typeof data.portId !== 'undefined' ? parseInt(data.portId, 10) : chlor.portId;
|
|
111
|
+
if (portId === 0 && sys.controllerType !== ControllerType.Nixie) return Promise.reject(new InvalidEquipmentDataError(`You may not install a chlorinator on an ${sys.controllerType} system that is assigned to the Primary Port that is under Nixe control`, 'Chlorinator', portId));
|
|
112
|
+
if (portId !== chlor.portId && sys.chlorinators.count(elem => elem.id !== this.chlor.id && elem.portId === portId && elem.master !== 2) > 0) return Promise.reject(new InvalidEquipmentDataError(`Another chlorinator is installed on port #${portId}. Only one chlorinator can be installed per port.`, 'Chlorinator', portId));
|
|
113
|
+
if (isNaN(portId)) return Promise.reject(new InvalidEquipmentDataError(`Invalid port Id`, 'Chlorinator', data.portId));
|
|
114
|
+
if (typeof body === 'undefined') return Promise.reject(new InvalidEquipmentDataError(`Invalid body assignment`, 'Chlorinator', data.body || chlor.body));
|
|
107
115
|
if (isNaN(poolSetpoint)) poolSetpoint = 0;
|
|
108
116
|
if (isNaN(spaSetpoint)) spaSetpoint = 0;
|
|
117
|
+
|
|
109
118
|
chlor.ignoreSaltReading = (typeof data.ignoreSaltReading !== 'undefined') ? utils.makeBool(data.ignoreSaltReading) : utils.makeBool(chlor.ignoreSaltReading);
|
|
110
119
|
// Do a final validation pass so we dont send this off in a mess.
|
|
111
120
|
let schlor = state.chlorinators.getItemById(chlor.id, true);
|
|
@@ -114,12 +123,17 @@ export class NixieChlorinator extends NixieEquipment {
|
|
|
114
123
|
schlor.superChlor = chlor.superChlor = superChlor;
|
|
115
124
|
schlor.superChlorHours = chlor.superChlorHours = superChlorHours;
|
|
116
125
|
schlor.type = chlor.type = chlorType;
|
|
117
|
-
chlor.model = model;
|
|
126
|
+
schlor.model = chlor.model = model;
|
|
118
127
|
schlor.body = chlor.body = body.val;
|
|
128
|
+
chlor.portId = portId;
|
|
119
129
|
chlor.disabled = disabled;
|
|
120
130
|
chlor.isDosing = isDosing;
|
|
121
131
|
schlor.name = chlor.name = data.name || chlor.name || `Chlorinator ${chlor.id}`;
|
|
122
132
|
schlor.isActive = chlor.isActive = true;
|
|
133
|
+
if (!chlor.superChlor) {
|
|
134
|
+
this.superChlorStart = 0;
|
|
135
|
+
this.superChlorinating = false;
|
|
136
|
+
}
|
|
123
137
|
}
|
|
124
138
|
catch (err) { logger.error(`setChlorinatorAsync: ${err.message}`); return Promise.reject(err); }
|
|
125
139
|
}
|
|
@@ -148,9 +162,23 @@ export class NixieChlorinator extends NixieEquipment {
|
|
|
148
162
|
this.pollEquipment();
|
|
149
163
|
} catch (err) { logger.error(`Error initializing ${this.chlor.name} : ${err.message}`); }
|
|
150
164
|
}
|
|
151
|
-
public isBodyOn() {
|
|
152
|
-
|
|
153
|
-
|
|
165
|
+
public isBodyOn() { return sys.board.bodies.isBodyOn(this.chlor.body); }
|
|
166
|
+
public setSuperChlor(cstate: ChlorinatorState) {
|
|
167
|
+
if (this.chlor.superChlor) {
|
|
168
|
+
if (!this.superChlorinating) {
|
|
169
|
+
// Deal with the start time.
|
|
170
|
+
let hours = this.chlor.superChlorHours * 3600;
|
|
171
|
+
let offset = cstate.superChlorRemaining > 0 ? Math.max((hours - (hours - cstate.superChlorRemaining)), 0) : 0;
|
|
172
|
+
this.superChlorStart = new Date().getTime() - offset;
|
|
173
|
+
this.superChlorinating = true;
|
|
174
|
+
}
|
|
175
|
+
cstate.superChlorRemaining = this.superChlorRemaining;
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
this.superChlorStart = 0;
|
|
179
|
+
this.superChlorinating = false;
|
|
180
|
+
cstate.superChlorRemaining = 0;
|
|
181
|
+
}
|
|
154
182
|
}
|
|
155
183
|
public async pollEquipment() {
|
|
156
184
|
let self = this;
|
|
@@ -190,34 +218,45 @@ export class NixieChlorinator extends NixieEquipment {
|
|
|
190
218
|
// Disable the control panel by sending an action 0 the chlorinator should respond with an action 1.
|
|
191
219
|
//[16, 2, 80, 0][0][98, 16, 3]
|
|
192
220
|
let success = await new Promise<boolean>((resolve, reject) => {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
221
|
+
if (conn.isPortEnabled(this.chlor.portId || 0)) {
|
|
222
|
+
let out = Outbound.create({
|
|
223
|
+
portId: this.chlor.portId || 0,
|
|
224
|
+
protocol: Protocol.Chlorinator,
|
|
225
|
+
//dest: this.chlor.id,
|
|
226
|
+
dest: 1,
|
|
227
|
+
action: 0,
|
|
228
|
+
payload: [0],
|
|
229
|
+
retries: 3, // IntelliCenter tries 4 times to get a response.
|
|
230
|
+
response: Response.create({ protocol: Protocol.Chlorinator, action: 1 }),
|
|
231
|
+
onAbort: () => { this.chlor.superChlor = cstate.superChlor = false; this.setSuperChlor(cstate); },
|
|
232
|
+
onComplete: (err) => {
|
|
233
|
+
if (err) {
|
|
234
|
+
// This flag is cleared in ChlorinatorStateMessage
|
|
235
|
+
this.chlor.superChlor = cstate.superChlor = false;
|
|
236
|
+
this.setSuperChlor(cstate);
|
|
237
|
+
cstate.status = 128;
|
|
238
|
+
resolve(false);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
// If this is successful the action 1 message will have been
|
|
242
|
+
// digested by ChlorinatorStateMessage and the lastComm will have been set clearing the
|
|
243
|
+
// communication lost flag.
|
|
244
|
+
resolve(true);
|
|
245
|
+
}
|
|
246
|
+
cstate.emitEquipmentChange();
|
|
212
247
|
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
|
|
248
|
+
});
|
|
249
|
+
conn.queueSendMessage(out);
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
cstate.status = 0;
|
|
253
|
+
resolve(true);
|
|
254
|
+
}
|
|
216
255
|
});
|
|
217
256
|
return success;
|
|
218
257
|
} catch (err) { logger.error(`Communication error with Chlorinator ${this.chlor.name} : ${err.message}`); }
|
|
219
258
|
}
|
|
220
|
-
public async setOutput() {
|
|
259
|
+
public async setOutput(): Promise<boolean> {
|
|
221
260
|
try {
|
|
222
261
|
// A couple of things need to be in place before setting the output.
|
|
223
262
|
// 1. The chlorinator will have to have responded to the takeControl message.
|
|
@@ -226,57 +265,63 @@ export class NixieChlorinator extends NixieEquipment {
|
|
|
226
265
|
// 3. If we are superchlorinating and the remaing superChlor time is > 0 then we need to keep it at 100%.
|
|
227
266
|
// 4. If the chlorinator disabled flag is set then we need to make sure the setpoint is 0.
|
|
228
267
|
let cstate = state.chlorinators.getItemById(this.chlor.id, true);
|
|
229
|
-
let body = state.temps.bodies.getBodyIsOn();
|
|
230
268
|
let setpoint = 0;
|
|
231
|
-
if (
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
269
|
+
if (this.isBodyOn()) {
|
|
270
|
+
if (sys.equipment.shared) {
|
|
271
|
+
let body = state.temps.bodies.getBodyIsOn();
|
|
272
|
+
setpoint = (body.id === 1) ? this.chlor.poolSetpoint : this.chlor.spaSetpoint;
|
|
273
|
+
}
|
|
274
|
+
else setpoint = this.chlor.body === 0 ? this.chlor.poolSetpoint : this.chlor.spaSetpoint;
|
|
275
|
+
if (this.chlor.isDosing) setpoint = 100;
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
this.chlor.superChlor = cstate.superChlor = false;
|
|
279
|
+
this.setSuperChlor(cstate);
|
|
236
280
|
}
|
|
281
|
+
if (this.chlor.disabled === true) setpoint = 0; // Our target should be 0 because we have other things going on. For instance,
|
|
237
282
|
// RKS: Not sure if it needs to be smart enough to force an off message when the comms die.
|
|
238
283
|
//if (cstate.status === 128) setpoint = 0; // If we haven't been able to get a response from the clorinator tell is to turn itself off.
|
|
239
284
|
// Perhaps we will be luckier on the next poll cycle.
|
|
240
285
|
// Tell the chlorinator that we are to use the current output.
|
|
241
286
|
//[16, 2, 80, 17][0][115, 16, 3]
|
|
242
|
-
cstate.targetOutput = setpoint;
|
|
287
|
+
cstate.targetOutput = cstate.superChlor ? 100 : setpoint;
|
|
243
288
|
let success = await new Promise<boolean>((resolve, reject) => {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
// ChlorinatorStateMessage module.
|
|
261
|
-
cstate.currentOutput = setpoint;
|
|
262
|
-
if (!this.superChlorinating && cstate.superChlor) {
|
|
263
|
-
cstate.superChlorRemaining = cstate.superChlorHours * 3600;
|
|
264
|
-
this.superChlorStart = Math.floor(new Date().getTime() / 1000) * 1000;
|
|
289
|
+
if (conn.isPortEnabled(this.chlor.portId || 0)) {
|
|
290
|
+
let out = Outbound.create({
|
|
291
|
+
portId: this.chlor.portId || 0,
|
|
292
|
+
protocol: Protocol.Chlorinator,
|
|
293
|
+
//dest: this.chlor.id,
|
|
294
|
+
dest: 1,
|
|
295
|
+
action: 17,
|
|
296
|
+
payload: [cstate.targetOutput],
|
|
297
|
+
retries: 7, // IntelliCenter tries 8 times to make this happen.
|
|
298
|
+
response: Response.create({ protocol: Protocol.Chlorinator, action: 18 }),
|
|
299
|
+
onAbort: () => { },
|
|
300
|
+
onComplete: (err) => {
|
|
301
|
+
if (err) {
|
|
302
|
+
cstate.currentOutput = 0;
|
|
303
|
+
cstate.status = 128;
|
|
304
|
+
resolve(false);
|
|
265
305
|
}
|
|
266
|
-
else
|
|
267
|
-
cstate.
|
|
306
|
+
else {
|
|
307
|
+
cstate.currentOutput = cstate.targetOutput;
|
|
308
|
+
this.setSuperChlor(cstate);
|
|
309
|
+
resolve(true);
|
|
268
310
|
}
|
|
269
|
-
else if (!cstate.superChlor)
|
|
270
|
-
cstate.superChlorRemaining = 0;
|
|
271
|
-
resolve(true);
|
|
272
311
|
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
312
|
+
});
|
|
313
|
+
// #338
|
|
314
|
+
if (setpoint === 16) { out.appendPayloadByte(0); }
|
|
315
|
+
conn.queueSendMessage(out);
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
cstate.currentOutput = cstate.targetOutput;
|
|
319
|
+
this.setSuperChlor(cstate);
|
|
320
|
+
resolve(true);
|
|
321
|
+
}
|
|
278
322
|
});
|
|
279
|
-
|
|
323
|
+
cstate.emitEquipmentChange();
|
|
324
|
+
return success;
|
|
280
325
|
} catch (err) { logger.error(`Communication error with Chlorinator ${this.chlor.name} : ${err.message}`); return Promise.reject(err);}
|
|
281
326
|
|
|
282
327
|
}
|
|
@@ -290,25 +335,29 @@ export class NixieChlorinator extends NixieEquipment {
|
|
|
290
335
|
// Ask the chlorinator for its model.
|
|
291
336
|
//[16, 2, 80, 20][0][118, 16, 3]
|
|
292
337
|
let success = await new Promise<boolean>((resolve, reject) => {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
338
|
+
if (conn.isPortEnabled(this.chlor.portId || 0)) {
|
|
339
|
+
let out = Outbound.create({
|
|
340
|
+
portId: this.chlor.portId || 0,
|
|
341
|
+
protocol: Protocol.Chlorinator,
|
|
342
|
+
//dest: this.chlor.id,
|
|
343
|
+
dest: 1,
|
|
344
|
+
action: 20,
|
|
345
|
+
payload: [0],
|
|
346
|
+
retries: 3, // IntelliCenter tries 4 times to get a response.
|
|
347
|
+
response: Response.create({ protocol: Protocol.Chlorinator, action: 3 }),
|
|
348
|
+
onAbort: () => { },
|
|
349
|
+
onComplete: (err) => {
|
|
350
|
+
if (err) resolve(false);
|
|
351
|
+
else resolve(true);
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
conn.queueSendMessage(out);
|
|
355
|
+
}
|
|
356
|
+
else { resolve(true); }
|
|
307
357
|
});
|
|
358
|
+
return success;
|
|
308
359
|
}
|
|
309
|
-
else return
|
|
360
|
+
else return false;
|
|
310
361
|
} catch (err) { logger.error(`Communication error with Chlorinator ${this.chlor.name} : ${err.message}`); return Promise.reject(err);}
|
|
311
|
-
|
|
312
362
|
}
|
|
313
|
-
|
|
314
363
|
}
|
|
@@ -8,6 +8,7 @@ import { CircuitState, state, ICircuitState, } from "../../State";
|
|
|
8
8
|
import { setTimeout, clearTimeout } from 'timers';
|
|
9
9
|
import { NixieControlPanel } from '../Nixie';
|
|
10
10
|
import { webApp, InterfaceServerResponse } from "../../../web/Server";
|
|
11
|
+
import { delayMgr } from '../../../controller/Lockouts';
|
|
11
12
|
|
|
12
13
|
export class NixieCircuitCollection extends NixieEquipmentCollection<NixieCircuit> {
|
|
13
14
|
public pollingInterval: number = 2000;
|
|
@@ -23,7 +24,7 @@ export class NixieCircuitCollection extends NixieEquipmentCollection<NixieCircui
|
|
|
23
24
|
}
|
|
24
25
|
} catch (err) { return Promise.reject(`Nixie Control Panel deleteCircuitAsync ${err.message}`); }
|
|
25
26
|
}
|
|
26
|
-
public async sendOnOffSequenceAsync(id: number, count: number) {
|
|
27
|
+
public async sendOnOffSequenceAsync(id: number, count: number | { isOn: boolean, timeout: number }[]) {
|
|
27
28
|
try {
|
|
28
29
|
let c: NixieCircuit = this.find(elem => elem.id === id) as NixieCircuit;
|
|
29
30
|
if (typeof c === 'undefined') return Promise.reject(new Error(`NCP: Circuit ${id} could not be found to send sequence ${count}.`));
|
|
@@ -60,7 +61,7 @@ export class NixieCircuitCollection extends NixieEquipmentCollection<NixieCircui
|
|
|
60
61
|
try {
|
|
61
62
|
let c: NixieCircuit = this.find(elem => elem.id === cstate.id) as NixieCircuit;
|
|
62
63
|
await c.checkCircuitEggTimerExpirationAsync(cstate);
|
|
63
|
-
} catch (err) { logger.error(`NCP: Error
|
|
64
|
+
} catch (err) { logger.error(`NCP: Error synching circuit states: ${err}`); }
|
|
64
65
|
}
|
|
65
66
|
public async initAsync(circuits: CircuitCollection) {
|
|
66
67
|
try {
|
|
@@ -118,6 +119,10 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
118
119
|
constructor(ncp: INixieControlPanel, circuit: Circuit) {
|
|
119
120
|
super(ncp);
|
|
120
121
|
this.circuit = circuit;
|
|
122
|
+
// Clear out the delays.
|
|
123
|
+
let cstate = state.circuits.getItemById(circuit.id);
|
|
124
|
+
cstate.startDelay = false;
|
|
125
|
+
cstate.stopDelay = false;
|
|
121
126
|
}
|
|
122
127
|
public get id(): number { return typeof this.circuit !== 'undefined' ? this.circuit.id : -1; }
|
|
123
128
|
public get eggTimerOff(): Timestamp { return typeof this.timeOn !== 'undefined' && !this.circuit.dontStop ? this.timeOn.clone().addMinutes(this.circuit.eggTimer) : undefined; }
|
|
@@ -127,17 +132,20 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
127
132
|
}
|
|
128
133
|
catch (err) { logger.error(`Nixie setCircuitAsync: ${err.message}`); return Promise.reject(err); }
|
|
129
134
|
}
|
|
130
|
-
public async sendOnOffSequenceAsync(count: number, timeout?:number): Promise<InterfaceServerResponse> {
|
|
135
|
+
public async sendOnOffSequenceAsync(count: number | { isOn: boolean, timeout: number }[], timeout?:number): Promise<InterfaceServerResponse> {
|
|
131
136
|
try {
|
|
132
137
|
this._sequencing = true;
|
|
133
138
|
let arr = [];
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
139
|
+
if (typeof count === 'number') {
|
|
140
|
+
let t = typeof timeout === 'undefined' ? 100 : timeout;
|
|
141
|
+
arr.push({ isOn: false, timeout: t }); // This may not be needed but we always need to start from off.
|
|
142
|
+
//[{ isOn: true, timeout: 1000 }, { isOn: false, timeout: 1000 }]
|
|
143
|
+
for (let i = 0; i < count; i++) {
|
|
144
|
+
arr.push({ isOn: true, timeout: t });
|
|
145
|
+
if (i < count - 1) arr.push({ isOn: false, timeout: t });
|
|
146
|
+
}
|
|
140
147
|
}
|
|
148
|
+
else arr = count;
|
|
141
149
|
// The documentation for IntelliBrite is incorrect. The sequence below will give us Party mode.
|
|
142
150
|
// Party mode:2
|
|
143
151
|
// Start: Off
|
|
@@ -157,7 +165,15 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
157
165
|
} catch (err) { logger.error(`Nixie: Error sending circuit sequence ${this.id}: ${count}`); }
|
|
158
166
|
finally { this._sequencing = false; }
|
|
159
167
|
}
|
|
160
|
-
public async
|
|
168
|
+
public async setThemeAsync(cstate: ICircuitState, theme: number): Promise<InterfaceServerResponse> {
|
|
169
|
+
try {
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
return new InterfaceServerResponse(200, 'Sucess');
|
|
174
|
+
} catch (err) { logger.error(`Nixie: Error setting light theme ${cstate.id}-${cstate.name} to ${theme}`); }
|
|
175
|
+
}
|
|
176
|
+
public async setCircuitStateAsync(cstate: ICircuitState, val: boolean, scheduled: boolean = false): Promise<InterfaceServerResponse> {
|
|
161
177
|
try {
|
|
162
178
|
if (val !== cstate.isOn) {
|
|
163
179
|
logger.info(`NCP: Setting Circuit ${cstate.name} to ${val}`);
|
|
@@ -169,18 +185,30 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
169
185
|
// Check to see if we should be on by poking the schedules.
|
|
170
186
|
}
|
|
171
187
|
if (utils.isNullOrEmpty(this.circuit.connectionId) || utils.isNullOrEmpty(this.circuit.deviceBinding)) {
|
|
172
|
-
|
|
173
|
-
|
|
188
|
+
if (val && val !== cstate.isOn){
|
|
189
|
+
sys.board.circuits.setEndTime(sys.circuits.getInterfaceById(cstate.id), cstate, val);
|
|
190
|
+
}
|
|
191
|
+
else if (!val){
|
|
192
|
+
if (cstate.manualPriorityActive) delayMgr.cancelManualPriorityDelay(cstate.id);
|
|
193
|
+
cstate.manualPriorityActive = false; // if the delay was previously cancelled, still need to turn this off
|
|
194
|
+
}
|
|
195
|
+
cstate.isOn = val;
|
|
174
196
|
return new InterfaceServerResponse(200, 'Success');
|
|
175
197
|
}
|
|
176
198
|
if (this._sequencing) return new InterfaceServerResponse(200, 'Success');
|
|
177
199
|
let res = await NixieEquipment.putDeviceService(this.circuit.connectionId, `/state/device/${this.circuit.deviceBinding}`, { isOn: val, latch: val ? 10000 : undefined });
|
|
178
200
|
if (res.status.code === 200) {
|
|
179
|
-
sys.board.circuits.setEndTime(sys.circuits.getInterfaceById(cstate.id), cstate, val);
|
|
180
|
-
cstate.isOn = val;
|
|
181
201
|
// Set this up so we can process our egg timer.
|
|
182
|
-
if (!cstate.isOn && val) { this.timeOn = new Timestamp(); }
|
|
183
|
-
else if (!val) this.timeOn = undefined;
|
|
202
|
+
//if (!cstate.isOn && val) { cstate.startTime = this.timeOn = new Timestamp(); }
|
|
203
|
+
//else if (!val) cstate.startTime = this.timeOn = undefined;
|
|
204
|
+
if (val && val !== cstate.isOn){
|
|
205
|
+
sys.board.circuits.setEndTime(sys.circuits.getInterfaceById(cstate.id), cstate, val);
|
|
206
|
+
}
|
|
207
|
+
else if (!val){
|
|
208
|
+
delayMgr.cancelManualPriorityDelays();
|
|
209
|
+
cstate.manualPriorityActive = false; // if the delay was previously cancelled, still need to turn this off
|
|
210
|
+
}
|
|
211
|
+
cstate.isOn = val;
|
|
184
212
|
}
|
|
185
213
|
return res;
|
|
186
214
|
} catch (err) { logger.error(`Nixie: Error setting circuit state ${cstate.id}-${cstate.name} to ${val}`); }
|
|
@@ -190,9 +218,11 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
190
218
|
// (this should already be turned off) or the egg timer has expired
|
|
191
219
|
try {
|
|
192
220
|
if (!cstate.isActive || !cstate.isOn) return;
|
|
193
|
-
if (cstate.endTime
|
|
194
|
-
|
|
195
|
-
|
|
221
|
+
if (typeof cstate.endTime !== 'undefined') {
|
|
222
|
+
if (cstate.endTime.toDate() < new Timestamp().toDate()) {
|
|
223
|
+
await sys.board.circuits.setCircuitStateAsync(cstate.id, false);
|
|
224
|
+
cstate.emitEquipmentChange();
|
|
225
|
+
}
|
|
196
226
|
}
|
|
197
227
|
} catch (err) { logger.error(`Error syncing circuit: ${err}`); }
|
|
198
228
|
}
|
|
@@ -220,6 +250,8 @@ export class NixieCircuit extends NixieEquipment {
|
|
|
220
250
|
public async closeAsync() {
|
|
221
251
|
try {
|
|
222
252
|
let cstate = state.circuits.getItemById(this.circuit.id);
|
|
253
|
+
cstate.stopDelay = false;
|
|
254
|
+
cstate.startDelay = false;
|
|
223
255
|
await this.setCircuitStateAsync(cstate, false);
|
|
224
256
|
cstate.emitEquipmentChange();
|
|
225
257
|
}
|