nodejs-poolcontroller 7.5.1 → 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.
@@ -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
- await this.setPumpStateAsync(pstate);
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
- let pt = sys.board.valueMaps.pumpTypes.get(this.pump.type);
258
- if (pt.hasBody) _newSpeed = sys.board.bodies.isBodyOn(this.pump.body) ? 1 : 0;
259
- if (this._targetSpeed !== _newSpeed) logger.info(`NCP: Setting Pump ${this.pump.name} to ${_newSpeed > 0 ? 'on' : 'off'}.`);
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
- let pumpCircuits: PumpCircuit[] = this.pump.circuits.get();
310
- for (let i = 0; i < pumpCircuits.length; i++) {
311
- let circ = state.circuits.getInterfaceById(pumpCircuits[i].circuit);
312
- // relay speeds are bit-shifted 'or' based on 1,2,4,8
313
- if (circ.isOn) _newSpeed |= (1 << pumpCircuits[i].relay - 1);
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);
@@ -352,7 +383,6 @@ export class NixiePumpRS485 extends NixiePump {
352
383
  return Promise.reject(err);
353
384
  }
354
385
  finally { this.suspendPolling = false; }
355
-
356
386
  };
357
387
  protected async setDriveStateAsync(running: boolean = true) {
358
388
  return new Promise<void>((resolve, reject) => {
@@ -503,75 +533,82 @@ export class NixiePumpRS485 extends NixiePump {
503
533
  }
504
534
  }
505
535
  export class NixiePumpVS extends NixiePumpRS485 {
506
- public setTargetSpeed() {
536
+ public setTargetSpeed(pState: PumpState) {
507
537
  let _newSpeed = 0;
508
- let pumpCircuits = this.pump.circuits.get();
509
- for (let i = 0; i < pumpCircuits.length; i++) {
510
- let circ = state.circuits.getInterfaceById(pumpCircuits[i].circuit);
511
- let pc = pumpCircuits[i];
512
- if (circ.isOn) _newSpeed = Math.max(_newSpeed, pc.speed);
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
+ }
513
546
  }
514
547
  if (isNaN(_newSpeed)) _newSpeed = 0;
548
+ this._targetSpeed = _newSpeed;
515
549
  if (this._targetSpeed !== 0) Math.min(Math.max(this.pump.minSpeed, this._targetSpeed), this.pump.maxSpeed);
516
550
  if (this._targetSpeed !== _newSpeed) logger.info(`NCP: Setting Pump ${this.pump.name} to ${_newSpeed} RPM.`);
517
- this._targetSpeed = _newSpeed;
518
551
  }
519
552
  }
520
553
  export class NixiePumpVF extends NixiePumpRS485 {
521
- public setTargetSpeed() {
554
+ public setTargetSpeed(pState: PumpState) {
522
555
  let _newSpeed = 0;
523
- let pumpCircuits = this.pump.circuits.get();
524
- for (let i = 0; i < pumpCircuits.length; i++) {
525
- let circ = state.circuits.getInterfaceById(pumpCircuits[i].circuit);
526
- let pc = pumpCircuits[i];
527
- if (circ.isOn) _newSpeed = Math.max(_newSpeed, pc.flow);
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
+ }
528
563
  }
529
564
  if (isNaN(_newSpeed)) _newSpeed = 0;
565
+ this._targetSpeed = _newSpeed;
530
566
  if (this._targetSpeed !== 0) Math.min(Math.max(this.pump.minFlow, this._targetSpeed), this.pump.maxFlow);
531
567
  if (this._targetSpeed !== _newSpeed) logger.info(`NCP: Setting Pump ${this.pump.name} to ${_newSpeed} GPM.`);
532
- this._targetSpeed = _newSpeed;
533
568
  }
534
569
  }
535
570
  export class NixiePumpVSF extends NixiePumpRS485 {
536
- public setTargetSpeed() {
571
+ public setTargetSpeed(pState: PumpState) {
537
572
  let _newSpeed = 0;
538
- let pumpCircuits = this.pump.circuits.get();
539
- let pt = sys.board.valueMaps.pumpTypes.get(this.pump.type);
540
- // 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
541
- // 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
542
- // the GPM to RPM but if there is none then it will use GPM.
543
573
  let maxRPM = 0;
544
574
  let maxGPM = 0;
545
575
  let flows = 0;
546
576
  let speeds = 0;
547
- let toRPM = (flowRate: number, minSpeed: number = 450, maxSpeed: number = 3450) => {
548
- let eff = .03317 * maxSpeed;
549
- let rpm = Math.min((flowRate * maxSpeed) / eff, maxSpeed);
550
- return rpm > 0 ? Math.max(rpm, minSpeed) : 0;
551
- };
552
- let toGPM = (speed: number, maxSpeed: number = 3450, minFlow: number = 15, maxFlow: number = 140) => {
553
- let eff = .03317 * maxSpeed;
554
- let gpm = Math.min((eff * speed) / maxSpeed, maxFlow);
555
- return gpm > 0 ? Math.max(gpm, minFlow) : 0;
556
- }
557
- for (let i = 0; i < pumpCircuits.length; i++) {
558
- let circ = state.circuits.getInterfaceById(pumpCircuits[i].circuit);
559
- let pc = pumpCircuits[i];
560
- if (circ.isOn) {
561
- if (pc.units > 0) {
562
- maxGPM = Math.max(maxGPM, pc.flow);
563
- // Calculate an RPM from this flow.
564
- maxRPM = Math.max(maxGPM, toRPM(pc.flow, pt.minSpeed, pt.maxSpeed));
565
- flows++;
566
- }
567
- else {
568
- maxRPM = Math.max(maxRPM, pc.speed);
569
- maxGPM = Math.max(maxGPM, toGPM(pc.speed, pt.maxSpeed, pt.minFlow, pt.maxFlow));
570
- speeds++;
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
+ }
571
608
  }
572
609
  }
610
+ _newSpeed = speeds > 0 || flows === 0 ? maxRPM : maxGPM;
573
611
  }
574
- _newSpeed = speeds > 0 || flows === 0 ? maxRPM : maxGPM;
575
612
  if (isNaN(_newSpeed)) _newSpeed = 0;
576
613
  // Send the flow message if it is flow and the rpm message if it is rpm.
577
614
  if (this._targetSpeed !== _newSpeed) logger.info(`NCP: Setting Pump ${this.pump.name} to ${_newSpeed} ${flows > 0 ? 'GPM' : 'RPM'}.`);
@@ -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.info(`Nixie: Set valve ${vstate.id}-${vstate.name} to ${isDiverted}`);
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodejs-poolcontroller",
3
- "version": "7.5.1",
3
+ "version": "7.6.0",
4
4
  "description": "nodejs-poolController",
5
5
  "main": "app.js",
6
6
  "author": {
@@ -1,42 +1,42 @@
1
1
  {
2
- "context": {
3
- "name": "MQTT",
4
- "options": {
5
- "formatter": [
6
- {
7
- "transform": ".toLowerCase()"
8
- },
9
- {
10
- "regexkey": "\\s",
11
- "replace": "",
12
- "description": "Remove whitespace"
13
- },
14
- {
15
- "regexkey": "\\/",
16
- "replace": "",
17
- "description": "Remove /"
18
- },
19
- {
20
- "regexkey": "\\+",
21
- "replace": "",
22
- "description": "Remove +"
23
- },
24
- {
25
- "regexkey": "\\$",
26
- "replace": "",
27
- "description": "Remove $"
28
- },
29
- {
30
- "regexkey": "\\#",
31
- "replace": "",
32
- "description": "Remove #"
33
- }
34
- ],
35
- "rootTopic-DIRECTIONS": "You can override the root topic by renaming _rootTopic to rootTopic",
36
- "_rootTopic": "@bind=(state.equipment.alias).replace(' ','-').replace('/','').toLowerCase();",
37
- "clientId": "@bind='mqttjs_njsPC_'+Math.random().toString(16).substr(2, 8);"
2
+ "context": {
3
+ "name": "MQTT",
4
+ "options": {
5
+ "formatter": [
6
+ {
7
+ "transform": ".toLowerCase()"
8
+ },
9
+ {
10
+ "regexkey": "\\s",
11
+ "replace": "",
12
+ "description": "Remove whitespace"
13
+ },
14
+ {
15
+ "regexkey": "\\/",
16
+ "replace": "",
17
+ "description": "Remove /"
18
+ },
19
+ {
20
+ "regexkey": "\\+",
21
+ "replace": "",
22
+ "description": "Remove +"
23
+ },
24
+ {
25
+ "regexkey": "\\$",
26
+ "replace": "",
27
+ "description": "Remove $"
28
+ },
29
+ {
30
+ "regexkey": "\\#",
31
+ "replace": "",
32
+ "description": "Remove #"
38
33
  }
39
- },
34
+ ],
35
+ "rootTopic-DIRECTIONS": "You can override the root topic by renaming _rootTopic to rootTopic",
36
+ "_rootTopic": "@bind=(state.equipment.alias).replace(' ','-').replace('/','').toLowerCase();",
37
+ "clientId": "@bind='mqttjs_njsPC_'+Math.random().toString(16).substr(2, 8);"
38
+ }
39
+ },
40
40
  "events": [
41
41
  {
42
42
  "name": "config",
@@ -67,7 +67,7 @@
67
67
  },
68
68
  {
69
69
  "topic": "state/startTime",
70
- "message": "@bind=data.startTime;"
70
+ "message": "@bind=data.startTime;"
71
71
  }
72
72
  ]
73
73
  },
@@ -582,6 +582,17 @@
582
582
  }
583
583
  ]
584
584
  },
585
+ {
586
+ "name": "chemicalDose",
587
+ "description": "Event when a chemical is being dosed",
588
+ "topics": [
589
+ {
590
+ "topic": "state/chemControllers/@bind=data.id;/@bind=data.chem;",
591
+ "message": "@bind=data;",
592
+ "enabled": true
593
+ }
594
+ ]
595
+ },
585
596
  {
586
597
  "name": "filter",
587
598
  "description": "Populate the filter topic",
@@ -92,7 +92,7 @@
92
92
  {
93
93
  "topic": "state/circuits/@bind=data.id;/endTime",
94
94
  "message": "@bind=data.endTime;",
95
- "description": "The end time for the circuit."
95
+ "description": "The end time for the circuit."
96
96
  },
97
97
  {
98
98
  "topic": "state/circuits/@bind=data.id;/lightingTheme",
@@ -602,6 +602,17 @@
602
602
  }
603
603
  ]
604
604
  },
605
+ {
606
+ "name": "chemicalDose",
607
+ "description": "Event when a chemical is being dosed",
608
+ "topics": [
609
+ {
610
+ "topic": "state/chemControllers/@bind=data.id;/@bind=data.chem;",
611
+ "message": "@bind=data;",
612
+ "enabled": true
613
+ }
614
+ ]
615
+ },
605
616
  {
606
617
  "name": "filter",
607
618
  "description": "Populate the filter topic",
@@ -112,7 +112,7 @@ export class ConfigRoute {
112
112
  invalidIds: sys.board.equipmentIds.invalidIds.get(),
113
113
  equipmentIds: sys.equipment.equipmentIds.features,
114
114
  equipmentNames: sys.board.circuits.getCircuitNames(),
115
- functions: sys.board.valueMaps.featureFunctions.toArray(),
115
+ functions: sys.board.features.getFeatureFunctions(),
116
116
  features: sys.features.get()
117
117
  };
118
118
  return res.status(200).send(opts);
@@ -592,8 +592,8 @@ export class ConfigRoute {
592
592
  return res.status(200).send(circuitFunctions);
593
593
  });
594
594
  app.get('/config/features/functions', (req, res) => {
595
- let circuitFunctions = sys.board.circuits.getCircuitFunctions();
596
- return res.status(200).send(circuitFunctions);
595
+ let featureFunctions = sys.board.features.getFeatureFunctions();
596
+ return res.status(200).send(featureFunctions);
597
597
  });
598
598
  app.get('/config/circuit/:id', (req, res) => {
599
599
  // todo: need getInterfaceById.get() in case features are requested here
@@ -874,7 +874,7 @@ export class ConfigRoute {
874
874
  });
875
875
  app.get('/app/config/options/backup', async (req, res, next) => {
876
876
  try {
877
- let opts = config.getSection('controller.backups', { automatic: false, interval: { days: 30, hours: 0, keepCount: 5, servers: [] } });
877
+ let opts = config.getSection('controller.backups', { automatic: false, interval: { days: 30, hours: 0 }, keepCount: 5, servers: [] });
878
878
  let servers = await sys.ncp.getREMServers();
879
879
  if (typeof servers !== 'undefined') {
880
880
  // Just in case somebody deletes the backup section and doesn't put it back properly.
@@ -893,7 +893,7 @@ export class ConfigRoute {
893
893
  });
894
894
  app.get('/app/config/options/restore', async (req, res, next) => {
895
895
  try {
896
- let opts = config.getSection('controller.backups', { automatic: false, interval: { days: 30, hours: 0, keepCount: 5, servers: [], backupFiles: [] } });
896
+ let opts = config.getSection('controller.backups', { automatic: false, interval: { days: 30, hours: 0 }, keepCount: 5, servers: [], backupFiles: [] });
897
897
  let servers = await sys.ncp.getREMServers();
898
898
  if (typeof servers !== 'undefined') {
899
899
  for (let i = 0; i < servers.length; i++) {
@@ -914,7 +914,7 @@ export class ConfigRoute {
914
914
  app.put('/app/config/options/backup', async (req, res, next) => {
915
915
  try {
916
916
  config.setSection('controller.backups', req.body);
917
- let opts = config.getSection('controller.backups', { automatic: false, interval: { days: 30, hours: 0, keepCount: 5, servers: [] } });
917
+ let opts = config.getSection('controller.backups', { automatic: false, interval: { days: 30, hours: 0 }, keepCount: 5, servers: [] });
918
918
  webApp.autoBackup = utils.makeBool(opts.automatic);
919
919
  await webApp.checkAutoBackup();
920
920
  return res.status(200).send(opts);