UNPKG

homebridge-econet-rheem

Version:

Homebridge plugin based on pyeconet for control of Rheem water heaters

180 lines 7.16 kB
import { Equipment } from './equipment.js'; import { ThermostatOperationMode, TemperatureUnits } from './enums.js'; export class Thermostat extends Equipment { enabled = false; running = false; cool_set_point = 0; cool_lower_limit = 0; cool_upper_limit = 0; heat_set_point = 0; heat_lower_limit = 0; heat_upper_limit = 0; dead_band = 0; text_modes = []; supported_modes = []; current_mode = ThermostatOperationMode.UNKNOWN; temp_units = TemperatureUnits.CELSIUS; // eslint-disable-next-line @typescript-eslint/no-explicit-any constructor(api, restUpdate) { super(api); this.updateFromREST(restUpdate); } get isEnabled() { return this.enabled; } get isRunning() { return this.running; } get currentTemp() { return this.dead_band; } get coolSetPoint() { return this.cool_set_point; } get coolSetPointLimits() { return [this.cool_lower_limit, this.cool_upper_limit]; } get heatSetPoint() { return this.heat_set_point; } get heatSetPointLimits() { return [this.heat_lower_limit, this.heat_upper_limit]; } get deadband() { return this.dead_band; } get modes() { return this.supported_modes; } get mode() { return this.current_mode; } get units() { return this.temp_units; } // eslint-disable-next-line @typescript-eslint/no-explicit-any updateFromREST(update) { super.updateFromREST(update); this.enabled = update['@ENABLED']?.value === 1; this.running = update['@RUNNINGSTATUS'] !== ''; this.cool_set_point = update['@COOLSETPOINT']?.value || 0; const coolLimits = update['@COOLSETPOINT']?.constraints; if (coolLimits) { this.cool_lower_limit = coolLimits.lowerLimit; this.cool_upper_limit = coolLimits.upperLimit; } this.heat_set_point = update['@HEATSETPOINT']?.value || 0; const heatLimits = update['@HEATSETPOINT']?.constraints; if (heatLimits) { this.heat_lower_limit = heatLimits.lowerLimit; this.heat_upper_limit = heatLimits.upperLimit; } this.dead_band = update['@DEADBAND']?.value || 0; this.text_modes = update['@MODE']?.constraints.enumText; this.supported_modes = []; const modes = update['@MODE']?.constraints.enumText; if (modes) { for (const mode of modes) { const opMode = this._modeFromString(mode); if (opMode !== ThermostatOperationMode.UNKNOWN) { this.supported_modes.push(opMode); } } } this.current_mode = this.modes[update['@MODE']?.value] ?? ThermostatOperationMode.UNKNOWN; this.temp_units = update['@DEADBAND']?.constraints.units === 'deg F' ? TemperatureUnits.FAHRENHEIT : TemperatureUnits.CELSIUS; this.didUpdate(); } // eslint-disable-next-line @typescript-eslint/no-explicit-any updateFromMQTT(update) { if ('@ENABLED' in update) { this.enabled = update['@ENABLED'] === 1 || update['@ENABLED']?.value === 1; this._api.log.debug(`${this.deviceName} enabled = ${this.enabled}`); } this._api.log.error('MQTT not yet implemented on thermostat: ', JSON.stringify(update, null, 2)); this.didUpdate(); } _modeFromString(strValue) { const cleanedString = strValue.trim().replace(' ', '').toUpperCase(); switch (cleanedString) { case 'OFF': return ThermostatOperationMode.OFF; case 'HEATING': return ThermostatOperationMode.HEATING; case 'COOLING': return ThermostatOperationMode.COOLING; case 'AUTO': return ThermostatOperationMode.AUTO; case 'FANONLY': return ThermostatOperationMode.FAN_ONLY; case 'EMERGENCYHEAT': return ThermostatOperationMode.EMERGENCY_HEAT; default: this._api.log.error('Unknown thermostat mode:', strValue); return ThermostatOperationMode.UNKNOWN; } } setEnabled(enabled) { this._api.publish({ '@ENABLED': enabled ? 1 : 0 }, this.deviceId, this.serialNumber); } setMode(mode) { const payload = {}; this.text_modes.forEach((textMode, index) => { if (mode === this._modeFromString(textMode)) { payload['@MODE'] = index; } }); if (Object.keys(payload).length > 0) { this._api.publish(payload, this.deviceId, this.serialNumber); } } setSetPoint(targetTemp, targetTempCool, targetTempHeat) { const coolPayload = {}; const heatPayload = {}; if (targetTempCool || (targetTemp && this.mode === ThermostatOperationMode.COOLING)) { const temp = targetTempCool ?? targetTemp; const [lower, upper] = this.coolSetPointLimits; if (lower <= temp && temp <= upper) { coolPayload['@COOLSETPOINT'] = temp; } else { this._api.log.error(`Cool set point out of range. Lower: ${lower}, Upper: ${upper}, Set point: ${temp}`); } } if (targetTempHeat || (targetTemp && [ThermostatOperationMode.HEATING, ThermostatOperationMode.EMERGENCY_HEAT].includes(this.mode))) { const temp = targetTempHeat ?? targetTemp; const [lower, upper] = this.heatSetPointLimits; if (lower <= temp && temp <= upper) { heatPayload['@HEATSETPOINT'] = temp; } else { this._api.log.error(`Heat set point out of range. Lower: ${lower}, Upper: ${upper}, Set point: ${temp}`); } } let hasSetTemp = false; if (coolPayload && [ThermostatOperationMode.AUTO, ThermostatOperationMode.COOLING].includes(this.mode)) { this._api.publish(coolPayload, this.deviceId, this.serialNumber); hasSetTemp = true; } if (heatPayload && [ThermostatOperationMode.AUTO, ThermostatOperationMode.HEATING, ThermostatOperationMode.EMERGENCY_HEAT].includes(this.mode)) { this._api.publish(heatPayload, this.deviceId, this.serialNumber); hasSetTemp = true; } if (targetTemp && !hasSetTemp) { let payload = {}; if (this.mode === ThermostatOperationMode.COOLING) { payload = coolPayload; } else if ([ThermostatOperationMode.HEATING, ThermostatOperationMode.EMERGENCY_HEAT].includes(this.mode)) { payload = heatPayload; } else { this._api.log.error(`Can't auto determine set point to set when mode is: ${this.mode}`); } if (Object.keys(payload).length > 0) { this._api.publish(payload, this.deviceId, this.serialNumber); } } } } //# sourceMappingURL=thermostat.js.map