nodejs-poolcontroller 7.4.0 → 7.5.1

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 (55) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  2. package/Changelog +3 -0
  3. package/README.md +2 -2
  4. package/app.ts +2 -0
  5. package/config/Config.ts +3 -0
  6. package/config/VersionCheck.ts +8 -4
  7. package/controller/Equipment.ts +89 -29
  8. package/controller/Errors.ts +14 -1
  9. package/controller/State.ts +75 -31
  10. package/controller/boards/EasyTouchBoard.ts +81 -36
  11. package/controller/boards/IntelliCenterBoard.ts +96 -32
  12. package/controller/boards/IntelliTouchBoard.ts +103 -29
  13. package/controller/boards/NixieBoard.ts +79 -27
  14. package/controller/boards/SystemBoard.ts +1552 -822
  15. package/controller/comms/Comms.ts +84 -9
  16. package/controller/comms/messages/Messages.ts +10 -4
  17. package/controller/comms/messages/config/ChlorinatorMessage.ts +13 -4
  18. package/controller/comms/messages/config/CircuitGroupMessage.ts +6 -0
  19. package/controller/comms/messages/config/CoverMessage.ts +1 -0
  20. package/controller/comms/messages/config/EquipmentMessage.ts +4 -0
  21. package/controller/comms/messages/config/ExternalMessage.ts +43 -25
  22. package/controller/comms/messages/config/FeatureMessage.ts +8 -1
  23. package/controller/comms/messages/config/GeneralMessage.ts +8 -0
  24. package/controller/comms/messages/config/HeaterMessage.ts +10 -9
  25. package/controller/comms/messages/config/IntellichemMessage.ts +4 -1
  26. package/controller/comms/messages/config/OptionsMessage.ts +13 -1
  27. package/controller/comms/messages/config/PumpMessage.ts +4 -20
  28. package/controller/comms/messages/config/RemoteMessage.ts +4 -0
  29. package/controller/comms/messages/config/ScheduleMessage.ts +11 -0
  30. package/controller/comms/messages/config/SecurityMessage.ts +1 -0
  31. package/controller/comms/messages/config/ValveMessage.ts +12 -2
  32. package/controller/comms/messages/status/ChlorinatorStateMessage.ts +2 -3
  33. package/controller/comms/messages/status/EquipmentStateMessage.ts +74 -22
  34. package/controller/comms/messages/status/HeaterStateMessage.ts +15 -6
  35. package/controller/comms/messages/status/IntelliChemStateMessage.ts +37 -26
  36. package/controller/nixie/Nixie.ts +18 -16
  37. package/controller/nixie/chemistry/ChemController.ts +57 -37
  38. package/controller/nixie/chemistry/Chlorinator.ts +7 -8
  39. package/controller/nixie/circuits/Circuit.ts +17 -0
  40. package/controller/nixie/pumps/Pump.ts +49 -24
  41. package/controller/nixie/schedules/Schedule.ts +1 -1
  42. package/defaultConfig.json +15 -0
  43. package/issue_template.md +1 -1
  44. package/logger/DataLogger.ts +37 -22
  45. package/package.json +3 -1
  46. package/web/Server.ts +515 -27
  47. package/web/bindings/influxDB.json +35 -0
  48. package/web/bindings/mqtt.json +62 -3
  49. package/web/bindings/mqttAlt.json +57 -4
  50. package/web/interfaces/httpInterface.ts +2 -0
  51. package/web/interfaces/influxInterface.ts +3 -2
  52. package/web/interfaces/mqttInterface.ts +12 -1
  53. package/web/services/config/Config.ts +162 -37
  54. package/web/services/state/State.ts +47 -3
  55. package/web/services/state/StateSocket.ts +1 -1
@@ -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, homegrown]
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/Changelog CHANGED
@@ -1,5 +1,8 @@
1
1
  # Changelog
2
2
 
3
+ ## 7.5
4
+ 1. Backup/restore
5
+ 2. Intellitouch add expansion modules
3
6
  ## 7.4
