homebridge-z2m-thermostat-pilot-wire
Version:
Combine a temperature sensor and a control outlet to create a thermostat
127 lines • 5.83 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const mqtt_1 = require("mqtt");
class Thermostat {
constructor(log, config, api) {
this.state = {
currentTemperature: 0,
targetTemperature: 20,
currentHeatingCoolingState: 0,
targetHeatingCoolingState: 0,
};
this.log = log;
this.config = config;
this.service = new api.hap.Service.Thermostat(config.name);
this.characteristic = api.hap.Characteristic;
let url = "mqtt://";
if (config.mqtt.user) {
url += config.mqtt.user;
if (config.mqtt.password) {
url += `:${config.mqtt.password}`;
}
url += "@";
}
url += `${config.mqtt.address}:${config.mqtt.port}`;
log.info(`Connecting to ${url.replace(/\/\/.*?:.*?@/, "//")}`);
this.mqttClient = (0, mqtt_1.connect)(url);
this.mqttClient.on("error", (error) => {
log.error("MQTT error", error);
});
this.mqttClient.on("connect", () => {
const topic = this.topic(config.temperature);
log.info(`Subscribe to: ${topic}`);
this.mqttClient.subscribe(topic);
});
this.mqttClient.on("message", (topic, msg) => {
const message = JSON.parse(msg.toString());
const { temperature } = message;
this.state.currentTemperature = temperature;
this.log.info(`Room temperature is "${temperature}°C"`);
this.service.setCharacteristic(this.characteristic.CurrentTemperature, this.state.currentTemperature);
// Update HeatingCoolingState based on current temperature and target
this.updateHeatingCoolingState();
});
this.service
.getCharacteristic(this.characteristic.CurrentTemperature)
.onGet(() => this.state.currentTemperature);
this.service
.getCharacteristic(this.characteristic.CurrentHeatingCoolingState)
.onGet(() => this.state.currentHeatingCoolingState);
this.service
.getCharacteristic(this.characteristic.TargetHeatingCoolingState)
.setProps({
minValue: 0,
maxValue: 1,
validValues: [0, 1],
})
.onGet(() => this.state.targetHeatingCoolingState)
.onSet((value) => {
this.log.info(`Setting TargetHeatingCoolingState to "${value}"`);
this.state.targetHeatingCoolingState = value;
if (value === this.characteristic.TargetHeatingCoolingState.OFF) {
this.updateOutletState(value);
}
});
this.service
.getCharacteristic(this.characteristic.TargetTemperature)
.setProps({
minValue: 10,
maxValue: 30,
minStep: 0.5,
})
.onGet(() => this.state.targetTemperature)
.onSet((value) => {
this.log.info(`Setting TargetTemperature to "${value}°C"`);
this.state.targetTemperature = value;
this.updateHeatingCoolingState();
});
this.service.getCharacteristic(this.characteristic.TemperatureDisplayUnits);
this.informationService = new api.hap.Service.AccessoryInformation()
.setCharacteristic(this.characteristic.Manufacturer, "Custom Manufacturer")
.setCharacteristic(this.characteristic.Model, "Custom Model");
log.info("Thermostat finished initializing!");
}
async updateHeatingCoolingState() {
if (this.state.targetHeatingCoolingState === this.characteristic.TargetHeatingCoolingState.OFF) {
this.log.info("Operation cancelled : TargetHeatingCoolingState is \"OFF\"");
return;
}
if (this.state.currentTemperature >= this.state.targetTemperature + 0.5) {
if (this.state.currentHeatingCoolingState !== this.characteristic.CurrentHeatingCoolingState.OFF) {
this.log.info("Setting CurrentHeatingCoolingState to \"OFF\"");
this.state.currentHeatingCoolingState = this.characteristic.CurrentHeatingCoolingState.OFF;
this.updateOutletState(this.characteristic.CurrentHeatingCoolingState.OFF);
}
}
else if (this.state.currentTemperature < this.state.targetTemperature - 0.5) {
if (this.state.currentHeatingCoolingState !== this.characteristic.CurrentHeatingCoolingState.HEAT) {
this.log.info("Setting CurrentHeatingCoolingState to \"HEAT\"");
this.state.currentHeatingCoolingState = this.characteristic.CurrentHeatingCoolingState.HEAT;
this.updateOutletState(this.characteristic.CurrentHeatingCoolingState.HEAT);
}
}
this.service.setCharacteristic(this.characteristic.CurrentHeatingCoolingState, this.state.currentHeatingCoolingState);
}
topic(value) {
return `${this.config.mqtt.baseTopic || "zigbee2mqtt"}/${value}`;
}
updateOutletState(value) {
const _value = this.config.invertOnOff === false ? value === 1 : value === 0;
const state = _value ? "ON" : "OFF";
const topic = this.topic(this.config.outlet) + "/set";
this.log.info(`Sending "${state}" to topic "${topic}"`);
return new Promise((resolve, reject) => {
this.mqttClient.publish(topic, JSON.stringify({ state }), { qos: 2 }, (error) => {
if (error) {
return reject(error);
}
return resolve(value);
});
});
}
getServices() {
return [this.informationService, this.service];
}
}
exports.default = Thermostat;
//# sourceMappingURL=thermostat.js.map