homebridge-tasmota-thermostat
Version:
Homebridge plugin for using Tasmota's thermostat feature in Apple Home.
309 lines • 16.1 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
const mqtt = __importStar(require("mqtt"));
let hap;
class TasmotaThermostat {
constructor(log, config, api) {
this.switchOn = false;
this.currentState = hap.Characteristic.CurrentHeatingCoolingState.OFF;
this.targetState = hap.Characteristic.TargetHeatingCoolingState.OFF;
this.currentTemperature = 0;
this.currentRelativeHumidity = 0;
this.targetTemperature = 10;
this.temperatureDisplayUnits = hap.Characteristic.TemperatureDisplayUnits.CELSIUS;
this.log = log;
this.config = config;
this.api = api;
// extract name from config
this.name = config.name;
this.mqttUrl = config.mqtt.url;
this.mqttName = config.mqtt.thermostat_topic_name;
// create a new Thermostat service
this.thermostatService = new hap.Service.Thermostat(this.name);
// create handlers for required characteristics
this.thermostatService.getCharacteristic(hap.Characteristic.CurrentHeatingCoolingState)
.onGet(this.handleCurrentHeatingCoolingStateGet.bind(this));
this.thermostatService.getCharacteristic(hap.Characteristic.TargetHeatingCoolingState)
.onGet(this.handleTargetHeatingCoolingStateGet.bind(this))
.onSet(this.handleTargetHeatingCoolingStateSet.bind(this))
.setProps({
validValues: [
hap.Characteristic.TargetHeatingCoolingState.OFF,
hap.Characteristic.TargetHeatingCoolingState.HEAT,
],
});
this.thermostatService.getCharacteristic(hap.Characteristic.CurrentRelativeHumidity)
.onGet(this.handleCurrentRelativeHumidityStateGet.bind(this));
this.thermostatService.getCharacteristic(hap.Characteristic.CurrentTemperature)
.onGet(this.handleCurrentTemperatureGet.bind(this));
this.thermostatService.getCharacteristic(hap.Characteristic.TargetTemperature)
.onGet(this.handleTargetTemperatureGet.bind(this))
.onSet(this.handleTargetTemperatureSet.bind(this));
this.thermostatService.getCharacteristic(hap.Characteristic.TemperatureDisplayUnits)
.onGet(this.handleTemperatureDisplayUnitsGet.bind(this))
.onSet(this.handleTemperatureDisplayUnitsSet.bind(this));
this.switchService = new hap.Service.Switch(this.name);
this.switchService.getCharacteristic(hap.Characteristic.On)
.on("get" /* GET */, (callback) => {
log.info('Current state of the switch was returned: ' + (this.switchOn ? 'ON' : 'OFF'));
this.client.publish('cmnd/' + this.mqttName + '/POWER', '');
callback(undefined, this.switchOn);
})
.on("set" /* SET */, (value, callback) => {
this.switchOn = value;
log.info('Switch state was set to: ' + (this.switchOn ? 'ON' : 'OFF'));
this.client.publish('cmnd/' + this.mqttName + '/POWER', this.switchOn ? 'ON' : 'OFF');
callback();
});
this.client = mqtt.connect(this.mqttUrl);
this.client.on('connect', () => {
this.client.subscribe('tele/' + this.mqttName + '/SENSOR', (err) => {
if (err) {
this.log('MQTT Sensor Subscription error:' + err);
}
else {
this.log('MQTT Sensor Subscribed');
}
});
this.client.subscribe('tele/' + this.mqttName + '/STATE', (err) => {
if (err) {
this.log('MQTT State Subscription error:' + err);
}
else {
this.log('MQTT State Subscribed');
}
});
this.client.subscribe('stat/' + this.mqttName + '/STATUS10', (err) => {
if (err) {
this.log('MQTT Status Subscription error:' + err);
}
else {
this.log('MQTT Status Subscribed');
}
});
this.client.subscribe('stat/' + this.mqttName + '/RESULT', (err) => {
if (err) {
this.log('MQTT Result Subscription error:' + err);
}
else {
this.log('MQTT Result Subscribed');
}
});
});
this.client.on('message', (topic, message) => {
// message is Buffer
log.info('Topic: ' + topic + '\nMessage: ' + message.toString());
const payload = JSON.parse(message.toString());
if (topic === 'tele/' + this.mqttName + '/STATE') {
if (payload['POWER']) {
const power = payload['POWER'];
this.switchOn = power === 'ON';
this.switchService.updateCharacteristic(hap.Characteristic.On, this.switchOn);
// this.currentState = power === 'ON' ? hap.Characteristic.CurrentHeatingCoolingState.HEAT :
// hap.Characteristic.CurrentHeatingCoolingState.OFF;
// this.thermostatService.updateCharacteristic(hap.Characteristic.CurrentHeatingCoolingState, this.currentState);
}
}
if (topic === 'tele/' + this.mqttName + '/SENSOR') {
if (payload['BME280']) {
const bme280 = payload['BME280'];
if (bme280['Temperature']) {
const temperature = bme280['Temperature'];
this.currentTemperature = temperature;
this.thermostatService.updateCharacteristic(hap.Characteristic.CurrentTemperature, temperature);
}
if (bme280['Humidity']) {
const humidity = bme280['Humidity'];
this.currentRelativeHumidity = humidity;
this.thermostatService.updateCharacteristic(hap.Characteristic.CurrentRelativeHumidity, humidity);
}
}
if (payload['Thermostat0']) {
const thermostat0 = payload['Thermostat0'];
if (thermostat0['ThermostatModeSet']) {
const thermostatModeSet = thermostat0['ThermostatModeSet'];
this.targetState = thermostatModeSet === 1 ? hap.Characteristic.TargetHeatingCoolingState.HEAT :
hap.Characteristic.TargetHeatingCoolingState.OFF;
this.thermostatService.updateCharacteristic(hap.Characteristic.TargetHeatingCoolingState, this.targetState);
this.currentState = thermostatModeSet === 1 ? hap.Characteristic.CurrentHeatingCoolingState.HEAT :
hap.Characteristic.CurrentHeatingCoolingState.OFF;
this.thermostatService.updateCharacteristic(hap.Characteristic.CurrentHeatingCoolingState, this.currentState);
}
if (thermostat0['TempTargetSet']) {
const tempTargetSet = thermostat0['TempTargetSet'];
this.targetTemperature = tempTargetSet;
this.thermostatService.updateCharacteristic(hap.Characteristic.TargetTemperature, this.targetTemperature);
}
}
}
if (topic === 'stat/' + this.mqttName + '/STATUS10') {
if (payload['StatusSNS']) {
const statusSNS = payload['StatusSNS'];
if (statusSNS['BME280']) {
const bme280 = statusSNS['BME280'];
if (bme280['Temperature']) {
const temperature = bme280['Temperature'];
this.currentTemperature = temperature;
this.thermostatService.updateCharacteristic(hap.Characteristic.CurrentTemperature, temperature);
}
if (bme280['Humidity']) {
const humidity = bme280['Humidity'];
this.currentRelativeHumidity = humidity;
this.thermostatService.updateCharacteristic(hap.Characteristic.CurrentRelativeHumidity, humidity);
}
}
if (statusSNS['Thermostat0']) {
const thermostat0 = statusSNS['Thermostat0'];
if (thermostat0['ThermostatModeSet']) {
const thermostatModeSet = thermostat0['ThermostatModeSet'];
this.targetState = thermostatModeSet === 1 ? hap.Characteristic.TargetHeatingCoolingState.HEAT :
hap.Characteristic.TargetHeatingCoolingState.OFF;
this.thermostatService.updateCharacteristic(hap.Characteristic.TargetHeatingCoolingState, this.targetState);
this.currentState = thermostatModeSet === 1 ? hap.Characteristic.CurrentHeatingCoolingState.HEAT :
hap.Characteristic.CurrentHeatingCoolingState.OFF;
this.thermostatService.updateCharacteristic(hap.Characteristic.CurrentHeatingCoolingState, this.currentState);
}
if (thermostat0['TempTargetSet']) {
const tempTargetSet = thermostat0['TempTargetSet'];
this.targetTemperature = tempTargetSet;
this.thermostatService.updateCharacteristic(hap.Characteristic.TargetTemperature, this.targetTemperature);
}
}
}
}
if (topic === 'stat/' + this.mqttName + '/RESULT') {
if (payload['POWER']) {
const power = payload['POWER'];
this.switchOn = power === 'ON';
this.switchService.updateCharacteristic(hap.Characteristic.On, this.switchOn);
// this.currentState = power === 'ON' ? hap.Characteristic.CurrentHeatingCoolingState.HEAT :
// hap.Characteristic.CurrentHeatingCoolingState.OFF;
// this.thermostatService.updateCharacteristic(hap.Characteristic.CurrentHeatingCoolingState, this.currentState);
}
if (payload['ThermostatModeSet1']) {
const thermostatModeSet1 = payload['ThermostatModeSet1'];
this.targetState = thermostatModeSet1 === 1 ? hap.Characteristic.TargetHeatingCoolingState.HEAT :
hap.Characteristic.TargetHeatingCoolingState.OFF;
this.thermostatService.updateCharacteristic(hap.Characteristic.TargetHeatingCoolingState, this.targetState);
this.currentState = thermostatModeSet1 === 1 ? hap.Characteristic.CurrentHeatingCoolingState.HEAT :
hap.Characteristic.CurrentHeatingCoolingState.OFF;
this.thermostatService.updateCharacteristic(hap.Characteristic.CurrentHeatingCoolingState, this.currentState);
}
if (payload['TempTargetSet1']) {
const tempTargetSet1 = payload['TempTargetSet1'];
this.targetTemperature = tempTargetSet1;
this.thermostatService.updateCharacteristic(hap.Characteristic.TargetTemperature, this.targetTemperature);
}
}
});
}
/**
* Handle requests to get the current value of the "Current Heating Cooling State" characteristic
*/
handleCurrentHeatingCoolingStateGet() {
this.log.info('Triggered GET CurrentHeatingCoolingState');
// this.client.publish('cmnd/' + this.mqttName + '/POWER', '');
this.client.publish('cmnd/' + this.mqttName + '/THERMOSTATMODESET', '');
return this.currentState;
}
/**
* Handle requests to get the current value of the "Target Heating Cooling State" characteristic
*/
handleTargetHeatingCoolingStateGet() {
this.log.info('Triggered GET TargetHeatingCoolingState');
this.client.publish('cmnd/' + this.mqttName + '/THERMOSTATMODESET', '');
return this.targetState;
}
/**
* Handle requests to set the "Target Heating Cooling State" characteristic
*/
handleTargetHeatingCoolingStateSet(value) {
this.log.info('Triggered SET TargetHeatingCoolingState:' + value);
this.targetState = value;
this.currentState = value;
if (this.targetState === hap.Characteristic.TargetHeatingCoolingState.HEAT) {
this.client.publish('cmnd/' + this.mqttName + '/THERMOSTATMODESET', '1');
}
else {
this.client.publish('cmnd/' + this.mqttName + '/THERMOSTATMODESET', '0');
}
}
/**
* Handle requests to get the current value of the "Current Temperature" characteristic
*/
handleCurrentTemperatureGet() {
this.log.info('Triggered GET CurrentTemperature');
this.client.publish('cmnd/' + this.mqttName + '/STATUS', '10');
return this.currentTemperature;
}
/**
* Handle requests to get the current value of the "Current Relative Humidity" characteristic
*/
handleCurrentRelativeHumidityStateGet() {
this.log.info('Triggered GET CurrentRelativeHumidity');
this.client.publish('cmnd/' + this.mqttName + '/STATUS', '10');
return this.currentRelativeHumidity;
}
/**
* Handle requests to get the current value of the "Target Temperature" characteristic
*/
handleTargetTemperatureGet() {
this.log.info('Triggered GET TargetTemperature');
this.client.publish('cmnd/' + this.mqttName + '/TEMPTARGETSET', '');
return this.targetTemperature;
}
/**
* Handle requests to set the "Target Temperature" characteristic
*/
handleTargetTemperatureSet(value) {
this.log.info('Triggered SET TargetTemperature:' + value);
this.targetTemperature = value;
this.client.publish('cmnd/' + this.mqttName + '/TEMPTARGETSET', this.targetTemperature.toString());
}
/**
* Handle requests to get the current value of the "Temperature Display Units" characteristic
*/
handleTemperatureDisplayUnitsGet() {
this.log.info('Triggered GET TemperatureDisplayUnits');
return this.temperatureDisplayUnits;
}
/**
* Handle requests to set the "Temperature Display Units" characteristic
*/
handleTemperatureDisplayUnitsSet(value) {
this.log.info('Triggered SET TemperatureDisplayUnits:' + value);
}
/*
* This method is called directly after creation of this instance.
* It should return all services which should be added to the accessory.
*/
getServices() {
return [
this.thermostatService,
this.switchService,
];
}
}
module.exports = (api) => {
hap = api.hap;
api.registerAccessory('TasmotaThermostat', TasmotaThermostat);
};
//# sourceMappingURL=index.js.map