4
7
  1. Filter object, emit, monitoring
5
8
 
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # nodejs-poolController - Version 7.4
1
+ # nodejs-poolController - Version 7.5
2
2
 
3
3
  ## What is nodejs-poolController
4
4
 
@@ -15,7 +15,7 @@ Equipment supported
15
15
  1. Pumps: Intelliflow VS/VSF/VF, older models
16
16
  1. Chlorinators: Intellichlor, Aqua-Rite and OEM brands
17
17
  1. Heaters: Gas, solar, heatpump
18
- 1. Intellichem and homegrown chemical controllers
18
+ 1. Intellichem and Relay Equipment Manager (REM) chemical controllers
19
19
  1. Intellivalve (coming soon)
20
20
  1. Home Automation: SmartThings, Hubitat, ISY, Vera, Siri, Echo
21
21
  1. Chemical probes (pH, ORP, flow sensors, EC, etc.)
package/app.ts CHANGED
@@ -35,6 +35,7 @@ export async function initAsync() {
35
35
  await state.init();
36
36
  await webApp.init();
37
37
  await sys.start();
38
+ await webApp.initAutoBackup();
38
39
  } catch (err) { console.log(`Error Initializing nodejs-PoolController ${err.message}`); }
39
40
  //return Promise.resolve()
40
41
  // .then(function () { config.init(); })
