diff --git a/CHANGELOG.md b/CHANGELOG.md index d54df1c76..7a2961d9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - External sensors (like Dallas DS18*) are sent as a nested MQTT topic including their unqiue identifier - `mqttlog` console command renamed to `mqttqueue` to only show the current publish queue - `status` payload on start-up shows the IP and Version of EMS-ESP +- `thermostat mode` takes a string like manual,auto,heat,day,night,eco,comfort,holiday,nofrost ### Removed - `autodetect scan` diff --git a/platformio.ini b/platformio.ini index 7d99ce738..837d143fa 100644 --- a/platformio.ini +++ b/platformio.ini @@ -14,7 +14,7 @@ default_envs = release ; -DFORCE_SERIAL ; -DMYESP_DEBUG ; -DSENSOR_MQTT_USEID -;custom_flags = -DFORCE_SERIAL -DMYESP_DEBUG +;custom_flags = -DFORCE_SERIAL -DMYESP_DEBUG -DEMSESP_SIMULATE custom_flags = # Available lwIP variants (macros): diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index ebe108b09..0f8355f2b 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -113,8 +113,8 @@ static const command_t project_cmds[] PROGMEM = { {false, "queue", "show current Tx queue"}, {false, "send XX ...", "send raw telegram data to EMS bus (XX are hex values)"}, {false, "thermostat read ", "send read request to the thermostat for heating circuit hc 1-4"}, - {false, "thermostat temp [mode] [hc]", "set current thermostat temperature. mode=0-6 (see wiki), hc=1-4"}, - {false, "thermostat mode ", "set mode (0=off, 1=manual, 2=auto) for heating circuit hc 1-4"}, + {false, "thermostat temp [mode] [hc]", "set current thermostat temperature. mode=0-6 (see wiki) for hc=1-4"}, + {false, "thermostat mode [hc]", "set mode (manual,auto,heat,day,night,eco,comfort,holiday,nofrost)"}, {false, "boiler read ", "send read request to boiler"}, {false, "boiler wwtemp ", "set boiler warm water temperature"}, {false, "boiler wwactive ", "set boiler warm water on/off"}, @@ -1618,14 +1618,15 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) { ok = true; } else { // get modevalue and heatingcircuit - _THERMOSTAT_TEMP_MODE temp_mode = (_THERMOSTAT_TEMP_MODE)_readIntNumber(); // next parameter is the temp mode type - uint8_t hc = _readIntNumber(); // next parameter is the heating circuit + _EMS_THERMOSTAT_MODE temp_mode = (_EMS_THERMOSTAT_MODE)_readIntNumber(); // next parameter is the temp mode type + uint8_t hc = _readIntNumber(); // next parameter is the heating circuit ems_setThermostatTemp(temp, hc, temp_mode); ok = true; } } else if (strcmp(second_cmd, "mode") == 0) { - uint8_t hc = _readIntNumber(); // next parameter is the heating circuit - ems_setThermostatMode(_readIntNumber(), hc); + char * mode_s = _readWord(); + uint8_t hc = (wc == 3) ? EMS_THERMOSTAT_DEFAULTHC : _readIntNumber(); + ems_setThermostatMode(mode_s, hc); ok = true; } else if (strcmp(second_cmd, "read") == 0) { ems_doReadCommand(_readHexNumber(), EMS_Thermostat.device_id); @@ -1951,13 +1952,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_MODE_HA, topic); if (hc) { if (EMS_Thermostat.hc[hc - 1].active) { - if (strncmp(message, "auto", 4) == 0) { - ems_setThermostatMode(2, hc); - } else if ((strncmp(message, "day", 4) == 0) || (strncmp(message, "manual", 6) == 0) || (strncmp(message, "heat", 4) == 0)) { - ems_setThermostatMode(1, hc); - } else if ((strncmp(message, "night", 5) == 0) || (strncmp(message, "off", 3) == 0)) { - ems_setThermostatMode(0, hc); - } + ems_setThermostatMode(message, hc); return; } } @@ -1997,13 +1992,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { if (data_cmd == nullptr) { return; } - if (strncmp(data_cmd, "auto", 4) == 0) { - ems_setThermostatMode(2, hc); - } else if ((strncmp(data_cmd, "day", 4) == 0) || (strncmp(data_cmd, "manual", 6) == 0) || (strncmp(data_cmd, "heat", 4) == 0)) { - ems_setThermostatMode(1, hc); - } else if ((strncmp(data_cmd, "night", 5) == 0) || (strncmp(data_cmd, "off", 3) == 0)) { - ems_setThermostatMode(0, hc); - } + ems_setThermostatMode(data_cmd, hc); return; } } @@ -2014,7 +2003,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { if (EMS_Thermostat.hc[hc - 1].active) { float f = doc["data"]; if (f) { - ems_setThermostatTemp(f, hc, THERMOSTAT_TEMP_MODE_NIGHT); // night + ems_setThermostatTemp(f, hc, EMS_THERMOSTAT_MODE_NIGHT); // night return; } } @@ -2026,7 +2015,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { if (EMS_Thermostat.hc[hc - 1].active) { float f = doc["data"]; if (f) { - ems_setThermostatTemp(f, hc, THERMOSTAT_TEMP_MODE_DAY); // day + ems_setThermostatTemp(f, hc, EMS_THERMOSTAT_MODE_DAY); // day } return; } @@ -2038,7 +2027,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { if (EMS_Thermostat.hc[hc - 1].active) { float f = doc["data"]; if (f) { - ems_setThermostatTemp(f, hc, THERMOSTAT_TEMP_MODE_HOLIDAY); // holiday + ems_setThermostatTemp(f, hc, EMS_THERMOSTAT_MODE_HOLIDAY); // holiday } return; } @@ -2050,7 +2039,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { if (EMS_Thermostat.hc[hc - 1].active) { float f = doc["data"]; if (f) { - ems_setThermostatTemp(f, hc, THERMOSTAT_TEMP_MODE_ECO); // holiday + ems_setThermostatTemp(f, hc, EMS_THERMOSTAT_MODE_ECO); // holiday } return; } @@ -2062,7 +2051,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { if (EMS_Thermostat.hc[hc - 1].active) { float f = doc["data"]; if (f) { - ems_setThermostatTemp(f, hc, THERMOSTAT_TEMP_MODE_HEAT); // holiday + ems_setThermostatTemp(f, hc, EMS_THERMOSTAT_MODE_HEAT); // holiday } return; } @@ -2074,7 +2063,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { if (EMS_Thermostat.hc[hc - 1].active) { float f = doc["data"]; if (f) { - ems_setThermostatTemp(f, hc, THERMOSTAT_TEMP_MODE_NOFROST); // holiday + ems_setThermostatTemp(f, hc, EMS_THERMOSTAT_MODE_NOFROST); // holiday } return; } diff --git a/src/ems.cpp b/src/ems.cpp index 412b23e14..769ce4ca6 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -2339,7 +2339,7 @@ void ems_sendRawTelegram(char * telegram) { * hc_num is 1 to 4 * temptype 0=normal, 1=night temp, 2=day temp, 3=holiday temp */ -void ems_setThermostatTemp(float temperature, uint8_t hc_num, _THERMOSTAT_TEMP_MODE temptype) { +void ems_setThermostatTemp(float temperature, uint8_t hc_num, _EMS_THERMOSTAT_MODE temptype) { if (!ems_getThermostatEnabled()) { myDebug_P(PSTR("Thermostat not online.")); return; @@ -2425,17 +2425,17 @@ void ems_setThermostatTemp(float temperature, uint8_t hc_num, _THERMOSTAT_TEMP_M else if ((model == EMS_DEVICE_FLAG_RC35) || (model == EMS_DEVICE_FLAG_RC30N)) { switch (temptype) { - case THERMOSTAT_TEMP_MODE_NIGHT: // change the night temp + case EMS_THERMOSTAT_MODE_NIGHT: // change the night temp EMS_TxTelegram.offset = EMS_OFFSET_RC35Set_temp_night; break; - case THERMOSTAT_TEMP_MODE_DAY: // change the day temp + case EMS_THERMOSTAT_MODE_DAY: // change the day temp EMS_TxTelegram.offset = EMS_OFFSET_RC35Set_temp_day; break; - case THERMOSTAT_TEMP_MODE_HOLIDAY: // change the holiday temp + case EMS_THERMOSTAT_MODE_HOLIDAY: // change the holiday temp EMS_TxTelegram.offset = EMS_OFFSET_RC35Set_temp_holiday; break; default: - case THERMOSTAT_TEMP_MODE_AUTO: // automatic selection, if no type is defined, we use the standard code + case EMS_THERMOSTAT_MODE_AUTO: // automatic selection, if no type is defined, we use the standard code if (model == EMS_DEVICE_FLAG_RC35) { EMS_TxTelegram.offset = EMS_OFFSET_RC35Set_seltemp; // https://github.com/proddy/EMS-ESP/issues/310 } else { @@ -2468,17 +2468,17 @@ void ems_setThermostatTemp(float temperature, uint8_t hc_num, _THERMOSTAT_TEMP_M // see https://github.com/proddy/EMS-ESP/issues/335#issuecomment-593324716) if (model == EMS_DEVICE_FLAG_JUNKERS1) { switch (temptype) { - case THERMOSTAT_TEMP_MODE_NOFROST: + case EMS_THERMOSTAT_MODE_NOFROST: EMS_TxTelegram.offset = EMS_OFFSET_JunkersSetMessage_no_frost_temp; break; - case THERMOSTAT_TEMP_MODE_NIGHT: + case EMS_THERMOSTAT_MODE_NIGHT: EMS_TxTelegram.offset = EMS_OFFSET_JunkersSetMessage_night_temp; break; - case THERMOSTAT_TEMP_MODE_DAY: + case EMS_THERMOSTAT_MODE_DAY: EMS_TxTelegram.offset = EMS_OFFSET_JunkersSetMessage_day_temp; break; default: - case THERMOSTAT_TEMP_MODE_AUTO: // automatic selection, if no type is defined, we use the standard code + case EMS_THERMOSTAT_MODE_AUTO: // automatic selection, if no type is defined, we use the standard code EMS_TxTelegram.offset = (EMS_Thermostat.hc[hc_num - 1].mode_type == 0) ? EMS_OFFSET_JunkersSetMessage_night_temp : EMS_OFFSET_JunkersSetMessage_day_temp; break; @@ -2488,14 +2488,14 @@ void ems_setThermostatTemp(float temperature, uint8_t hc_num, _THERMOSTAT_TEMP_M } else { // EMS_DEVICE_FLAG_JUNKERS2 switch (temptype) { - case THERMOSTAT_TEMP_MODE_NOFROST: + case EMS_THERMOSTAT_MODE_NOFROST: EMS_TxTelegram.offset = EMS_OFFSET_JunkersSetMessage2_no_frost_temp; break; - case THERMOSTAT_TEMP_MODE_ECO: + case EMS_THERMOSTAT_MODE_ECO: EMS_TxTelegram.offset = EMS_OFFSET_JunkersSetMessage2_eco_temp; break; default: - case THERMOSTAT_TEMP_MODE_HEAT: + case EMS_THERMOSTAT_MODE_HEAT: EMS_TxTelegram.offset = EMS_OFFSET_JunkersSetMessage3_heat; break; } @@ -2515,13 +2515,38 @@ void ems_setThermostatTemp(float temperature, uint8_t hc_num, _THERMOSTAT_TEMP_M EMS_TxQueue.push(EMS_TxTelegram); } +// wrapper for setting thermostat mode, taking a string as an argument +void ems_setThermostatMode(const char * mode_s, uint8_t hc_num) { + if (strncmp(mode_s, "auto", 4) == 0) { + ems_setThermostatMode(EMS_THERMOSTAT_MODE_AUTO, hc_num); + } else if (strncmp(mode_s, "day", 3) == 0) { + ems_setThermostatMode(EMS_THERMOSTAT_MODE_DAY, hc_num); + } else if (strncmp(mode_s, "manual", 6) == 0) { + ems_setThermostatMode(EMS_THERMOSTAT_MODE_MANUAL, hc_num); + } else if (strncmp(mode_s, "heat", 4) == 0) { + ems_setThermostatMode(EMS_THERMOSTAT_MODE_HEAT, hc_num); + } else if (strncmp(mode_s, "night", 5) == 0) { + ems_setThermostatMode(EMS_THERMOSTAT_MODE_NIGHT, hc_num); + } else if (strncmp(mode_s, "off", 3) == 0) { + ems_setThermostatMode(EMS_THERMOSTAT_MODE_OFF, hc_num); + } else if (strncmp(mode_s, "comfort", 7) == 0) { + ems_setThermostatMode(EMS_THERMOSTAT_MODE_COMFORT, hc_num); + } else if (strncmp(mode_s, "holiday", 7) == 0) { + ems_setThermostatMode(EMS_THERMOSTAT_MODE_HOLIDAY, hc_num); + } else if (strncmp(mode_s, "nofrost", 7) == 0) { + ems_setThermostatMode(EMS_THERMOSTAT_MODE_NOFROST, hc_num); + } else if (strncmp(mode_s, "eco", 3) == 0) { + ems_setThermostatMode(EMS_THERMOSTAT_MODE_ECO, hc_num); + } +} + /** * Set the thermostat working mode * 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 * hc_num is 1 to 4 */ -void ems_setThermostatMode(uint8_t mode, uint8_t hc_num) { +void ems_setThermostatMode(_EMS_THERMOSTAT_MODE mode, uint8_t hc_num) { if (!ems_getThermostatEnabled()) { myDebug_P(PSTR("Thermostat not online.")); return; @@ -2537,28 +2562,85 @@ void ems_setThermostatMode(uint8_t mode, uint8_t hc_num) { return; } - uint8_t model = ems_getThermostatFlags(); - uint8_t device_id = EMS_Thermostat.device_id; - uint8_t set_mode; - - // RC300/1000/3000 have different settings - if ((model == EMS_DEVICE_FLAG_RC300) || (model == EMS_DEVICE_FLAG_RC100)) { - if (mode == 1) { - set_mode = 0; // manual + // set the value to send via EMS depending on the mode type + uint8_t set_mode_value = 0x02; // default is 2 which is usually auto + char mode_str[20]; + switch (mode) { + case EMS_THERMOSTAT_MODE_AUTO: + strlcpy(mode_str, "auto", sizeof(mode_str)); + set_mode_value = 2; + break; + case EMS_THERMOSTAT_MODE_NIGHT: + strlcpy(mode_str, "night", sizeof(mode_str)); + set_mode_value = 0; + break; + case EMS_THERMOSTAT_MODE_DAY: + strlcpy(mode_str, "day", sizeof(mode_str)); + set_mode_value = 1; + break; + case EMS_THERMOSTAT_MODE_HOLIDAY: + strlcpy(mode_str, "holiday", sizeof(mode_str)); + set_mode_value = 2; // auto + break; + case EMS_THERMOSTAT_MODE_NOFROST: + strlcpy(mode_str, "nofrost", sizeof(mode_str)); + set_mode_value = 1; + break; + case EMS_THERMOSTAT_MODE_ECO: + strlcpy(mode_str, "eco", sizeof(mode_str)); + set_mode_value = 2; // same as auto + break; + case EMS_THERMOSTAT_MODE_HEAT: + strlcpy(mode_str, "heat", sizeof(mode_str)); + set_mode_value = 1; + break; + case EMS_THERMOSTAT_MODE_OFF: + strlcpy(mode_str, "off", sizeof(mode_str)); + set_mode_value = 0; + break; + case EMS_THERMOSTAT_MODE_MANUAL: + strlcpy(mode_str, "manual", sizeof(mode_str)); + set_mode_value = 1; + break; + case EMS_THERMOSTAT_MODE_UNKNOWN: + default: + strlcpy(mode_str, "unknown", sizeof(mode_str)); + set_mode_value = 2; // auto + break; + } + + // now override the mode value setting depending on the thermostat type + // handle the different mode values to send per thermostat type + uint8_t model = ems_getThermostatFlags(); + switch (model) { + case EMS_DEVICE_FLAG_RC300: + case EMS_DEVICE_FLAG_RC100: + if (mode == EMS_THERMOSTAT_MODE_AUTO) { + set_mode_value = 0xFF; // special value for auto } else { - set_mode = 0xFF; // auto + set_mode_value = 0; // everything else, like manual/day etc.. } - } else { - set_mode = mode; + break; + case EMS_DEVICE_FLAG_JUNKERS1: + case EMS_DEVICE_FLAG_JUNKERS2: + if (mode == EMS_THERMOSTAT_MODE_NOFROST) { + set_mode_value = 0x01; + } else if (mode == EMS_THERMOSTAT_MODE_ECO) { + set_mode_value = 0x02; + } else if ((mode == EMS_THERMOSTAT_MODE_DAY) || (mode == EMS_THERMOSTAT_MODE_HEAT)) { + set_mode_value = 0x03; // comfort + } else if (mode == EMS_THERMOSTAT_MODE_AUTO) { + set_mode_value = 0x04; + } + break; + default: + break; } - // 0=off, 1=manual, 2=auto - if (mode == 0) { - myDebug_P(PSTR("Setting thermostat mode to off for heating circuit %d"), hc_num); - } else if (set_mode == 1) { - myDebug_P(PSTR("Setting thermostat mode to manual for heating circuit %d"), hc_num); - } else if (set_mode == 2) { - myDebug_P(PSTR("Setting thermostat mode to auto for heating circuit %d"), hc_num); + if (hc_num == 1) { + myDebug_P(PSTR("Setting thermostat mode to %s"), mode_str); + } else { + myDebug_P(PSTR("Setting thermostat mode to %s for heating circuit %d"), mode_str, hc_num); } _EMS_TxTelegram EMS_TxTelegram = EMS_TX_TELEGRAM_NEW; // create new Tx @@ -2566,9 +2648,9 @@ void ems_setThermostatMode(uint8_t mode, uint8_t hc_num) { EMS_Sys_Status.txRetryCount = 0; // reset retry counter EMS_TxTelegram.action = EMS_TX_TELEGRAM_WRITE; - EMS_TxTelegram.dest = device_id; + EMS_TxTelegram.dest = EMS_Thermostat.device_id; EMS_TxTelegram.length = EMS_MIN_TELEGRAM_LENGTH; - EMS_TxTelegram.dataValue = set_mode; + EMS_TxTelegram.dataValue = set_mode_value; // handle different thermostat types if (model == EMS_DEVICE_FLAG_RC20) { @@ -2602,11 +2684,13 @@ void ems_setThermostatMode(uint8_t mode, uint8_t hc_num) { // Junkers } else if (model == EMS_DEVICE_FLAG_JUNKERS1) { + EMS_TxTelegram.emsplus = true; // Assuming here that all Junkers use EMS+ EMS_TxTelegram.type = EMS_TYPE_JunkersSetMessage1_HC1 + hc_num - 1; EMS_TxTelegram.comparisonPostRead = EMS_TYPE_JunkersStatusMessage_HC1; EMS_TxTelegram.offset = EMS_OFFSET_JunkersSetMessage_set_mode; EMS_TxTelegram.type_validate = EMS_TxTelegram.type; } else if (model == EMS_DEVICE_FLAG_JUNKERS2) { + EMS_TxTelegram.emsplus = true; // Assuming here that all Junkers use EMS+ EMS_TxTelegram.type = EMS_TYPE_JunkersSetMessage2_HC1 + hc_num - 1; EMS_TxTelegram.comparisonPostRead = EMS_TYPE_JunkersStatusMessage_HC1; EMS_TxTelegram.offset = EMS_OFFSET_JunkersSetMessage_set_mode; diff --git a/src/ems.h b/src/ems.h index 18844b1ce..0425282c5 100644 --- a/src/ems.h +++ b/src/ems.h @@ -71,7 +71,7 @@ enum EMS_DEVICE_FLAG_TYPES : uint8_t { #define EMS_BOILER_BURNPOWER_TAPWATER 100 #define EMS_BOILER_SELFLOWTEMP_HEATING 30 // was 70, changed to 30 for https://github.com/proddy/EMS-ESP/issues/193 -// define min & maximum setable tapwater temperature +// define min & maximum setable tapwater temperatures #define EMS_BOILER_TAPWATER_TEMPERATURE_MAX 60 #define EMS_BOILER_TAPWATER_TEMPERATURE_MIN 30 @@ -443,24 +443,17 @@ typedef struct { } _EMS_Type; typedef enum : uint8_t { - THERMOSTAT_TEMP_MODE_AUTO = 0, - THERMOSTAT_TEMP_MODE_NIGHT, - THERMOSTAT_TEMP_MODE_DAY, - THERMOSTAT_TEMP_MODE_HOLIDAY, - THERMOSTAT_TEMP_MODE_NOFROST, - THERMOSTAT_TEMP_MODE_ECO, // 'sparen' - THERMOSTAT_TEMP_MODE_HEAT // 'heizen' -} _THERMOSTAT_TEMP_MODE; - -typedef enum { - EMS_THERMOSTAT_MODE_UNKNOWN, + EMS_THERMOSTAT_MODE_UNKNOWN = 0, EMS_THERMOSTAT_MODE_OFF, EMS_THERMOSTAT_MODE_MANUAL, EMS_THERMOSTAT_MODE_AUTO, + EMS_THERMOSTAT_MODE_HEAT, // 'heizen' EMS_THERMOSTAT_MODE_NIGHT, EMS_THERMOSTAT_MODE_DAY, - EMS_THERMOSTAT_MODE_ECO, - EMS_THERMOSTAT_MODE_COMFORT + EMS_THERMOSTAT_MODE_ECO, // 'sparen' + EMS_THERMOSTAT_MODE_COMFORT, + EMS_THERMOSTAT_MODE_HOLIDAY, + EMS_THERMOSTAT_MODE_NOFROST } _EMS_THERMOSTAT_MODE; // function definitions @@ -475,8 +468,9 @@ void ems_printTxQueue(); void ems_testTelegram(uint8_t test_num); void ems_startupTelegrams(); bool ems_checkEMSBUSAlive(); -void ems_setThermostatTemp(float temperature, uint8_t hc, _THERMOSTAT_TEMP_MODE temptype = THERMOSTAT_TEMP_MODE_AUTO); -void ems_setThermostatMode(uint8_t mode, uint8_t hc); +void ems_setThermostatTemp(float temperature, uint8_t hc, _EMS_THERMOSTAT_MODE temptype = EMS_THERMOSTAT_MODE_AUTO); +void ems_setThermostatMode(_EMS_THERMOSTAT_MODE mode, uint8_t hc); +void ems_setThermostatMode(const char * mode_s, uint8_t hc); void ems_setWarmWaterTemp(uint8_t temperature); void ems_setFlowTemp(uint8_t temperature); void ems_setWarmWaterActivated(bool activated); diff --git a/src/version.h b/src/version.h index bdc83bbf2..f493957a8 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define APP_VERSION "1.9.5b51" +#define APP_VERSION "1.9.5b52"