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
|
@@ -215,8 +215,8 @@ export class NixiePump extends NixieEquipment {
|
|
|
215
215
|
if (typeof this._pollTimer !== 'undefined' || this._pollTimer) clearTimeout(this._pollTimer);
|
|
216
216
|
this._pollTimer = null;
|
|
217
217
|
// let success = false;
|
|
218
|
-
this.setTargetSpeed();
|
|
219
218
|
let pstate = state.pumps.getItemById(this.pump.id);
|
|
219
|
+
this.setTargetSpeed(pstate);
|
|
220
220
|
await this.setPumpStateAsync(pstate);
|
|
221
221
|
}
|
|
222
222
|
catch (err) { logger.error(`Nixie Error running pump sequence - ${err}`); }
|
|
@@ -239,7 +239,10 @@ export class NixiePump extends NixieEquipment {
|
|
|
239
239
|
this._pollTimer = null;
|
|
240
240
|
this._targetSpeed = 0;
|
|
241
241
|
let pstate = state.pumps.getItemById(this.pump.id);
|
|
242
|
-
|
|
242
|
+
try {
|
|
243
|
+
await this.setPumpStateAsync(pstate);
|
|
244
|
+
// Since we are closing we need to not reject.
|
|
245
|
+
} catch (err) { logger.error(`Nixie Closing pump closeAsync: ${err.message}`); }
|
|
243
246
|
// This will make sure the timer is dead and we are completely closed.
|
|
244
247
|
this.closing = true;
|
|
245
248
|
if (typeof this._pollTimer !== 'undefined' || this._pollTimer) clearTimeout(this._pollTimer);
|
|
@@ -248,19 +251,43 @@ export class NixiePump extends NixieEquipment {
|
|
|
248
251
|
catch (err) { logger.error(`Nixie Pump closeAsync: ${err.message}`); return Promise.reject(err); }
|
|
249
252
|
}
|
|
250
253
|
public logData(filename: string, data: any) { this.controlPanel.logData(filename, data); }
|
|
251
|
-
protected setTargetSpeed() { };
|
|
254
|
+
protected setTargetSpeed(pstate: PumpState) { };
|
|
255
|
+
protected isBodyOn(bodyCode: number) {
|
|
256
|
+
let assoc = sys.board.valueMaps.pumpBodies.transform(bodyCode);
|
|
257
|
+
switch (assoc.name) {
|
|
258
|
+
case 'body1':
|
|
259
|
+
case 'pool':
|
|
260
|
+
return state.temps.bodies.getItemById(1).isOn;
|
|
261
|
+
case 'body2':
|
|
262
|
+
case 'spa':
|
|
263
|
+
return state.temps.bodies.getItemById(2).isOn;
|
|
264
|
+
case 'body3':
|
|
265
|
+
return state.temps.bodies.getItemById(3).isOn;
|
|
266
|
+
case 'body4':
|
|
267
|
+
return state.temps.bodies.getItemById(4).isOn;
|
|
268
|
+
case 'poolspa':
|
|
269
|
+
if (sys.equipment.shared && sys.equipment.maxBodies >= 2) {
|
|
270
|
+
return state.temps.bodies.getItemById(1).isOn === true || state.temps.bodies.getItemById(2).isOn === true;
|
|
271
|
+
}
|
|
272
|
+
else
|
|
273
|
+
return state.temps.bodies.getItemById(1).isOn;
|
|
274
|
+
}
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
252
277
|
}
|
|
253
278
|
export class NixiePumpSS extends NixiePump {
|
|
254
|
-
public setTargetSpeed() {
|
|
279
|
+
public setTargetSpeed(pState: PumpState) {
|
|
255
280
|
// Turn on ss pumps.
|
|
256
281
|
let _newSpeed = 0;
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
282
|
+
if (!pState.pumpOnDelay) {
|
|
283
|
+
let pt = sys.board.valueMaps.pumpTypes.get(this.pump.type);
|
|
284
|
+
if (pt.hasBody) _newSpeed = this.isBodyOn(this.pump.body) ? 1 : 0;
|
|
285
|
+
//console.log(`BODY: ${sys.board.bodies.isBodyOn(this.pump.body)} CODE: ${this.pump.body}`);
|
|
286
|
+
}
|
|
287
|
+
if (this._targetSpeed !== _newSpeed) logger.info(`NCP: Setting Pump ${this.pump.name} to ${_newSpeed > 0 ? 'on' : 'off'}. ${sys.board.bodies.isBodyOn(this.pump.body)}`);
|
|
260
288
|
if (isNaN(_newSpeed)) _newSpeed = 0;
|
|
261
289
|
this._targetSpeed = _newSpeed;
|
|
262
290
|
}
|
|
263
|
-
|
|
264
291
|
public async setPumpStateAsync(pstate: PumpState) {
|
|
265
292
|
let relays: PumpRelay[] = this.pump.relays.get();
|
|
266
293
|
let relayState = 0;
|
|
@@ -301,16 +328,20 @@ export class NixiePumpSS extends NixiePump {
|
|
|
301
328
|
}
|
|
302
329
|
}
|
|
303
330
|
export class NixiePumpDS extends NixiePumpSS {
|
|
304
|
-
public setTargetSpeed() {
|
|
331
|
+
public setTargetSpeed(pState: PumpState) {
|
|
305
332
|
// Turn on sf pumps. The new speed will be the relays associated with the pump. I believe when this comes out in the final
|
|
306
333
|
// wash it should engage all the relays for all speeds associated with the pump. The pump logic will determine which program is
|
|
307
334
|
// the one to engage.
|
|
308
335
|
let _newSpeed = 0;
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
336
|
+
if (!pState.pumpOnDelay) {
|
|
337
|
+
let pumpCircuits: PumpCircuit[] = this.pump.circuits.get();
|
|
338
|
+
if (!pState.pumpOnDelay) {
|
|
339
|
+
for (let i = 0; i < pumpCircuits.length; i++) {
|
|
340
|
+
let circ = state.circuits.getInterfaceById(pumpCircuits[i].circuit);
|
|
341
|
+
// relay speeds are bit-shifted 'or' based on 1,2,4,8
|
|
342
|
+
if (circ.isOn) _newSpeed |= (1 << pumpCircuits[i].relay - 1);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
314
345
|
}
|
|
315
346
|
if (isNaN(_newSpeed)) _newSpeed = 0;
|
|
316
347
|
this.logSpeed(_newSpeed);
|
|
@@ -335,15 +366,16 @@ export class NixiePumpRS485 extends NixiePump {
|
|
|
335
366
|
let pt = sys.board.valueMaps.pumpTypes.get(this.pump.type);
|
|
336
367
|
// Since these process are async the closing flag can be set
|
|
337
368
|
// between calls. We need to check it in between each call.
|
|
338
|
-
if (!this.closing) await this.setDriveStateAsync(
|
|
339
|
-
if (!this.closing) {
|
|
340
|
-
if (this._targetSpeed >= pt.minFlow && this._targetSpeed <= pt.maxFlow) await this.setPumpGPMAsync(
|
|
341
|
-
else if (this._targetSpeed >= pt.minSpeed && this._targetSpeed <= pt.maxSpeed) await this.setPumpRPMAsync(
|
|
342
|
-
}
|
|
369
|
+
try { if (!this.closing) await this.setDriveStateAsync(); } catch (err) {}
|
|
370
|
+
try { if (!this.closing) {
|
|
371
|
+
if (this._targetSpeed >= pt.minFlow && this._targetSpeed <= pt.maxFlow) await this.setPumpGPMAsync();
|
|
372
|
+
else if (this._targetSpeed >= pt.minSpeed && this._targetSpeed <= pt.maxSpeed) await this.setPumpRPMAsync();
|
|
373
|
+
} } catch (err) {}
|
|
343
374
|
|
|
344
|
-
if(!this.closing) await
|
|
345
|
-
if(!this.closing) await
|
|
346
|
-
if(!this.closing) await this.
|
|
375
|
+
try { if(!this.closing) await this.setPumpFeature(6); } catch (err) {};
|
|
376
|
+
try { if(!this.closing) await utils.sleep(1000); } catch (err) {};
|
|
377
|
+
try { if(!this.closing) await this.requestPumpStatus(); } catch (err) {};
|
|
378
|
+
try { if(!this.closing) await this.setPumpToRemoteControl(); } catch (err) {};
|
|
347
379
|
return new InterfaceServerResponse(200, 'Success');
|
|
348
380
|
}
|
|
349
381
|
catch (err) {
|
|
@@ -351,9 +383,8 @@ export class NixiePumpRS485 extends NixiePump {
|
|
|
351
383
|
return Promise.reject(err);
|
|
352
384
|
}
|
|
353
385
|
finally { this.suspendPolling = false; }
|
|
354
|
-
|
|
355
386
|
};
|
|
356
|
-
protected async setDriveStateAsync(
|
|
387
|
+
protected async setDriveStateAsync(running: boolean = true) {
|
|
357
388
|
return new Promise<void>((resolve, reject) => {
|
|
358
389
|
let out = Outbound.create({
|
|
359
390
|
protocol: Protocol.Pump,
|
|
@@ -373,7 +404,7 @@ export class NixiePumpRS485 extends NixiePump {
|
|
|
373
404
|
conn.queueSendMessage(out);
|
|
374
405
|
});
|
|
375
406
|
};
|
|
376
|
-
protected async requestPumpStatus(
|
|
407
|
+
protected async requestPumpStatus() {
|
|
377
408
|
return new Promise<void>((resolve, reject) => {
|
|
378
409
|
let out = Outbound.create({
|
|
379
410
|
protocol: Protocol.Pump,
|
|
@@ -393,7 +424,7 @@ export class NixiePumpRS485 extends NixiePump {
|
|
|
393
424
|
conn.queueSendMessage(out);
|
|
394
425
|
})
|
|
395
426
|
};
|
|
396
|
-
protected setPumpToRemoteControl(
|
|
427
|
+
protected setPumpToRemoteControl(running: boolean = true) {
|
|
397
428
|
return new Promise<void>((resolve, reject) => {
|
|
398
429
|
let out = Outbound.create({
|
|
399
430
|
protocol: Protocol.Pump,
|
|
@@ -414,13 +445,15 @@ export class NixiePumpRS485 extends NixiePump {
|
|
|
414
445
|
conn.queueSendMessage(out);
|
|
415
446
|
});
|
|
416
447
|
}
|
|
417
|
-
protected
|
|
448
|
+
protected setPumpFeature(feature?: number) {
|
|
449
|
+
// empty payload (possibly 0?, too) is no feature
|
|
450
|
+
// 6: Feature 1
|
|
418
451
|
return new Promise<void>((resolve, reject) => {
|
|
419
452
|
let out = Outbound.create({
|
|
420
453
|
protocol: Protocol.Pump,
|
|
421
454
|
dest: this.pump.address,
|
|
422
455
|
action: 5,
|
|
423
|
-
payload: [],
|
|
456
|
+
payload: typeof feature === 'undefined' ? [] : [ feature ],
|
|
424
457
|
retries: 2,
|
|
425
458
|
repsonse: true,
|
|
426
459
|
onComplete: (err, msg: Outbound) => {
|
|
@@ -434,7 +467,7 @@ export class NixiePumpRS485 extends NixiePump {
|
|
|
434
467
|
conn.queueSendMessage(out);
|
|
435
468
|
});
|
|
436
469
|
};
|
|
437
|
-
protected async setPumpRPMAsync(
|
|
470
|
+
protected async setPumpRPMAsync() {
|
|
438
471
|
return new Promise<void>((resolve, reject) => {
|
|
439
472
|
let out = Outbound.create({
|
|
440
473
|
protocol: Protocol.Pump,
|
|
@@ -455,14 +488,14 @@ export class NixiePumpRS485 extends NixiePump {
|
|
|
455
488
|
conn.queueSendMessage(out);
|
|
456
489
|
});
|
|
457
490
|
};
|
|
458
|
-
protected async setPumpGPMAsync(
|
|
491
|
+
protected async setPumpGPMAsync() {
|
|
459
492
|
// packet for vf; vsf will override
|
|
460
493
|
return new Promise<void>((resolve, reject) => {
|
|
461
494
|
let out = Outbound.create({
|
|
462
495
|
protocol: Protocol.Pump,
|
|
463
496
|
dest: this.pump.address,
|
|
464
|
-
action:
|
|
465
|
-
payload: [
|
|
497
|
+
action: 1,
|
|
498
|
+
payload: [2, 228, 0, this._targetSpeed],
|
|
466
499
|
retries: 1,
|
|
467
500
|
response: true,
|
|
468
501
|
onComplete: (err, msg) => {
|
|
@@ -484,10 +517,10 @@ export class NixiePumpRS485 extends NixiePump {
|
|
|
484
517
|
this._pollTimer = null;
|
|
485
518
|
let pstate = state.pumps.getItemById(this.pump.id);
|
|
486
519
|
this._targetSpeed = 0;
|
|
487
|
-
try { await this.setDriveStateAsync(
|
|
488
|
-
try { await this.
|
|
489
|
-
try { await this.setDriveStateAsync(
|
|
490
|
-
try { await this.setPumpToRemoteControl(
|
|
520
|
+
try { await this.setDriveStateAsync(false); } catch (err) { logger.error(`Error closing pump ${this.pump.name}: ${err.message}`) }
|
|
521
|
+
try { await this.setPumpFeature(); } catch (err) { logger.error(`Error closing pump ${this.pump.name}: ${err.message}`) }
|
|
522
|
+
try { await this.setDriveStateAsync(false); } catch (err) { logger.error(`Error closing pump ${this.pump.name}: ${err.message}`) }
|
|
523
|
+
try { await this.setPumpToRemoteControl(false); } catch (err) { logger.error(`Error closing pump ${this.pump.name}: ${err.message}`) }
|
|
491
524
|
this.closing = true;
|
|
492
525
|
// Make sure the polling timer is dead after we have closted this all off. That way we do not
|
|
493
526
|
// have another process that revives it from the dead.
|
|
@@ -500,88 +533,117 @@ export class NixiePumpRS485 extends NixiePump {
|
|
|
500
533
|
}
|
|
501
534
|
}
|
|
502
535
|
export class NixiePumpVS extends NixiePumpRS485 {
|
|
503
|
-
public setTargetSpeed() {
|
|
536
|
+
public setTargetSpeed(pState: PumpState) {
|
|
504
537
|
let _newSpeed = 0;
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
let
|
|
509
|
-
|
|
538
|
+
if (!pState.pumpOnDelay) {
|
|
539
|
+
let pumpCircuits = this.pump.circuits.get();
|
|
540
|
+
|
|
541
|
+
for (let i = 0; i < pumpCircuits.length; i++) {
|
|
542
|
+
let circ = state.circuits.getInterfaceById(pumpCircuits[i].circuit);
|
|
543
|
+
let pc = pumpCircuits[i];
|
|
544
|
+
if (circ.isOn) _newSpeed = Math.max(_newSpeed, pc.speed);
|
|
545
|
+
}
|
|
510
546
|
}
|
|
511
547
|
if (isNaN(_newSpeed)) _newSpeed = 0;
|
|
548
|
+
this._targetSpeed = _newSpeed;
|
|
512
549
|
if (this._targetSpeed !== 0) Math.min(Math.max(this.pump.minSpeed, this._targetSpeed), this.pump.maxSpeed);
|
|
513
550
|
if (this._targetSpeed !== _newSpeed) logger.info(`NCP: Setting Pump ${this.pump.name} to ${_newSpeed} RPM.`);
|
|
514
|
-
this._targetSpeed = _newSpeed;
|
|
515
551
|
}
|
|
516
552
|
}
|
|
517
553
|
export class NixiePumpVF extends NixiePumpRS485 {
|
|
518
|
-
public setTargetSpeed() {
|
|
554
|
+
public setTargetSpeed(pState: PumpState) {
|
|
519
555
|
let _newSpeed = 0;
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
let
|
|
523
|
-
|
|
524
|
-
|
|
556
|
+
if (!pState.pumpOnDelay) {
|
|
557
|
+
let pumpCircuits = this.pump.circuits.get();
|
|
558
|
+
for (let i = 0; i < pumpCircuits.length; i++) {
|
|
559
|
+
let circ = state.circuits.getInterfaceById(pumpCircuits[i].circuit);
|
|
560
|
+
let pc = pumpCircuits[i];
|
|
561
|
+
if (circ.isOn) _newSpeed = Math.max(_newSpeed, pc.flow);
|
|
562
|
+
}
|
|
525
563
|
}
|
|
526
564
|
if (isNaN(_newSpeed)) _newSpeed = 0;
|
|
565
|
+
this._targetSpeed = _newSpeed;
|
|
527
566
|
if (this._targetSpeed !== 0) Math.min(Math.max(this.pump.minFlow, this._targetSpeed), this.pump.maxFlow);
|
|
528
567
|
if (this._targetSpeed !== _newSpeed) logger.info(`NCP: Setting Pump ${this.pump.name} to ${_newSpeed} GPM.`);
|
|
529
|
-
this._targetSpeed = _newSpeed;
|
|
530
568
|
}
|
|
531
569
|
}
|
|
532
570
|
export class NixiePumpVSF extends NixiePumpRS485 {
|
|
533
|
-
public setTargetSpeed() {
|
|
571
|
+
public setTargetSpeed(pState: PumpState) {
|
|
534
572
|
let _newSpeed = 0;
|
|
535
|
-
let pumpCircuits = this.pump.circuits.get();
|
|
536
|
-
let pt = sys.board.valueMaps.pumpTypes.get(this.pump.type);
|
|
537
|
-
// VSF pumps present a problem. In fact they do not currently operate properly on Touch panels. On touch these need to either be all in RPM or GPM
|
|
538
|
-
// if there is a mix in the circuit array then they will not work. In IntelliCenter if there is an RPM setting in the mix it will use RPM by converting
|
|
539
|
-
// the GPM to RPM but if there is none then it will use GPM.
|
|
540
573
|
let maxRPM = 0;
|
|
541
574
|
let maxGPM = 0;
|
|
542
575
|
let flows = 0;
|
|
543
576
|
let speeds = 0;
|
|
544
|
-
|
|
545
|
-
let
|
|
546
|
-
let
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
let
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
let
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
577
|
+
if (!pState.pumpOnDelay) {
|
|
578
|
+
let pumpCircuits = this.pump.circuits.get();
|
|
579
|
+
let pt = sys.board.valueMaps.pumpTypes.get(this.pump.type);
|
|
580
|
+
// VSF pumps present a problem. In fact they do not currently operate properly on Touch panels. On touch these need to either be all in RPM or GPM
|
|
581
|
+
// if there is a mix in the circuit array then they will not work. In IntelliCenter if there is an RPM setting in the mix it will use RPM by converting
|
|
582
|
+
// the GPM to RPM but if there is none then it will use GPM.
|
|
583
|
+
let toRPM = (flowRate: number, minSpeed: number = 450, maxSpeed: number = 3450) => {
|
|
584
|
+
let eff = .03317 * maxSpeed;
|
|
585
|
+
let rpm = Math.min((flowRate * maxSpeed) / eff, maxSpeed);
|
|
586
|
+
return rpm > 0 ? Math.max(rpm, minSpeed) : 0;
|
|
587
|
+
};
|
|
588
|
+
let toGPM = (speed: number, maxSpeed: number = 3450, minFlow: number = 15, maxFlow: number = 140) => {
|
|
589
|
+
let eff = .03317 * maxSpeed;
|
|
590
|
+
let gpm = Math.min((eff * speed) / maxSpeed, maxFlow);
|
|
591
|
+
return gpm > 0 ? Math.max(gpm, minFlow) : 0;
|
|
592
|
+
}
|
|
593
|
+
for (let i = 0; i < pumpCircuits.length; i++) {
|
|
594
|
+
let circ = state.circuits.getInterfaceById(pumpCircuits[i].circuit);
|
|
595
|
+
let pc = pumpCircuits[i];
|
|
596
|
+
if (circ.isOn) {
|
|
597
|
+
if (pc.units > 0) {
|
|
598
|
+
maxGPM = Math.max(maxGPM, pc.flow);
|
|
599
|
+
// Calculate an RPM from this flow.
|
|
600
|
+
maxRPM = Math.max(maxGPM, toRPM(pc.flow, pt.minSpeed, pt.maxSpeed));
|
|
601
|
+
flows++;
|
|
602
|
+
}
|
|
603
|
+
else {
|
|
604
|
+
maxRPM = Math.max(maxRPM, pc.speed);
|
|
605
|
+
maxGPM = Math.max(maxGPM, toGPM(pc.speed, pt.maxSpeed, pt.minFlow, pt.maxFlow));
|
|
606
|
+
speeds++;
|
|
607
|
+
}
|
|
568
608
|
}
|
|
569
609
|
}
|
|
610
|
+
_newSpeed = speeds > 0 || flows === 0 ? maxRPM : maxGPM;
|
|
570
611
|
}
|
|
571
|
-
_newSpeed = speeds > 0 || flows === 0 ? maxRPM : maxGPM;
|
|
572
612
|
if (isNaN(_newSpeed)) _newSpeed = 0;
|
|
573
613
|
// Send the flow message if it is flow and the rpm message if it is rpm.
|
|
574
614
|
if (this._targetSpeed !== _newSpeed) logger.info(`NCP: Setting Pump ${this.pump.name} to ${_newSpeed} ${flows > 0 ? 'GPM' : 'RPM'}.`);
|
|
575
615
|
this._targetSpeed = _newSpeed;
|
|
576
616
|
}
|
|
577
|
-
protected async
|
|
578
|
-
// vsf
|
|
617
|
+
protected async setPumpRPMAsync() {
|
|
618
|
+
// vsf action is 10 for rpm
|
|
579
619
|
return new Promise<void>((resolve, reject) => {
|
|
580
620
|
let out = Outbound.create({
|
|
581
621
|
protocol: Protocol.Pump,
|
|
582
622
|
dest: this.pump.address,
|
|
583
623
|
action: 10,
|
|
584
|
-
payload: [
|
|
624
|
+
payload: [2, 196, Math.floor(this._targetSpeed / 256), this._targetSpeed % 256],
|
|
625
|
+
retries: 1,
|
|
626
|
+
// timeout: 250,
|
|
627
|
+
response: true,
|
|
628
|
+
onComplete: (err, msg) => {
|
|
629
|
+
if (err) {
|
|
630
|
+
logger.error(`Error sending setPumpRPMAsync for ${this.pump.name}: ${err.message}`);
|
|
631
|
+
reject(err);
|
|
632
|
+
}
|
|
633
|
+
else resolve();
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
conn.queueSendMessage(out);
|
|
637
|
+
});
|
|
638
|
+
};
|
|
639
|
+
protected async setPumpGPMAsync() {
|
|
640
|
+
// vsf payload; different from vf payload
|
|
641
|
+
return new Promise<void>((resolve, reject) => {
|
|
642
|
+
let out = Outbound.create({
|
|
643
|
+
protocol: Protocol.Pump,
|
|
644
|
+
dest: this.pump.address,
|
|
645
|
+
action: 9,
|
|
646
|
+
payload: [2, 196, 0, this._targetSpeed],
|
|
585
647
|
retries: 1,
|
|
586
648
|
response: true,
|
|
587
649
|
onComplete: (err, msg) => {
|
|
@@ -141,8 +141,9 @@ export class NixieSchedule extends NixieEquipment {
|
|
|
141
141
|
let body = sys.bodies.find(elem => elem.circuit === circuit.id);
|
|
142
142
|
if (typeof body !== 'undefined') {
|
|
143
143
|
let heatSource = sys.board.valueMaps.heatSources.transform(this.schedule.heatSource);
|
|
144
|
-
if (heatSource !== 'nochange') {
|
|
144
|
+
if (heatSource.name !== 'nochange') {
|
|
145
145
|
switch (heatSource.name) {
|
|
146
|
+
case 'nochange':
|
|
146
147
|
case 'dontchange':
|
|
147
148
|
break;
|
|
148
149
|
case 'off':
|
|
@@ -233,7 +234,7 @@ export class NixieSchedule extends NixieEquipment {
|
|
|
233
234
|
}
|
|
234
235
|
public logData(filename: string, data: any) { this.controlPanel.logData(filename, data); }
|
|
235
236
|
}
|
|
236
|
-
class
|
|
237
|
+
class NixieScheduleContext {
|
|
237
238
|
constructor() {
|
|
238
239
|
|
|
239
240
|
}
|
|
@@ -102,7 +102,7 @@ export class NixieValve extends NixieEquipment {
|
|
|
102
102
|
try {
|
|
103
103
|
// Here we go we need to set the valve state.
|
|
104
104
|
if (vstate.isDiverted !== isDiverted) {
|
|
105
|
-
logger.
|
|
105
|
+
logger.verbose(`Nixie: Set valve ${vstate.id}-${vstate.name} to ${isDiverted}`);
|
|
106
106
|
}
|
|
107
107
|
if (utils.isNullOrEmpty(this.valve.connectionId) || utils.isNullOrEmpty(this.valve.deviceBinding)) {
|
|
108
108
|
vstate.isDiverted = isDiverted;
|
package/defaultConfig.json
CHANGED
|
@@ -17,7 +17,18 @@
|
|
|
17
17
|
"autoOpen": false,
|
|
18
18
|
"lock": false
|
|
19
19
|
}
|
|
20
|
+
},
|
|
21
|
+
"backups": {
|
|
22
|
+
"automatic": false,
|
|
23
|
+
"interval": {
|
|
24
|
+
"days": 30,
|
|
25
|
+
"hours": 0
|
|
26
|
+
},
|
|
27
|
+
"keepCount": 5,
|
|
28
|
+
"njsPC": true,
|
|
29
|
+
"servers": []
|
|
20
30
|
}
|
|
31
|
+
|
|
21
32
|
},
|
|
22
33
|
"web": {
|
|
23
34
|
"servers": {
|
|
@@ -52,6 +63,7 @@
|
|
|
52
63
|
"interfaces": {
|
|
53
64
|
"smartThings": {
|
|
54
65
|
"name": "SmartThings",
|
|
66
|
+
"type": "rest",
|
|
55
67
|
"enabled": false,
|
|
56
68
|
"fileName": "smartThings-Hubitat.json",
|
|
57
69
|
"globals": {},
|
|
@@ -62,6 +74,7 @@
|
|
|
62
74
|
},
|
|
63
75
|
"hubitat": {
|
|
64
76
|
"name": "Hubitat",
|
|
77
|
+
"type": "rest",
|
|
65
78
|
"enabled": false,
|
|
66
79
|
"fileName": "smartThings-Hubitat.json",
|
|
67
80
|
"globals": {},
|
|
@@ -72,6 +85,7 @@
|
|
|
72
85
|
},
|
|
73
86
|
"vera": {
|
|
74
87
|
"name": "Vera",
|
|
88
|
+
"type": "rest",
|
|
75
89
|
"enabled": false,
|
|
76
90
|
"fileName": "vera.json",
|
|
77
91
|
"vars": {
|
|
@@ -83,6 +97,7 @@
|
|
|
83
97
|
}
|
|
84
98
|
},
|
|
85
99
|
"valveRelay": {
|
|
100
|
+
"type": "rest",
|
|
86
101
|
"name": "Valve Relays",
|
|
87
102
|
"enabled": false,
|
|
88
103
|
"fileName": "valveRelays.json",
|
|
@@ -100,15 +115,31 @@
|
|
|
100
115
|
"enabled": false,
|
|
101
116
|
"fileName": "influxDB.json",
|
|
102
117
|
"options": {
|
|
118
|
+
"version": 1,
|
|
103
119
|
"protocol": "http",
|
|
104
120
|
"host": "192.168.0.1",
|
|
105
|
-
"port":
|
|
121
|
+
"port": 9999,
|
|
106
122
|
"username": "",
|
|
107
123
|
"password": "",
|
|
108
124
|
"database": "pool",
|
|
109
125
|
"retentionPolicy": "autogen"
|
|
110
126
|
}
|
|
111
127
|
},
|
|
128
|
+
"influxDBv2": {
|
|
129
|
+
"name": "InfluxDBv2",
|
|
130
|
+
"type": "influx",
|
|
131
|
+
"enabled": false,
|
|
132
|
+
"fileName": "influxDB.json",
|
|
133
|
+
"options": {
|
|
134
|
+
"version": 2,
|
|
135
|
+
"protocol": "http",
|
|
136
|
+
"host": "192.168.0.1",
|
|
137
|
+
"port": 9999,
|
|
138
|
+
"token": "...LuyM84JJx93Qvc7tfaXPbI_mFFjRBjaA==",
|
|
139
|
+
"org": "example-org",
|
|
140
|
+
"bucket": "57ec4eed2d90a50b"
|
|
141
|
+
}
|
|
142
|
+
},
|
|
112
143
|
"mqtt": {
|
|
113
144
|
"name": "MQTT",
|
|
114
145
|
"type": "mqtt",
|
package/issue_template.md
CHANGED
|
@@ -33,7 +33,7 @@ Follow the instructions to complete a [packet capture](https://github.com/tagyou
|
|
|
33
33
|
- Pump(s) manufacturer and model: [e.g. IntelliFlow 2 VST 011056]
|
|
34
34
|
- Chlorinator: [e.g. iChlor, IntelliChlor-40]
|
|
35
35
|
- Heater(s): [e.g. gas, solar, heatpump, ultratemp]
|
|
36
|
-
- Chemical controller: [e.g. IntelliChem,
|
|
36
|
+
- Chemical controller: [e.g. IntelliChem, Relay Equipment Manager (REM)]
|
|
37
37
|
- Valves: [e.g. Intellivalve]
|
|
38
38
|
- Any other relevant equipment:
|
|
39
39
|
|
package/logger/DataLogger.ts
CHANGED
|
@@ -29,8 +29,10 @@ export class DataLogger {
|
|
|
29
29
|
}
|
|
30
30
|
let arr: T[] = [];
|
|
31
31
|
for (let i = 0; i < lines.length; i++) {
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
try {
|
|
33
|
+
let entry = DataLogger.createEntry<T>(type, lines[i]);
|
|
34
|
+
arr.push(entry);
|
|
35
|
+
} catch (err) { logger.error(`Skipping invalid dose history entry: ${err.message}`); }
|
|
34
36
|
}
|
|
35
37
|
return arr;
|
|
36
38
|
} catch (err) { logger.error(err); }
|
|
@@ -47,6 +49,7 @@ export class DataLogger {
|
|
|
47
49
|
let newLines = ['\r', '\n'];
|
|
48
50
|
let arr: T[] = [];
|
|
49
51
|
if (fs.existsSync(logPath)) {
|
|
52
|
+
console.log(`Reading logfile ${logPath}`);
|
|
50
53
|
// Alright what we have created here is a method to read the data from the end of
|
|
51
54
|
// a log file in reverse order (tail) that works for all os implementations. It is
|
|
52
55
|
// really dumb that this isn't part of the actual file processing.
|
|
@@ -81,15 +84,16 @@ export class DataLogger {
|
|
|
81
84
|
// record then we shoud save off the line and read the next record.
|
|
82
85
|
if (newLines.includes(char) || pos === 0) {
|
|
83
86
|
if (chars.length > 0) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
87
|
+
try {
|
|
88
|
+
let entry = DataLogger.createEntry<T>(type, chars.join(''));
|
|
89
|
+
if (typeof fn === 'function') {
|
|
90
|
+
let rc = fn(arr.length + 1, entry, arr);
|
|
91
|
+
if (rc === true) arr.push(entry);
|
|
92
|
+
else if (rc === false) break;
|
|
93
|
+
}
|
|
94
|
+
else
|
|
95
|
+
arr.push(entry);
|
|
96
|
+
} catch (err) { logger.error(`Skipping invalid dose history entry: ${err.message}`); }
|
|
93
97
|
}
|
|
94
98
|
chars = [];
|
|
95
99
|
}
|
|
@@ -142,14 +146,16 @@ export class DataLogger {
|
|
|
142
146
|
// record then we shoud save off the line and read the next record.
|
|
143
147
|
if (newLines.includes(char) || pos === 0) {
|
|
144
148
|
if (chars.length > 0) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
149
|
+
try {
|
|
150
|
+
let entry = DataLogger.createEntry<T>(type, chars.join(''));
|
|
151
|
+
if (typeof fn === 'function') {
|
|
152
|
+
let rc = fn(arr.length + 1, entry, arr);
|
|
153
|
+
if (rc === true) arr.push(entry);
|
|
154
|
+
else if (rc === false) break;
|
|
155
|
+
}
|
|
156
|
+
else
|
|
157
|
+
arr.push(entry);
|
|
158
|
+
} catch (err) { logger.error(`Skipping invalid dose history entry: ${err.message}`); }
|
|
153
159
|
}
|
|
154
160
|
chars = [];
|
|
155
161
|
}
|
|
@@ -276,7 +282,6 @@ export class DataLogger {
|
|
|
276
282
|
let entry = DataLogger.createEntry<T>(type, chars.join(''));
|
|
277
283
|
if (typeof fn === 'function') {
|
|
278
284
|
let rc = fn(arr.length + 1, entry, arr);
|
|
279
|
-
console.log(rc);
|
|
280
285
|
if (rc === true) arr.push(entry);
|
|
281
286
|
else if (rc === false) break;
|
|
282
287
|
}
|
|
@@ -399,11 +404,21 @@ export class DataLoggerEntry {
|
|
|
399
404
|
// Parse the data from the log entry if it exists.
|
|
400
405
|
if (typeof entry === 'object') entry = JSON.stringify(entry);
|
|
401
406
|
if (typeof entry === 'string') this.parse(entry);
|
|
407
|
+
else {
|
|
408
|
+
//console.log(`A DATALOGGER ENTRY DOES NOT HAVE A PROPER TYPE ${typeof entry} *************************************`);
|
|
409
|
+
//console.log(entry);
|
|
410
|
+
}
|
|
402
411
|
}
|
|
403
|
-
public createInstance(entry?: string) { return new DataLoggerEntry(entry); }
|
|
412
|
+
public static createInstance(entry?: string) { return new DataLoggerEntry(entry); }
|
|
404
413
|
public parse(entry: string) {
|
|
405
414
|
let obj = typeof entry !== 'undefined' ? JSON.parse(entry, this.dateParser) : {};
|
|
406
|
-
|
|
415
|
+
if (typeof entry === 'undefined') {
|
|
416
|
+
console.log(`A DATALOGGER ENTRY WAS NOT DEFINED *************************`);
|
|
417
|
+
}
|
|
418
|
+
else if (entry === '') {
|
|
419
|
+
console.log(`THE INCOMING DATALOGGER ENTRY WAS EMPTY ***************************`)
|
|
420
|
+
}
|
|
421
|
+
let o = extend(true, this, obj);
|
|
407
422
|
}
|
|
408
423
|
protected dateParser(key, value) {
|
|
409
424
|
if (typeof value === 'string') {
|