homebridge-rinnai-touch-platform
Version:
Homebridge Plugin to control heating/cooling via a Rinnai Touch WiFi Module
442 lines • 17.6 kB
JavaScript
"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