diff --git a/src/emsesp.cpp b/src/emsesp.cpp
index 61791328e..a5ddb715f 100644
--- a/src/emsesp.cpp
+++ b/src/emsesp.cpp
@@ -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);
}
diff --git a/src/emsesp.h b/src/emsesp.h
index b93a5803a..5d61ea418 100644
--- a/src/emsesp.h
+++ b/src/emsesp.h
@@ -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
diff --git a/src/roomcontrol.cpp b/src/roomcontrol.cpp
new file mode 100644
index 000000000..ec17eae7f
--- /dev/null
+++ b/src/roomcontrol.cpp
@@ -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 .
+ */
+
+#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
diff --git a/src/roomcontrol.h b/src/roomcontrol.h
new file mode 100644
index 000000000..14c68552e
--- /dev/null
+++ b/src/roomcontrol.h
@@ -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 .
+ */
+
+#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
diff --git a/src/thermostat.cpp b/src/thermostat.cpp
index 1fafff48b..a25984303 100644
--- a/src/thermostat.cpp
+++ b/src/thermostat.cpp
@@ -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 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) {
- LOG_INFO(F("Setting display to %d"), ds);
- write_command(EMS_TYPE_IBASettings, 0, 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) {
- LOG_INFO(F("Setting building to %d"), bg);
- write_command(EMS_TYPE_IBASettings, 6, 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) {
- LOG_INFO(F("Setting building to %d"), lg);
- write_command(EMS_TYPE_IBASettings, 1, 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 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
diff --git a/src/thermostat.h b/src/thermostat.h
index 34c996682..65852f345 100644
--- a/src/thermostat.h
+++ b/src/thermostat.h
@@ -29,6 +29,7 @@
#include "emsesp.h"
#include "helpers.h"
#include "mqtt.h"
+#include "roomcontrol.h"
#include
@@ -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 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);