homebridge-econet-rheem 1.0.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 (38) hide show
  1. package/LICENSE +176 -0
  2. package/README.md +64 -0
  3. package/config.schema.json +30 -0
  4. package/dist/accessories/thermostatAccessory.d.ts +26 -0
  5. package/dist/accessories/thermostatAccessory.js +185 -0
  6. package/dist/accessories/thermostatAccessory.js.map +1 -0
  7. package/dist/accessories/waterHeaterAccessory.d.ts +21 -0
  8. package/dist/accessories/waterHeaterAccessory.js +86 -0
  9. package/dist/accessories/waterHeaterAccessory.js.map +1 -0
  10. package/dist/index.d.ts +6 -0
  11. package/dist/index.js +9 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/model/econet.d.ts +39 -0
  14. package/dist/model/econet.js +230 -0
  15. package/dist/model/econet.js.map +1 -0
  16. package/dist/model/enums.d.ts +13 -0
  17. package/dist/model/enums.js +16 -0
  18. package/dist/model/enums.js.map +1 -0
  19. package/dist/model/equipment.d.ts +16 -0
  20. package/dist/model/equipment.js +34 -0
  21. package/dist/model/equipment.js.map +1 -0
  22. package/dist/model/thermostat.d.ts +36 -0
  23. package/dist/model/thermostat.js +180 -0
  24. package/dist/model/thermostat.js.map +1 -0
  25. package/dist/model/utils.d.ts +3 -0
  26. package/dist/model/utils.js +14 -0
  27. package/dist/model/utils.js.map +1 -0
  28. package/dist/model/waterHeater.d.ts +22 -0
  29. package/dist/model/waterHeater.js +68 -0
  30. package/dist/model/waterHeater.js.map +1 -0
  31. package/dist/platform.d.ts +13 -0
  32. package/dist/platform.js +99 -0
  33. package/dist/platform.js.map +1 -0
  34. package/dist/settings.d.ts +8 -0
  35. package/dist/settings.js +9 -0
  36. package/dist/settings.js.map +1 -0
  37. package/notes +7 -0
  38. package/package.json +52 -0
