mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 00:09:51 +03:00
add remote room controller, add mqtt-set for thermostat-settings
This commit is contained in:
@@ -563,6 +563,8 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
|
||||
//LOG_TRACE(F("Rx: %s"), Helpers::data_to_hex(data, length).c_str());
|
||||
uint8_t first_value = data[0];
|
||||
if (((first_value & 0x7F) == txservice_.ems_bus_id()) && (length > 1)) {
|
||||
// if we ask ourself at roomcontrol for version e.g. 0B 98 02 ...
|
||||
Roomctrl::check((data[1] ^ 0x80 ^ rxservice_.ems_mask()), data, length);
|
||||
rxservice_.add(data, length); // just for logging
|
||||
return; // it's an echo
|
||||
}
|
||||
@@ -614,8 +616,12 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
|
||||
EMSbus::last_bus_activity(uuid::get_uptime()); // set the flag indication the EMS bus is active
|
||||
txservice_.send();
|
||||
}
|
||||
// send remote room temperature if active
|
||||
Roomctrl::send(first_value ^ 0x80 ^ rxservice_.ems_mask());
|
||||
return;
|
||||
} else {
|
||||
// check if there is a message for the roomcontroller
|
||||
Roomctrl::check((data[1] ^ 0x80 ^ rxservice_.ems_mask()), data, length);
|
||||
// add to RxQueue, what ever it is.
|
||||
rxservice_.add(data, length);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "console.h"
|
||||
#include "boiler.h"
|
||||
#include "shower.h"
|
||||
#include "roomcontrol.h"
|
||||
|
||||
#define LOG_TRACE_WATCH_NONE 0 // no watch set
|
||||
#define ESP_DELAY 1
|
||||
|
||||
128
src/roomcontrol.cpp
Normal file
128
src/roomcontrol.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||
* Copyright 2019 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "roomcontrol.h"
|
||||
|
||||
MAKE_PSTR(logger_name, "roomctrl")
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
uint32_t rc_time_ = 0;
|
||||
uint16_t hc_ = EMS_VALUE_USHORT_NOTSET;
|
||||
int16_t remotetemp[4] = {
|
||||
EMS_VALUE_SHORT_NOTSET, EMS_VALUE_SHORT_NOTSET, EMS_VALUE_SHORT_NOTSET, EMS_VALUE_SHORT_NOTSET
|
||||
};
|
||||
/**
|
||||
* set the temperature,
|
||||
*/
|
||||
void Roomctrl::set_remotetemp(uint8_t hc, int16_t temp){
|
||||
remotetemp[hc] = temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* if remote control is active send the temperature every minute
|
||||
*/
|
||||
void Roomctrl::send(uint8_t addr) {
|
||||
uint8_t hc_ = addr - ADDR;
|
||||
// check address, reply only on addresses 0x18..0x1B
|
||||
if (hc_ > 3) {
|
||||
return;
|
||||
}
|
||||
// no reply if the temperature is not set
|
||||
if (remotetemp[hc_] == EMS_VALUE_SHORT_NOTSET) {
|
||||
return;
|
||||
}
|
||||
if (millis() - rc_time_ > 60000) { // send every minute
|
||||
rc_time_ = millis();
|
||||
temperature(addr, 0x00); // send to all
|
||||
} else {
|
||||
// acknowledge every poll, otherwise the master shows error A11-822
|
||||
EMSuart::send_poll(addr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check if there is a message for the remote room controller
|
||||
*/
|
||||
void Roomctrl::check(uint8_t addr, uint8_t * data, const uint8_t length) {
|
||||
uint8_t hc_num = addr - ADDR;
|
||||
// check address, reply only on addresses 0x18..0x1B
|
||||
if (hc_num > 3) {
|
||||
return;
|
||||
}
|
||||
// no reply if the temperature is not set
|
||||
if (remotetemp[hc_num] == EMS_VALUE_SHORT_NOTSET) {
|
||||
return;
|
||||
}
|
||||
// for now we only reply to version and remote temperature
|
||||
if (data[2] == 0x02) {
|
||||
version(addr, data[0]);
|
||||
} else if (data[2] == 0xAF && data[3] == 0) {
|
||||
temperature(addr, data[0]);
|
||||
} else {
|
||||
unknown(addr, data[0], data[2], data[3]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* send version info RC20 (Prod. 113, Ver. 02.01) or RC20RF (Prod. 93, Ver. 02.00)
|
||||
*/
|
||||
void Roomctrl::version(uint8_t addr, uint8_t dst) {
|
||||
uint8_t data[10];
|
||||
data[0] = addr;
|
||||
data[1] = dst;
|
||||
data[2] = 0x02;
|
||||
data[3] = 0;
|
||||
data[4] = 113; // set RC20 id 113, Ver 02.01
|
||||
data[5] = 0x02;
|
||||
data[6] = 0x01;
|
||||
data[7] = EMSbus::calculate_crc(data, 7); // apppend CRC
|
||||
EMSuart::transmit(data, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* unknown message id, we reply with empty message
|
||||
*/
|
||||
void Roomctrl::unknown(uint8_t addr, uint8_t dst, uint8_t type, uint8_t offset) {
|
||||
uint8_t data[10];
|
||||
data[0] = addr;
|
||||
data[1] = dst;
|
||||
data[2] = type;
|
||||
data[3] = offset;
|
||||
data[4] = EMSbus::calculate_crc(data, 4); // apppend CRC
|
||||
EMSuart::transmit(data, 5);
|
||||
}
|
||||
|
||||
/**
|
||||
* send the room temperature in message 0xAF
|
||||
*/
|
||||
void Roomctrl::temperature(uint8_t addr, uint8_t dst) {
|
||||
uint8_t data[10];
|
||||
uint8_t hc_ = addr - ADDR;
|
||||
data[0] = addr;
|
||||
data[1] = dst;
|
||||
data[2] = 0xAF;
|
||||
data[3] = 0;
|
||||
data[4] = (uint8_t)(remotetemp[hc_] >> 8);
|
||||
data[5] = (uint8_t)(remotetemp[hc_] & 0xFF);
|
||||
data[6] = 0;
|
||||
data[7] = EMSbus::calculate_crc(data, 7); // apppend CRC
|
||||
EMSuart::transmit(data, 8);
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
45
src/roomcontrol.h
Normal file
45
src/roomcontrol.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||
* Copyright 2019 Paul Derbyshire
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EMSESP_ROOMCTRL_H
|
||||
#define EMSESP_ROOMCTRL_H
|
||||
|
||||
#include "emsesp.h"
|
||||
#include "telegram.h"
|
||||
#include "uart/emsuart_esp8266.h"
|
||||
#include "uart/emsuart_esp32.h"
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
class Roomctrl {
|
||||
public:
|
||||
static void send(uint8_t addr);
|
||||
static void check(uint8_t addr, uint8_t * data, const uint8_t length);
|
||||
static void set_remotetemp(uint8_t hc, int16_t temp);
|
||||
|
||||
private:
|
||||
#define ADDR 0x18
|
||||
static void version(uint8_t addr, uint8_t dst);
|
||||
static void unknown(uint8_t addr, uint8_t dst, uint8_t type, uint8_t offset);
|
||||
static void temperature(uint8_t addr, uint8_t dst);
|
||||
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
#endif
|
||||
@@ -238,6 +238,7 @@ void Thermostat::thermostat_cmd(const char * message) {
|
||||
strlcpy(hc_name, "hc", 6);
|
||||
uint8_t hc_num = hc->hc_num();
|
||||
strlcat(hc_name, Helpers::itoa(s, hc_num), 6);
|
||||
|
||||
if (nullptr != doc[hc_name]["mode"]) {
|
||||
std::string mode = doc[hc_name]["mode"]; // first check mode
|
||||
set_mode(mode, hc_num);
|
||||
@@ -268,11 +269,38 @@ void Thermostat::thermostat_cmd(const char * message) {
|
||||
}
|
||||
if (float f = doc[hc_name]["remotetemp"]) {
|
||||
if (f > 100 || f < 0) {
|
||||
hc->remotetemp = EMS_VALUE_SHORT_NOTSET;
|
||||
Roomctrl::set_remotetemp(hc_num - 1, EMS_VALUE_SHORT_NOTSET);
|
||||
} else {
|
||||
hc->remotetemp = (uint16_t)(f * 10);
|
||||
Roomctrl::set_remotetemp(hc_num - 1, (int16_t)(f * 10));
|
||||
}
|
||||
}
|
||||
if (nullptr != doc[hc_name]["control"]) {
|
||||
uint8_t ctrl = doc[hc_name]["control"];
|
||||
set_control(ctrl, hc_num);
|
||||
}
|
||||
if (float ct = doc["calinttemp"]) {
|
||||
set_settings_calinttemp((int8_t)(ct *10));
|
||||
}
|
||||
if (nullptr != doc["minexttemp"]) {
|
||||
int8_t mt = doc["minexttemp"];
|
||||
set_settings_minexttemp(mt);
|
||||
}
|
||||
if (nullptr != doc["building"]) {
|
||||
uint8_t bd = doc["building"];
|
||||
set_settings_building(bd);
|
||||
}
|
||||
if (nullptr != doc["language"]) {
|
||||
uint8_t lg = doc["language"];
|
||||
set_settings_language(lg);
|
||||
}
|
||||
if (nullptr != doc["display"]) {
|
||||
uint8_t dp = doc["display"];
|
||||
set_settings_display(dp);
|
||||
}
|
||||
if (nullptr != doc["clockoffset"]) {
|
||||
int8_t co = doc["clockoffset"];
|
||||
set_settings_clockoffset(co);
|
||||
}
|
||||
}
|
||||
|
||||
const char * command = doc["cmd"];
|
||||
@@ -301,7 +329,6 @@ void Thermostat::thermostat_cmd(const char * message) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set night temp value
|
||||
if (strcmp(command, "nighttemp") == 0) {
|
||||
float f = doc["data"];
|
||||
if (f) {
|
||||
@@ -310,7 +337,6 @@ void Thermostat::thermostat_cmd(const char * message) {
|
||||
}
|
||||
}
|
||||
|
||||
// set daytemp value
|
||||
if (strcmp(command, "daytemp") == 0) {
|
||||
float f = doc["data"];
|
||||
if (f) {
|
||||
@@ -319,7 +345,6 @@ void Thermostat::thermostat_cmd(const char * message) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set holiday value
|
||||
if (strcmp(command, "holidaytemp") == 0) {
|
||||
float f = doc["data"];
|
||||
if (f) {
|
||||
@@ -328,7 +353,6 @@ void Thermostat::thermostat_cmd(const char * message) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set eco value
|
||||
if (strcmp(command, "ecotemp") == 0) {
|
||||
float f = doc["data"];
|
||||
if (f) {
|
||||
@@ -337,7 +361,6 @@ void Thermostat::thermostat_cmd(const char * message) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set heat value
|
||||
if (strcmp(command, "heattemp") == 0) {
|
||||
float f = doc["data"];
|
||||
if (f) {
|
||||
@@ -346,7 +369,6 @@ void Thermostat::thermostat_cmd(const char * message) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set nofrost value
|
||||
if (strcmp(command, "nofrosttemp") == 0) {
|
||||
float f = doc["data"];
|
||||
if (f) {
|
||||
@@ -354,6 +376,7 @@ void Thermostat::thermostat_cmd(const char * message) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(command, "summertemp") == 0) {
|
||||
float f = doc["data"];
|
||||
if (f) {
|
||||
@@ -361,6 +384,7 @@ void Thermostat::thermostat_cmd(const char * message) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(command, "designtemp") == 0) {
|
||||
float f = doc["data"];
|
||||
if (f) {
|
||||
@@ -368,7 +392,8 @@ void Thermostat::thermostat_cmd(const char * message) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (strcmp(command, "offettemp") == 0) {
|
||||
|
||||
if (strcmp(command, "offsettemp") == 0) {
|
||||
float f = doc["data"];
|
||||
if (f) {
|
||||
set_temperature(f, HeatingCircuit::Mode::OFFSET, hc_num);
|
||||
@@ -1114,22 +1139,68 @@ void Thermostat::process_RCTime(std::shared_ptr<const Telegram> telegram) {
|
||||
);
|
||||
}
|
||||
|
||||
// 0xA5 - Set minimum external temperature
|
||||
void Thermostat::set_settings_minexttemp(const int8_t mt) {
|
||||
if (((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) || ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35)) {
|
||||
LOG_INFO(F("Setting min external temperature to %d"), mt);
|
||||
write_command(EMS_TYPE_IBASettings, 5, mt);
|
||||
}
|
||||
}
|
||||
|
||||
// 0xA5 - Clock offset
|
||||
void Thermostat::set_settings_clockoffset(const int8_t co) {
|
||||
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
|
||||
LOG_INFO(F("Setting clock offset to %d"), co);
|
||||
write_command(EMS_TYPE_IBASettings, 12, co);
|
||||
}
|
||||
}
|
||||
// 0xA5 - Calibrate internal temperature
|
||||
void Thermostat::set_settings_calinttemp(const int8_t ct) {
|
||||
if (((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) || ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35)) {
|
||||
LOG_INFO(F("Calibrating internal temperature to %d.%d"), ct / 10, ct < 0 ? -ct % 10 : ct % 10);
|
||||
write_command(EMS_TYPE_IBASettings, 2, ct);
|
||||
}
|
||||
}
|
||||
|
||||
// 0xA5 - Set the display settings
|
||||
void Thermostat::set_settings_display(const uint8_t ds) {
|
||||
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
|
||||
LOG_INFO(F("Setting display to %d"), ds);
|
||||
write_command(EMS_TYPE_IBASettings, 0, ds);
|
||||
}
|
||||
}
|
||||
|
||||
// 0xA5 - Set the building settings
|
||||
void Thermostat::set_settings_building(const uint8_t bg) {
|
||||
if (((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) || ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35)) {
|
||||
LOG_INFO(F("Setting building to %d"), bg);
|
||||
write_command(EMS_TYPE_IBASettings, 6, bg);
|
||||
}
|
||||
}
|
||||
|
||||
// 0xA5 Set the language settings
|
||||
void Thermostat::set_settings_language(const uint8_t lg) {
|
||||
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
|
||||
LOG_INFO(F("Setting building to %d"), lg);
|
||||
write_command(EMS_TYPE_IBASettings, 1, lg);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the control-mode for hc 0-off, 1-RC20, 2-RC3x
|
||||
void Thermostat::set_control(const uint8_t ctrl,const uint8_t hc_num) {
|
||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
||||
if (hc == nullptr) {
|
||||
LOG_WARNING(F("set control: Heating Circuit %d not found or activated"), hc_num);
|
||||
return;
|
||||
}
|
||||
if (ctrl > 2) {
|
||||
LOG_WARNING(F("set control: Invalid control mode: %d"), ctrl);
|
||||
return;
|
||||
}
|
||||
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
|
||||
LOG_INFO(F("Setting Circuit-control for hc%d to %d"), hc_num, ctrl);
|
||||
write_command(set_typeids[hc->hc_num() - 1], 26, ctrl);
|
||||
}
|
||||
}
|
||||
|
||||
// sets the thermostat working mode, where mode is a string
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "emsesp.h"
|
||||
#include "helpers.h"
|
||||
#include "mqtt.h"
|
||||
#include "roomcontrol.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -61,7 +62,6 @@ class Thermostat : public EMSdevice {
|
||||
uint8_t nofrosttemp = EMS_VALUE_UINT_NOTSET;
|
||||
uint8_t designtemp = EMS_VALUE_UINT_NOTSET; // heatingcurve design temp at MinExtTemp
|
||||
int8_t offsettemp = EMS_VALUE_INT_NOTSET; // heatingcurve offest temp at roomtemp signed!
|
||||
uint16_t remotetemp = EMS_VALUE_SHORT_NOTSET; // for simulating a RC20 remote
|
||||
|
||||
|
||||
uint8_t hc_num() const {
|
||||
@@ -231,9 +231,13 @@ class Thermostat : public EMSdevice {
|
||||
void process_EasyMonitor(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
// set functions
|
||||
void set_settings_minexttemp(const int8_t mt);
|
||||
void set_settings_calinttemp(const int8_t ct);
|
||||
void set_settings_clockoffset(const int8_t co);
|
||||
void set_settings_display(const uint8_t ds);
|
||||
void set_settings_building(const uint8_t bg);
|
||||
void set_settings_language(const uint8_t lg);
|
||||
void set_control(const uint8_t ctrl, const uint8_t hc_num);
|
||||
void set_mode(const uint8_t mode, const uint8_t hc_num);
|
||||
void set_mode(const std::string & mode, const uint8_t hc_num);
|
||||
void set_temperature(const float temperature, const std::string & mode, const uint8_t hc_num);
|
||||
|
||||
Reference in New Issue
Block a user