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.
Files changed (64) hide show
  1. package/.github/ISSUE_TEMPLATE/1-bug-report.yml +84 -0
  2. package/.github/ISSUE_TEMPLATE/2-docs.md +12 -0
  3. package/.github/ISSUE_TEMPLATE/3-proposal.md +28 -0
  4. package/.github/ISSUE_TEMPLATE/config.yml +8 -0
  5. package/Changelog +19 -0
  6. package/Dockerfile +3 -3
  7. package/README.md +13 -8
  8. package/app.ts +1 -1
  9. package/config/Config.ts +38 -2
  10. package/config/VersionCheck.ts +27 -12
  11. package/controller/Constants.ts +2 -1
  12. package/controller/Equipment.ts +193 -9
  13. package/controller/Errors.ts +10 -0
  14. package/controller/Lockouts.ts +503 -0
  15. package/controller/State.ts +269 -64
  16. package/controller/boards/AquaLinkBoard.ts +1000 -0
  17. package/controller/boards/BoardFactory.ts +4 -0
  18. package/controller/boards/EasyTouchBoard.ts +468 -144
  19. package/controller/boards/IntelliCenterBoard.ts +466 -307
  20. package/controller/boards/IntelliTouchBoard.ts +37 -5
  21. package/controller/boards/NixieBoard.ts +671 -141
  22. package/controller/boards/SystemBoard.ts +1397 -641
  23. package/controller/comms/Comms.ts +462 -362
  24. package/controller/comms/messages/Messages.ts +174 -30
  25. package/controller/comms/messages/config/ChlorinatorMessage.ts +6 -3
  26. package/controller/comms/messages/config/CircuitMessage.ts +1 -0
  27. package/controller/comms/messages/config/ExternalMessage.ts +10 -8
  28. package/controller/comms/messages/config/HeaterMessage.ts +141 -29
  29. package/controller/comms/messages/config/OptionsMessage.ts +9 -2
  30. package/controller/comms/messages/config/PumpMessage.ts +53 -35
  31. package/controller/comms/messages/config/ScheduleMessage.ts +33 -25
  32. package/controller/comms/messages/config/ValveMessage.ts +2 -2
  33. package/controller/comms/messages/status/ChlorinatorStateMessage.ts +38 -86
  34. package/controller/comms/messages/status/EquipmentStateMessage.ts +59 -23
  35. package/controller/comms/messages/status/HeaterStateMessage.ts +57 -3
  36. package/controller/comms/messages/status/IntelliChemStateMessage.ts +56 -8
  37. package/controller/comms/messages/status/PumpStateMessage.ts +23 -1
  38. package/controller/nixie/Nixie.ts +1 -1
  39. package/controller/nixie/bodies/Body.ts +3 -0
  40. package/controller/nixie/chemistry/ChemController.ts +164 -51
  41. package/controller/nixie/chemistry/Chlorinator.ts +137 -88
  42. package/controller/nixie/circuits/Circuit.ts +51 -19
  43. package/controller/nixie/heaters/Heater.ts +241 -31
  44. package/controller/nixie/pumps/Pump.ts +488 -206
  45. package/controller/nixie/schedules/Schedule.ts +91 -35
  46. package/controller/nixie/valves/Valve.ts +1 -1
  47. package/defaultConfig.json +20 -0
  48. package/package.json +21 -21
  49. package/web/Server.ts +94 -49
  50. package/web/bindings/aqualinkD.json +505 -0
  51. package/web/bindings/influxDB.json +71 -1
  52. package/web/bindings/mqtt.json +98 -39
  53. package/web/bindings/mqttAlt.json +59 -1
  54. package/web/interfaces/baseInterface.ts +1 -0
  55. package/web/interfaces/httpInterface.ts +23 -2
  56. package/web/interfaces/influxInterface.ts +45 -10
  57. package/web/interfaces/mqttInterface.ts +114 -54
  58. package/web/services/config/Config.ts +55 -132
  59. package/web/services/state/State.ts +81 -4
  60. package/web/services/state/StateSocket.ts +4 -4
  61. package/web/services/utilities/Utilities.ts +8 -6
  62. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -52
  63. package/config copy.json +0 -300
  64. package/issue_template.md +0 -52
@@ -4,12 +4,13 @@ import { logger } from '../../../logger/Logger';
4
4
 
5
5
  import { NixieEquipment, NixieChildEquipment, NixieEquipmentCollection, INixieControlPanel } from "../NixieEquipment";