@@ -0,0 +1,39 @@
1
+ import { Logger } from 'homebridge';
2
+ import { Equipment } from './equipment.js';
3
+ export declare const WATER_HEATER = "WH";
4
+ export declare const THERMOSTAT = "HVAC";
5
+ export declare class PyeconetError extends Error {
6
+ constructor(message: string);
7
+ }
8
+ export declare class InvalidCredentialsError extends PyeconetError {
9
+ constructor(message: string);
10
+ }
11
+ export declare class InvalidResponseFormat extends PyeconetError {
12
+ constructor(message: string);
13
+ }
14
+ export declare class GenericHTTPError extends PyeconetError {
15
+ constructor(message: string);
16
+ }
17
+ export declare class EconetApi {
18
+ readonly log: Logger;
19
+ private readonly email;
20
+ private readonly verbose;
21
+ private _userToken;
22
+ private _accountId;
23
+ private _equipment;
24
+ private _mqttClient;
25
+ constructor(log: Logger, email: string, verbose: boolean);
26
+ get userToken(): string | null;
27
+ get accountId(): string | null;
28
+ static login(log: Logger, email: string, password: string, verbose: boolean): Promise<EconetApi>;
29
+ private _authenticate;
30
+ private _getClientId;
31
+ subscribe(): void;
32
+ publish(payload: {
33
+ [key: string]: number;
34
+ }, deviceId: string, serialNumber: string): void;
35
+ unsubscribe(): void;
36
+ private _getLocation;
37
+ getEquipment(): Promise<void>;
38
+ getEquipmentByType(types: string[]): Promise<Map<string, Equipment[]>>;
39
+ }
@@ -0,0 +1,230 @@
1
+ import mqtt from 'mqtt';
2
+ import { WaterHeater } from './waterHeater.js';
3
+ import { Thermostat } from './thermostat.js';
4
+ const HOST = 'rheem.clearblade.com';
5
+ const REST_URL = `https://${HOST}/api/v/1`;
6
+ const CLEAR_BLADE_SYSTEM_KEY = 'e2e699cb0bb0bbb88fc8858cb5a401';
7
+ const CLEAR_BLADE_SYSTEM_SECRET = 'E2E699CB0BE6C6FADDB1B0BC9A20';
8
+ const HEADERS = {
9
+ 'ClearBlade-SystemKey': CLEAR_BLADE_SYSTEM_KEY,
10
+ 'ClearBlade-SystemSecret': CLEAR_BLADE_SYSTEM_SECRET,
11
+ 'Content-Type': 'application/json; charset=UTF-8',
12
+ };
13
+ export const WATER_HEATER = 'WH';
14
+ export const THERMOSTAT = 'HVAC';
15
+ export class PyeconetError extends Error {
16
+ constructor(message) {
17
+ super(message);
18
+ this.name = 'PyeconetError';
19
+ }
20
+ }
21
+ export class InvalidCredentialsError extends PyeconetError {
22
+ constructor(message) {
23
+ super(message);
24
+ this.name = 'InvalidCredentialsError';
25
+ }
26
+ }
27
+ export class InvalidResponseFormat extends PyeconetError {
28
+ constructor(message) {
29
+ super(message);
30
+ this.name = 'InvalidResponseFormat';
31
+ }
32
+ }
33
+ export class GenericHTTPError extends PyeconetError {
34
+ constructor(message) {
35
+ super(message);
36
+ this.name = 'GenericHTTPError';
37
+ }
38
+ }
39
+ export class EconetApi {
40
+ log;
41
+ email;
42
+ verbose;
43
+ _userToken = null;
44
+ _accountId = null;
45
+ _equipment = new Map();
46
+ _mqttClient = null;
47
+ constructor(log, email, verbose) {
48
+ this.log = log;
49
+ this.email = email;
50
+ this.verbose = verbose;
51
+ }
52
+ get userToken() {
53
+ return this._userToken;
54
+ }
55
+ get accountId() {
56
+ return this._accountId;
57
+ }
58
+ static async login(log, email, password, verbose) {
59
+ const api = new EconetApi(log, email, verbose);
60
+ await api._authenticate({ email, password });
61
+ return api;
62
+ }
63
+ async _authenticate(payload) {
64
+ const response = await fetch(`${REST_URL}/user/auth`, {
65
+ method: 'POST',
66
+ headers: HEADERS,
67
+ body: JSON.stringify(payload),
68
+ });
69
+ if (response.status === 200) {
70
+ const json = await response.json();
71
+ if (json.options.success) {
72
+ this._userToken = json.user_token;
73
+ this._accountId = json.options.account_id;
74
+ }
75
+ else {
76
+ throw new InvalidCredentialsError(json.options.message || 'Invalid credentials');
77
+ }
78
+ }
79
+ else {
80
+ throw new GenericHTTPError(`HTTP error: ${response.status}`);
81
+ }
82
+ }
83
+ _getClientId() {
84
+ const timeString = Date.now().toString().replace('.', '').slice(0, 13);
85
+ return `${this.email}${timeString}_android`;
86
+ }
87
+ subscribe() {
88
+ if (!this._equipment.size) {
89
+ return;
90
+ }
91
+ const clientId = this._getClientId();
92
+ const connectionOptions = {
93
+ clientId,
94
+ username: this._userToken,
95
+ password: CLEAR_BLADE_SYSTEM_KEY,
96
+ rejectUnauthorized: true,
97
+ keepalive: 90,
98
+ };
99
+ this._mqttClient = mqtt.connect(`mqtts://${HOST}:1884`, connectionOptions);
100
+ this._mqttClient.on('connect', () => {
101
+ this._mqttClient.subscribe(`user/${this._accountId}/device/reported`);
102
+ this._mqttClient.subscribe(`user/${this._accountId}/device/desired`);
103
+ });
104
+ this._mqttClient.on('message', (topic, message) => {
105
+ try {
106
+ const unpackedJson = JSON.parse(message.toString());
107
+ if (this.verbose) {
108
+ this.log.debug(`Received MQTT message from topic: ${topic}\n`, JSON.stringify(unpackedJson, null, 2));
109
+ }
110
+ const serial = unpackedJson.serial_number;
111
+ const equipment = this._equipment.get(serial);
112
+ if (equipment) {
113
+ equipment.updateFromMQTT(unpackedJson);
114
+ }
115
+ else if ('@SIGNAL' in unpackedJson) {
116
+ for (const eq of this._equipment.values()) {
117
+ if (eq.deviceId === unpackedJson.device_name) {
118
+ eq.updateFromMQTT(unpackedJson);
119
+ }
120
+ }
121
+ }
122
+ }
123
+ catch (e) {
124
+ this.log.error('Failed to parse MQTT message:', message.toString());
125
+ }
126
+ });
127
+ this._mqttClient.on('offline', () => {
128
+ this.log.debug('MQTT client went offline');
129
+ });
130
+ let reconnectAttempts = 1;
131
+ this._mqttClient.on('close', () => {
132
+ this.log.debug('MQTT connection closed, attempting to reconnect...');
133
+ setTimeout(() => {
134
+ this._mqttClient.reconnect(connectionOptions);
135
+ reconnectAttempts *= 2;
136
+ }, Math.min(300000, 5000 * reconnectAttempts)); // Exponential backoff: 5s, 10s, 20s... 300s
137
+ });
138
+ this._mqttClient.on('error', (err) => {
139
+ this.log.error('MQTT error:', err);
140
+ });
141
+ }
142
+ publish(payload, deviceId, serialNumber) {
143
+ const dateTime = new Date().toISOString().replace(/\.\d{3}Z$/, '');
144
+ const transactionId = `ANDROID_${dateTime}`;
145
+ const publishPayload = {
146
+ transactionId,
147
+ device_name: deviceId,
148
+ serial_number: serialNumber,
149
+ ...payload,
150
+ };
151
+ if (this._mqttClient) {
152
+ const topic = `user/${this._accountId}/device/desired`;
153
+ const payload = JSON.stringify(publishPayload, null, 2);
154
+ this.log.debug(`Publishing MQTT message to topic: ${topic}\n`, payload);
155
+ this._mqttClient.publish(topic, payload);
156
+ }
157
+ }
158
+ unsubscribe() {
159
+ if (this._mqttClient) {
160
+ this._mqttClient.end();
161
+ }
162
+ }
163
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
164
+ async _getLocation() {
165
+ const headers = { ...HEADERS, 'ClearBlade-UserToken': this._userToken };
166
+ const payload = {
167
+ location_only: false,
168
+ type: 'com.econet.econetconsumerandroid',
169
+ version: '6.0.0-375-01b4870e',
170
+ };
171
+ const response = await fetch(`${REST_URL}/code/${CLEAR_BLADE_SYSTEM_KEY}/getUserDataForApp`, {
172
+ method: 'POST',
173
+ headers,
174
+ body: JSON.stringify(payload),
175
+ });
176
+ if (response.status === 200) {
177
+ const json = await response.json();
178
+ if (json.success) {
179
+ return json.results.locations;
180
+ }
181
+ throw new InvalidResponseFormat('Invalid response format');
182
+ }
183
+ throw new GenericHTTPError(`HTTP error: ${response.status}`);
184
+ }
185
+ async getEquipment() {
186
+ const locations = await this._getLocation();
187
+ for (const location of locations) {
188
+ for (const equip of location.equiptments) {
189
+ if ('error' in equip) {
190
+ this.log.error(`econet equipment error: ${equip.error}`);
191
+ continue;
192
+ }
193
+ if (this.verbose) {
194
+ this.log.debug('Creating Equipment with data:\n', JSON.stringify(equip, null, 2));
195
+ }
196
+ let equipObj;
197
+ if (equip.device_type === WATER_HEATER) {
198
+ equipObj = new WaterHeater(this, equip);
199
+ }
200
+ else if (equip.device_type === THERMOSTAT) {
201
+ equipObj = new Thermostat(this, equip);
202
+ }
203
+ else {
204
+ continue;
205
+ }
206
+ this._equipment.set(equipObj.serialNumber, equipObj);
207
+ if (equip.device_type === THERMOSTAT && equip.zoning_devices) {
208
+ for (const zoningDevice of equip.zoning_devices) {
209
+ const zoningEquip = new Thermostat(this, zoningDevice);
210
+ this._equipment.set(zoningEquip.serialNumber, zoningEquip);
211
+ }
212
+ }
213
+ }
214
+ }
215
+ }
216
+ async getEquipmentByType(types) {
217
+ if (!this._equipment.size) {
218
+ await this.getEquipment();
219
+ }
220
+ const result = new Map();
221
+ types.forEach((type) => result.set(type, []));
222
+ for (const equip of this._equipment.values()) {
223
+ if (types.includes(equip instanceof WaterHeater ? WATER_HEATER : THERMOSTAT)) {
224
+ result.get(equip instanceof WaterHeater ? WATER_HEATER : THERMOSTAT).push(equip);
225
+ }
226
+ }
227
+ return result;
228
+ }
229
+ }
230
+ //# sourceMappingURL=econet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"econet.js","sourceRoot":"","sources":["../../src/model/econet.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export declare enum ThermostatOperationMode {
2
+ OFF = 1,
3
+ HEATING = 2,
4
+ COOLING = 3,
5
+ AUTO = 4,
6
+ FAN_ONLY = 5,
7
+ EMERGENCY_HEAT = 6,
8
+ UNKNOWN = 99
9
+ }
10
+ export declare enum TemperatureUnits {
11
+ FAHRENHEIT = 1,
12
+ CELSIUS = 2
13
+ }
@@ -0,0 +1,16 @@
1
+ export var ThermostatOperationMode;
2
+ (function (ThermostatOperationMode) {
3
+ ThermostatOperationMode[ThermostatOperationMode["OFF"] = 1] = "OFF";
4
+ ThermostatOperationMode[ThermostatOperationMode["HEATING"] = 2] = "HEATING";
5
+ ThermostatOperationMode[ThermostatOperationMode["COOLING"] = 3] = "COOLING";
6
+ ThermostatOperationMode[ThermostatOperationMode["AUTO"] = 4] = "AUTO";
7
+ ThermostatOperationMode[ThermostatOperationMode["FAN_ONLY"] = 5] = "FAN_ONLY";
8
+ ThermostatOperationMode[ThermostatOperationMode["EMERGENCY_HEAT"] = 6] = "EMERGENCY_HEAT";
9
+ ThermostatOperationMode[ThermostatOperationMode["UNKNOWN"] = 99] = "UNKNOWN";
10
+ })(ThermostatOperationMode || (ThermostatOperationMode = {}));
11
+ export var TemperatureUnits;
12
+ (function (TemperatureUnits) {
13
+ TemperatureUnits[TemperatureUnits["FAHRENHEIT"] = 1] = "FAHRENHEIT";
14
+ TemperatureUnits[TemperatureUnits["CELSIUS"] = 2] = "CELSIUS";
15
+ })(TemperatureUnits || (TemperatureUnits = {}));
16
+ //# sourceMappingURL=enums.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enums.js","sourceRoot":"","sources":["../../src/model/enums.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,uBAQX;AARD,WAAY,uBAAuB;IACjC,mEAAO,CAAA;IACP,2EAAW,CAAA;IACX,2EAAW,CAAA;IACX,qEAAQ,CAAA;IACR,6EAAY,CAAA;IACZ,yFAAkB,CAAA;IAClB,4EAAY,CAAA;AACd,CAAC,EARW,uBAAuB,KAAvB,uBAAuB,QAQlC;AAED,MAAM,CAAN,IAAY,gBAGX;AAHD,WAAY,gBAAgB;IAC1B,mEAAc,CAAA;IACd,6DAAW,CAAA;AACb,CAAC,EAHW,gBAAgB,KAAhB,gBAAgB,QAG3B"}
@@ -0,0 +1,16 @@
1
+ import { EconetApi } from './econet.js';
2
+ export declare abstract class Equipment {
3
+ private device_id?;
4
+ private serial_number?;
5
+ private device_name?;
6
+ protected _api: EconetApi;
7
+ private _onUpdateCallback;
8
+ constructor(api: EconetApi);
9
+ get deviceId(): string;
10
+ get serialNumber(): string;
11
+ get deviceName(): string;
12
+ setOnUpdateCallback(callback: (serialNumber: string) => void): void;
13
+ protected didUpdate(): void;
14
+ protected updateFromREST(update: any): void;
15
+ abstract updateFromMQTT(update: any): void;
16
+ }
@@ -0,0 +1,34 @@
1
+ export class Equipment {
2
+ device_id;
3
+ serial_number;
4
+ device_name;
5
+ _api;
6
+ _onUpdateCallback = null;
7
+ constructor(api) {
8
+ this._api = api;
9
+ }
10
+ get deviceId() {
11
+ return this.device_id || 'undefined';
12
+ }
13
+ get serialNumber() {
14
+ return this.serial_number || 'undefined';
15
+ }
16
+ get deviceName() {
17
+ return this.device_name || 'undefined';
18
+ }
19
+ setOnUpdateCallback(callback) {
20
+ this._onUpdateCallback = callback;
21
+ }
22
+ didUpdate() {
23
+ if (this._onUpdateCallback) {
24
+ this._onUpdateCallback(this.serialNumber);
25
+ }
26
+ }
27
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
+ updateFromREST(update) {
29
+ this.device_id = update.device_name;
30
+ this.serial_number = update.serial_number;
31
+ this.device_name = update['@NAME'].value;
32
+ }
33
+ }
34
+ //# sourceMappingURL=equipment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"equipment.js","sourceRoot":"","sources":["../../src/model/equipment.ts"],"names":[],"mappings":"AAEA,MAAM,OAAgB,SAAS;IACrB,SAAS,CAAiB;IAC1B,aAAa,CAAiB;IAC9B,WAAW,CAAiB;IAE1B,IAAI,CAAY;IAClB,iBAAiB,GAA4C,IAAI,CAAC;IAE1E,YAAY,GAAc;QACxB,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;IAClB,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,IAAI,WAAW,CAAC;IACvC,CAAC;IAED,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,aAAa,IAAI,WAAW,CAAC;IAC3C,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC;IACzC,CAAC;IAED,mBAAmB,CAAC,QAAwC;QAC1D,IAAI,CAAC,iBAAiB,GAAG,QAAQ,CAAC;IACpC,CAAC;IAES,SAAS;QACjB,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAED,8DAA8D;IACpD,cAAc,CAAC,MAAW;QAClC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,WAAW,CAAC;QACpC,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;QAC1C,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;IAC3C,CAAC;CAIF"}
@@ -0,0 +1,36 @@
1
+ import { Equipment } from './equipment.js';
2
+ import { EconetApi } from './econet.js';
3
+ import { ThermostatOperationMode, TemperatureUnits } from './enums.js';
4
+ export declare class Thermostat extends Equipment {
5
+ private enabled;
6
+ private running;
7
+ private cool_set_point;
8
+ private cool_lower_limit;
9
+ private cool_upper_limit;
10
+ private heat_set_point;
11
+ private heat_lower_limit;
12
+ private heat_upper_limit;
13
+ private dead_band;
14
+ private text_modes;
15
+ private supported_modes;
16
+ private current_mode;
17
+ private temp_units;
18
+ constructor(api: EconetApi, restUpdate: any);
19
+ get isEnabled(): boolean;
20
+ get isRunning(): boolean;
21
+ get currentTemp(): number;
22
+ get coolSetPoint(): number;
23
+ get coolSetPointLimits(): [number, number];
24
+ get heatSetPoint(): number;
25
+ get heatSetPointLimits(): [number, number];
26
+ get deadband(): number;
27
+ get modes(): ThermostatOperationMode[];
28
+ get mode(): ThermostatOperationMode;
29
+ get units(): TemperatureUnits;
30
+ protected updateFromREST(update: any): void;
31
+ updateFromMQTT(update: any): void;
32
+ private _modeFromString;
33
+ setEnabled(enabled: boolean): void;
34
+ setMode(mode: ThermostatOperationMode): void;
35
+ setSetPoint(targetTemp?: number, targetTempCool?: number, targetTempHeat?: number): void;
36
+ }
@@ -0,0 +1,180 @@
1
+ import { Equipment } from './equipment.js';
2
+ import { ThermostatOperationMode, TemperatureUnits } from './enums.js';
3
+ export class Thermostat extends Equipment {
4
+ enabled = false;
5
+ running = false;
6
+ cool_set_point = 0;
7
+ cool_lower_limit = 0;
8
+ cool_upper_limit = 0;
9
+ heat_set_point = 0;
10
+ heat_lower_limit = 0;
11
+ heat_upper_limit = 0;
12
+ dead_band = 0;
13
+ text_modes = [];
14
+ supported_modes = [];
15
+ current_mode = ThermostatOperationMode.UNKNOWN;
16
+ temp_units = TemperatureUnits.CELSIUS;
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ constructor(api, restUpdate) {
19
+ super(api);
20
+ this.updateFromREST(restUpdate);
21
+ }
22
+ get isEnabled() {
23
+ return this.enabled;
24
+ }
25
+ get isRunning() {
26
+ return this.running;
27
+ }
28
+ get currentTemp() {
29
+ return this.dead_band;
30
+ }
31
+ get coolSetPoint() {
32
+ return this.cool_set_point;
33
+ }
34
+ get coolSetPointLimits() {
35
+ return [this.cool_lower_limit, this.cool_upper_limit];
36
+ }
37
+ get heatSetPoint() {
38
+ return this.heat_set_point;
39
+ }
40
+ get heatSetPointLimits() {
41
+ return [this.heat_lower_limit, this.heat_upper_limit];
42
+ }
43
+ get deadband() {
44
+ return this.dead_band;
45
+ }
46
+ get modes() {
47
+ return this.supported_modes;
48
+ }
49
+ get mode() {
50
+ return this.current_mode;
51
+ }
52
+ get units() {
53
+ return this.temp_units;
54
+ }
55
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
56
+ updateFromREST(update) {
57
+ super.updateFromREST(update);
58
+ this.enabled = update['@ENABLED']?.value === 1;
59
+ this.running = update['@RUNNINGSTATUS'] !== '';
60
+ this.cool_set_point = update['@COOLSETPOINT']?.value || 0;
61
+ const coolLimits = update['@COOLSETPOINT']?.constraints;
62
+ if (coolLimits) {
63
+ this.cool_lower_limit = coolLimits.lowerLimit;
64
+ this.cool_upper_limit = coolLimits.upperLimit;
65
+ }
66
+ this.heat_set_point = update['@HEATSETPOINT']?.value || 0;
67
+ const heatLimits = update['@HEATSETPOINT']?.constraints;
68
+ if (heatLimits) {
69
+ this.heat_lower_limit = heatLimits.lowerLimit;
70
+ this.heat_upper_limit = heatLimits.upperLimit;
71
+ }
72
+ this.dead_band = update['@DEADBAND']?.value || 0;
73
+ this.text_modes = update['@MODE']?.constraints.enumText;
74
+ this.supported_modes = [];
75
+ const modes = update['@MODE']?.constraints.enumText;
76
+ if (modes) {
77
+ for (const mode of modes) {
78
+ const opMode = this._modeFromString(mode);
79
+ if (opMode !== ThermostatOperationMode.UNKNOWN) {
80
+ this.supported_modes.push(opMode);
81
+ }
82
+ }
83
+ }
84
+ this.current_mode = this.modes[update['@MODE']?.value] ?? ThermostatOperationMode.UNKNOWN;
85
+ this.temp_units = update['@DEADBAND']?.constraints.units === 'deg F' ? TemperatureUnits.FAHRENHEIT : TemperatureUnits.CELSIUS;
86
+ this.didUpdate();
87
+ }
88
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
89
+ updateFromMQTT(update) {
90
+ if ('@ENABLED' in update) {
91
+ this.enabled = update['@ENABLED'] === 1 || update['@ENABLED']?.value === 1;
92
+ this._api.log.debug(`${this.deviceName} enabled = ${this.enabled}`);
93
+ }
94
+ this._api.log.error('MQTT not yet implemented on thermostat: ', JSON.stringify(update, null, 2));
95
+ this.didUpdate();
96
+ }
97
+ _modeFromString(strValue) {
98
+ const cleanedString = strValue.trim().replace(' ', '').toUpperCase();
99
+ switch (cleanedString) {
100
+ case 'OFF':
101
+ return ThermostatOperationMode.OFF;
102
+ case 'HEATING':
103
+ return ThermostatOperationMode.HEATING;
104
+ case 'COOLING':
105
+ return ThermostatOperationMode.COOLING;
106
+ case 'AUTO':
107
+ return ThermostatOperationMode.AUTO;
108
+ case 'FANONLY':
109
+ return ThermostatOperationMode.FAN_ONLY;
110
+ case 'EMERGENCYHEAT':
111
+ return ThermostatOperationMode.EMERGENCY_HEAT;
112
+ default:
113
+ this._api.log.error('Unknown thermostat mode:', strValue);
114
+ return ThermostatOperationMode.UNKNOWN;
115
+ }
116
+ }
117
+ setEnabled(enabled) {
118
+ this._api.publish({ '@ENABLED': enabled ? 1 : 0 }, this.deviceId, this.serialNumber);
119
+ }
120
+ setMode(mode) {
121
+ const payload = {};
122
+ this.text_modes.forEach((textMode, index) => {
123
+ if (mode === this._modeFromString(textMode)) {
124
+ payload['@MODE'] = index;
125
+ }
126
+ });
127
+ if (Object.keys(payload).length > 0) {
128
+ this._api.publish(payload, this.deviceId, this.serialNumber);
129
+ }
130
+ }
131
+ setSetPoint(targetTemp, targetTempCool, targetTempHeat) {
132
+ const coolPayload = {};
133
+ const heatPayload = {};
134
+ if (targetTempCool || (targetTemp && this.mode === ThermostatOperationMode.COOLING)) {
135
+ const temp = targetTempCool ?? targetTemp;
136
+ const [lower, upper] = this.coolSetPointLimits;
137
+ if (lower <= temp && temp <= upper) {
138
+ coolPayload['@COOLSETPOINT'] = temp;
139
+ }
140
+ else {
141
+ this._api.log.error(`Cool set point out of range. Lower: ${lower}, Upper: ${upper}, Set point: ${temp}`);
142
+ }
143
+ }
144
+ if (targetTempHeat || (targetTemp && [ThermostatOperationMode.HEATING, ThermostatOperationMode.EMERGENCY_HEAT].includes(this.mode))) {
145
+ const temp = targetTempHeat ?? targetTemp;
146
+ const [lower, upper] = this.heatSetPointLimits;
147
+ if (lower <= temp && temp <= upper) {
148
+ heatPayload['@HEATSETPOINT'] = temp;
149
+ }
150
+ else {
151
+ this._api.log.error(`Heat set point out of range. Lower: ${lower}, Upper: ${upper}, Set point: ${temp}`);
152
+ }
153
+ }
154
+ let hasSetTemp = false;
155
+ if (coolPayload && [ThermostatOperationMode.AUTO, ThermostatOperationMode.COOLING].includes(this.mode)) {
156
+ this._api.publish(coolPayload, this.deviceId, this.serialNumber);
157
+ hasSetTemp = true;
158
+ }
159
+ if (heatPayload && [ThermostatOperationMode.AUTO, ThermostatOperationMode.HEATING, ThermostatOperationMode.EMERGENCY_HEAT].includes(this.mode)) {
160
+ this._api.publish(heatPayload, this.deviceId, this.serialNumber);
161
+ hasSetTemp = true;
162
+ }
163
+ if (targetTemp && !hasSetTemp) {
164
+ let payload = {};
165
+ if (this.mode === ThermostatOperationMode.COOLING) {
166
+ payload = coolPayload;
167
+ }
168
+ else if ([ThermostatOperationMode.HEATING, ThermostatOperationMode.EMERGENCY_HEAT].includes(this.mode)) {
169
+ payload = heatPayload;
170
+ }
171
+ else {
172
+ this._api.log.error(`Can't auto determine set point to set when mode is: ${this.mode}`);
173
+ }
174
+ if (Object.keys(payload).length > 0) {
175
+ this._api.publish(payload, this.deviceId, this.serialNumber);
176
+ }
177
+ }
178
+ }
179
+ }
180
+ //# sourceMappingURL=thermostat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thermostat.js","sourceRoot":"","sources":["../../src/model/thermostat.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { TemperatureUnits } from '../model/enums.js';
2
+ export declare const toCelsius: (temp: number, units: TemperatureUnits) => number;
3
+ export declare const fromCelsius: (temp: number, units: TemperatureUnits) => number;
@@ -0,0 +1,14 @@
1
+ import { TemperatureUnits } from '../model/enums.js';
2
+ const fahrenheitToCelsius = (fahrenheit) => {
3
+ return Number(((fahrenheit - 32) * 5 / 9).toFixed(1));
4
+ };
5
+ const celsiusToFahrenheit = (celsius) => {
6
+ return Math.round((celsius * 9 / 5) + 32);
7
+ };
8
+ export const toCelsius = (temp, units) => {
9
+ return units === TemperatureUnits.FAHRENHEIT ? fahrenheitToCelsius(temp) : temp;
10
+ };
11
+ export const fromCelsius = (temp, units) => {
12
+ return units === TemperatureUnits.FAHRENHEIT ? celsiusToFahrenheit(temp) : temp;
13
+ };
14
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/model/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,mBAAmB,GAAG,CAAC,UAAkB,EAAU,EAAE;IACzD,OAAO,MAAM,CAAC,CAAC,CAAC,UAAU,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,OAAe,EAAU,EAAE;IACtD,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;AAC5C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,KAAuB,EAAU,EAAE;IACzE,OAAO,KAAK,KAAK,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAClF,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,KAAuB,EAAU,EAAE;IAC3E,OAAO,KAAK,KAAK,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAClF,CAAC,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { Equipment } from './equipment.js';
2
+ import { EconetApi } from './econet.js';
3
+ import { TemperatureUnits } from './enums.js';
4
+ export declare class WaterHeater extends Equipment {
5
+ private enabled;
6
+ private running;
7
+ private temp_units;
8
+ private lower_limit;
9
+ private upper_limit;
10
+ private set_point;
11
+ constructor(api: EconetApi, restUpdate: any);
12
+ get isEnabled(): boolean;
13
+ get isRunning(): boolean;
14
+ get units(): TemperatureUnits;
15
+ get limits(): [number, number];
16
+ get currentTemp(): number;
17
+ get setPoint(): number;
18
+ protected updateFromREST(update: any): void;
19
+ updateFromMQTT(update: any): void;
20
+ setEnabled(enabled: boolean): void;
21
+ setSetPoint(setPoint: number): void;
22
+ }