mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 16:29:51 +03:00
support for multiple HCs - https://github.com/proddy/EMS-ESP/issues/162
This commit is contained in:
10
CHANGELOG.md
10
CHANGELOG.md
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.9.1 beta] 2019-09-07
|
||||
|
||||
### Added
|
||||
|
||||
- Support for multiple Heating Circuits (RC35 only for now and writing via telnet) - https://github.com/proddy/EMS-ESP/issues/162
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed `heating_circuit` parameter
|
||||
|
||||
## [1.9.0] 2019-09-01
|
||||
|
||||
### Changed
|
||||
|
||||
273
src/ems-esp.cpp
273
src/ems-esp.cpp
@@ -39,8 +39,6 @@ DS18 ds18;
|
||||
// set to value >0 if the ESP is overheating or there are timing issues. Recommend a value of 1.
|
||||
#define EMSESP_DELAY 0 // initially set to 0 for no delay. Change to 1 if getting WDT resets from wifi
|
||||
|
||||
#define DEFAULT_HEATINGCIRCUIT 1 // default to HC1 for thermostats that support multiple heating circuits like the RC35
|
||||
|
||||
// timers, all values are in seconds
|
||||
#define DEFAULT_PUBLISHTIME 120 // every 2 minutes publish MQTT values, including Dallas sensors
|
||||
Ticker publishValuesTimer;
|
||||
@@ -102,7 +100,6 @@ typedef struct {
|
||||
uint8_t led_gpio; // pin for LED
|
||||
uint8_t dallas_gpio; // pin for attaching external dallas temperature sensors
|
||||
bool dallas_parasite; // on/off is using parasite
|
||||
uint8_t heating_circuit; // number of heating circuit, 1 or 2
|
||||
uint8_t tx_mode; // TX mode 1,2 or 3
|
||||
} _EMSESP_Settings;
|
||||
|
||||
@@ -141,9 +138,9 @@ static const command_t project_cmds[] PROGMEM = {
|
||||
{false, "autodetect [deep]", "detect EMS devices and attempt to automatically set boiler and thermostat types"},
|
||||
{false, "shower <timer | alert>", "toggle either timer or alert on/off"},
|
||||
{false, "send XX ...", "send raw telegram data as hex to EMS bus"},
|
||||
{false, "thermostat read <type ID>", "send read request to the thermostat"},
|
||||
{false, "thermostat temp <degrees>", "set current thermostat temperature"},
|
||||
{false, "thermostat mode <mode>", "set mode (0=low/night, 1=manual/day, 2=auto)"},
|
||||
{false, "thermostat read <type ID>", "send read request to the thermostat for heating circuit hc 1-4"},
|
||||
{false, "thermostat temp [hc] <degrees>", "set current thermostat temperature"},
|
||||
{false, "thermostat mode [hc] <mode>", "set mode (0=low/night, 1=manual/day, 2=auto) for heating circuit hc 1-4"},
|
||||
{false, "thermostat scan <type ID>", "probe thermostat on all type id responses"},
|
||||
{false, "boiler read <type ID>", "send read request to boiler"},
|
||||
{false, "boiler wwtemp <degrees>", "set boiler warm water temperature"},
|
||||
@@ -392,29 +389,33 @@ void _renderBoolValue(const char * prefix, uint8_t value) {
|
||||
|
||||
// figures out the thermostat mode
|
||||
// returns 0xFF=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day
|
||||
uint8_t _getThermostatMode() {
|
||||
// hc_num is 1 to 4
|
||||
uint8_t _getThermostatMode(uint8_t hc_num) {
|
||||
int thermoMode = EMS_VALUE_INT_NOTSET;
|
||||
uint8_t model = ems_getThermostatModel();
|
||||
|
||||
if (ems_getThermostatModel() == EMS_MODEL_RC20) {
|
||||
if (EMS_Thermostat.mode == 0) {
|
||||
uint8_t mode = EMS_Thermostat.hc[hc_num - 1].mode;
|
||||
|
||||
if (model == EMS_MODEL_RC20) {
|
||||
if (mode == 0) {
|
||||
thermoMode = 0; // low
|
||||
} else if (EMS_Thermostat.mode == 1) {
|
||||
} else if (mode == 1) {
|
||||
thermoMode = 1; // manual
|
||||
} else if (EMS_Thermostat.mode == 2) {
|
||||
} else if (mode == 2) {
|
||||
thermoMode = 2; // auto
|
||||
}
|
||||
} else if (ems_getThermostatModel() == EMS_MODEL_RC300) {
|
||||
if (EMS_Thermostat.mode == 0) {
|
||||
} else if (model == EMS_MODEL_RC300) {
|
||||
if (mode == 0) {
|
||||
thermoMode = 1; // manual
|
||||
} else if (EMS_Thermostat.mode == 1) {
|
||||
} else if (mode == 1) {
|
||||
thermoMode = 2; // auto
|
||||
}
|
||||
} else { // default for all thermostats
|
||||
if (EMS_Thermostat.mode == 0) {
|
||||
} else { // default for all other thermostats
|
||||
if (mode == 0) {
|
||||
thermoMode = 3; // night
|
||||
} else if (EMS_Thermostat.mode == 1) {
|
||||
} else if (mode == 1) {
|
||||
thermoMode = 4; // day
|
||||
} else if (EMS_Thermostat.mode == 2) {
|
||||
} else if (mode == 2) {
|
||||
thermoMode = 2; // auto
|
||||
}
|
||||
}
|
||||
@@ -602,44 +603,48 @@ void showInfo() {
|
||||
myDebug_P(PSTR("%sThermostat stats:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF);
|
||||
myDebug_P(PSTR(" Thermostat: %s"), ems_getThermostatDescription(buffer_type, false));
|
||||
|
||||
// Render Current & Setpoint Room Temperature
|
||||
if (ems_getThermostatModel() == EMS_MODEL_EASY) {
|
||||
// Temperatures are *100
|
||||
_renderShortValue("Set room temperature", "C", EMS_Thermostat.setpoint_roomTemp, 10); // *100
|
||||
_renderShortValue("Current room temperature", "C", EMS_Thermostat.curr_roomTemp, 10); // *100
|
||||
} else if ((ems_getThermostatModel() == EMS_MODEL_FR10) || (ems_getThermostatModel() == EMS_MODEL_FW100)
|
||||
|| (ems_getThermostatModel() == EMS_MODEL_FW120)) {
|
||||
// Temperatures are *10
|
||||
_renderShortValue("Set room temperature", "C", EMS_Thermostat.setpoint_roomTemp, 1); // *10
|
||||
_renderShortValue("Current room temperature", "C", EMS_Thermostat.curr_roomTemp, 1); // *10
|
||||
} else {
|
||||
// because we store in 2 bytes short, when converting to a single byte we'll loose the negative value if its unset
|
||||
_renderShortValue("Setpoint room temperature", "C", EMS_Thermostat.setpoint_roomTemp, 2); // convert to a single byte * 2
|
||||
_renderShortValue("Current room temperature", "C", EMS_Thermostat.curr_roomTemp, 1); // is *10
|
||||
}
|
||||
|
||||
// Render Day/Night/Holiday Temperature
|
||||
if ((EMS_Thermostat.holidaytemp > 0) && (EMSESP_Settings.heating_circuit == 2)) { // only if we are on a RC35 we show more info
|
||||
_renderIntValue("Day temperature", "C", EMS_Thermostat.daytemp, 2); // convert to a single byte * 2
|
||||
_renderIntValue("Night temperature", "C", EMS_Thermostat.nighttemp, 2); // convert to a single byte * 2
|
||||
_renderIntValue("Vacation temperature", "C", EMS_Thermostat.holidaytemp, 2); // convert to a single byte * 2
|
||||
}
|
||||
|
||||
// Render Thermostat Date & Time
|
||||
// not for EASY
|
||||
if ((ems_getThermostatModel() != EMS_MODEL_EASY)) {
|
||||
myDebug_P(PSTR(" Thermostat time is %02d:%02d:%02d %d/%d/%d"),
|
||||
EMS_Thermostat.hour,
|
||||
EMS_Thermostat.minute,
|
||||
EMS_Thermostat.second,
|
||||
EMS_Thermostat.day,
|
||||
EMS_Thermostat.month,
|
||||
EMS_Thermostat.year + 2000);
|
||||
uint8_t model = ems_getThermostatModel();
|
||||
if ((model != EMS_MODEL_EASY)) {
|
||||
myDebug_P(PSTR(" Thermostat time is %s"), EMS_Thermostat.datetime);
|
||||
}
|
||||
|
||||
uint8_t _m_setpoint, _m_curr;
|
||||
switch (model) {
|
||||
case EMS_MODEL_EASY:
|
||||
_m_setpoint = 10; // *100
|
||||
_m_curr = 10; // *100
|
||||
break;
|
||||
case EMS_MODEL_FR10:
|
||||
case EMS_MODEL_FW100:
|
||||
case EMS_MODEL_FW120:
|
||||
_m_setpoint = 1; // *10
|
||||
_m_curr = 1; // *10
|
||||
break;
|
||||
default: // RC30,RC35 etc...
|
||||
_m_setpoint = 2; // *2
|
||||
_m_curr = 1; // *10
|
||||
break;
|
||||
}
|
||||
|
||||
// go through all Heating Circuits
|
||||
for (uint8_t hc_num = 1; hc_num <= EMS_THERMOSTAT_MAXHC; hc_num++) {
|
||||
// only show if we have data for the Heating Circuit
|
||||
if (EMS_Thermostat.hc[hc_num - 1].active) {
|
||||
myDebug_P(PSTR(" Heating Circuit %d"), hc_num);
|
||||
// Render Current & Setpoint Room Temperature for each thermostat type
|
||||
_renderShortValue(" Setpoint room temperature", "C", EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp, _m_setpoint);
|
||||
_renderShortValue(" Current room temperature", "C", EMS_Thermostat.hc[hc_num - 1].curr_roomTemp, _m_curr);
|
||||
|
||||
// Render Day/Night/Holiday Temperature on RC35s
|
||||
if (model == EMS_MODEL_RC35) {
|
||||
_renderIntValue(" Day temperature", "C", EMS_Thermostat.hc[hc_num - 1].daytemp, 2); // convert to a single byte * 2
|
||||
_renderIntValue(" Night temperature", "C", EMS_Thermostat.hc[hc_num - 1].nighttemp, 2); // convert to a single byte * 2
|
||||
_renderIntValue(" Vacation temperature", "C", EMS_Thermostat.hc[hc_num - 1].holidaytemp, 2); // convert to a single byte * 2
|
||||
}
|
||||
|
||||
// Render Termostat Mode, if we have a mode
|
||||
uint8_t thermoMode = _getThermostatMode(); // 0xFF=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day
|
||||
|
||||
uint8_t thermoMode = _getThermostatMode(hc_num); // 0xFF=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day
|
||||
if (thermoMode == 0) {
|
||||
myDebug_P(PSTR(" Mode is set to low"));
|
||||
} else if (thermoMode == 1) {
|
||||
@@ -652,8 +657,10 @@ void showInfo() {
|
||||
myDebug_P(PSTR(" Mode is set to day"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dallas
|
||||
// Dallas external temp sensors
|
||||
if (EMSESP_Settings.dallas_sensors != 0) {
|
||||
myDebug_P(PSTR("")); // newline
|
||||
char buffer[128] = {0};
|
||||
@@ -826,48 +833,55 @@ void publishValues(bool force) {
|
||||
last_boilerActive = ((EMS_Boiler.tapwaterActive << 1) + EMS_Boiler.heatingActive); // remember last state
|
||||
}
|
||||
|
||||
// handle the thermostat values separately
|
||||
// only send thermostat values if we actually have them
|
||||
if (ems_getThermostatEnabled() && ((EMS_Thermostat.curr_roomTemp != EMS_VALUE_SHORT_NOTSET) && (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET))) {
|
||||
// handle the thermostat values
|
||||
if (ems_getThermostatEnabled()) {
|
||||
uint8_t total_active_hc = 0; // number of HCs
|
||||
for (uint8_t hc_v = 0; hc_v < EMS_THERMOSTAT_MAXHC; hc_v++) {
|
||||
_EMS_Thermostat_HC * thermostat = &EMS_Thermostat.hc[hc_v];
|
||||
|
||||
total_active_hc++; // increase count for #HCs we encounter
|
||||
|
||||
// only send if we have an active Heating Circuit with real data
|
||||
if ((thermostat->active) && (thermostat->curr_roomTemp != EMS_VALUE_SHORT_NOTSET) && (thermostat->setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)) {
|
||||
// build new json object
|
||||
doc.clear();
|
||||
JsonObject rootThermostat = doc.to<JsonObject>();
|
||||
|
||||
rootThermostat[THERMOSTAT_HC] = _int_to_char(s, EMSESP_Settings.heating_circuit);
|
||||
rootThermostat[THERMOSTAT_HC] = _int_to_char(s, (thermostat->hc) + 1); // heating circuit 1..4
|
||||
|
||||
// different logic depending on thermostat types
|
||||
if (ems_getThermostatModel() == EMS_MODEL_EASY) {
|
||||
if (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_SELTEMP] = (double)EMS_Thermostat.setpoint_roomTemp / 100;
|
||||
if (EMS_Thermostat.curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_CURRTEMP] = (double)EMS_Thermostat.curr_roomTemp / 100;
|
||||
if (thermostat->setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_SELTEMP] = (double)thermostat->setpoint_roomTemp / 100;
|
||||
if (thermostat->curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_CURRTEMP] = (double)thermostat->curr_roomTemp / 100;
|
||||
} else if ((ems_getThermostatModel() == EMS_MODEL_FR10) || (ems_getThermostatModel() == EMS_MODEL_FW100)
|
||||
|| (ems_getThermostatModel() == EMS_MODEL_FW120)) {
|
||||
if (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_SELTEMP] = (double)EMS_Thermostat.setpoint_roomTemp / 10;
|
||||
if (EMS_Thermostat.curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_CURRTEMP] = (double)EMS_Thermostat.curr_roomTemp / 10;
|
||||
if (thermostat->setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_SELTEMP] = (double)thermostat->setpoint_roomTemp / 10;
|
||||
if (thermostat->curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_CURRTEMP] = (double)thermostat->curr_roomTemp / 10;
|
||||
} else {
|
||||
if (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_SELTEMP] = (double)EMS_Thermostat.setpoint_roomTemp / 2;
|
||||
if (EMS_Thermostat.curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_CURRTEMP] = (double)EMS_Thermostat.curr_roomTemp / 10;
|
||||
if (thermostat->setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_SELTEMP] = (double)thermostat->setpoint_roomTemp / 2;
|
||||
if (thermostat->curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_CURRTEMP] = (double)thermostat->curr_roomTemp / 10;
|
||||
|
||||
if (EMS_Thermostat.daytemp != EMS_VALUE_INT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_DAYTEMP] = (double)EMS_Thermostat.daytemp / 2;
|
||||
if (EMS_Thermostat.nighttemp != EMS_VALUE_INT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_NIGHTTEMP] = (double)EMS_Thermostat.nighttemp / 2;
|
||||
if (EMS_Thermostat.holidaytemp != EMS_VALUE_INT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_HOLIDAYTEMP] = (double)EMS_Thermostat.holidaytemp / 2;
|
||||
if (thermostat->daytemp != EMS_VALUE_INT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_DAYTEMP] = (double)thermostat->daytemp / 2;
|
||||
if (thermostat->nighttemp != EMS_VALUE_INT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_NIGHTTEMP] = (double)thermostat->nighttemp / 2;
|
||||
if (thermostat->holidaytemp != EMS_VALUE_INT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_HOLIDAYTEMP] = (double)thermostat->holidaytemp / 2;
|
||||
|
||||
if (EMS_Thermostat.heatingtype != EMS_VALUE_INT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_HEATINGTYPE] = EMS_Thermostat.heatingtype;
|
||||
if (thermostat->heatingtype != EMS_VALUE_INT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_HEATINGTYPE] = thermostat->heatingtype;
|
||||
|
||||
if (EMS_Thermostat.circuitcalctemp != EMS_VALUE_INT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_CIRCUITCALCTEMP] = EMS_Thermostat.circuitcalctemp;
|
||||
if (thermostat->circuitcalctemp != EMS_VALUE_INT_NOTSET)
|
||||
rootThermostat[THERMOSTAT_CIRCUITCALCTEMP] = thermostat->circuitcalctemp;
|
||||
}
|
||||
|
||||
uint8_t thermoMode = _getThermostatMode(); // 0xFF=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day
|
||||
uint8_t thermoMode = _getThermostatMode(hc_v + 1); // 0xFF=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day
|
||||
|
||||
// Termostat Mode
|
||||
if (thermoMode == 0) {
|
||||
@@ -899,7 +913,17 @@ void publishValues(bool force) {
|
||||
myDebugLog("Publishing thermostat data via MQTT");
|
||||
|
||||
// send values via MQTT
|
||||
myESP.mqttPublish(TOPIC_THERMOSTAT_DATA, data);
|
||||
|
||||
char thermostat_topicname[20];
|
||||
strlcpy(thermostat_topicname, TOPIC_THERMOSTAT_DATA, sizeof(thermostat_topicname)); // "thermostat_data"
|
||||
// if we have more than 1 active Heating Circuit, postfix with the HC number
|
||||
if (total_active_hc > 1) {
|
||||
char buffer[4];
|
||||
strlcat(thermostat_topicname, itoa(total_active_hc, buffer, 10), sizeof(thermostat_topicname));
|
||||
}
|
||||
myESP.mqttPublish(thermostat_topicname, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1066,7 +1090,7 @@ void do_scanThermostat() {
|
||||
|
||||
// do a system health check every now and then to see if we all connections
|
||||
void do_systemCheck() {
|
||||
if (!ems_getBusConnected()) {
|
||||
if (!ems_getBusConnected() && !myESP.getUseSerial()) {
|
||||
myDebug_P(PSTR("Error! Unable to read the EMS bus."));
|
||||
}
|
||||
}
|
||||
@@ -1180,9 +1204,6 @@ bool LoadSaveCallback(MYESP_FSACTION action, JsonObject json) {
|
||||
EMSESP_Settings.listen_mode = settings["listen_mode"];
|
||||
ems_setTxDisabled(EMSESP_Settings.listen_mode);
|
||||
|
||||
EMSESP_Settings.heating_circuit = settings["heating_circuit"] | DEFAULT_HEATINGCIRCUIT;
|
||||
ems_setThermostatHC(EMSESP_Settings.heating_circuit);
|
||||
|
||||
EMSESP_Settings.tx_mode = settings["tx_mode"] | 1; // default to 1 (generic)
|
||||
ems_setTxMode(EMSESP_Settings.tx_mode);
|
||||
|
||||
@@ -1200,7 +1221,6 @@ bool LoadSaveCallback(MYESP_FSACTION action, JsonObject json) {
|
||||
settings["shower_timer"] = EMSESP_Settings.shower_timer;
|
||||
settings["shower_alert"] = EMSESP_Settings.shower_alert;
|
||||
settings["publish_time"] = EMSESP_Settings.publish_time;
|
||||
settings["heating_circuit"] = EMSESP_Settings.heating_circuit;
|
||||
settings["tx_mode"] = EMSESP_Settings.tx_mode;
|
||||
|
||||
return true;
|
||||
@@ -1308,18 +1328,6 @@ bool SetListCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, co
|
||||
ok = true;
|
||||
}
|
||||
|
||||
// heating_circuit
|
||||
if ((strcmp(setting, "heating_circuit") == 0) && (wc == 2)) {
|
||||
uint8_t hc = atoi(value);
|
||||
if ((hc >= 1) && (hc <= 2)) {
|
||||
EMSESP_Settings.heating_circuit = hc;
|
||||
ems_setThermostatHC(hc);
|
||||
ok = true;
|
||||
} else {
|
||||
myDebug_P(PSTR("Error. Usage: set heating_circuit <1 | 2>"));
|
||||
}
|
||||
}
|
||||
|
||||
// tx_mode
|
||||
if ((strcmp(setting, "tx_mode") == 0) && (wc == 2)) {
|
||||
uint8_t mode = atoi(value);
|
||||
@@ -1338,7 +1346,6 @@ bool SetListCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, co
|
||||
myDebug_P(PSTR(" led_gpio=%d"), EMSESP_Settings.led_gpio);
|
||||
myDebug_P(PSTR(" dallas_gpio=%d"), EMSESP_Settings.dallas_gpio);
|
||||
myDebug_P(PSTR(" dallas_parasite=%s"), EMSESP_Settings.dallas_parasite ? "on" : "off");
|
||||
myDebug_P(PSTR(" heating_circuit=%d"), EMSESP_Settings.heating_circuit);
|
||||
myDebug_P(PSTR(" tx_mode=%d"), EMSESP_Settings.tx_mode);
|
||||
myDebug_P(PSTR(" listen_mode=%s"), EMSESP_Settings.listen_mode ? "on" : "off");
|
||||
myDebug_P(PSTR(" shower_timer=%s"), EMSESP_Settings.shower_timer ? "on" : "off");
|
||||
@@ -1487,13 +1494,21 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) {
|
||||
}
|
||||
|
||||
// thermostat commands
|
||||
if ((strcmp(first_cmd, "thermostat") == 0) && (wc == 3)) {
|
||||
if ((strcmp(first_cmd, "thermostat") == 0) && (wc >= 3)) {
|
||||
char * second_cmd = _readWord();
|
||||
uint8_t hc = EMS_THERMOSTAT_DEFAULTHC;
|
||||
|
||||
if (strcmp(second_cmd, "temp") == 0) {
|
||||
ems_setThermostatTemp(_readFloatNumber());
|
||||
if (wc == 4) {
|
||||
hc = _readIntNumber(); // next parameter is the heating circuit
|
||||
}
|
||||
ems_setThermostatTemp(_readFloatNumber(), hc);
|
||||
ok = true;
|
||||
} else if (strcmp(second_cmd, "mode") == 0) {
|
||||
ems_setThermostatMode(_readIntNumber());
|
||||
if (wc == 4) {
|
||||
hc = _readIntNumber(); // next parameter is the heating circuit
|
||||
}
|
||||
ems_setThermostatMode(_readIntNumber(), hc);
|
||||
ok = true;
|
||||
} else if (strcmp(second_cmd, "read") == 0) {
|
||||
ems_doReadCommand(_readHexNumber(), EMS_Thermostat.device_id);
|
||||
@@ -1602,7 +1617,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
|
||||
float f = strtof((char *)message, 0);
|
||||
char s[10] = {0};
|
||||
myDebug_P(PSTR("MQTT topic: thermostat temperature value %s"), _float_to_char(s, f));
|
||||
ems_setThermostatTemp(f);
|
||||
ems_setThermostatTemp(f, EMS_THERMOSTAT_DEFAULTHC);
|
||||
publishValues(true); // publish back immediately, can't remember why I do this?!
|
||||
}
|
||||
|
||||
@@ -1610,21 +1625,11 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
|
||||
if (strcmp(topic, TOPIC_THERMOSTAT_CMD_MODE) == 0) {
|
||||
myDebug_P(PSTR("MQTT topic: thermostat mode value %s"), message);
|
||||
if (strcmp((char *)message, "auto") == 0) {
|
||||
ems_setThermostatMode(2);
|
||||
ems_setThermostatMode(2, EMS_THERMOSTAT_DEFAULTHC);
|
||||
} else if (strcmp((char *)message, "day") == 0 || strcmp((char *)message, "manual") == 0) {
|
||||
ems_setThermostatMode(1);
|
||||
ems_setThermostatMode(1, EMS_THERMOSTAT_DEFAULTHC);
|
||||
} else if (strcmp((char *)message, "night") == 0 || strcmp((char *)message, "off") == 0) {
|
||||
ems_setThermostatMode(0);
|
||||
}
|
||||
}
|
||||
|
||||
// thermostat heating circuit change
|
||||
if (strcmp(topic, TOPIC_THERMOSTAT_CMD_HC) == 0) {
|
||||
myDebug_P(PSTR("MQTT topic: thermostat heating circuit value %s"), message);
|
||||
uint8_t hc = atoi((char *)message);
|
||||
if ((hc >= 1) && (hc <= 2)) {
|
||||
EMSESP_Settings.heating_circuit = hc;
|
||||
ems_setThermostatHC(hc);
|
||||
ems_setThermostatMode(0, EMS_THERMOSTAT_DEFAULTHC);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1633,7 +1638,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
|
||||
float f = strtof((char *)message, 0);
|
||||
char s[10] = {0};
|
||||
myDebug_P(PSTR("MQTT topic: new thermostat night temperature value %s"), _float_to_char(s, f));
|
||||
ems_setThermostatTemp(f, 1);
|
||||
ems_setThermostatTemp(f, EMS_THERMOSTAT_DEFAULTHC, 1);
|
||||
}
|
||||
|
||||
// set daytemp value
|
||||
@@ -1641,7 +1646,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
|
||||
float f = strtof((char *)message, 0);
|
||||
char s[10] = {0};
|
||||
myDebug_P(PSTR("MQTT topic: new thermostat day temperature value %s"), _float_to_char(s, f));
|
||||
ems_setThermostatTemp(f, 2);
|
||||
ems_setThermostatTemp(f, EMS_THERMOSTAT_DEFAULTHC, 2);
|
||||
}
|
||||
|
||||
// set holiday value
|
||||
@@ -1649,7 +1654,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
|
||||
float f = strtof((char *)message, 0);
|
||||
char s[10] = {0};
|
||||
myDebug_P(PSTR("MQTT topic: new thermostat holiday temperature value %s"), _float_to_char(s, f));
|
||||
ems_setThermostatTemp(f, 3);
|
||||
ems_setThermostatTemp(f, EMS_THERMOSTAT_DEFAULTHC, 3);
|
||||
}
|
||||
|
||||
// wwActivated
|
||||
@@ -1770,27 +1775,30 @@ void WebCallback(JsonObject root) {
|
||||
char buffer[200];
|
||||
thermostat["tm"] = ems_getThermostatDescription(buffer, true);
|
||||
|
||||
// TODO: enable support multiple HCs
|
||||
uint8_t hc_num = EMS_THERMOSTAT_DEFAULTHC; // default to HC1
|
||||
|
||||
// Render Current & Setpoint Room Temperature
|
||||
if (ems_getThermostatModel() == EMS_MODEL_EASY) {
|
||||
if (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
thermostat["ts"] = (double)EMS_Thermostat.setpoint_roomTemp / 100;
|
||||
if (EMS_Thermostat.curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
thermostat["tc"] = (double)EMS_Thermostat.curr_roomTemp / 100;
|
||||
if (EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
thermostat["ts"] = (double)EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp / 100;
|
||||
if (EMS_Thermostat.hc[hc_num - 1].curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
thermostat["tc"] = (double)EMS_Thermostat.hc[hc_num - 1].curr_roomTemp / 100;
|
||||
} else if ((ems_getThermostatModel() == EMS_MODEL_FR10) || (ems_getThermostatModel() == EMS_MODEL_FW100)
|
||||
|| (ems_getThermostatModel() == EMS_MODEL_FW120)) {
|
||||
if (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
thermostat["ts"] = (double)EMS_Thermostat.setpoint_roomTemp / 10;
|
||||
if (EMS_Thermostat.curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
thermostat["tc"] = (double)EMS_Thermostat.curr_roomTemp / 10;
|
||||
if (EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
thermostat["ts"] = (double)EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp / 10;
|
||||
if (EMS_Thermostat.hc[hc_num - 1].curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
thermostat["tc"] = (double)EMS_Thermostat.hc[hc_num - 1].curr_roomTemp / 10;
|
||||
} else {
|
||||
if (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
thermostat["ts"] = (double)EMS_Thermostat.setpoint_roomTemp / 2;
|
||||
if (EMS_Thermostat.curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
thermostat["tc"] = (double)EMS_Thermostat.curr_roomTemp / 10;
|
||||
if (EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
thermostat["ts"] = (double)EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp / 2;
|
||||
if (EMS_Thermostat.hc[hc_num - 1].curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
thermostat["tc"] = (double)EMS_Thermostat.hc[hc_num - 1].curr_roomTemp / 10;
|
||||
}
|
||||
|
||||
// Render Termostat Mode, if we have a mode
|
||||
uint8_t thermoMode = _getThermostatMode(); // 0xFF=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day
|
||||
uint8_t thermoMode = _getThermostatMode(hc_num); // 0xFF=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day
|
||||
if (thermoMode == 0) {
|
||||
thermostat["tmode"] = "low";
|
||||
} else if (thermoMode == 1) {
|
||||
@@ -1899,7 +1907,6 @@ void initEMSESP() {
|
||||
EMSESP_Settings.dallas_sensors = 0;
|
||||
EMSESP_Settings.led_gpio = EMSESP_LED_GPIO;
|
||||
EMSESP_Settings.dallas_gpio = EMSESP_DALLAS_GPIO;
|
||||
EMSESP_Settings.heating_circuit = 1; // default heating circuit to HC1
|
||||
EMSESP_Settings.tx_mode = 1; // default tx mode
|
||||
|
||||
// shower settings
|
||||
|
||||
278
src/ems.cpp
278
src/ems.cpp
@@ -159,6 +159,10 @@ const _EMS_Type EMS_Types[] = {
|
||||
{EMS_MODEL_RC35, EMS_TYPE_RC35StatusMessage_HC1, "RC35StatusMessage_HC1", _process_RC35StatusMessage},
|
||||
{EMS_MODEL_RC35, EMS_TYPE_RC35Set_HC2, "RC35Set_HC2", _process_RC35Set},
|
||||
{EMS_MODEL_RC35, EMS_TYPE_RC35StatusMessage_HC2, "RC35StatusMessage_HC2", _process_RC35StatusMessage},
|
||||
{EMS_MODEL_RC35, EMS_TYPE_RC35Set_HC3, "RC35Set_HC2", _process_RC35Set},
|
||||
{EMS_MODEL_RC35, EMS_TYPE_RC35StatusMessage_HC3, "RC35StatusMessage_HC3", _process_RC35StatusMessage},
|
||||
{EMS_MODEL_RC35, EMS_TYPE_RC35Set_HC4, "RC35Set_HC4", _process_RC35Set},
|
||||
{EMS_MODEL_RC35, EMS_TYPE_RC35StatusMessage_HC4, "RC35StatusMessage_HC4", _process_RC35StatusMessage},
|
||||
|
||||
// ES73
|
||||
{EMS_MODEL_ES73, EMS_TYPE_RCOutdoorTempMessage, "RCOutdoorTempMessage", _process_RCOutdoorTempMessage},
|
||||
@@ -234,25 +238,24 @@ void ems_init() {
|
||||
EMS_Sys_Status.emsPollAck[0] = EMS_ID_ME;
|
||||
|
||||
// thermostat
|
||||
EMS_Thermostat.setpoint_roomTemp = EMS_VALUE_SHORT_NOTSET;
|
||||
EMS_Thermostat.curr_roomTemp = EMS_VALUE_SHORT_NOTSET;
|
||||
EMS_Thermostat.hour = 0;
|
||||
EMS_Thermostat.minute = 0;
|
||||
EMS_Thermostat.second = 0;
|
||||
EMS_Thermostat.day = 0;
|
||||
EMS_Thermostat.month = 0;
|
||||
EMS_Thermostat.year = 0;
|
||||
EMS_Thermostat.mode = EMS_VALUE_INT_NOTSET;
|
||||
EMS_Thermostat.day_mode = EMS_VALUE_INT_NOTSET;
|
||||
EMS_Thermostat.device_id = EMS_ID_NONE;
|
||||
strlcpy(EMS_Thermostat.datetime, "?", sizeof(EMS_Thermostat.datetime));
|
||||
EMS_Thermostat.write_supported = false;
|
||||
EMS_Thermostat.hc = 1; // default heating circuit is 1
|
||||
EMS_Thermostat.daytemp = EMS_VALUE_INT_NOTSET; // 0x47 byte
|
||||
EMS_Thermostat.nighttemp = EMS_VALUE_INT_NOTSET; // 0x47 byte
|
||||
EMS_Thermostat.holidaytemp = EMS_VALUE_INT_NOTSET; // 0x47 byte
|
||||
EMS_Thermostat.heatingtype = EMS_VALUE_INT_NOTSET; // 0x47 byte floor heating = 3
|
||||
EMS_Thermostat.circuitcalctemp = EMS_VALUE_INT_NOTSET; // 0x48 byte 14
|
||||
EMS_Thermostat.device_id = EMS_ID_NONE;
|
||||
|
||||
// init all heating circuits
|
||||
for (uint8_t i = 0; i < EMS_THERMOSTAT_MAXHC; i++) {
|
||||
EMS_Thermostat.hc[i].hc = i;
|
||||
EMS_Thermostat.hc[i].active = false;
|
||||
EMS_Thermostat.hc[i].mode = EMS_VALUE_INT_NOTSET;
|
||||
EMS_Thermostat.hc[i].day_mode = EMS_VALUE_INT_NOTSET;
|
||||
EMS_Thermostat.hc[i].daytemp = EMS_VALUE_INT_NOTSET;
|
||||
EMS_Thermostat.hc[i].nighttemp = EMS_VALUE_INT_NOTSET;
|
||||
EMS_Thermostat.hc[i].holidaytemp = EMS_VALUE_INT_NOTSET;
|
||||
EMS_Thermostat.hc[i].heatingtype = EMS_VALUE_INT_NOTSET; // floor heating = 3
|
||||
EMS_Thermostat.hc[i].circuitcalctemp = EMS_VALUE_INT_NOTSET;
|
||||
EMS_Thermostat.hc[i].setpoint_roomTemp = EMS_VALUE_SHORT_NOTSET;
|
||||
EMS_Thermostat.hc[i].curr_roomTemp = EMS_VALUE_SHORT_NOTSET;
|
||||
}
|
||||
|
||||
// UBAParameterWW
|
||||
EMS_Boiler.wWActivated = EMS_VALUE_INT_NOTSET; // Warm Water activated
|
||||
@@ -357,10 +360,6 @@ void ems_setEmsRefreshed(bool b) {
|
||||
EMS_Sys_Status.emsRefreshed = b;
|
||||
}
|
||||
|
||||
void ems_setThermostatHC(uint8_t hc) {
|
||||
EMS_Thermostat.hc = hc;
|
||||
}
|
||||
|
||||
bool ems_getBoilerEnabled() {
|
||||
return (EMS_Boiler.device_id != EMS_ID_NONE);
|
||||
}
|
||||
@@ -1344,8 +1343,11 @@ void _process_UBAMonitorSlow(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
* e.g. 17 0B 91 00 80 1E 00 CB 27 00 00 00 00 05 01 00 CB 00 (CRC=47), #data=14
|
||||
*/
|
||||
void _process_RC10StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
EMS_Thermostat.setpoint_roomTemp = _toByte(EMS_OFFSET_RC10StatusMessage_setpoint); // is * 2
|
||||
EMS_Thermostat.curr_roomTemp = _toShort(EMS_OFFSET_RC10StatusMessage_curr); // is * 10
|
||||
uint8_t hc = EMS_THERMOSTAT_DEFAULTHC - 1; // use HC1
|
||||
|
||||
EMS_Thermostat.hc[hc].active = true;
|
||||
EMS_Thermostat.hc[hc].setpoint_roomTemp = _toByte(EMS_OFFSET_RC10StatusMessage_setpoint); // is * 2
|
||||
EMS_Thermostat.hc[hc].curr_roomTemp = _toShort(EMS_OFFSET_RC10StatusMessage_curr); // is * 10
|
||||
|
||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
||||
}
|
||||
@@ -1356,8 +1358,11 @@ void _process_RC10StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
* received every 60 seconds
|
||||
*/
|
||||
void _process_RC20StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
EMS_Thermostat.setpoint_roomTemp = _toByte(EMS_OFFSET_RC20StatusMessage_setpoint); // is * 2
|
||||
EMS_Thermostat.curr_roomTemp = _toShort(EMS_OFFSET_RC20StatusMessage_curr); // is * 10
|
||||
uint8_t hc = EMS_THERMOSTAT_DEFAULTHC - 1; // use HC1
|
||||
|
||||
EMS_Thermostat.hc[hc].active = true;
|
||||
EMS_Thermostat.hc[hc].setpoint_roomTemp = _toByte(EMS_OFFSET_RC20StatusMessage_setpoint); // is * 2
|
||||
EMS_Thermostat.hc[hc].curr_roomTemp = _toShort(EMS_OFFSET_RC20StatusMessage_curr); // is * 10
|
||||
|
||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
||||
}
|
||||
@@ -1367,29 +1372,35 @@ void _process_RC20StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
* For reading the temp values only * received every 60 seconds
|
||||
*/
|
||||
void _process_RC30StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
EMS_Thermostat.setpoint_roomTemp = _toByte(EMS_OFFSET_RC30StatusMessage_setpoint); // is * 2
|
||||
EMS_Thermostat.curr_roomTemp = _toShort(EMS_OFFSET_RC30StatusMessage_curr); // note, its 2 bytes here
|
||||
uint8_t hc = EMS_THERMOSTAT_DEFAULTHC - 1; // use HC1
|
||||
|
||||
EMS_Thermostat.hc[hc].active = true;
|
||||
EMS_Thermostat.hc[hc].setpoint_roomTemp = _toByte(EMS_OFFSET_RC30StatusMessage_setpoint); // is * 2
|
||||
EMS_Thermostat.hc[hc].curr_roomTemp = _toShort(EMS_OFFSET_RC30StatusMessage_curr); // note, its 2 bytes here
|
||||
|
||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
||||
}
|
||||
|
||||
/**
|
||||
* type 0x3E and 0x48 - data from the RC35 thermostat (0x10) - 16 bytes
|
||||
* type 0x3E (HC1), 0x48 (HC2), 0x52 (HC3), 0x5C (HC4) - HK1MonitorMessage - data from the RC35 thermostat (0x10) - 16 bytes
|
||||
*
|
||||
* For reading the temp values only
|
||||
* received every 60 seconds
|
||||
*/
|
||||
void _process_RC35StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
EMS_Thermostat.setpoint_roomTemp = _toByte(EMS_OFFSET_RC35StatusMessage_setpoint); // is * 2
|
||||
uint8_t hc_num = _getHeatingCircuit(EMS_RxTelegram); // which HC is it?
|
||||
|
||||
EMS_Thermostat.hc[hc_num].setpoint_roomTemp = _toByte(EMS_OFFSET_RC35StatusMessage_setpoint); // is * 2
|
||||
|
||||
// check if temp sensor is unavailable
|
||||
if (EMS_RxTelegram->data[3] == 0x7D) {
|
||||
EMS_Thermostat.curr_roomTemp = EMS_VALUE_SHORT_NOTSET;
|
||||
EMS_Thermostat.hc[hc_num].curr_roomTemp = EMS_VALUE_SHORT_NOTSET;
|
||||
} else {
|
||||
EMS_Thermostat.curr_roomTemp = _toShort(EMS_OFFSET_RC35StatusMessage_curr);
|
||||
EMS_Thermostat.hc[hc_num].curr_roomTemp = _toShort(EMS_OFFSET_RC35StatusMessage_curr);
|
||||
}
|
||||
EMS_Thermostat.day_mode = _bitRead(EMS_OFFSET_RC35StatusMessage_mode, 1); // get day mode flag
|
||||
EMS_Thermostat.hc[hc_num].day_mode = _bitRead(EMS_OFFSET_RC35StatusMessage_mode, 1); // get day mode flag
|
||||
|
||||
EMS_Thermostat.circuitcalctemp = _toByte(EMS_OFFSET_RC35Set_circuitcalctemp); // 0x48 calculated temperature
|
||||
EMS_Thermostat.hc[hc_num].circuitcalctemp = _toByte(EMS_OFFSET_RC35Set_circuitcalctemp); // 0x48 calculated temperature
|
||||
|
||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
||||
}
|
||||
@@ -1399,8 +1410,11 @@ void _process_RC35StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
* The Easy has a digital precision of its floats to 2 decimal places, so values must be divided by 100
|
||||
*/
|
||||
void _process_EasyStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
EMS_Thermostat.curr_roomTemp = _toShort(EMS_OFFSET_EasyStatusMessage_curr); // is *100
|
||||
EMS_Thermostat.setpoint_roomTemp = _toShort(EMS_OFFSET_EasyStatusMessage_setpoint); // is *100
|
||||
uint8_t hc = EMS_THERMOSTAT_DEFAULTHC - 1; // use HC1
|
||||
|
||||
EMS_Thermostat.hc[hc].active = true;
|
||||
EMS_Thermostat.hc[hc].curr_roomTemp = _toShort(EMS_OFFSET_EasyStatusMessage_curr); // is *100
|
||||
EMS_Thermostat.hc[hc].setpoint_roomTemp = _toShort(EMS_OFFSET_EasyStatusMessage_setpoint); // is *100
|
||||
|
||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
||||
}
|
||||
@@ -1410,23 +1424,26 @@ void _process_EasyStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
* EMS+ messages may come in with different offsets so handle them here
|
||||
*/
|
||||
void _process_RCPLUSStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
uint8_t hc = EMS_THERMOSTAT_DEFAULTHC - 1; // use HC1
|
||||
EMS_Thermostat.hc[hc].active = true;
|
||||
|
||||
// handle single data values
|
||||
if (EMS_RxTelegram->data_length == 1) {
|
||||
switch (EMS_RxTelegram->offset) {
|
||||
case EMS_OFFSET_RCPLUSStatusMessage_curr: // setpoint target temp
|
||||
EMS_Thermostat.curr_roomTemp = _toShort(0); // value is * 10
|
||||
EMS_Thermostat.hc[hc].curr_roomTemp = _toShort(0); // value is * 10
|
||||
break;
|
||||
case EMS_OFFSET_RCPLUSStatusMessage_setpoint: // current target temp
|
||||
EMS_Thermostat.setpoint_roomTemp = _toByte(0); // value is * 2
|
||||
EMS_Thermostat.hc[hc].setpoint_roomTemp = _toByte(0); // value is * 2
|
||||
break;
|
||||
case EMS_OFFSET_RCPLUSStatusMessage_currsetpoint: // current setpoint temp, e.g. Thermostat -> all, telegram: 10 00 FF 06 01 A5 22
|
||||
EMS_Thermostat.setpoint_roomTemp = _toByte(0); // value is * 2
|
||||
EMS_Thermostat.hc[hc].setpoint_roomTemp = _toByte(0); // value is * 2
|
||||
break;
|
||||
case EMS_OFFSET_RCPLUSStatusMessage_mode: // thermostat mode auto/manual
|
||||
// manual : 10 00 FF 0A 01 A5 02
|
||||
// auto : Thermostat -> all, type 0x01A5 telegram: 10 00 FF 0A 01 A5 03
|
||||
EMS_Thermostat.mode = _bitRead(0, 0); // bit 1, mode (auto=1 or manual=0)
|
||||
EMS_Thermostat.day_mode = _bitRead(0, 1); // get day mode flag
|
||||
EMS_Thermostat.hc[hc].mode = _bitRead(0, 0); // bit 1, mode (auto=1 or manual=0)
|
||||
EMS_Thermostat.hc[EMS_TYPE_RC35StatusMessage_HC3].day_mode = _bitRead(0, 1); // get day mode flag
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1434,10 +1451,10 @@ void _process_RCPLUSStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
// the whole telegram
|
||||
// e.g. Thermostat -> all, telegram: 10 00 FF 00 01 A5 00 D7 21 00 00 00 00 30 01 84 01 01 03 01 84 01 F1 00 00 11 01 00 08 63 00
|
||||
// 10 00 FF 00 01 A5 80 00 01 30 28 00 30 28 01 54 03 03 01 01 54 02 A8 00 00 11 01 03 FF FF 00
|
||||
EMS_Thermostat.curr_roomTemp = _toShort(EMS_OFFSET_RCPLUSStatusMessage_curr); // value is * 10
|
||||
EMS_Thermostat.setpoint_roomTemp = _toByte(EMS_OFFSET_RCPLUSStatusMessage_setpoint); // value is * 2
|
||||
EMS_Thermostat.day_mode = _bitRead(EMS_OFFSET_RCPLUSStatusMessage_mode, 1); // get day mode flag
|
||||
EMS_Thermostat.mode = _bitRead(EMS_OFFSET_RCPLUSStatusMessage_mode, 0); // bit 1, mode (auto=1 or manual=0)
|
||||
EMS_Thermostat.hc[hc].curr_roomTemp = _toShort(EMS_OFFSET_RCPLUSStatusMessage_curr); // value is * 10
|
||||
EMS_Thermostat.hc[hc].setpoint_roomTemp = _toByte(EMS_OFFSET_RCPLUSStatusMessage_setpoint); // value is * 2
|
||||
EMS_Thermostat.hc[hc].day_mode = _bitRead(EMS_OFFSET_RCPLUSStatusMessage_mode, 1); // get day mode flag
|
||||
EMS_Thermostat.hc[hc].mode = _bitRead(EMS_OFFSET_RCPLUSStatusMessage_mode, 0); // bit 1, mode (auto=1 or manual=0)
|
||||
}
|
||||
|
||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
||||
@@ -1455,10 +1472,13 @@ void _process_RCPLUSStatusMode(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
*/
|
||||
void _process_JunkersStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
if (EMS_RxTelegram->offset == 0) {
|
||||
uint8_t hc = EMS_THERMOSTAT_DEFAULTHC - 1; // use HC1
|
||||
EMS_Thermostat.hc[hc].active = true;
|
||||
|
||||
// e.g. for FR10: 90 00 FF 00 00 6F 03 01 00 BE 00 BF
|
||||
// e.g. for FW100: 90 00 FF 00 00 6F 03 02 00 D7 00 DA F3 34 00 C4
|
||||
EMS_Thermostat.curr_roomTemp = _toShort(EMS_OFFSET_JunkersStatusMessage_curr); // value is * 10
|
||||
EMS_Thermostat.setpoint_roomTemp = _toShort(EMS_OFFSET_JunkersStatusMessage_setpoint); // value is * 10
|
||||
EMS_Thermostat.hc[hc].curr_roomTemp = _toShort(EMS_OFFSET_JunkersStatusMessage_curr); // value is * 10
|
||||
EMS_Thermostat.hc[hc].setpoint_roomTemp = _toShort(EMS_OFFSET_JunkersStatusMessage_setpoint); // value is * 10
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1471,18 +1491,20 @@ void _process_RCPLUSSetMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t hc = EMS_THERMOSTAT_DEFAULTHC - 1; // use HC1
|
||||
EMS_Thermostat.hc[hc].active = true;
|
||||
|
||||
// check for single values
|
||||
// but ignore values of 0xFF, e.g. 10 00 FF 08 01 B9 FF
|
||||
if ((EMS_RxTelegram->data_length == 1) && (_toByte(0) != 0xFF)) {
|
||||
// check for setpoint temps, e.g. Thermostat -> all, type 0x01B9, telegram: 10 00 FF 08 01 B9 26 (CRC=1A) #data=1
|
||||
|
||||
if ((EMS_RxTelegram->offset == EMS_OFFSET_RCPLUSSet_temp_setpoint) || (EMS_RxTelegram->offset == EMS_OFFSET_RCPLUSSet_manual_setpoint)) {
|
||||
EMS_Thermostat.setpoint_roomTemp = _toByte(0); // value is * 2
|
||||
EMS_Thermostat.hc[hc].setpoint_roomTemp = _toByte(0); // value is * 2
|
||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
||||
|
||||
// check for mode, eg. 10 00 FF 08 01 B9 FF
|
||||
} else if (EMS_RxTelegram->offset == EMS_OFFSET_RCPLUSSet_mode) {
|
||||
EMS_Thermostat.mode = (_toByte(0) == 0xFF); // Auto = xFF, Manual = x00 (auto=1 or manual=0)
|
||||
EMS_Thermostat.hc[hc].mode = (_toByte(0) == 0xFF); // Auto = xFF, Manual = x00 (auto=1 or manual=0)
|
||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
||||
}
|
||||
|
||||
@@ -1491,9 +1513,9 @@ void _process_RCPLUSSetMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
|
||||
// check for long broadcasts
|
||||
if (EMS_RxTelegram->offset == 0) {
|
||||
EMS_Thermostat.mode = _toByte(EMS_OFFSET_RCPLUSSet_mode);
|
||||
EMS_Thermostat.daytemp = _toByte(EMS_OFFSET_RCPLUSSet_temp_comfort2); // is * 2
|
||||
EMS_Thermostat.nighttemp = _toByte(EMS_OFFSET_RCPLUSSet_temp_eco); // is * 2
|
||||
EMS_Thermostat.hc[hc].mode = _toByte(EMS_OFFSET_RCPLUSSet_mode);
|
||||
EMS_Thermostat.hc[hc].daytemp = _toByte(EMS_OFFSET_RCPLUSSet_temp_comfort2); // is * 2
|
||||
EMS_Thermostat.hc[hc].nighttemp = _toByte(EMS_OFFSET_RCPLUSSet_temp_eco); // is * 2
|
||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
||||
}
|
||||
}
|
||||
@@ -1511,7 +1533,10 @@ void _process_RC10Set(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
* received only after requested
|
||||
*/
|
||||
void _process_RC20Set(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
EMS_Thermostat.mode = _toByte(EMS_OFFSET_RC20Set_mode);
|
||||
uint8_t hc = EMS_THERMOSTAT_DEFAULTHC - 1; // use HC1
|
||||
|
||||
EMS_Thermostat.hc[hc].active = true;
|
||||
EMS_Thermostat.hc[hc].mode = _toByte(EMS_OFFSET_RC20Set_mode); // fixed for HC1
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1519,21 +1544,50 @@ void _process_RC20Set(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
* received only after requested
|
||||
*/
|
||||
void _process_RC30Set(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
EMS_Thermostat.mode = _toByte(EMS_OFFSET_RC30Set_mode);
|
||||
uint8_t hc = EMS_THERMOSTAT_DEFAULTHC - 1; // use HC1
|
||||
|
||||
EMS_Thermostat.hc[hc].active = true;
|
||||
EMS_Thermostat.hc[hc].mode = _toByte(EMS_OFFSET_RC30Set_mode); // fixed for HC1
|
||||
}
|
||||
|
||||
// return which heating circuit it is, 1-4
|
||||
uint8_t _getHeatingCircuit(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
uint8_t hc_num;
|
||||
switch (EMS_RxTelegram->type) {
|
||||
case EMS_TYPE_RC35StatusMessage_HC1:
|
||||
case EMS_TYPE_RC35Set_HC1:
|
||||
default:
|
||||
hc_num = 1;
|
||||
break;
|
||||
case EMS_TYPE_RC35StatusMessage_HC2:
|
||||
case EMS_TYPE_RC35Set_HC2:
|
||||
hc_num = 2;
|
||||
break;
|
||||
case EMS_TYPE_RC35StatusMessage_HC3:
|
||||
case EMS_TYPE_RC35Set_HC3:
|
||||
hc_num = 3;
|
||||
break;
|
||||
case EMS_TYPE_RC35StatusMessage_HC4:
|
||||
case EMS_TYPE_RC35Set_HC4:
|
||||
hc_num = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
return (hc_num);
|
||||
}
|
||||
|
||||
/**
|
||||
* type 0x3D and 0x47 - for reading the mode from the RC35 thermostat (0x10)
|
||||
* Working Mode Heating Circuit 1 & 2 (HC1, HC2)
|
||||
* type 0x3D (HC1), 0x47 (HC2), 0x51 (HC3), 0x5B (HC4) - Working Mode Heating - for reading the mode from the RC35 thermostat (0x10)
|
||||
* received only after requested
|
||||
*/
|
||||
void _process_RC35Set(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
EMS_Thermostat.mode = _toByte(EMS_OFFSET_RC35Set_mode);
|
||||
uint8_t hc_num = _getHeatingCircuit(EMS_RxTelegram); // which HC is it?
|
||||
|
||||
EMS_Thermostat.daytemp = _toByte(EMS_OFFSET_RC35Set_temp_day); // is * 2
|
||||
EMS_Thermostat.nighttemp = _toByte(EMS_OFFSET_RC35Set_temp_night); // is * 2
|
||||
EMS_Thermostat.holidaytemp = _toByte(EMS_OFFSET_RC35Set_temp_holiday); // is * 2
|
||||
EMS_Thermostat.heatingtype = _toByte(EMS_OFFSET_RC35Set_heatingtype); // byte 0 bit floor heating = 3 0x47
|
||||
EMS_Thermostat.hc[hc_num].mode = _toByte(EMS_OFFSET_RC35Set_mode);
|
||||
EMS_Thermostat.hc[hc_num].daytemp = _toByte(EMS_OFFSET_RC35Set_temp_day); // is * 2
|
||||
EMS_Thermostat.hc[hc_num].nighttemp = _toByte(EMS_OFFSET_RC35Set_temp_night); // is * 2
|
||||
EMS_Thermostat.hc[hc_num].holidaytemp = _toByte(EMS_OFFSET_RC35Set_temp_holiday); // is * 2
|
||||
EMS_Thermostat.hc[hc_num].heatingtype = _toByte(EMS_OFFSET_RC35Set_heatingtype); // byte 0 bit floor heating = 3
|
||||
|
||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
||||
}
|
||||
@@ -1703,12 +1757,23 @@ void _process_RCTime(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
return; // not supported
|
||||
}
|
||||
|
||||
EMS_Thermostat.hour = _toByte(2);
|
||||
EMS_Thermostat.minute = _toByte(4);
|
||||
EMS_Thermostat.second = _toByte(5);
|
||||
EMS_Thermostat.day = _toByte(3);
|
||||
EMS_Thermostat.month = _toByte(1);
|
||||
EMS_Thermostat.year = _toByte(0);
|
||||
// render time to HH:MM:SS DD/MM/YYYY
|
||||
char time_sp[25];
|
||||
char buffer[4];
|
||||
|
||||
strlcpy(time_sp, _smallitoa(_toByte(2), buffer), sizeof(time_sp)); // hour
|
||||
strlcat(time_sp, ":", sizeof(time_sp));
|
||||
strlcat(time_sp, _smallitoa(_toByte(4), buffer), sizeof(time_sp)); // minute
|
||||
strlcat(time_sp, ":", sizeof(time_sp));
|
||||
strlcat(time_sp, _smallitoa(_toByte(5), buffer), sizeof(time_sp)); // second
|
||||
strlcat(time_sp, " ", sizeof(time_sp));
|
||||
strlcat(time_sp, _smallitoa(_toByte(3), buffer), sizeof(time_sp)); // day
|
||||
strlcat(time_sp, "/", sizeof(time_sp));
|
||||
strlcat(time_sp, _smallitoa(_toByte(1), buffer), sizeof(time_sp)); // month
|
||||
strlcat(time_sp, "/", sizeof(time_sp));
|
||||
strlcat(time_sp, itoa(_toByte(0) + 2000, buffer, 10), sizeof(time_sp)); // year
|
||||
|
||||
strlcpy(EMS_Thermostat.datetime, time_sp, sizeof(time_sp)); // store
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2027,7 +2092,7 @@ void ems_getThermostatValues() {
|
||||
|
||||
uint8_t model_id = EMS_Thermostat.model_id;
|
||||
uint8_t device_id = EMS_Thermostat.device_id;
|
||||
uint8_t hc = EMS_Thermostat.hc;
|
||||
uint8_t statusMsg, opMode;
|
||||
|
||||
switch (model_id) {
|
||||
case EMS_MODEL_RC20:
|
||||
@@ -2043,12 +2108,22 @@ void ems_getThermostatValues() {
|
||||
break;
|
||||
case EMS_MODEL_RC35:
|
||||
case EMS_MODEL_ES73:
|
||||
if (hc == 1) {
|
||||
ems_doReadCommand(EMS_TYPE_RC35StatusMessage_HC1, device_id); // to get the temps
|
||||
ems_doReadCommand(EMS_TYPE_RC35Set_HC1, device_id); // to get the mode
|
||||
} else if (hc == 2) {
|
||||
ems_doReadCommand(EMS_TYPE_RC35StatusMessage_HC2, device_id); // to get the temps
|
||||
ems_doReadCommand(EMS_TYPE_RC35Set_HC2, device_id); // to get the mode
|
||||
for (uint8_t hc_num = 1; hc_num <= EMS_THERMOSTAT_MAXHC; hc_num++) {
|
||||
if (hc_num == 1) {
|
||||
statusMsg = EMS_TYPE_RC35StatusMessage_HC1;
|
||||
opMode = EMS_TYPE_RC35Set_HC1;
|
||||
} else if (hc_num == 2) {
|
||||
statusMsg = EMS_TYPE_RC35StatusMessage_HC2;
|
||||
opMode = EMS_TYPE_RC35Set_HC2;
|
||||
} else if (hc_num == 3) {
|
||||
statusMsg = EMS_TYPE_RC35StatusMessage_HC3;
|
||||
opMode = EMS_TYPE_RC35Set_HC3;
|
||||
} else if (hc_num == 4) {
|
||||
statusMsg = EMS_TYPE_RC35StatusMessage_HC4;
|
||||
opMode = EMS_TYPE_RC35Set_HC4;
|
||||
}
|
||||
ems_doReadCommand(statusMsg, device_id); // to get the temps
|
||||
ems_doReadCommand(opMode, device_id); // to get the mode
|
||||
}
|
||||
break;
|
||||
case EMS_MODEL_RC300:
|
||||
@@ -2482,13 +2557,13 @@ void ems_sendRawTelegram(char * telegram) {
|
||||
* Set the temperature of the thermostat
|
||||
* temptype 0 = normal, 1=night temp, 2=day temp, 3=holiday temp
|
||||
*/
|
||||
void ems_setThermostatTemp(float temperature, uint8_t temptype) {
|
||||
void ems_setThermostatTemp(float temperature, uint8_t hc_num, uint8_t temptype) {
|
||||
if (!ems_getThermostatEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EMS_Thermostat.write_supported) {
|
||||
myDebug_P(PSTR("Write not supported for this Thermostat model"));
|
||||
myDebug_P(PSTR("Write not supported yet for this Thermostat model"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2498,12 +2573,11 @@ void ems_setThermostatTemp(float temperature, uint8_t temptype) {
|
||||
|
||||
uint8_t model_id = EMS_Thermostat.model_id;
|
||||
uint8_t device_id = EMS_Thermostat.device_id;
|
||||
uint8_t hc = EMS_Thermostat.hc; // heating circuit
|
||||
|
||||
EMS_TxTelegram.action = EMS_TX_TELEGRAM_WRITE;
|
||||
EMS_TxTelegram.dest = device_id;
|
||||
|
||||
myDebug_P(PSTR("Setting new thermostat temperature"));
|
||||
myDebug_P(PSTR("Setting new thermostat temperature for heating circuit %d"), hc_num);
|
||||
|
||||
if (model_id == EMS_MODEL_RC20) {
|
||||
EMS_TxTelegram.type = EMS_TYPE_RC20Set;
|
||||
@@ -2526,9 +2600,9 @@ void ems_setThermostatTemp(float temperature, uint8_t temptype) {
|
||||
} else if (model_id == EMS_MODEL_RC300) {
|
||||
EMS_TxTelegram.type = EMS_TYPE_RCPLUSSet; // for 3000 and 1010, e.g. 0B 10 FF (0A | 08) 01 89 2B
|
||||
// check mode
|
||||
if (EMS_Thermostat.mode == 1) { // auto
|
||||
if (EMS_Thermostat.hc[hc_num].mode == 1) { // auto
|
||||
EMS_TxTelegram.offset = 0x08; // auto offset
|
||||
} else if (EMS_Thermostat.mode == 0) { // manuaL
|
||||
} else if (EMS_Thermostat.hc[hc_num].mode == 0) { // manuaL
|
||||
EMS_TxTelegram.offset = 0x0A; // manual offset
|
||||
}
|
||||
// EMS_TxTelegram.type_validate = EMS_TYPE_RCPLUSStatusMessage; // validate by reading from a different telegram
|
||||
@@ -2549,24 +2623,28 @@ void ems_setThermostatTemp(float temperature, uint8_t temptype) {
|
||||
break;
|
||||
default:
|
||||
case 0: // automatic selection, if no type is defined, we use the standard code
|
||||
if (EMS_Thermostat.day_mode == 0) {
|
||||
if (EMS_Thermostat.hc[hc_num].day_mode == 0) {
|
||||
EMS_TxTelegram.offset = EMS_OFFSET_RC35Set_temp_night;
|
||||
} else if (EMS_Thermostat.day_mode == 1) {
|
||||
} else if (EMS_Thermostat.hc[hc_num].day_mode == 1) {
|
||||
EMS_TxTelegram.offset = EMS_OFFSET_RC35Set_temp_day;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (hc == 1) {
|
||||
// heating circuit 1
|
||||
|
||||
if (hc_num == 1) {
|
||||
EMS_TxTelegram.type = EMS_TYPE_RC35Set_HC1;
|
||||
EMS_TxTelegram.comparisonPostRead = EMS_TYPE_RC35StatusMessage_HC1;
|
||||
EMS_TxTelegram.type_validate = EMS_TxTelegram.type;
|
||||
} else {
|
||||
// heating circuit 2
|
||||
} else if (hc_num == 2) {
|
||||
EMS_TxTelegram.type = EMS_TYPE_RC35Set_HC2;
|
||||
EMS_TxTelegram.comparisonPostRead = EMS_TYPE_RC35StatusMessage_HC2;
|
||||
EMS_TxTelegram.type_validate = EMS_TxTelegram.type;
|
||||
} else if (hc_num == 3) {
|
||||
EMS_TxTelegram.type = EMS_TYPE_RC35Set_HC3;
|
||||
EMS_TxTelegram.comparisonPostRead = EMS_TYPE_RC35StatusMessage_HC3;
|
||||
} else if (hc_num == 4) {
|
||||
EMS_TxTelegram.type = EMS_TYPE_RC35Set_HC4;
|
||||
EMS_TxTelegram.comparisonPostRead = EMS_TYPE_RC35StatusMessage_HC4;
|
||||
}
|
||||
EMS_TxTelegram.type_validate = EMS_TxTelegram.type;
|
||||
}
|
||||
|
||||
EMS_TxTelegram.length = EMS_MIN_TELEGRAM_LENGTH;
|
||||
@@ -2583,7 +2661,7 @@ void ems_setThermostatTemp(float temperature, uint8_t temptype) {
|
||||
* (0=low/night, 1=manual/day, 2=auto/clock), 0xA8 on a RC20 and 0xA7 on RC30
|
||||
* 0x01B9 for EMS+ 300/1000/3000, Auto=0xFF Manual=0x00. See https://github.com/proddy/EMS-ESP/wiki/RC3xx-Thermostats
|
||||
*/
|
||||
void ems_setThermostatMode(uint8_t mode) {
|
||||
void ems_setThermostatMode(uint8_t mode, uint8_t hc_num) {
|
||||
if (!ems_getThermostatEnabled()) {
|
||||
return;
|
||||
}
|
||||
@@ -2595,7 +2673,6 @@ void ems_setThermostatMode(uint8_t mode) {
|
||||
|
||||
uint8_t model_id = EMS_Thermostat.model_id;
|
||||
uint8_t device_id = EMS_Thermostat.device_id;
|
||||
uint8_t hc = EMS_Thermostat.hc;
|
||||
|
||||
// RC300/1000/3000 have different settings
|
||||
if (model_id == EMS_MODEL_RC300) {
|
||||
@@ -2606,7 +2683,7 @@ void ems_setThermostatMode(uint8_t mode) {
|
||||
}
|
||||
}
|
||||
|
||||
myDebug_P(PSTR("Setting thermostat mode to %d"), mode);
|
||||
myDebug_P(PSTR("Setting thermostat mode to %d for heating circuit"), mode, hc_num);
|
||||
|
||||
_EMS_TxTelegram EMS_TxTelegram = EMS_TX_TELEGRAM_NEW; // create new Tx
|
||||
EMS_TxTelegram.timestamp = millis(); // set timestamp
|
||||
@@ -2631,14 +2708,21 @@ void ems_setThermostatMode(uint8_t mode) {
|
||||
EMS_TxTelegram.comparisonPostRead = EMS_TYPE_RC30StatusMessage;
|
||||
|
||||
} else if ((model_id == EMS_MODEL_RC35) || (model_id == EMS_MODEL_ES73)) {
|
||||
EMS_TxTelegram.type = (hc == 2) ? EMS_TYPE_RC35Set_HC2 : EMS_TYPE_RC35Set_HC1;
|
||||
if (hc_num == 1) {
|
||||
EMS_TxTelegram.type = EMS_TYPE_RC35Set_HC1;
|
||||
EMS_TxTelegram.comparisonPostRead = EMS_TYPE_RC35StatusMessage_HC1;
|
||||
} else if (hc_num == 2) {
|
||||
EMS_TxTelegram.type = EMS_TYPE_RC35Set_HC2;
|
||||
EMS_TxTelegram.comparisonPostRead = EMS_TYPE_RC35StatusMessage_HC2;
|
||||
} else if (hc_num == 3) {
|
||||
EMS_TxTelegram.type = EMS_TYPE_RC35Set_HC3;
|
||||
EMS_TxTelegram.comparisonPostRead = EMS_TYPE_RC35StatusMessage_HC3;
|
||||
} else if (hc_num == 4) {
|
||||
EMS_TxTelegram.type = EMS_TYPE_RC35Set_HC4;
|
||||
EMS_TxTelegram.comparisonPostRead = EMS_TYPE_RC35StatusMessage_HC4;
|
||||
}
|
||||
EMS_TxTelegram.offset = EMS_OFFSET_RC35Set_mode;
|
||||
EMS_TxTelegram.type_validate = EMS_TxTelegram.type;
|
||||
if (hc == 1) {
|
||||
EMS_TxTelegram.comparisonPostRead = EMS_TYPE_RC35StatusMessage_HC1;
|
||||
} else {
|
||||
EMS_TxTelegram.comparisonPostRead = EMS_TYPE_RC35StatusMessage_HC2;
|
||||
}
|
||||
|
||||
} else if (model_id == EMS_MODEL_RC300) {
|
||||
EMS_TxTelegram.type = EMS_TYPE_RCPLUSSet; // for 3000 and 1010, e.g. 48 10 FF 00 01 B9 00 for manual
|
||||
|
||||
93
src/ems.h
93
src/ems.h
@@ -81,16 +81,14 @@
|
||||
#define EMS_ID_HP 0x38 // HeatPump
|
||||
#define EMS_ID_GATEWAY 0x48 // KM200 Web Gateway
|
||||
|
||||
#define EMS_PRODUCTID_HEATRONICS 95 // ProductID for a Junkers Heatronic3 device
|
||||
|
||||
#define EMS_PRODUCTID_SM10 73 // ProductID for SM10 solar module
|
||||
#define EMS_PRODUCTID_SM100 163 // ProductID for SM10 solar module
|
||||
#define EMS_PRODUCTID_ISM1 101 // ProductID for SM10 solar module
|
||||
// Product IDs
|
||||
#define EMS_PRODUCTID_HEATRONICS 95 // Junkers Heatronic3 device
|
||||
#define EMS_PRODUCTID_SM10 73 // SM10 solar module
|
||||
#define EMS_PRODUCTID_SM100 163 // SM100 solar module
|
||||
#define EMS_PRODUCTID_ISM1 101 // Junkers ISM1 solar module
|
||||
|
||||
#define EMS_MIN_TELEGRAM_LENGTH 6 // minimal length for a validation telegram, including CRC
|
||||
|
||||
// max length of a telegram, including CRC, for Rx and Tx.
|
||||
#define EMS_MAX_TELEGRAM_LENGTH 32
|
||||
#define EMS_MAX_TELEGRAM_LENGTH 32 // max length of a telegram, including CRC, for Rx and Tx.
|
||||
|
||||
// default values for null values
|
||||
#define EMS_VALUE_INT_ON 1 // boolean true
|
||||
@@ -100,6 +98,8 @@
|
||||
#define EMS_VALUE_USHORT_NOTSET 0x8000 // for 2-byte unsigned shorts
|
||||
#define EMS_VALUE_LONG_NOTSET 0xFFFFFF // for 3-byte longs
|
||||
|
||||
#define EMS_THERMOSTAT_MAXHC 4 // max number of heating circuits
|
||||
#define EMS_THERMOSTAT_DEFAULTHC 1 // default heating circuit is 1
|
||||
#define EMS_THERMOSTAT_WRITE_YES true
|
||||
#define EMS_THERMOSTAT_WRITE_NO false
|
||||
|
||||
@@ -273,7 +273,13 @@ typedef struct {
|
||||
/*
|
||||
* Telegram package defintions
|
||||
*/
|
||||
typedef struct { // UBAParameterWW
|
||||
typedef struct {
|
||||
// settings
|
||||
uint8_t device_id; // this is typically always 0x08
|
||||
uint8_t product_id;
|
||||
char version[10];
|
||||
|
||||
// UBAParameterWW
|
||||
uint8_t wWActivated; // Warm Water activated
|
||||
uint8_t wWSelTemp; // Warm Water selected temperature
|
||||
uint8_t wWCircPump; // Warm Water circulation pump Available
|
||||
@@ -324,23 +330,19 @@ typedef struct { // UBAParameterWW
|
||||
uint8_t tapwaterActive; // Hot tap water is on/off
|
||||
uint8_t heatingActive; // Central heating is on/off
|
||||
|
||||
// settings
|
||||
char version[10];
|
||||
uint8_t device_id; // this is typically always 0x08
|
||||
uint8_t product_id;
|
||||
} _EMS_Boiler;
|
||||
|
||||
/*
|
||||
* Telegram package defintions for Other EMS devices
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint8_t HPModulation; // heatpump modulation in %
|
||||
uint8_t HPSpeed; // speed 0-100 %
|
||||
uint8_t device_id; // the device ID of the Heat Pump (e.g. 0x30)
|
||||
uint8_t model_id; // Solar Module / Heat Pump model (e.g. 3 > EMS_MODEL_OTHER )
|
||||
uint8_t model_id; // Solar Module / Heat Pump model
|
||||
uint8_t product_id;
|
||||
char version[10];
|
||||
|
||||
uint8_t HPModulation; // heatpump modulation in %
|
||||
uint8_t HPSpeed; // speed 0-100 %
|
||||
} _EMS_HeatPump;
|
||||
|
||||
typedef struct {
|
||||
@@ -352,6 +354,11 @@ typedef struct {
|
||||
|
||||
// SM Solar Module - SM10/SM100/ISM1
|
||||
typedef struct {
|
||||
uint8_t device_id; // the device ID of the Solar Module
|
||||
uint8_t model_id; // Solar Module
|
||||
uint8_t product_id;
|
||||
char version[10];
|
||||
|
||||
int16_t collectorTemp; // collector temp
|
||||
int16_t bottomTemp; // bottom temp
|
||||
uint8_t pumpModulation; // modulation solar pump
|
||||
@@ -361,35 +368,35 @@ typedef struct {
|
||||
uint16_t EnergyToday;
|
||||
uint16_t EnergyTotal;
|
||||
uint32_t pumpWorkMin; // Total solar pump operating time
|
||||
uint8_t device_id; // the device ID of the Solar Module
|
||||
uint8_t model_id; // Solar Module
|
||||
uint8_t product_id;
|
||||
char version[10];
|
||||
} _EMS_SolarModule;
|
||||
|
||||
// heating circuit
|
||||
typedef struct {
|
||||
uint8_t hc; // heating circuit 1,2, 3 or 4
|
||||
bool active; // true if there is data for this HC
|
||||
int16_t setpoint_roomTemp; // current set temp
|
||||
int16_t curr_roomTemp; // current room temp
|
||||
uint8_t mode; // 0=low, 1=manual, 2=auto
|
||||
bool day_mode; // 0=night, 1=day
|
||||
uint8_t daytemp;
|
||||
uint8_t nighttemp;
|
||||
uint8_t holidaytemp;
|
||||
uint8_t heatingtype; // type of heating: 1 radiator, 2 convectors, 3 floors, 4 room supply
|
||||
uint8_t circuitcalctemp; // calculated setpoint flow temperature
|
||||
} _EMS_Thermostat_HC;
|
||||
|
||||
// Thermostat data
|
||||
typedef struct {
|
||||
uint8_t device_id; // the device ID of the thermostat
|
||||
uint8_t model_id; // thermostat model
|
||||
uint8_t product_id;
|
||||
bool write_supported;
|
||||
uint8_t hc; // heating circuit 1 or 2
|
||||
char version[10];
|
||||
int16_t setpoint_roomTemp; // current set temp
|
||||
int16_t curr_roomTemp; // current room temp
|
||||
uint8_t mode; // 0=low, 1=manual, 2=auto
|
||||
bool day_mode; // 0=night, 1=day
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
uint8_t day;
|
||||
uint8_t month;
|
||||
uint8_t year;
|
||||
uint8_t daytemp;
|
||||
uint8_t nighttemp;
|
||||
uint8_t holidaytemp;
|
||||
uint8_t heatingtype;
|
||||
uint8_t circuitcalctemp;
|
||||
|
||||
char datetime[25]; // HH:MM:SS DD/MM/YYYY
|
||||
bool write_supported;
|
||||
|
||||
_EMS_Thermostat_HC hc[EMS_THERMOSTAT_MAXHC - 1]; // array for the 4 heating circuits
|
||||
|
||||
} _EMS_Thermostat;
|
||||
|
||||
// call back function signature for processing telegram types
|
||||
@@ -419,9 +426,8 @@ void ems_startupTelegrams();
|
||||
bool ems_checkEMSBUSAlive();
|
||||
void ems_clearDeviceList();
|
||||
|
||||
void ems_setThermostatTemp(float temperature, uint8_t temptype = 0);
|
||||
void ems_setThermostatMode(uint8_t mode);
|
||||
void ems_setThermostatHC(uint8_t hc);
|
||||
void ems_setThermostatTemp(float temperature, uint8_t hc, uint8_t temptype = 0);
|
||||
void ems_setThermostatMode(uint8_t mode, uint8_t hc);
|
||||
void ems_setWarmWaterTemp(uint8_t temperature);
|
||||
void ems_setFlowTemp(uint8_t temperature);
|
||||
void ems_setWarmWaterActivated(bool activated);
|
||||
@@ -432,9 +438,10 @@ void ems_setEmsRefreshed(bool b);
|
||||
void ems_setWarmWaterModeComfort(uint8_t comfort);
|
||||
void ems_setModels();
|
||||
void ems_setTxDisabled(bool b);
|
||||
bool ems_getTxDisabled();
|
||||
void ems_setTxMode(uint8_t mode);
|
||||
|
||||
uint8_t _getHeatingCircuit(_EMS_RxTelegram * EMS_RxTelegram);
|
||||
|
||||
char * ems_getThermostatDescription(char * buffer, bool name_only = false);
|
||||
char * ems_getBoilerDescription(char * buffer, bool name_only = false);
|
||||
char * ems_getSolarModuleDescription(char * buffer, bool name_only = false);
|
||||
@@ -456,6 +463,8 @@ uint8_t ems_getSolarModuleModel();
|
||||
void ems_discoverModels();
|
||||
bool ems_getTxCapable();
|
||||
uint32_t ems_getPollFrequency();
|
||||
bool ems_getTxDisabled();
|
||||
|
||||
|
||||
// private functions
|
||||
uint8_t _crcCalculator(uint8_t * data, uint8_t len);
|
||||
|
||||
@@ -91,12 +91,18 @@
|
||||
// RC35 specific
|
||||
#define EMS_TYPE_RC35StatusMessage_HC1 0x3E // is an automatic thermostat broadcast giving us temps on HC1
|
||||
#define EMS_TYPE_RC35StatusMessage_HC2 0x48 // is an automatic thermostat broadcast giving us temps on HC2
|
||||
#define EMS_TYPE_RC35StatusMessage_HC3 0x52 // is an automatic thermostat broadcast giving us temps on HC3
|
||||
#define EMS_TYPE_RC35StatusMessage_HC4 0x5C // is an automatic thermostat broadcast giving us temps on HC4
|
||||
|
||||
#define EMS_OFFSET_RC35StatusMessage_setpoint 2 // desired temp
|
||||
#define EMS_OFFSET_RC35StatusMessage_curr 3 // current temp
|
||||
#define EMS_OFFSET_RC35StatusMessage_mode 1 //day mode
|
||||
|
||||
#define EMS_TYPE_RC35Set_HC1 0x3D // for setting values like temp and mode (Working mode HC1)
|
||||
#define EMS_TYPE_RC35Set_HC2 0x47 // for setting values like temp and mode (Working mode HC2)
|
||||
#define EMS_TYPE_RC35Set_HC3 0x51 // for setting values like temp and mode (Working mode HC3)
|
||||
#define EMS_TYPE_RC35Set_HC4 0x5B // for setting values like temp and mode (Working mode HC4)
|
||||
|
||||
#define EMS_OFFSET_RC35Set_mode 7 // position of thermostat mode
|
||||
#define EMS_OFFSET_RC35Set_temp_day 2 // position of thermostat setpoint temperature for day time
|
||||
#define EMS_OFFSET_RC35Set_temp_night 1 // position of thermostat setpoint temperature for night time
|
||||
|
||||
Reference in New Issue
Block a user