homebridge-rinnai-touch-platform
Version:
Homebridge Plugin to control heating/cooling via a Rinnai Touch WiFi Module
499 lines • 21.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.HomeAssistantFormat = void 0;
const RinnaiService_1 = require("../rinnai/RinnaiService");
class HomeAssistantFormat {
constructor(platform, client) {
this.platform = platform;
this.client = client;
this.subTopics = new Map();
this.topicPayloads = new Map();
this.modeMap = {
'heat': RinnaiService_1.OperatingModes.HEATING,
'cool': RinnaiService_1.OperatingModes.COOLING,
'evap': RinnaiService_1.OperatingModes.EVAPORATIVE_COOLING,
};
this.prefix = this.platform.settings.mqtt.topicPrefix
? `${this.platform.settings.mqtt.topicPrefix}/`
: '';
this.subTopics
.set(`${this.prefix}hvac/fan_mode/set`, this.setHvacFanMode.bind(this))
.set(`${this.prefix}hvac/fan_speed/set`, this.setHvacFanSpeed.bind(this))
.set(`${this.prefix}hvac/mode/set`, this.setHvacMode.bind(this))
.set(`${this.prefix}hvac/temperature/set`, this.setHvacTemperature.bind(this))
.set(`${this.prefix}switch/zone/a/set`, this.setSwitchZone.bind(this))
.set(`${this.prefix}switch/zone/b/set`, this.setSwitchZone.bind(this))
.set(`${this.prefix}switch/zone/c/set`, this.setSwitchZone.bind(this))
.set(`${this.prefix}switch/zone/d/set`, this.setSwitchZone.bind(this))
.set(`${this.prefix}switch/heat/set`, this.setSwitchMode.bind(this))
.set(`${this.prefix}switch/cool/set`, this.setSwitchMode.bind(this))
.set(`${this.prefix}switch/evap/set`, this.setSwitchMode.bind(this))
.set(`${this.prefix}switch/fan/set`, this.setSwitchFan.bind(this))
.set(`${this.prefix}switch/manual/set`, this.setSwitchManual.bind(this))
.set(`${this.prefix}switch/manual/a/set`, this.setSwitchManual.bind(this))
.set(`${this.prefix}switch/manual/b/set`, this.setSwitchManual.bind(this))
.set(`${this.prefix}switch/manual/c/set`, this.setSwitchManual.bind(this))
.set(`${this.prefix}switch/manual/d/set`, this.setSwitchManual.bind(this))
.set(`${this.prefix}switch/pump/set`, this.setSwitchPump.bind(this));
// Publish on status change
if (this.platform.settings.mqtt.publishStatusChanged) {
this.platform.service.session.on('status', () => {
this.publishTopics();
});
this.platform.temperatureService.on('temperature_change', () => {
this.publishTopics();
});
}
}
get subscriptionTopics() {
return [...this.subTopics.keys()];
}
process(topic, payload) {
this.platform.log.debug(this.constructor.name, 'process', topic, payload);
try {
const setValue = this.subTopics.get(topic);
if (setValue) {
setValue(topic, payload);
}
}
catch (error) {
if (error instanceof Error) {
this.platform.log.error(error.message);
}
}
}
async setHvacFanMode(topic, payload) {
this.platform.log.debug(this.constructor.name, 'setHvacFanMode', topic, payload);
try {
if (!this.platform.service.getFanState()) {
this.platform.log.warn('MQTT: Setting fan mode only supported for "fan_only" mode');
await this.publishTopics();
return;
}
let fanSpeed;
switch (payload) {
case 'low':
fanSpeed = 5;
break;
case 'medium':
fanSpeed = 10;
break;
case 'high':
fanSpeed = 15;
break;
default:
this.platform.log.warn(`MQTT: Invalid fan mode '${payload}' in payload`);
await this.publishTopics();
return;
}
await this.platform.service.setFanSpeed(fanSpeed);
}
catch (error) {
if (error instanceof Error) {
this.platform.log.error(error.message);
}
}
}
async setHvacFanSpeed(topic, payload) {
this.platform.log.debug(this.constructor.name, 'setHvacFanSpeed', topic, payload);
try {
if (!this.platform.service.getFanState()) {
this.platform.log.warn('MQTT: Setting fan speed only supported for "fan_only" mode');
await this.publishTopics();
return;
}
const fanSpeed = parseInt(payload);
if (isNaN(fanSpeed)) {
this.platform.log.warn(`MQTT: Invalid fan speed specified: ${payload}`);
return;
}
if (fanSpeed < 0 || fanSpeed > 16) {
this.platform.log.warn(`MQTT: Fan speed ${fanSpeed} not between 1 and 16`);
return;
}
await this.platform.service.setFanSpeed(fanSpeed);
}
catch (error) {
if (error instanceof Error) {
this.platform.log.error(error.message);
}
}
}
async setHvacMode(topic, payload) {
this.platform.log.debug(this.constructor.name, 'setHvacMode', topic, payload);
try {
switch (payload) {
case 'fan_only':
await this.platform.service.setPowerState(false);
await this.platform.service.setFanState(true);
break;
case 'off':
await this.platform.service.setPowerState(false);
await this.platform.service.setFanState(false);
break;
case 'heat':
await this.platform.service.setFanState(false);
await this.platform.service.setOperatingMode(RinnaiService_1.OperatingModes.HEATING);
await this.platform.service.setPowerState(true);
break;
case 'cool':
await this.platform.service.setFanState(false);
await this.platform.service.setOperatingMode(this.platform.service.getHasEvaporative()
? RinnaiService_1.OperatingModes.EVAPORATIVE_COOLING
: RinnaiService_1.OperatingModes.COOLING);
await this.platform.service.setPowerState(true);
break;
default:
this.platform.log.warn(`MQTT: Invalid mode '${payload}' in payload`);
await this.publishTopics();
return;
}
}
catch (error) {
if (error instanceof Error) {
this.platform.log.error(error.message);
}
}
}
async setHvacTemperature(topic, payload) {
this.platform.log.debug(this.constructor.name, 'setHvacTemperature', topic, payload);
try {
if (!this.platform.service.getPowerState() || this.platform.service.getFanState()) {
this.platform.log.warn('MQTT: Setting temperature only supported for "heat" and "cool" modes');
await this.publishTopics();
return;
}
const json = JSON.parse(payload);
if (typeof json === 'object') {
for (const zone in json) {
if (this.isValidTemperature(json[zone])) {
await this.platform.service.setSetPointTemperature(json[zone], zone);
}
else {
await this.publishTopics();
}
}
}
else {
if (this.isValidTemperature(json)) {
await this.platform.service.setSetPointTemperature(json);
}
else {
await this.publishTopics();
}
}
}
catch (error) {
if (error instanceof Error) {
this.platform.log.error(error.message);
}
}
}
isValidTemperature(temp) {
this.platform.log.debug(this.constructor.name, 'isValidTemperature', temp);
const value = parseInt(`${temp}`);
if (isNaN(value)) {
this.platform.log.warn(`MQTT: Invalid temperature specified: ${temp}`);
return false;
}
if (value < 0 || value > 30) {
this.platform.log.warn(`MQTT: Temperature ${temp} not between 0 and 30`);
return false;
}
return true;
}
async setSwitchZone(topic, payload) {
this.platform.log.debug(this.constructor.name, 'setSwitchZone', topic, payload);
try {
const zone = this.getTopicComponent(topic, -2).toUpperCase();
const value = payload.toLowerCase() === 'on';
await this.platform.service.setUserEnabled(value, zone);
}
catch (error) {
if (error instanceof Error) {
this.platform.log.error(error.message);
}
}
}
async setSwitchMode(topic, payload) {
this.platform.log.debug(this.constructor.name, 'setSwitchMode', topic, payload);
try {
const mode = this.getTopicComponent(topic, -2).toLowerCase();
const operatingMode = this.modeMap[mode];
const state = payload.toLowerCase() === 'on';
if (this.platform.service.getFanState()) {
await this.platform.service.setFanState(false);
}
if (state) {
await this.platform.service.setOperatingMode(operatingMode);
await this.platform.service.setPowerState(true);
}
else {
await this.platform.service.setPowerState(false);
}
}
catch (error) {
if (error instanceof Error) {
this.platform.log.error(error.message);
}
}
}
async setSwitchFan(topic, payload) {
this.platform.log.debug(this.constructor.name, 'setSwitchFan', topic, payload);
try {
const state = payload.toLowerCase() === 'on';
if (this.platform.service.getOperatingMode() === RinnaiService_1.OperatingModes.EVAPORATIVE_COOLING) {
if (state && !this.platform.service.getPowerState()) {
await this.platform.service.setPowerState(true);
}
await this.platform.service.setControlMode(RinnaiService_1.ControlModes.MANUAL);
}
else {
if (state && this.platform.service.getPowerState()) {
await this.platform.service.setPowerState(false);
}
}
await this.platform.service.setFanState(state);
}
catch (error) {
if (error instanceof Error) {
this.platform.log.error(error.message);
}
}
}
async setSwitchManual(topic, payload) {
this.platform.log.debug(this.constructor.name, 'setSwitchManual', topic, payload);
try {
if (!this.platform.service.getPowerState() && !this.platform.service.getFanState()) {
this.platform.log.warn('MQTT: Setting manual operation not supported for "off" mode');
await this.publishTopics();
return;
}
let zone = this.getTopicComponent(topic, -2).toUpperCase();
zone = zone.length !== 1 ? 'U' : zone;
const state = payload.toLowerCase() === 'on'
? RinnaiService_1.ControlModes.MANUAL
: RinnaiService_1.ControlModes.AUTO;
this.platform.service.setControlMode(state, zone);
}
catch (error) {
if (error instanceof Error) {
this.platform.log.error(error.message);
}
}
}
async setSwitchPump(topic, payload) {
this.platform.log.debug(this.constructor.name, 'setSwitchPump', topic, payload);
try {
if (this.platform.service.getOperatingMode() !== RinnaiService_1.OperatingModes.EVAPORATIVE_COOLING) {
this.platform.log.warn('MQTT: Setting pump state only supported when in "Evaporative Cooling" mode');
await this.publishTopics();
return;
}
if (!this.platform.service.getPowerState()) {
this.platform.log.warn('MQTT: Setting pump state not supported for "off" mode');
await this.publishTopics();
return;
}
if (this.platform.service.getControlMode() !== RinnaiService_1.ControlModes.MANUAL) {
this.platform.log.warn('MQTT: Setting pump state not supported for "auto" operation');
await this.publishTopics();
return;
}
const state = payload.toLowerCase() === 'on';
this.platform.service.setPumpState(state);
}
catch (error) {
if (error instanceof Error) {
this.platform.log.error(error.message);
}
}
}
getTopicComponent(topic, index) {
const components = topic.split('/');
if (index >= 0) {
return components[index];
}
return components[components.length + index];
}
async publishTopics() {
this.platform.log.debug(this.constructor.name, 'publishTopics');
try {
this.publishHvacAction();
this.publishHvacCurrentTemperature();
this.publishHvacFanMode();
this.publishHvacFanSpeed();
this.publishHvacMode();
this.publishHvacTemperature();
this.publishSwitchZone();
this.publishSwitchMode();
this.publishSwitchFan();
this.publishSwitchManual();
this.publishSwitchPump();
}
catch (error) {
if (error instanceof Error) {
this.platform.log.error(error.message);
}
}
}
publishHvacAction() {
this.platform.log.debug(this.constructor.name, 'publishHvacAction');
const payload = {};
for (const zone of this.platform.service.getZonesInstalled()) {
if (!this.platform.service.getUserEnabled(zone)) {
payload[zone] = 'off';
continue;
}
if (this.platform.service.getFanState()) {
payload[zone] = 'fan';
continue;
}
if (!this.platform.service.getPowerState()) {
payload[zone] = 'off';
continue;
}
if (!this.platform.service.getAutoEnabled(zone)) {
payload[zone] = 'idle';
continue;
}
payload[zone] = this.platform.service.getOperatingMode() === RinnaiService_1.OperatingModes.HEATING
? 'heating'
: 'cooling';
}
this.publish('hvac/action/get', JSON.stringify(payload));
}
publishHvacCurrentTemperature() {
this.platform.log.debug(this.constructor.name, 'publishHvacCurrentTemperature');
const payload = {};
for (const zone of this.platform.service.getZonesInstalled()) {
const temperature = this.platform.temperatureService.getTemperature(zone);
if (temperature !== undefined) {
payload[zone] = temperature;
}
}
this.publish('hvac/current_temperature/get', JSON.stringify(payload));
}
publishHvacFanMode() {
this.platform.log.debug(this.constructor.name, 'publishHvacFanMode');
const fanSpeed = this.platform.service.getFanSpeed();
let payload = 'low';
if (fanSpeed > 5) {
payload = 'medium';
}
if (fanSpeed > 10) {
payload = 'high';
}
this.publish('hvac/fan_mode/get', payload);
}
publishHvacFanSpeed() {
this.platform.log.debug(this.constructor.name, 'publishHvacFanSpeed');
const payload = this.platform.service.getFanSpeed();
this.publish('hvac/fan_speed/get', String(payload));
}
publishHvacMode() {
this.platform.log.debug(this.constructor.name, 'publishHvacMode');
let payload;
if (this.platform.service.getFanState()) {
payload = 'fan_only';
}
else if (!this.platform.service.getPowerState()) {
payload = 'off';
}
else if (this.platform.service.getOperatingMode() === RinnaiService_1.OperatingModes.HEATING) {
payload = 'heat';
}
else {
payload = 'cool';
}
this.publish('hvac/mode/get', payload);
}
publishHvacTemperature() {
var _a, _b;
this.platform.log.debug(this.constructor.name, 'publishHvacTemperature');
let payload;
if (this.platform.service.getHasMultiSetPoint()) {
payload = {};
for (const zone of this.platform.service.getZonesInstalled()) {
if (this.platform.service.getSetPointTemperature(zone) !== undefined) {
payload[zone] = (_a = this.platform.service.getSetPointTemperature(zone)) !== null && _a !== void 0 ? _a : 0;
}
}
}
else {
payload = (_b = this.platform.service.getSetPointTemperature()) !== null && _b !== void 0 ? _b : 0;
}
this.publish('hvac/temperature/get', JSON.stringify(payload));
}
publishSwitchZone() {
this.platform.log.debug(this.constructor.name, 'publishSwitchZone');
const zonesInstalled = this.platform.service.getZonesInstalled();
for (const zone of ['A', 'B', 'C', 'D']) {
if (zonesInstalled.includes(zone)) {
const payload = this.platform.service.getUserEnabled(zone) ? 'on' : 'off';
this.publish(`switch/zone/${zone.toLowerCase()}/get`, payload);
}
else {
this.publish(`switch/zone/${zone.toLowerCase()}/get`, 'off');
}
}
}
publishSwitchMode() {
this.platform.log.debug(this.constructor.name, 'publishSwitchMode');
let payload;
for (const mode of ['heat', 'cool', 'evap']) {
if (this.platform.service.getPowerState()) {
payload = this.platform.service.getOperatingMode() === this.modeMap[mode] ? 'on' : 'off';
}
else {
payload = 'off';
}
this.publish(`switch/${mode}/get`, payload);
}
}
publishSwitchFan() {
this.platform.log.debug(this.constructor.name, 'publishSwitchFan');
const payload = this.platform.service.getFanState() ? 'on' : 'off';
this.publish('switch/fan/get', payload);
}
publishSwitchManual() {
this.platform.log.debug(this.constructor.name, 'publishSwitchManual');
if (this.platform.service.getHasMultiSetPoint() && this.platform.service.getOperatingMode() !== RinnaiService_1.OperatingModes.EVAPORATIVE_COOLING) {
for (const zone of this.platform.service.getZonesInstalled()) {
if (this.platform.service.getControlMode(zone)) {
const payload = this.platform.service.getControlMode(zone) === RinnaiService_1.ControlModes.MANUAL ? 'on' : 'off';
this.publish(`switch/manual/${zone.toLowerCase()}/get`, payload);
}
}
}
else {
const payload = this.platform.service.getControlMode() === RinnaiService_1.ControlModes.MANUAL ? 'on' : 'off';
this.publish('switch/manual/get', payload);
}
}
publishSwitchPump() {
this.platform.log.debug(this.constructor.name, 'publishSwitchPump');
const payload = this.platform.service.getPumpState() ? 'on' : 'off';
this.publish('switch/pump/get', payload);
}
async publish(topic, payload) {
this.platform.log.debug(this.constructor.name, 'publish', topic, payload);
try {
if (payload === this.topicPayloads.get(topic) && !this.platform.settings.mqtt.publishAll) {
return;
}
this.topicPayloads.set(topic, payload);
await this.client.publish(`${this.prefix}${topic}`, payload, { retain: true });
if (this.platform.settings.mqtt.showMqttEvents) {
this.platform.log.info(`MQTT: Publish: ${this.prefix}${topic}, Payload: ${payload}`);
}
}
catch (error) {
if (error instanceof Error) {
this.platform.log.error(error.message);
}
}
}
}
exports.HomeAssistantFormat = HomeAssistantFormat;
//# sourceMappingURL=HomeAssistantFormat.js.map