6
6
  import { Heater, HeaterCollection, sys } from "../../../controller/Equipment";
7
- import { HeaterState, state, } from "../../State";
7
+ import { BodyTempState, HeaterState, state, } from "../../State";
8
8
  import { setTimeout, clearTimeout } from 'timers';
9
9
  import { NixieControlPanel } from '../Nixie';
10
10
  import { webApp, InterfaceServerResponse } from "../../../web/Server";
11
11
  import { conn } from '../../../controller/comms/Comms';
12
12
  import { Outbound, Protocol, Response } from '../../../controller/comms/messages/Messages';
13
+ import { delayMgr } from '../../Lockouts';
13
14
 
14
15
  export class NixieHeaterCollection extends NixieEquipmentCollection<NixieHeaterBase> {
15
16
  public async deleteHeaterAsync(id: number) {
@@ -96,6 +97,8 @@ export class NixieHeaterBase extends NixieEquipment {
96
97
  protected bodyOnTime: number;
97
98
  protected isOn: boolean = false;
98
99
  protected isCooling: boolean = false;
100
+ protected lastHeatCycle: Date;
101
+ protected lastCoolCycle: Date;
99
102
  constructor(ncp: INixieControlPanel, heater: Heater) {
100
103
  super(ncp);
101
104
  this.heater = heater;
@@ -103,6 +106,7 @@ export class NixieHeaterBase extends NixieEquipment {
103
106
  public get suspendPolling(): boolean { return this._suspendPolling > 0; }
104
107
  public set suspendPolling(val: boolean) { this._suspendPolling = Math.max(0, this._suspendPolling + (val ? 1 : -1)); }
105
108
  public get id(): number { return typeof this.heater !== 'undefined' ? this.heater.id : -1; }
109
+ public getCooldownTime() { return 0; }
106
110
  public static create(ncp: INixieControlPanel, heater: Heater): NixieHeaterBase {
107
111
  let type = sys.board.valueMaps.heaterTypes.transform(heater.type);
108
112
  switch (type.name) {
@@ -144,34 +148,52 @@ export class NixieHeaterBase extends NixieEquipment {
144
148
  }
145
149
  export class NixieGasHeater extends NixieHeaterBase {
146
150
  public pollingInterval: number = 10000;
147
- declare heater: Heater;
151
+ //declare heater: Heater;
148
152
  constructor(ncp: INixieControlPanel, heater: Heater) {
149
153
  super(ncp, heater);
150
154
  this.heater = heater;
155
+ if (typeof this.heater.stopTempDelta === 'undefined') this.heater.stopTempDelta = 1;
156
+ if (typeof this.heater.minCycleTime === 'undefined') this.heater.minCycleTime = 2;
151
157
  this.pollEquipmentAsync();
152
158
  }
153
159
  public get id(): number { return typeof this.heater !== 'undefined' ? this.heater.id : -1; }
160
+ public getCooldownTime(): number {
161
+ // Delays are always in terms of seconds so convert the minute to seconds.
162
+ if (this.heater.cooldownDelay === 0 || typeof this.lastHeatCycle === 'undefined') return 0;
163
+ let now = new Date().getTime();
164
+ let cooldown = this.isOn ? this.heater.cooldownDelay * 60000 : Math.round( ((this.lastHeatCycle.getDate() + this.heater.cooldownDelay * 60000) - now) / 1000);
165
+ return Math.min(Math.max(0, cooldown), this.heater.cooldownDelay * 60);
166
+ }
154
167
  public async setHeaterStateAsync(hstate: HeaterState, isOn: boolean) {
155
168
  try {
156
169
  // Initialize the desired state.
157
170
  this.isOn = isOn;
158
171
  this.isCooling = false;
172
+ let target = hstate.startupDelay === false && isOn;
173
+ if (target && typeof hstate.endTime !== 'undefined') {
174
+ // Calculate a short cycle time so that the gas heater does not cycle
175
+ // too often. For gas heaters this is 60 seconds. This gives enough time
176
+ // for the heater control circuit to make a full cycle.
177
+ if (new Date().getTime() - hstate.endTime.getTime() < this.heater.minCycleTime * 60000) {
178
+ logger.verbose(`${hstate.name} short cycle detected deferring turn on state`);
179
+ target = false;
180
+ }
181
+ }
159
182
  // Here we go we need to set the firemans switch state.
160
- if (hstate.isOn !== isOn) {
183
+ if (hstate.isOn !== target) {
161
184
  logger.info(`Nixie: Set Heater ${hstate.id}-${hstate.name} to ${isOn}`);
162
185
  }
163
- if (utils.isNullOrEmpty(this.heater.connectionId) || utils.isNullOrEmpty(this.heater.deviceBinding)) {
164
- hstate.isOn = isOn;
165
- return;
166
- }
167
- if (typeof this._lastState === 'undefined' || isOn || this._lastState !== isOn) {
168
- let res = await NixieEquipment.putDeviceService(this.heater.connectionId, `/state/device/${this.heater.deviceBinding}`, { isOn: isOn, latch: isOn ? 10000 : undefined });
169
- if (res.status.code === 200) this._lastState = hstate.isOn = isOn;
170
- else logger.error(`Nixie Error setting heater state: ${res.status.code} -${res.status.message} ${res.error.message}`);
171
- }
172
- else {
173
- hstate.isOn = isOn;
174
- return;
186
+ if (typeof this._lastState === 'undefined' || target || this._lastState !== target) {
187
+ if (utils.isNullOrEmpty(this.heater.connectionId) || utils.isNullOrEmpty(this.heater.deviceBinding)) {
188
+ this._lastState = hstate.isOn = target;
189
+ }
190
+ else {
191
+ let res = await NixieEquipment.putDeviceService(this.heater.connectionId, `/state/device/${this.heater.deviceBinding}`,
192
+ { isOn: target, latch: target ? 10000 : undefined });
193
+ if (res.status.code === 200) this._lastState = hstate.isOn = target;
194
+ else logger.error(`Nixie Error setting heater state: ${res.status.code} -${res.status.message} ${res.error.message}`);
195
+ }
196
+ if (target) this.lastHeatCycle = new Date();
175
197
  }
176
198
  } catch (err) { return logger.error(`Nixie Error setting heater state ${hstate.id}-${hstate.name}: ${err.message}`); }
177
199
  }
@@ -228,25 +250,59 @@ export class NixieSolarHeater extends NixieHeaterBase {
228
250
  public get id(): number { return typeof this.heater !== 'undefined' ? this.heater.id : -1; }
229
251
  public async setHeaterStateAsync(hstate: HeaterState, isOn: boolean, isCooling: boolean) {
230
252
  try {
253
+ let origState = hstate.isOn;
231
254
  // Initialize the desired state.
232
255
  this.isOn = isOn;
233
256
  this.isCooling = isCooling;
234
- // Here we go we need to set the firemans switch state.
235
- if (hstate.isOn !== isOn) {
236
- logger.info(`Nixie: Set Heater ${hstate.id}-${hstate.name} to ${isOn}`);
257
+ let target = hstate.startupDelay === false && isOn;
258
+ if (target && typeof hstate.endTime !== 'undefined') {
259
+ // Calculate a short cycle time so that the solar heater does not cycle
260
+ // too often. For solar heaters this is 60 seconds. This gives enough time
261
+ // for the valve to rotate and start heating. If the solar and water sensors are
262
+ // not having issues this should be plenty of time.
263
+ if (new Date().getTime() - hstate.endTime.getTime() < 60000) {
264
+ logger.verbose(`${hstate.name} short cycle detected deferring turn on state`);
265
+ target = false;
266
+ }
237
267
  }
238
- if (utils.isNullOrEmpty(this.heater.connectionId) || utils.isNullOrEmpty(this.heater.deviceBinding)) {
239
- hstate.isOn = isOn;
240
- return;
268
+
269
+ // Here we go we need to set the valve status that is attached to solar.
270
+ if (hstate.isOn !== target) {
271
+ logger.info(`Nixie: Set Heater ${hstate.id}-${hstate.name} to ${isOn}`);
241
272
  }
242
- if (typeof this._lastState === 'undefined' || isOn || this._lastState !== isOn) {
243
- let res = await NixieEquipment.putDeviceService(this.heater.connectionId, `/state/device/${this.heater.deviceBinding}`, { isOn: isOn, latch: isOn ? 10000 : undefined });
244
- if (res.status.code === 200) this._lastState = hstate.isOn = isOn;
245
- else logger.error(`Nixie Error setting heater state: ${res.status.code} -${res.status.message} ${res.error.message}`);
273
+ if (typeof this._lastState === 'undefined' || target || this._lastState !== target) {
274
+ if (utils.isNullOrEmpty(this.heater.connectionId) || utils.isNullOrEmpty(this.heater.deviceBinding)) {
275
+ this._lastState = hstate.isOn = target;
276
+ }
277
+ else {
278
+ let res = await NixieEquipment.putDeviceService(this.heater.connectionId, `/state/device/${this.heater.deviceBinding}`,
279
+ { isOn: target, latch: target ? 10000 : undefined });
280
+ if (res.status.code === 200) this._lastState = hstate.isOn = target;
281
+ else logger.error(`Nixie Error setting heater state: ${res.status.code} -${res.status.message} ${res.error.message}`);
282
+ }
283
+ if (target) {
284
+ if (isCooling) this.lastCoolCycle = new Date();
285
+ else if (isOn) this.lastHeatCycle = new Date();
286
+ }
246
287
  }
247
- else {
248
- hstate.isOn = isOn;
249
- return;
288
+ // In this instance we need to see if there are cleaner circuits that we need to turn off
289
+ // then delay for the current body because the solar just came on.
290
+ if (hstate.isOn && sys.general.options.cleanerSolarDelay && !origState) {
291
+ let arrTypes = sys.board.valueMaps.circuitFunctions.toArray().filter(x => { return x.name.indexOf('cleaner') !== -1 && x.body === hstate.bodyId });
292
+ let cleaners = sys.circuits.filter(x => { return arrTypes.findIndex(t => { return t.val === x.type }) !== -1 });
293
+ // Turn off all the cleaner circuits and set an on delay if they are on.
294
+ for (let i = 0; i < cleaners.length; i++) {
295
+ let cleaner = cleaners.getItemByIndex(i);
296
+ if (cleaner.isActive) {
297
+ let cstate = state.circuits.getItemById(cleaner.id);
298
+ if (cstate.isOn && sys.general.options.cleanerSolarDelayTime > 0) {
299
+ // Turn off the circuit then set a delay.
300
+ logger.info(`Setting cleaner solar delay for ${cleaner.name} to ${sys.general.options.cleanerSolarDelayTime}`);
301
+ await sys.board.circuits.setCircuitStateAsync(cstate.id, false);
302
+ delayMgr.setCleanerStartDelay(cstate, hstate.bodyId, sys.general.options.cleanerSolarDelayTime);
303
+ }
304
+ }
305
+ }
250
306
  }
251
307
  } catch (err) { return logger.error(`Nixie Error setting heater state ${hstate.id}-${hstate.name}: ${err.message}`); }
252
308
  }
@@ -304,6 +360,11 @@ export class NixieHeatpump extends NixieHeaterBase {
304
360
  this.suspendPolling = true;
305
361
  this.isOn = isOn;
306
362
  this.isCooling = isCooling;
363
+ if (!hstate.startupDelay) {
364
+ if (isOn && !isCooling) this.lastHeatCycle = new Date();
365
+ else if (isCooling) this.lastCoolCycle = new Date();
366
+ }
367
+ // When this is implemented lets not forget to deal with the startup and any desired cool down delay. See UltraTemp for implementation.
307
368
  } catch (err) { return logger.error(`Nixie Error setting heater state ${hstate.id}-${hstate.name}: ${err.message}`); }
308
369
  finally { this.suspendPolling = false; }
309
370
  }
@@ -334,6 +395,7 @@ export class NixieHeatpump extends NixieHeaterBase {
334
395
  sheater.type = 2;
335
396
  let success = await new Promise<boolean>((resolve, reject) => {
336
397
  let out = Outbound.create({
398
+ portId: this.heater.portId || 0,
337
399
  protocol: Protocol.Heater,
338
400
  source: 16,
339
401
  dest: this.heater.address,
@@ -395,10 +457,55 @@ export class NixieUltratemp extends NixieHeatpump {
395
457
  }, this.pollingInterval || 10000);
396
458
  }
397
459
  }
460
+ public async setHeaterStateAsync(hstate: HeaterState, isOn: boolean, isCooling: boolean) {
461
+ try {
462
+ // Initialize the desired state.
463
+ this.isCooling = isCooling;
464
+ if (hstate.isOn !== isOn) {
465
+ logger.info(`Nixie: Set Heater ${hstate.id}-${hstate.name} to ${isCooling ? 'cooling' : isOn ? 'heating' : 'off'}`);
466
+
467
+ }
468
+ if (isOn && !hstate.startupDelay) this.lastHeatCycle = new Date();
469
+ hstate.isOn = isOn;
470
+ } catch (err) { return logger.error(`Nixie Error setting heater state ${hstate.id}-${hstate.name}: ${err.message}`); }
471
+ }
472
+ public async releaseHeater(sheater: HeaterState): Promise<boolean> {
473
+ try {
474
+ let success = await new Promise<boolean>((resolve, reject) => {
475
+ let out = Outbound.create({
476
+ portId: this.heater.portId || 0,
477
+ protocol: Protocol.Heater,
478
+ source: 16,
479
+ dest: this.heater.address,
480
+ action: 114,
481
+ payload: [],
482
+ retries: 3, // We are going to try 4 times.
483
+ response: Response.create({ protocol: Protocol.Heater, action: 115 }),
484
+ onAbort: () => { },
485
+ onComplete: (err) => {
486
+ if (err) {
487
+ // If the Ultratemp is not responding we need to store that off but at this point we know none of the codes. If a 115 does
488
+ // come across this will be cleared by the processing of that message.
489
+ sheater.commStatus = sys.board.valueMaps.equipmentCommStatus.getValue('commerr');
490
+ state.equipment.messages.setMessageByCode(`heater:${sheater.id}:comms`, 'error', `Communication error with ${sheater.name}`);
491
+ resolve(false);
492
+ }
493
+ else { resolve(true); }
494
+ }
495
+ });
496
+ out.appendPayloadBytes(0, 10);
497
+ out.setPayloadByte(0, 144);
498
+ out.setPayloadByte(1, 0, 0);
499
+ conn.queueSendMessage(out);
500
+ });
501
+ return success;
502
+ } catch (err) { logger.error(`Communication error with Ultratemp : ${err.message}`); }
503
+ }
398
504
  public async setStatus(sheater: HeaterState): Promise<boolean> {
399
505
  try {
400
506
  let success = await new Promise<boolean>((resolve, reject) => {
401
507
  let out = Outbound.create({
508
+ portId: this.heater.portId || 0,
402
509
  protocol: Protocol.Heater,
403
510
  source: 16,
404
511
  dest: this.heater.address,
@@ -420,7 +527,16 @@ export class NixieUltratemp extends NixieHeatpump {
420
527
  });
421
528
  out.appendPayloadBytes(0, 10);
422
529
  out.setPayloadByte(0, 144);
423
- out.setPayloadByte(1, this.isOn ? (this.isCooling ? 2 : 1) : 0, 0);
530
+ // If we are in startup delay simply tell the heater that it is off.
531
+ if (sheater.startupDelay || this.closing)
532
+ out.setPayloadByte(1, 0, 0);
533
+ else {
534
+ if (this.isOn) {
535
+ if (!this.isCooling) this.lastHeatCycle = new Date();
536
+ else this.lastCoolCycle = new Date();
537
+ }
538
+ out.setPayloadByte(1, this.isOn ? (this.isCooling ? 2 : 1) : 0, 0);
539
+ }
424
540
  conn.queueSendMessage(out);
425
541
  });
426
542
  return success;
@@ -432,10 +548,104 @@ export class NixieUltratemp extends NixieHeatpump {
432
548
  this.closing = true;
433
549
  if (typeof this._pollTimer !== 'undefined' || this._pollTimer) clearTimeout(this._pollTimer);
434
550
  this._pollTimer = null;
551
+ let sheater = state.heaters.getItemById(this.id);
552
+ await this.releaseHeater(sheater);
435
553
  logger.info(`Closing Heater ${this.heater.name}`);
436
-
437
554
  }
438
555
  catch (err) { logger.error(`Ultratemp closeAsync: ${err.message}`); return Promise.reject(err); }
439
556
  }
440
557
  }
441
- export class NixieMastertemp extends NixieGasHeater {}
558
+ export class NixieMastertemp extends NixieGasHeater {
559
+ constructor(ncp: INixieControlPanel, heater: Heater) {
560
+ super(ncp, heater);
561
+ // Set the polling interval to 3 seconds.
562
+ this.pollEquipmentAsync();
563
+ this.pollingInterval = 3000;
564
+ }
565
+ /* public getCooldownTime(): number {
566
+ // Delays are always in terms of seconds so convert the minute to seconds.
567
+ if (this.heater.cooldownDelay === 0 || typeof this.lastHeatCycle === 'undefined') return 0;
568
+ let now = new Date().getTime();
569
+ let cooldown = this.isOn ? this.heater.cooldownDelay * 60000 : Math.round(((this.lastHeatCycle.getDate() + this.heater.cooldownDelay * 60000) - now) / 1000);
570
+ return Math.min(Math.max(0, cooldown), this.heater.cooldownDelay * 60);
571
+ } */
572
+ public async setHeaterStateAsync(hstate: HeaterState, isOn: boolean) {
573
+ try {
574
+ // Initialize the desired state.
575
+ this.isCooling = false;
576
+ // Here we go we need to set the firemans switch state.
577
+ if (hstate.isOn !== isOn) {
578
+ logger.info(`Nixie: Set Heater ${hstate.id}-${hstate.name} to ${isOn}`);
579
+ }
580
+ if (isOn && !hstate.startupDelay) this.lastHeatCycle = new Date();
581
+ hstate.isOn = isOn;
582
+ } catch (err) { return logger.error(`Nixie Error setting heater state ${hstate.id}-${hstate.name}: ${err.message}`); }
583
+ }
584
+ public async pollEquipmentAsync() {
585
+ let self = this;
586
+ try {
587
+ this.suspendPolling = true;
588
+ if (typeof this._pollTimer !== 'undefined' || this._pollTimer) clearTimeout(this._pollTimer);
589
+ this._pollTimer = null;
590
+ if (this._suspendPolling > 1) return;
591
+ let sheater = state.heaters.getItemById(this.heater.id, !this.closing);
592
+ if (!this.closing) await this.setStatus(sheater);
593
+ }
594
+ catch (err) { logger.error(`Error polling MasterTemp heater - ${err}`); }
595
+ finally {
596
+ this.suspendPolling = false; if (!this.closing) this._pollTimer = setTimeout(async () => {
597
+ try { await self.pollEquipmentAsync() } catch (err) { }
598
+ }, this.pollingInterval || 3000);
599
+ }
600
+ }
601
+ public async setStatus(sheater: HeaterState): Promise<boolean> {
602
+ try {
603
+ let success = await new Promise<boolean>((resolve, reject) => {
604
+ let out = Outbound.create({
605
+ portId: this.heater.portId || 0,
606
+ protocol: Protocol.Heater,
607
+ source: 16,
608
+ dest: this.heater.address,
609
+ action: 112,
610
+ payload: [],
611
+ retries: 3, // We are going to try 4 times.
612
+ response: Response.create({ protocol: Protocol.Heater, action: 116 }),
613
+ onAbort: () => { },
614
+ onComplete: (err) => {
615
+ if (err) {
616
+ // If the MasterTemp is not responding we need to store that off but at this point we know none of the codes. If a 115 does
617
+ // come across this will be cleared by the processing of that message.
618
+ sheater.commStatus = sys.board.valueMaps.equipmentCommStatus.getValue('commerr');
619
+ state.equipment.messages.setMessageByCode(`heater:${sheater.id}:comms`, 'error', `Communication error with ${sheater.name}`);
620
+ resolve(false);
621
+ }
622
+ else { resolve(true); }
623
+ }
624
+ });
625
+ out.appendPayloadBytes(0, 11);
626
+ // If we have a startup delay we need to simply send 0 to the heater to make sure that it is off.
627
+ if (sheater.startupDelay)
628
+ out.setPayloadByte(0, 0);
629
+ else {
630
+ // The cooldown delay is a bit hard to figure out here since I think the heater does it on its own.
631
+ out.setPayloadByte(0, sheater.bodyId <= 2 ? sheater.bodyId : 0);
632
+ }
633
+ out.setPayloadByte(1, sys.bodies.getItemById(1).heatSetpoint || 0);
634
+ out.setPayloadByte(2, sys.bodies.getItemById(2).heatSetpoint || 0);
635
+ conn.queueSendMessage(out);
636
+ });
637
+ return success;
638
+ } catch (err) { logger.error(`Communication error with MasterTemp : ${err.message}`); }
639
+ }
640
+ public async closeAsync() {
641
+ try {
642
+ this.suspendPolling = true;
643
+ this.closing = true;
644
+ if (typeof this._pollTimer !== 'undefined' || this._pollTimer) clearTimeout(this._pollTimer);
645
+ this._pollTimer = null;
646
+ logger.info(`Closing Heater ${this.heater.name}`);
647
+
648
+ }
649
+ catch (err) { logger.error(`MasterTemp closeAsync: ${err.message}`); return Promise.reject(err); }
650
+ }
651
+ }