add remote room controller, add mqtt-set for thermostat-settings

This commit is contained in:
MichaelDvP
2020-06-04 14:35:39 +02:00
parent be7445d024
commit 5e90d264bc
6 changed files with 271 additions and 16 deletions

View File

@@ -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()); //LOG_TRACE(F("Rx: %s"), Helpers::data_to_hex(data, length).c_str());
uint8_t first_value = data[0]; uint8_t first_value = data[0];
if (((first_value & 0x7F) == txservice_.ems_bus_id()) && (length > 1)) { 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 rxservice_.add(data, length); // just for logging
return; // it's an echo 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 EMSbus::last_bus_activity(uuid::get_uptime()); // set the flag indication the EMS bus is active
txservice_.send(); txservice_.send();
} }
// send remote room temperature if active
Roomctrl::send(first_value ^ 0x80 ^ rxservice_.ems_mask());
return; return;
} else { } 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. // add to RxQueue, what ever it is.
rxservice_.add(data, length); rxservice_.add(data, length);
} }

View File

@@ -44,6 +44,7 @@
#include "console.h" #include "console.h"
#include "boiler.h" #include "boiler.h"
#include "shower.h" #include "shower.h"
#include "roomcontrol.h"
#define LOG_TRACE_WATCH_NONE 0 // no watch set #define LOG_TRACE_WATCH_NONE 0 // no watch set
#define ESP_DELAY 1 #define ESP_DELAY 1

128
src/roomcontrol.cpp Normal file
View 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
View 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

View File

