UNPKG

homebridge-rinnai-touch-platform

Version:

Homebridge Plugin to control heating/cooling via a Rinnai Touch WiFi Module

442 lines 17.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RinnaiService = exports.ScheduleOverrideModes = exports.ControlModes = exports.OperatingStates = exports.OperatingModes = void 0; const events = require("events"); const Status_1 = require("../models/Status"); const Fault_1 = require("../models/Fault"); const RinnaiSession_1 = require("./RinnaiSession"); const Command_1 = require("../models/Command"); var OperatingModes; (function (OperatingModes) { OperatingModes[OperatingModes["HEATING"] = 0] = "HEATING"; OperatingModes[OperatingModes["COOLING"] = 1] = "COOLING"; OperatingModes[OperatingModes["EVAPORATIVE_COOLING"] = 2] = "EVAPORATIVE_COOLING"; OperatingModes[OperatingModes["REVERSE_CYLCE"] = 3] = "REVERSE_CYLCE"; OperatingModes[OperatingModes["NONE"] = 4] = "NONE"; })(OperatingModes || (exports.OperatingModes = OperatingModes = {})); var OperatingStates; (function (OperatingStates) { OperatingStates[OperatingStates["NORMAL"] = 0] = "NORMAL"; OperatingStates[OperatingStates["CLOCK_SETTING"] = 1] = "CLOCK_SETTING"; OperatingStates[OperatingStates["PARAMETER_SETTING"] = 2] = "PARAMETER_SETTING"; OperatingStates[OperatingStates["USER_SETTING"] = 3] = "USER_SETTING"; OperatingStates[OperatingStates["PIN_ENTRY"] = 4] = "PIN_ENTRY"; })(OperatingStates || (exports.OperatingStates = OperatingStates = {})); var ControlModes; (function (ControlModes) { ControlModes[ControlModes["MANUAL"] = 0] = "MANUAL"; ControlModes[ControlModes["AUTO"] = 1] = "AUTO"; })(ControlModes || (exports.ControlModes = ControlModes = {})); var ScheduleOverrideModes; (function (ScheduleOverrideModes) { ScheduleOverrideModes[ScheduleOverrideModes["NONE"] = 0] = "NONE"; ScheduleOverrideModes[ScheduleOverrideModes["ADVANCE"] = 1] = "ADVANCE"; ScheduleOverrideModes[ScheduleOverrideModes["OPERATION"] = 2] = "OPERATION"; })(ScheduleOverrideModes || (exports.ScheduleOverrideModes = ScheduleOverrideModes = {})); class RinnaiService extends events.EventEmitter { constructor(options = {}) { var _a, _b; super(); this.faultDetected = false; this.AllZones = ['U', 'A', 'B', 'C', 'D']; this.days = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT']; this.log = (_a = options.log) !== null && _a !== void 0 ? _a : console; this.invertComfortLevel = (_b = options.invertComfortLevel) !== null && _b !== void 0 ? _b : true; this._session = new RinnaiSession_1.RinnaiSession({ log: options.log, address: options.address, port: options.port, showModuleEvents: options.showModuleEvents, showModuleStatus: options.showModuleStatus, bootTime: options.bootTime, bootPassword: options.bootPassword, }); } async init() { this.log.debug(this.constructor.name, 'init'); try { await this.session.start(); // Check that controller is in Normal Operating state let operatingState = this.session.status.getState(Status_1.States.OperatingState); while (operatingState !== 'N') { this.log.warn('Controller is not in \'Normal\' operating state. Will wait for 1 minute'); await this.session.delay(60000); operatingState = this.session.status.getState(Status_1.States.OperatingState); } this.session.on('status', this.handleStatus.bind(this)); } catch (error) { if (error instanceof Error) { this.log.error(error.message); } throw error; } } // // Getters // get session() { return this._session; } getHasMultiSetPoint() { return this.session.status.hasMultiSetPoint; } getTemperatureUnits() { var _a; return (_a = this.session.status.getState(Status_1.States.TemperatureUnits)) !== null && _a !== void 0 ? _a : 'C'; } getZoneName(zone) { var _a, _b; if (zone === 'U') { return 'Common'; } const name = (_b = (_a = this.session.status.getState(Status_1.States.ZoneName, zone)) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : ''; return name === '' ? `Zone ${zone}` : name; } getHasHeater() { return this.session.status.getState(Status_1.States.HasHeater) === 'Y'; } getHasCooler() { return this.session.status.getState(Status_1.States.HasCooler) === 'Y'; } getHasEvaporative() { return this.session.status.getState(Status_1.States.HasEvaporative) === 'Y'; } getOperatingMode() { const mode = this.session.status.getState(Status_1.States.OperatingMode); switch (mode) { case 'H': return OperatingModes.HEATING; case 'C': return OperatingModes.COOLING; case 'E': return OperatingModes.EVAPORATIVE_COOLING; case 'R': return OperatingModes.REVERSE_CYLCE; default: return OperatingModes.NONE; } } getOperatingStates() { const mode = this.session.status.getState(Status_1.States.OperatingState); switch (mode) { case 'N': return OperatingStates.NORMAL; case 'C': return OperatingStates.CLOCK_SETTING; case 'P': return OperatingStates.PARAMETER_SETTING; case 'U': return OperatingStates.USER_SETTING; default: return OperatingStates.PIN_ENTRY; } } getZoneInstalled(zone) { return this.session.status.getState(Status_1.States.ZoneInstalled, zone) === 'Y'; } getZonesInstalled() { const zones = []; for (const zone of this.AllZones) { if (this.getZoneInstalled(zone)) { zones.push(zone); } } return zones; } getPowerState() { return this.session.status.getState(Status_1.States.PowerState) === 'N'; } getFanState() { return this.session.status.modeEvap ? this.session.status.getState(Status_1.States.FanState) === 'N' : this.session.status.getState(Status_1.States.FanState) === 'Z'; } getFanSpeed() { const speed = this.session.status.getState(Status_1.States.FanSpeed); return speed === undefined ? 0.0 : parseInt(speed); } getPumpState() { return this.session.status.getState(Status_1.States.PumpState) === 'N'; } getControlMode(zone) { const controlMode = this.session.status.getState(Status_1.States.ControlMode, zone); return controlMode === 'M' ? ControlModes.MANUAL : ControlModes.AUTO; } getSetPointTemperature(zone) { const temperature = this.session.status.getState(Status_1.States.SetPointTemperature, zone); if (temperature === undefined) { return undefined; } return this.session.status.modeEvap ? this.toTemperature(temperature) : parseInt(temperature); } getScheduleOverride(zone) { const override = this.session.status.getState(Status_1.States.ScheduleOverride, zone); switch (override) { case 'N': return ScheduleOverrideModes.NONE; case 'A': return ScheduleOverrideModes.ADVANCE; default: return ScheduleOverrideModes.OPERATION; } } getHeaterCoolerActive(zone = 'U') { switch (this.getOperatingMode()) { case OperatingModes.HEATING: return this.getHasMultiSetPoint() || zone !== 'U' ? this.session.status.getState(Status_1.States.AutoEnabled, zone) === 'Y' : this.session.status.getState(Status_1.States.CallingForHeat) === 'Y'; case OperatingModes.COOLING: return this.getHasMultiSetPoint() || zone !== 'U' ? this.session.status.getState(Status_1.States.AutoEnabled, zone) === 'Y' : this.session.status.getState(Status_1.States.CallingForCool) === 'Y'; case OperatingModes.EVAPORATIVE_COOLING: return this.session.status.getState(Status_1.States.CoolerIsBusy) === 'Y'; default: return false; } } getUserEnabled(zone) { return this.session.status.getState(Status_1.States.UserEnabled, zone) === 'Y'; } getMeasuredTemperature(zone) { const temperature = this.session.status.getState(Status_1.States.MeasuredTemperature, zone); if (temperature !== undefined && temperature !== '999') { return parseInt(temperature) / 10.0; } } getAutoEnabled(zone) { return this.session.status.getState(Status_1.States.AutoEnabled, zone) === 'Y'; } // // Setters // async setOperatingMode(value) { this.log.debug(this.constructor.name, 'setOperatingMode', value); try { const state = OperatingModes[value].substring(0, 1); const command = new Command_1.Command({ command: Command_1.Commands.OperatingMode, state: state }); await this.session.sendCommand(command); } catch (error) { if (error instanceof Error) { this.log.error(error.message); } } } async setOperatingState(value) { this.log.debug(this.constructor.name, 'setOperatingState', value); try { const state = OperatingStates[value].substring(0, 1); const command = new Command_1.Command({ command: Command_1.Commands.OperatingState, state: state }); await this.session.sendCommand(command); } catch (error) { if (error instanceof Error) { this.log.error(error.message); } } } async setDayAndTime() { this.log.debug(this.constructor.name, 'setDayAndTime'); try { const now = new Date(); const day = this.days[now.getDay()]; const time = now.getHours().toString().padStart(2, '0') + ':' + now.getMinutes().toString().padStart(2, '0'); const states = [day, time]; const command = new Command_1.Command({ command: Command_1.Commands.SetDayAndTime, states: states }); await this.session.sendCommand(command); } catch (error) { if (error instanceof Error) { this.log.error(error.message); } } } async saveDayAndTime() { this.log.debug(this.constructor.name, 'saveDayAndTime'); try { const state = 'Y'; const command = new Command_1.Command({ command: Command_1.Commands.SaveDayAndTime, state: state }); await this.session.sendCommand(command); } catch (error) { if (error instanceof Error) { this.log.error(error.message); } } } async setPowerState(value) { this.log.debug(this.constructor.name, 'setPowerState', value); try { // Don't turn power off if fan is on if (value === false && this.getFanState() && this.getOperatingMode() !== OperatingModes.EVAPORATIVE_COOLING) { return; } const state = value ? 'N' : 'F'; const command = new Command_1.Command({ command: Command_1.Commands.PowerState, state: state }); await this.session.sendCommand(command); } catch (error) { if (error instanceof Error) { this.log.error(error.message); } } } async setFanState(value) { this.log.debug(this.constructor.name, 'setFanState', value); try { // Don't turn fan off if power if on if (value === false && this.getPowerState() && this.getOperatingMode() !== OperatingModes.EVAPORATIVE_COOLING) { return; } const state = value ? this.session.status.modeEvap ? 'N' : 'Z' : 'F'; const command = new Command_1.Command({ command: Command_1.Commands.FanState, state: state }); await this.session.sendCommand(command); } catch (error) { if (error instanceof Error) { this.log.error(error.message); } } } async setFanSpeed(value) { this.log.debug(this.constructor.name, 'setFanSpeed', value); try { const state = value.toString().padStart(2, '0'); const command = new Command_1.Command({ command: Command_1.Commands.FanSpeed, state: state }); await this.session.sendCommand(command); } catch (error) { if (error instanceof Error) { this.log.error(error.message); } } } async setSetPointTemperature(value, zone = 'U') { this.log.debug(this.constructor.name, 'setSetPointTemperature', value, zone); try { value = Math.round(value); value = this.session.status.modeEvap ? this.toComfortLevel(value) : this.toSetPointTemperature(value); const state = value.toString().padStart(2, '0'); const command = new Command_1.Command({ command: Command_1.Commands.SetPointTemperature, zone: zone, state: state }); await this.session.sendCommand(command); } catch (error) { if (error instanceof Error) { this.log.error(error.message); } } } // Zone Switch async setUserEnabled(value, zone) { this.log.debug(this.constructor.name, 'setUserEnabled', value, zone); try { const state = value ? 'Y' : 'N'; const command = new Command_1.Command({ command: Command_1.Commands.UserEnabled, zone: zone, state: state }); await this.session.sendCommand(command); } catch (error) { if (error instanceof Error) { this.log.error(error.message); } } } async setControlMode(value, zone = 'U') { this.log.debug(this.constructor.name, 'setControlMode', value, zone); try { const state = ControlModes[value].substr(0, 1); const command = new Command_1.Command({ command: Command_1.Commands.ControlMode, zone: zone, state: state }); await this.session.sendCommand(command); } catch (error) { if (error instanceof Error) { this.log.error(error.message); } } } async setScheduleOverride(value, zone = 'U') { this.log.debug(this.constructor.name, 'setScheduleOverride', value, zone); try { const state = ScheduleOverrideModes[value].substr(0, 1); const command = new Command_1.Command({ command: Command_1.Commands.ScheduleOverride, zone: zone, state: state }); await this.session.sendCommand(command); } catch (error) { if (error instanceof Error) { this.log.error(error.message); } } } async setPumpState(value) { this.log.debug(this.constructor.name, 'setPumpState', value); try { const state = value ? 'N' : 'F'; const command = new Command_1.Command({ command: Command_1.Commands.PumpState, state: state }); await this.session.sendCommand(command); } catch (error) { if (error instanceof Error) { this.log.error(error.message); } } } // // Event Handlers // handleStatus(status) { this.log.debug(this.constructor.name, 'handleStatus', status.toString()); const fault = new Fault_1.Fault(status); if (fault.detected || this.faultDetected) { this.faultDetected = fault.detected; this.emit('fault', fault); const faultMessage = fault.toString(); if (fault.detected && this.faultMessage !== faultMessage) { this.log.warn(faultMessage); this.faultMessage = faultMessage; return; } if (!fault.detected && this.faultMessage !== undefined) { this.log.warn(faultMessage); this.faultMessage = undefined; } } } // // Helpers // toComfortLevel(temperature) { temperature = Math.min(Math.max(temperature, 8), 30); let ratio = (temperature - 8) / 22; if (this.invertComfortLevel) { ratio = 1 - ratio; } return Math.round(ratio * 15 + 19); } toTemperature(comfortLevel) { let ratio = (parseInt(comfortLevel) - 19) / 15; if (this.invertComfortLevel) { ratio = 1 - ratio; } return Math.round(ratio * 22 + 8); } toSetPointTemperature(temperature) { temperature = Math.min(temperature, 30); if (temperature < 8) { temperature = 0; } return temperature; } } exports.RinnaiService = RinnaiService; //# sourceMappingURL=RinnaiService.js.map