@@ -70,6 +71,7 @@ export async function stopAsync(): Promise<void> {
70
71
  try {
71
72
  console.log('Shutting down open processes');
72
73
  // await sys.board.virtualPumpControllers.stopAsync();
74
+ await webApp.stopAutoBackup();
73
75
  await sys.stopAsync();
74
76
  await state.stopAsync();
75
77
  await conn.stopAsync();
package/config/Config.ts CHANGED
@@ -100,6 +100,8 @@ class Config {
100
100
  c[section] = val;
101
101
  this.update();
102
102
  }
103
+ // RKS: 09-21-21 - We are counting on the return from this being immutable. A copy of the data
104
+ // should always be returned here.
103
105
  public getSection(section?: string, opts?: any): any {
104
106
  if (typeof section === 'undefined') return this._cfg;
105
107
  let c: any = this._cfg;
@@ -118,6 +120,7 @@ class Config {
118
120
  let baseDir = process.cwd();
119
121
  this.ensurePath(baseDir + '/logs/');
120
122
  this.ensurePath(baseDir + '/data/');
123
+ this.ensurePath(baseDir + '/backups/');
121
124
  // this.ensurePath(baseDir + '/replay/');
122
125
  //setTimeout(() => { config.update(); }, 100);
123
126
  }
@@ -41,7 +41,7 @@ class VersionCheck {
41
41
  public checkGitLocal() {
42
42
  // check local git version
43
43
  try {
44
- let res = execSync('git rev-parse --abbrev-ref HEAD');
44
+ let res = execSync('git rev-parse --abbrev-ref HEAD', { stdio: 'pipe' });
45
45
  let out = res.toString().trim();
46
46
  logger.info(`The current git branch output is ${out}`);
47
47
  switch (out) {
@@ -54,10 +54,11 @@ class VersionCheck {
54
54
  }
55
55
  }
56
56
  catch (err) {
57
- logger.error(`Unable to retrieve local git branch. ${err}`);
57
+ state.appVersion.gitLocalBranch = '--';
58
+ logger.warn(`Unable to retrieve local git branch. ${err}`);
58
59
  }
59
60
  try {
60
- let res = execSync('git rev-parse HEAD');
61
+ let res = execSync('git rev-parse HEAD', { stdio: 'pipe' });
61
62
  let out = res.toString().trim();
62
63
  logger.info(`The current git commit output is ${out}`);
63
64
  switch (out) {
@@ -69,7 +70,10 @@ class VersionCheck {
69
70
  state.appVersion.gitLocalCommit = out;
70
71
  }
71
72
  }
72
- catch (err) { logger.error(`Unable to retrieve local git commit. ${err}`); }
73
+ catch (err) {
74
+ state.appVersion.gitLocalCommit = '--';
75
+ logger.warn(`Unable to retrieve local git commit. ${err}`);
76
+ }
73
77
  }
74
78
  private checkAll() {
75
79
  try {
@@ -31,6 +31,7 @@ import { conn } from './comms/Comms';
31
31
  import { versionCheck } from "../config/VersionCheck";
32
32
  import { NixieControlPanel } from "./nixie/Nixie";
33
33
  import { NixieBoard } from 'controller/boards/NixieBoard';
34
+ import { child } from "winston";
34
35
 
35
36
  interface IPoolSystem {
36
37
  cfgPath: string;
@@ -68,7 +69,7 @@ interface IPoolSystem {
68
69
  }
69
70
 
70
71
  export class PoolSystem implements IPoolSystem {
71
- public _hasChanged: boolean=false;
72
+ public _hasChanged: boolean = false;
72
73
  constructor() {
73
74
  this.cfgPath = path.posix.join(process.cwd(), '/data/poolConfig.json');
74
75
  }
@@ -99,7 +100,12 @@ export class PoolSystem implements IPoolSystem {
99
100
  { val: 3, name: 'IT5S', part: 'i5+3S', desc: 'IntelliTouch i5+3S', bodies: 1, circuits: 6, shared: false },
100
101
  { val: 4, name: 'IT9S', part: 'i9+3S', desc: 'IntelliTouch i9+3S', bodies: 1, circuits: 9, shared: false },
101
102
  { val: 5, name: 'IT10D', part: 'i10D', desc: 'IntelliTouch i10D', bodies: 1, circuits: 10, shared: false, dual: true }
103
+ ],
104
+ expansionModules: [
105
+ { val: 32, name: 'IT5X', part: 'i5X', desc: 'IntelliTouch i5X', circuits: 5, shared: false },
106
+ { val: 33, name: 'IT10X', part: 'i10X', desc: 'IntelliTouch i10X', circuits: 10, shared: false }
102
107
  ]
108
+
103
109
  });
104
110
  arr.push({
105
111
  type: 'intellicenter', name: 'IntelliCenter',
@@ -109,7 +115,8 @@ export class PoolSystem implements IPoolSystem {
109
115
  { val: 2, name: 'i8P', part: '521977Z', desc: 'IntelliCenter i8P', bodies: 1, valves: 2, circuits: 8, shared: false, dual: false, chlorinators: 1, chemControllers: 1 },
110
116
  { val: 3, name: 'i8PS', part: '521968Z', desc: 'IntelliCenter i8PS', bodies: 2, valves: 4, circuits: 9, shared: true, dual: false, chlorinators: 1, chemControllers: 1 },
111
117
  { val: 4, name: 'i10P', part: '521993Z', desc: 'IntelliCenter i10P', bodies: 1, valves: 2, circuits: 10, shared: false, dual: false, chlorinators: 1, chemControllers: 1 }, // This is a guess
112
- { val: 5, name: 'i10PS', part: '521873Z', desc: 'IntelliCenter i10PS', bodies: 2, valves: 4, circuits: 11, shared: true, dual: false, chlorinators: 1, chemControllers: 1 }
118
+ { val: 5, name: 'i10PS', part: '521873Z', desc: 'IntelliCenter i10PS', bodies: 2, valves: 4, circuits: 11, shared: true, dual: false, chlorinators: 1, chemControllers: 1 },
119
+ { val: 7, name: 'i10D', part: '523029Z', desc: 'IntelliCenter i10D', bodies: 2, valves: 2, circuits: 11, shared: false, dual: true, chlorinators: 2, chemControllers: 2 },
113
120
  ]
114
121
  });
115
122
  arr.push({
@@ -155,7 +162,7 @@ export class PoolSystem implements IPoolSystem {
155
162
  EqItemCollection.removeNullIds(cfg.remotes);
156
163
  EqItemCollection.removeNullIds(cfg.chemControllers);
157
164
  EqItemCollection.removeNullIds(cfg.filters);
158
- this.data = this.onchange(cfg, function() { sys.dirty = true; });
165
+ this.data = this.onchange(cfg, function () { sys.dirty = true; });
159
166
  this.general = new General(this.data, 'pool');
160
167
  this.equipment = new Equipment(this.data, 'equipment');
161
168
  this.configVersion = new ConfigVersion(this.data, 'configVersion');
@@ -516,7 +523,7 @@ class EqItemCollection<T> implements IEqItemCollection {
516
523
  }
517
524
  }
518
525
  public static removeNullIds(data: any) {
519
- if (typeof data !== 'undefined' && Array.isArray(data) && typeof data.length === 'number') {
526
+ if (typeof data !== 'undefined' && Array.isArray(data) && typeof data.length === 'number') {
520
527
  for (let i = data.length - 1; i >= 0; i--) {
521
528
  if (typeof data[i].id !== 'number') data.splice(i, 1);
522
529
  else if (typeof data[i].id === 'undefined' || isNaN(data[i].id)) data.splice(i, 1);
@@ -606,7 +613,7 @@ class EqItemCollection<T> implements IEqItemCollection {
606
613
  }
607
614
  public sort(fn: (a, b) => number) { this.data.sort(fn); }
608
615
  public count(fn: () => boolean): number { return this.data.filter(fn).length; }
609
- public getNextEquipmentId(range: EquipmentIdRange, exclude?:number[]): number {
616
+ public getNextEquipmentId(range: EquipmentIdRange, exclude?: number[]): number {
610
617
  for (let i = range.start; i <= range.end; i++) {
611
618
  let eq = this.data.find(elem => elem.id === i);
612
619
  if (typeof eq === 'undefined') {
@@ -647,7 +654,7 @@ export class General extends EqItem {
647
654
  if (master === -1)
648
655
  super.clear();
649
656
  }
650
-
657
+
651
658
  }
652
659
  // Custom Names are IntelliTouch Only
653
660
  export class CustomNameCollection extends EqItemCollection<CustomName> {
@@ -721,15 +728,14 @@ export class Options extends EqItem {
721
728
  public get clockMode(): number | any { return this.data.clockMode; }
722
729
  public set clockMode(val: number | any) { this.setDataVal('clockMode', sys.board.valueMaps.clockModes.encode(val)); }
723
730
  public get units(): number | any { return this.data.units; }
724
- public set units(val: number | any) { this.setDataVal('units', sys.board.valueMaps.tempUnits.encode(val)); }
731
+ public set units(val: number | any) { this.setDataVal('units', sys.board.valueMaps.systemUnits.encode(val)); }
725
732
  public get clockSource(): string { return this.data.clockSource; }
726
733
  public set clockSource(val: string) { this.setDataVal('clockSource', val); }
727
734
  public get adjustDST(): boolean { return this.data.adjustDST; }
728
735
  public set adjustDST(val: boolean) { this.setDataVal('adjustDST', val); }
729
736
  public get manualPriority(): boolean { return this.data.manualPriority; }
730
737
  public set manualPriority(val: boolean) { this.setDataVal('manualPriority', val); }
731
- public get vacationMode(): boolean { return this.data.vacationMode; }
732
- public set vacationMode(val: boolean) { this.setDataVal('vacationMode', val); }
738
+ public get vacation(): VacationOptions { return new VacationOptions(this.data, 'vacation', this); }
733
739
  public get manualHeat(): boolean { return this.data.manualHeat; }
734
740
  public set manualHeat(val: boolean) { this.setDataVal('manualHeat', val); }
735
741
  public get pumpDelay(): boolean { return this.data.pumpDelay; }
@@ -750,6 +756,42 @@ export class Options extends EqItem {
750
756
  //public get solarTempAdj2(): number { return typeof this.data.solarTempAdj2 === 'undefined' ? 0 : this.data.solarTempAdj2; }
751
757
  //public set solarTempAdj2(val: number) { this.setDataVal('solarTempAd2', val); }
752
758
  }
759
+ export class VacationOptions extends ChildEqItem {
760
+ public initData() {
761
+ if (typeof this.data.enabled === 'undefined') this.data.enabled = false;
762
+ if (typeof this.data.useTimeframe === 'undefined') this.data.useTimeframe = false;
763
+ }
764
+ private _startDate: Date;
765
+ private _endDate: Date;
766
+ public get enabled(): boolean { return this.data.enabled; }
767
+ public set enabled(val: boolean) { this.setDataVal('enabled', val); }
768
+ public get useTimeframe(): boolean { return this.data.useTimeframe; }
769
+ public set useTimeframe(val: boolean) { this.setDataVal('useTimeframe', val); }
770
+ public get startDate() {
771
+ if (typeof this._startDate === 'undefined') this._startDate = typeof this.data.startDate === 'string' ? new Date(this.data.startDate) : undefined;
772
+ return this._startDate;
773
+ }
774
+ public set startDate(val: Date | string | number) {
775
+ this._startDate = new Date(val);
776
+ this._saveDate('startDate', this._startDate);
777
+ }
778
+ public get endDate() {
779
+ if (typeof this._endDate === 'undefined') this._endDate = typeof this.data.endDate === 'string' ? new Date(this.data.endDate) : undefined;
780
+ return this._endDate;
781
+ }
782
+ public set endDate(val: Date | string | number) {
783
+ this._endDate = new Date(val);
784
+ this._saveDate('endDate', this._endDate);
785
+ }
786
+
787
+ private _saveDate(prop: string, dt: Date) {
788
+ if (typeof dt !== 'undefined' && !isNaN(dt.getTime())) {
789
+ dt.setHours(0, 0, 0, 0);
790
+ this.setDataVal(prop, Timestamp.toISOLocal(dt));
791
+ }
792
+ else this.setDataVal(prop, undefined);
793
+ }
794
+ }
753
795
  export class Location extends EqItem {
754
796
  public dataName = 'locationConfig';
755
797
  public get address(): string { return this.data.address; }
@@ -814,6 +856,8 @@ export class Equipment extends EqItem {
814
856
  public set shared(val: boolean) { this.setDataVal('shared', val); }
815
857
  public get dual(): boolean { return this.data.dual; }
816
858
  public set dual(val: boolean) { this.setDataVal('dual', val); }
859
+ public get intakeReturnValves(): boolean { return this.data.intakeReturnValves; }
860
+ public set intakeReturnValves(val: boolean) { this.setDataVal('intakeReturnValves', val); }
817
861
  public get maxBodies(): number { return this.data.maxBodies || 4; }
818
862
  public set maxBodies(val: number) { this.setDataVal('maxBodies', val); }
819
863
  public get maxValves(): number { return this.data.maxValves || 26; }
@@ -935,7 +979,6 @@ export class ConfigVersion extends EqItem {
935
979
  if (prop === 'lastUpdated') continue;
936
980
  this.data[prop] = 0;
937
981
  }
938
-
939
982
  }
940
983
  }
941
984
 
@@ -959,6 +1002,9 @@ export class BodyCollection extends EqItemCollection<Body> {
959
1002
  }
960
1003
  export class Body extends EqItem {
961
1004
  public dataName = 'bodyConfig';
1005
+ public initData() {
1006
+ if (typeof this.data.capacityUnits === 'undefined') this.data.capacityUnits = 1;
1007
+ }
962
1008
  public get id(): number { return this.data.id; }
963
1009
  public set id(val: number) { this.data.id = val; }
964
1010
  public get name(): string { return this.data.name; }
@@ -983,7 +1029,14 @@ export class Body extends EqItem {
983
1029
  public set heatSetpoint(val: number) { this.setDataVal('setPoint', val); }
984
1030
  public get coolSetpoint(): number { return this.data.coolSetpoint; }
985
1031
  public set coolSetpoint(val: number) { this.setDataVal('coolSetpoint', val); }
1032
+ public get capacityUnits(): number | any { return this.data.capacityUnits; }
1033
+ public set capacityUnits(val: number | any) { this.setDataVal('capacityUnits', sys.board.valueMaps.volumeUnits.encode(val)); }
986
1034
  public getHeatModes() { return sys.board.bodies.getHeatModes(this.id); }
1035
+ public getExtended() {
1036
+ let body = this.get(true);
1037
+ body.capacityUnits = sys.board.valueMaps.volumeUnits.transform(this.capacityUnits || 1);
1038
+ return body;
1039
+ }
987
1040
  }
988
1041
  export class ScheduleCollection extends EqItemCollection<Schedule> {
989
1042
  constructor(data: any, name?: string) { super(data, name || "schedules"); }
@@ -1031,12 +1084,12 @@ export class Schedule extends EqItem {
1031
1084
  public get isActive(): boolean { return this.data.isActive; }
1032
1085
  public set isActive(val: boolean) { this.setDataVal('isActive', val); }
1033
1086
  public get startMonth(): number { return this._startDate.getMonth() + 1; }
1034
- public set startMonth(val: number) { this._startDate.setMonth(val - 1); this._saveStartDate(); }
1035
- public get startDay(): number { return this._startDate.getDate(); }
1036
- public set startDay(val: number) { this._startDate.setDate(val); this._saveStartDate(); }
1037
- public get startYear(): number { return this._startDate.getFullYear(); }
1038
- public set startYear(val: number) { this._startDate.setFullYear(val < 100 ? val + 2000 : val); this._saveStartDate(); }
1039
- public get startDate(): Date { return this._startDate; }
1087
+ public set startMonth(val: number) { if (typeof this._startDate === 'undefined') this._startDate = new Date(); this._startDate.setMonth(val - 1); this._saveStartDate(); }
1088
+ public get startDay(): number { if (typeof this._startDate === 'undefined') this._startDate = new Date(); return this._startDate.getDate(); }
1089
+ public set startDay(val: number) { if (typeof this._startDate === 'undefined') this._startDate = new Date(); this._startDate.setDate(val); this._saveStartDate(); }
1090
+ public get startYear(): number { if (typeof this._startDate === 'undefined') this._startDate = new Date(); return this._startDate.getFullYear(); }
1091
+ public set startYear(val: number) { if (typeof this._startDate === 'undefined') this._startDate = new Date(); this._startDate.setFullYear(val < 100 ? val + 2000 : val); this._saveStartDate(); }
1092
+ public get startDate(): Date { return typeof this._startDate === 'undefined' ? this._startDate = new Date() : this._startDate; }
1040
1093
  public set startDate(val: Date) { this._startDate = val; }
1041
1094
  public get scheduleType(): number | any { return this.data.scheduleType; }
1042
1095
  public set scheduleType(val: number | any) { this.setDataVal('scheduleType', sys.board.valueMaps.scheduleTypes.encode(val)); }
@@ -1192,7 +1245,7 @@ export interface ICircuit {
1192
1245
  //showInCircuits?: boolean;
1193
1246
  showInFeatures?: boolean;
1194
1247
  macro?: boolean;
1195
- getLightThemes?: (type?:number) => {};
1248
+ getLightThemes?: (type?: number) => {};
1196
1249
  get(copy?: boolean);
1197
1250
  master: number;
1198
1251
  }
@@ -1211,6 +1264,9 @@ export class PumpCollection extends EqItemCollection<Pump> {
1211
1264
  }
1212
1265
  export class Pump extends EqItem {
1213
1266
  public dataName = 'pumpConfig';
1267
+ public initData() {
1268
+ if (typeof this.data.isVirtual !== 'undefined') delete this.data.isVirtual;
1269
+ }
1214
1270
  public get id(): number { return this.data.id; }
1215
1271
  public set id(val: number) { this.setDataVal('id', val); }
1216
1272
  public get address(): number { return this.data.address || this.data.id + 95; }
@@ -1257,8 +1313,10 @@ export class Pump extends EqItem {
1257
1313
  public set vacuumTime(val: number) { this.setDataVal('vacuumTime', val); }
1258
1314
  public get backgroundCircuit() { return this.data.backgroundCircuit; }
1259
1315
  public set backgroundCircuit(val: number) { this.setDataVal('backgroundCircuit', val); }
1260
- public get isVirtual() { return this.data.isVirtual; }
1261
- public set isVirtual(val: boolean) { this.setDataVal('isVirtual', val); }
1316
+ public get filterSize() { return this.data.filterSize; }
1317
+ public set filterSize(val: number) { this.setDataVal('filterSize', val); }
1318
+ // public get isVirtual() { return this.data.isVirtual; }
1319
+ // public set isVirtual(val: boolean) { this.setDataVal('isVirtual', val); }
1262
1320
  public get connectionId(): string { return this.data.connectionId; }
1263
1321
  public set connectionId(val: string) { this.setDataVal('connectionId', val); }
1264
1322
  public get deviceBinding(): string { return this.data.deviceBinding; }
@@ -1414,8 +1472,8 @@ export class Valve extends EqItem {
1414
1472
  public set isIntake(val: boolean) { this.setDataVal('isIntake', val); }
1415
1473
  public get isReturn(): boolean { return utils.makeBool(this.data.isReturn); }
1416
1474
  public set isReturn(val: boolean) { this.setDataVal('isReturn', val); }
1417
- public get isVirtual(): boolean { return utils.makeBool(this.data.isVirtual); }
1418
- public set isVirtual(val: boolean) { this.setDataVal('isVirtual', val); }
1475
+ // public get isVirtual(): boolean { return utils.makeBool(this.data.isVirtual); }
1476
+ // public set isVirtual(val: boolean) { this.setDataVal('isVirtual', val); }
1419
1477
  public get pinId(): number { return this.data.pinId || 0; }
1420
1478
  public set pinId(val: number) { this.setDataVal('pinId', val); }
1421
1479
  public get isActive(): boolean { return this.data.isActive; }
@@ -1462,8 +1520,6 @@ export class Heater extends EqItem {
1462
1520
  public set efficiencyMode(val: number) { this.setDataVal('efficiencyMode', val); }
1463
1521
  public get isActive(): boolean { return this.data.isActive; }
1464
1522
  public set isActive(val: boolean) { this.setDataVal('isActive', val); }
1465
- public get isVirtual(): boolean { return this.data.isVirtual; }
1466
- public set isVirtual(val: boolean) { this.setDataVal('isVirtual', val); }
1467
1523
  public get coolingEnabled(): boolean { return this.data.coolingEnabled; }
1468
1524
  public set coolingEnabled(val: boolean) { this.setDataVal('coolingEnabled', val); }
1469
1525
  public get heatingEnabled(): boolean { return this.data.heatingEnabled; }
@@ -1500,6 +1556,10 @@ export class Cover extends EqItem {
1500
1556
  public set normallyOn(val: boolean) { this.setDataVal('normallyOn', val); }
1501
1557
  public get circuits(): number[] { return this.data.circuits; }
1502
1558
  public set circuits(val: number[]) { this.setDataVal('circuits', val); }
1559
+ public get chlorActive(): boolean { return this.data.chlorActive; }
1560
+ public set chlorActive(val: boolean) { this.setDataVal('chlorActive', val); }
1561
+ public get chlorOutput(): boolean { return this.data.chlorOutput; }
1562
+ public set chlorOutput(val: boolean) { this.setDataVal('chlorOutput', val); }
1503
1563
  }
1504
1564
  export interface ICircuitGroup {
1505
1565
  id: number;
@@ -1821,7 +1881,7 @@ export class ChemController extends EqItem {
1821
1881
  //var chemController = {
1822
1882
  // id: 'number', // Id of the controller
1823
1883
  // name: 'string', // Name assigned to the controller
1824
- // type: 'valueMap', // intellichem, homegrown, rem -- There is an unknown but that should probably go away.
1884
+ // type: 'valueMap', // intellichem, rem -- There is an unknown but that should probably go away.
1825
1885
  // body: 'valueMap', // Body assigned to the chem controller.
1826
1886
  // address: 'number', // Address for IntelliChem controller only.
1827
1887
  // isActive: 'booean',
@@ -1910,8 +1970,8 @@ export class ChemController extends EqItem {
1910
1970
  public set address(val: number) { this.setDataVal('address', val); }
1911
1971
  public get isActive(): boolean { return this.data.isActive; }
1912
1972
  public set isActive(val: boolean) { this.setDataVal('isActive', val); }
1913
- public get isVirtual(): boolean { return this.data.isVirtual; }
1914
- public set isVirtual(val: boolean) { this.setDataVal('isVirtual', val); }
1973
+ // public get isVirtual(): boolean { return this.data.isVirtual; }
1974
+ // public set isVirtual(val: boolean) { this.setDataVal('isVirtual', val); }
1915
1975
  public get calciumHardness(): number { return this.data.calciumHardness; }
1916
1976
  public set calciumHardness(val: number) { this.setDataVal('calciumHardness', val); }
1917
1977
  public get cyanuricAcid(): number { return this.data.cyanuricAcid; }
@@ -2198,7 +2258,7 @@ export class ChemicalChlor extends ChildEqItem {
2198
2258
  public initData() {
2199
2259
  super.initData();
2200
2260
  }
2201
- public get enabled(): boolean {
2261
+ public get enabled(): boolean {
2202
2262
  let chlor = sys.chlorinators.getItemById(1);
2203
2263
  return chlor.isActive;
2204
2264
  }
@@ -2215,10 +2275,10 @@ export class ChemicalChlor extends ChildEqItem {
2215
2275
  return typeof model.chlorinePerSec !== 'undefined' ? model.chlorinePerSec : 0;
2216
2276
  }
2217
2277
  public set ratedLbs(val: number) { this.setDataVal('ratedLbs', val); }
2218
- public get superChlor() {
2278
+ public get superChlor() {
2219
2279
  let chlor = sys.chlorinators.getItemById(1);
2220
2280
  return typeof chlor.superChlor !== 'undefined' ? chlor.superChlor : false;
2221
- }
2281
+ }
2222
2282
  public getExtended() {
2223
2283
  let chlor = this.get(true);
2224
2284
  chlor.model = sys.board.valueMaps.chlorinatorModel.transform(this.model);
@@ -96,15 +96,28 @@ export class InvalidEquipmentDataError extends EquipmentError {
96
96
  }
97
97
  public eqData;
98
98
  }
99
+ export class ServiceProcessError extends ApiError {
100
+ constructor(message: string, serviceName: string, process?: string) {
101
+ super(message, 290, 400);
102
+ this.name = 'ServiceProcessError';
103
+ this.service = serviceName;
104
+ this.process = process;
105
+ }
106
+ public process: string;
107
+ public service: string;
108
+ }
99
109
  export class ServiceParameterError extends ApiError {
100
110
  constructor(message: string, serviceName: string, paramName: string, value) {
101
111
  super(message, 280, 400);
102
112
  this.name = 'InvalidServiceParameter';
113
+
103
114
  this.value = value;
104
- this.parameter = value;
115
+ this.parameter = paramName;
116
+ this.service = serviceName;
105
117
  }
106
118
  public value;
107
119
  public parameter: string;
120
+ public service: string;
108
121
  }
109
122
  export class InvalidOperationError extends ApiError {
110
123
  constructor(message: string, operation: string) {