@@ -238,6 +238,7 @@ void Thermostat::thermostat_cmd(const char * message) {
strlcpy(hc_name, "hc", 6); strlcpy(hc_name, "hc", 6);
uint8_t hc_num = hc->hc_num(); uint8_t hc_num = hc->hc_num();
strlcat(hc_name, Helpers::itoa(s, hc_num), 6); strlcat(hc_name, Helpers::itoa(s, hc_num), 6);
if (nullptr != doc[hc_name]["mode"]) { if (nullptr != doc[hc_name]["mode"]) {
std::string mode = doc[hc_name]["mode"]; // first check mode std::string mode = doc[hc_name]["mode"]; // first check mode
set_mode(mode, hc_num); set_mode(mode, hc_num);
@@ -268,11 +269,38 @@ void Thermostat::thermostat_cmd(const char * message) {
} }
if (float f = doc[hc_name]["remotetemp"]) { if (float f = doc[hc_name]["remotetemp"]) {
if (f > 100 || f < 0) { if (f > 100 || f < 0) {
hc->remotetemp = EMS_VALUE_SHORT_NOTSET; Roomctrl::set_remotetemp(hc_num - 1, EMS_VALUE_SHORT_NOTSET);
} else { } 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"]; const char * command = doc["cmd"];
@@ -301,7 +329,6 @@ void Thermostat::thermostat_cmd(const char * message) {
return; return;
} }
// set night temp value
if (strcmp(command, "nighttemp") == 0) { if (strcmp(command, "nighttemp") == 0) {
float f = doc["data"]; float f = doc["data"];
if (f) { if (f) {
@@ -310,7 +337,6 @@ void Thermostat::thermostat_cmd(const char * message) {
} }
} }
// set daytemp value
if (strcmp(command, "daytemp") == 0) { if (strcmp(command, "daytemp") == 0) {
float f = doc["data"]; float f = doc["data"];
if (f) { if (f) {
@@ -319,7 +345,6 @@ void Thermostat::thermostat_cmd(const char * message) {
return; return;
} }
// set holiday value
if (strcmp(command, "holidaytemp") == 0) { if (strcmp(command, "holidaytemp") == 0) {
float f = doc["data"]; float f = doc["data"];
if (f) { if (f) {
@@ -328,7 +353,6 @@ void Thermostat::thermostat_cmd(const char * message) {
return; return;
} }
// set eco value
if (strcmp(command, "ecotemp") == 0) { if (strcmp(command, "ecotemp") == 0) {
float f = doc["data"]; float f = doc["data"];
if (f) { if (f) {
@@ -337,7 +361,6 @@ void Thermostat::thermostat_cmd(const char * message) {
return; return;
} }
// set heat value
if (strcmp(command, "heattemp") == 0) { if (strcmp(command, "heattemp") == 0) {
float f = doc["data"]; float f = doc["data"];
if (f) { if (f) {
@@ -346,7 +369,6 @@ void Thermostat::thermostat_cmd(const char * message) {
return; return;
} }
// set nofrost value
if (strcmp(command, "nofrosttemp") == 0) { if (strcmp(command, "nofrosttemp") == 0) {
float f = doc["data"]; float f = doc["data"];
if (f) { if (f) {
@@ -354,6 +376,7 @@ void Thermostat::thermostat_cmd(const char * message) {
} }
return; return;
} }
if (strcmp(command, "summertemp") == 0) { if (strcmp(command, "summertemp") == 0) {
float f = doc["data"]; float f = doc["data"];
if (f) { if (f) {
@@ -361,6 +384,7 @@ void Thermostat::thermostat_cmd(const char * message) {
} }
return; return;
} }
if (strcmp(command, "designtemp") == 0) { if (strcmp(command, "designtemp") == 0) {
float f = doc["data"]; float f = doc["data"];
if (f) { if (f) {
@@ -368,7 +392,8 @@ void Thermostat::thermostat_cmd(const char * message) {
} }
return; return;
} }
if (strcmp(command, "offettemp") == 0) {
if (strcmp(command, "offsettemp") == 0) {
float f = doc["data"]; float f = doc["data"];
if (f) { if (f) {
set_temperature(f, HeatingCircuit::Mode::OFFSET, hc_num); 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 // 0xA5 - Set the display settings
void Thermostat::set_settings_display(const uint8_t ds) { 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); LOG_INFO(F("Setting display to %d"), ds);
write_command(EMS_TYPE_IBASettings, 0, ds); write_command(EMS_TYPE_IBASettings, 0, ds);
}
} }
// 0xA5 - Set the building settings // 0xA5 - Set the building settings
void Thermostat::set_settings_building(const uint8_t bg) { 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); LOG_INFO(F("Setting building to %d"), bg);
write_command(EMS_TYPE_IBASettings, 6, bg); write_command(EMS_TYPE_IBASettings, 6, bg);
}
} }
// 0xA5 Set the language settings // 0xA5 Set the language settings
void Thermostat::set_settings_language(const uint8_t lg) { 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); LOG_INFO(F("Setting building to %d"), lg);
write_command(EMS_TYPE_IBASettings, 1, 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 // sets the thermostat working mode, where mode is a string

View File

@@ -29,6 +29,7 @@
#include "emsesp.h" #include "emsesp.h"
#include "helpers.h" #include "helpers.h"
#include "mqtt.h" #include "mqtt.h"
#include "roomcontrol.h"
#include <vector> #include <vector>
@@ -61,7 +62,6 @@ class Thermostat : public EMSdevice {
uint8_t nofrosttemp = EMS_VALUE_UINT_NOTSET; uint8_t nofrosttemp = EMS_VALUE_UINT_NOTSET;
uint8_t designtemp = EMS_VALUE_UINT_NOTSET; // heatingcurve design temp at MinExtTemp 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! 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 { uint8_t hc_num() const {
@@ -231,9 +231,13 @@ class Thermostat : public EMSdevice {
void process_EasyMonitor(std::shared_ptr<const Telegram> telegram); void process_EasyMonitor(std::shared_ptr<const Telegram> telegram);
// set functions // 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_display(const uint8_t ds);
void set_settings_building(const uint8_t bg); void set_settings_building(const uint8_t bg);
void set_settings_language(const uint8_t lg); 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 uint8_t mode, const uint8_t hc_num);
void set_mode(const std::string & 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); void set_temperature(const float temperature, const std::string & mode, const uint8_t hc_num);