diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index f1a624557..634070e98 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -103,8 +103,8 @@ static const command_t project_cmds[] PROGMEM = { {true, "master_thermostat [product id]", "set default thermostat to use. Omit [product id] to show options."}, {false, "info", "show current values deciphered from the EMS messages"}, - {false, "log ", "logging: none, basic, thermo, solar, raw, jabber, verbose, watch a type or device"}, + #ifdef TESTS {false, "test ", "insert a test telegram on to the EMS bus"}, #endif @@ -120,6 +120,7 @@ static const command_t project_cmds[] PROGMEM = { {false, "thermostat mode [hc] ", "set mode (0=off, 1=manual, 2=auto) for heating circuit hc 1-4"}, {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"}, {false, "boiler tapwater ", "set boiler warm tap water on/off"}, {false, "boiler flowtemp ", "set boiler flow temperature"}, {false, "boiler comfort ", "set boiler warm water comfort setting"} @@ -232,6 +233,8 @@ void showInfo() { myDebug_P(PSTR(" System logging set to Jabber")); } else if (sysLog == EMS_SYS_LOGGING_WATCH) { myDebug_P(PSTR(" System logging set to Watch")); + } else if (sysLog == EMS_SYS_LOGGING_DEVICE) { + myDebug_P(PSTR(" System logging set to device")); } else { myDebug_P(PSTR(" System logging set to None")); } @@ -481,7 +484,7 @@ void showInfo() { myDebug_P(PSTR("%sMixing module stats:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF); myDebug_P(PSTR(" Mixing: %s"), ems_getDeviceDescription(EMS_DEVICE_TYPE_MIXING, buffer_type,false)); if (EMS_Boiler.switchTemp < EMS_VALUE_USHORT_NOTSET) - _renderShortValue("Switch temperature", "C", EMS_Boiler.switchTemp); + _renderUShortValue("Switch temperature", "C", EMS_Boiler.switchTemp); for (uint8_t hc_num = 1; hc_num <= EMS_THERMOSTAT_MAXHC; hc_num++) { if (EMS_Mixing.hc[hc_num - 1].active) { @@ -496,6 +499,17 @@ void showInfo() { _renderIntValue(" Current valve status", "", EMS_Mixing.hc[hc_num - 1].valveStatus); } } + for (uint8_t wwc_num = 1; wwc_num <= EMS_THERMOSTAT_MAXWWC; wwc_num++) { + if (EMS_Mixing.wwc[wwc_num - 1].active) { + myDebug_P(PSTR(" Warm Water Buffer %d"), wwc_num); + if (EMS_Mixing.wwc[wwc_num - 1].flowTemp < EMS_VALUE_USHORT_NOTSET) + _renderUShortValue(" Current warm water temperature", "C", EMS_Mixing.wwc[wwc_num - 1].flowTemp); + if (EMS_Mixing.wwc[wwc_num - 1].pumpMod != EMS_VALUE_INT_NOTSET) + _renderIntValue(" Current pump status", "", EMS_Mixing.wwc[wwc_num - 1].pumpMod); + if (EMS_Mixing.wwc[wwc_num - 1].tempStatus != EMS_VALUE_INT_NOTSET) + _renderIntValue(" Current temp status", "", EMS_Mixing.wwc[wwc_num - 1].tempStatus); + } + } } // Dallas external temp sensors @@ -777,7 +791,6 @@ void publishEMSValues(bool force) { strlcpy(hc, THERMOSTAT_HC, sizeof(hc)); strlcat(hc, _int_to_char(s, mixing->hc), sizeof(hc)); JsonObject dataMixing = rootMixing.createNestedObject(hc); - if (mixing->flowTemp < EMS_VALUE_USHORT_NOTSET) dataMixing["flowTemp"] = (float)mixing->flowTemp / 10; if (mixing->flowSetTemp != EMS_VALUE_INT_NOTSET) @@ -788,6 +801,23 @@ void publishEMSValues(bool force) { dataMixing["valveStatus"] = mixing->valveStatus; } } + for (uint8_t wwc_v = 1; wwc_v <= EMS_THERMOSTAT_MAXWWC; wwc_v++) { + _EMS_Mixing_WWC * mixing = &EMS_Mixing.wwc[wwc_v - 1]; + // only send if we have an active Warm water Circuit with real data + if (mixing->active) { + // build new json object + char wwc[10]; // wc{1-2} + strlcpy(wwc, "wwc", sizeof(wwc)); + strlcat(wwc, _int_to_char(s, mixing->wwc), sizeof(wwc)); + JsonObject dataMixing = rootMixing.createNestedObject(wwc); + if (mixing->flowTemp < EMS_VALUE_USHORT_NOTSET) + dataMixing["wwTemp"] = (float)mixing->flowTemp / 10; + if (mixing->pumpMod != EMS_VALUE_INT_NOTSET) + dataMixing["pumpStatus"] = mixing->pumpMod; + if (mixing->tempStatus != EMS_VALUE_INT_NOTSET) + dataMixing["tempStatus"] = mixing->tempStatus; + } + } data[0] = '\0'; // reset data for next package serializeJson(doc, data, sizeof(data)); @@ -1276,6 +1306,9 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) { } else if ((strcmp(second_cmd, "w") == 0) && (wc == 3)) { ems_setLogging(EMS_SYS_LOGGING_WATCH, _readHexNumber()); // get type_id ok = true; + } else if ((strcmp(second_cmd, "d") == 0) && (wc == 3)) { + ems_setLogging(EMS_SYS_LOGGING_DEVICE, _readHexNumber()); // get device_id + ok = true; } } @@ -1335,6 +1368,15 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) { } else if (strcmp(second_cmd, "flowtemp") == 0) { ems_setFlowTemp(_readIntNumber()); ok = true; + } else if (strcmp(second_cmd, "wwactive") == 0) { + char * third_cmd = _readWord(); + if (strcmp(third_cmd, "on") == 0) { + ems_setWarmWaterActivated(true); + ok = true; + } else if (strcmp(third_cmd, "off") == 0) { + ems_setWarmWaterActivated(false); + ok = true; + } } } @@ -1403,13 +1445,16 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { char topic_s[50]; char buffer[4]; for (uint8_t hc = 1; hc <= EMS_THERMOSTAT_MAXHC; hc++) { - strlcpy(topic_s, TOPIC_THERMOSTAT_CMD_TEMP_HA, sizeof(topic_s)); - strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s)); - myESP.mqttSubscribe(topic_s); + // subscribe onlyto active hc + if(EMS_Thermostat.hc[hc - 1].active) { + strlcpy(topic_s, TOPIC_THERMOSTAT_CMD_TEMP_HA, sizeof(topic_s)); + strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s)); + myESP.mqttSubscribe(topic_s); - strlcpy(topic_s, TOPIC_THERMOSTAT_CMD_MODE_HA, sizeof(topic_s)); - strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s)); - myESP.mqttSubscribe(topic_s); + strlcpy(topic_s, TOPIC_THERMOSTAT_CMD_MODE_HA, sizeof(topic_s)); + strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s)); + myESP.mqttSubscribe(topic_s); + } } // generic incoming MQTT command for Thermostat @@ -1574,7 +1619,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { uint8_t hc; // thermostat temp changes hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_TEMP_HA, topic); - if (hc) { + if (hc && EMS_Thermostat.hc[hc - 1].active) { float f = strtof((char *)message, 0); ems_setThermostatTemp(f, hc); publishEMSValues(true); // publish back immediately @@ -1583,7 +1628,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { // thermostat mode changes hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_MODE_HA, topic); - if (hc) { + if (hc && 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)) { @@ -1607,7 +1652,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { // thermostat temp changes hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_TEMP, command); - if (hc) { + if (hc && EMS_Thermostat.hc[hc - 1].active) { float f = doc["data"]; ems_setThermostatTemp(f, hc); publishEMSValues(true); // publish back immediately @@ -1616,7 +1661,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { // thermostat mode changes hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_MODE, command); - if (hc) { + if (hc && EMS_Thermostat.hc[hc - 1].active) { const char * data_cmd = doc["data"]; if (strncmp(data_cmd, "auto", 4) == 0) { ems_setThermostatMode(2, hc); @@ -1630,7 +1675,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { // set night temp value hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_NIGHTTEMP, command); - if (hc) { + if (hc && EMS_Thermostat.hc[hc - 1].active) { float f = doc["data"]; ems_setThermostatTemp(f, hc, 1); // night return; @@ -1638,7 +1683,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { // set daytemp value hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_DAYTEMP, command); - if (hc) { + if (hc && EMS_Thermostat.hc[hc - 1].active) { float f = doc["data"]; ems_setThermostatTemp(f, hc, 2); // day return; @@ -1646,7 +1691,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { // set holiday value hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_HOLIDAYTEMP, command); - if (hc) { + if (hc && EMS_Thermostat.hc[hc - 1].active) { float f = doc["data"]; ems_setThermostatTemp(f, hc, 3); // holiday return; @@ -1727,7 +1772,7 @@ void WebCallback(JsonObject root) { uint8_t hc_num = 1; // default to HC1 uint8_t model = ems_getThermostatModel(); - while (hc_num <= EMS_THERMOSTAT_MAXHC && !EMS_Thermostat.hc[hc_num - 1].active) hc_num++; + while (hc_num < EMS_THERMOSTAT_MAXHC && !EMS_Thermostat.hc[hc_num - 1].active) hc_num++; // first active hc // Render Current & Setpoint Room Temperature if (model == EMS_DEVICE_FLAG_EASY) { if (EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp > EMS_VALUE_SHORT_NOTSET) diff --git a/src/ems.cpp b/src/ems.cpp index 03f65ad2c..c4a40b791 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -128,6 +128,12 @@ void ems_init() { EMS_Mixing.hc[i].valveStatus = EMS_VALUE_INT_NOTSET; EMS_Mixing.hc[i].flowSetTemp = EMS_VALUE_INT_NOTSET; } + for (uint8_t i = 0; i < EMS_THERMOSTAT_MAXWWC; i++) { + EMS_Mixing.wwc[i].wwc = i + 1; + EMS_Mixing.wwc[i].flowTemp = EMS_VALUE_USHORT_NOTSET; + EMS_Mixing.wwc[i].pumpMod = EMS_VALUE_INT_NOTSET; + EMS_Mixing.wwc[i].tempStatus = EMS_VALUE_INT_NOTSET; + } // UBAParameterWW EMS_Boiler.wWActivated = EMS_VALUE_BOOL_NOTSET; // Warm Water activated @@ -281,9 +287,9 @@ _EMS_SYS_LOGGING ems_getLogging() { return EMS_Sys_Status.emsLogging; } -void ems_setLogging(_EMS_SYS_LOGGING loglevel, uint16_t type_id) { - EMS_Sys_Status.emsLogging_typeID = type_id; - ems_setLogging(EMS_SYS_LOGGING_WATCH, false); +void ems_setLogging(_EMS_SYS_LOGGING loglevel, uint16_t id) { + EMS_Sys_Status.emsLogging_ID = id; + ems_setLogging(loglevel, false); } void ems_setLogging(_EMS_SYS_LOGGING loglevel, bool quiet) { @@ -309,6 +315,8 @@ void ems_setLogging(_EMS_SYS_LOGGING loglevel, bool quiet) { myDebug_P(PSTR("System Logging set to Jabber mode")); } else if (loglevel == EMS_SYS_LOGGING_WATCH) { myDebug_P(PSTR("System Logging set to Watch mode")); + } else if (loglevel == EMS_SYS_LOGGING_DEVICE) { + myDebug_P(PSTR("System Logging set to Device mode")); } } @@ -850,8 +858,11 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) { // but still continue to process it if ((EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_RAW)) { _debugPrintTelegram("", &EMS_RxTelegram, COLOR_WHITE, true); - } else if ((EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_WATCH) && (EMS_RxTelegram.type == EMS_Sys_Status.emsLogging_typeID)) { + } else if ((EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_WATCH) && (EMS_RxTelegram.type == EMS_Sys_Status.emsLogging_ID)) { _debugPrintTelegram("", &EMS_RxTelegram, COLOR_WHITE, true); + // raw printout for log d [id] disabled, moved to _printMessage() +// } else if ((EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_DEVICE) && ((EMS_RxTelegram.src == EMS_Sys_Status.emsLogging_ID) || (EMS_RxTelegram.dest == EMS_Sys_Status.emsLogging_ID))) { +// _debugPrintTelegram("", &EMS_RxTelegram, COLOR_WHITE, true); } // Assume at this point we have something that vaguely resembles a telegram in the format [src] [dest] [type] [offset] [data] [crc] @@ -929,6 +940,11 @@ void _printMessage(_EMS_RxTelegram * EMS_RxTelegram) { if ((src == EMS_SolarModule.device_id) || (dest == EMS_SolarModule.device_id)) { _debugPrintTelegram(output_str, EMS_RxTelegram, color_s); } + } else if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_DEVICE) { + // only print ones to/from DeviceID + if ((src == EMS_Sys_Status.emsLogging_ID) || (dest == EMS_Sys_Status.emsLogging_ID)) { + _debugPrintTelegram(output_str, EMS_RxTelegram, color_s); + } } else { // always print _debugPrintTelegram(output_str, EMS_RxTelegram, color_s); @@ -1269,6 +1285,19 @@ void _process_MMPLUSStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { _setValue(EMS_RxTelegram, &EMS_Mixing.hc[hc].pumpMod, EMS_OFFSET_MMPLUSStatusMessage_pump_mod); _setValue(EMS_RxTelegram, &EMS_Mixing.hc[hc].valveStatus, EMS_OFFSET_MMPLUSStatusMessage_valve_status); } +// Mixer warm water loading - 0x0231, 0x0232 + +void _process_MMPLUSStatusMessageWW(_EMS_RxTelegram * EMS_RxTelegram) { + uint8_t wwc = (EMS_RxTelegram->type - EMS_TYPE_MMPLUSStatusMessage_WWC1); // 0 to 3 + if (wwc >= EMS_THERMOSTAT_MAXWWC) { + return; // invalid type + } + EMS_Mixing.wwc[wwc].active = true; + + _setValue(EMS_RxTelegram, &EMS_Mixing.wwc[wwc].flowTemp, EMS_OFFSET_MMPLUSStatusMessage_WW_flow_temp); + _setValue(EMS_RxTelegram, &EMS_Mixing.wwc[wwc].pumpMod, EMS_OFFSET_MMPLUSStatusMessage_WW_pump_mod); + _setValue(EMS_RxTelegram, &EMS_Mixing.wwc[wwc].tempStatus, EMS_OFFSET_MMPLUSStatusMessage_WW_temp_status); +} // Mixer - 0xAB void _process_MMStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { @@ -2859,6 +2888,10 @@ const _EMS_Type EMS_Types[] = { // Mixing devices MM10 - MM400 {EMS_DEVICE_UPDATE_FLAG_MIXING, EMS_TYPE_MMPLUSStatusMessage_HC1, "MMPLUSStatusMessage_HC1", _process_MMPLUSStatusMessage}, {EMS_DEVICE_UPDATE_FLAG_MIXING, EMS_TYPE_MMPLUSStatusMessage_HC2, "MMPLUSStatusMessage_HC2", _process_MMPLUSStatusMessage}, + {EMS_DEVICE_UPDATE_FLAG_MIXING, EMS_TYPE_MMPLUSStatusMessage_HC3, "MMPLUSStatusMessage_HC3", _process_MMPLUSStatusMessage}, + {EMS_DEVICE_UPDATE_FLAG_MIXING, EMS_TYPE_MMPLUSStatusMessage_HC4, "MMPLUSStatusMessage_HC4", _process_MMPLUSStatusMessage}, + {EMS_DEVICE_UPDATE_FLAG_MIXING, EMS_TYPE_MMPLUSStatusMessage_WWC1, "MMPLUSStatusMessage_WWC1", _process_MMPLUSStatusMessageWW}, + {EMS_DEVICE_UPDATE_FLAG_MIXING, EMS_TYPE_MMPLUSStatusMessage_WWC2, "MMPLUSStatusMessage_WWC2", _process_MMPLUSStatusMessageWW}, {EMS_DEVICE_UPDATE_FLAG_MIXING, EMS_TYPE_MMStatusMessage, "MMStatusMessage", _process_MMStatusMessage} }; diff --git a/src/ems.h b/src/ems.h index b7c596fb2..56c829474 100644 --- a/src/ems.h +++ b/src/ems.h @@ -34,6 +34,7 @@ // thermostat specific #define EMS_THERMOSTAT_MAXHC 4 // max number of heating circuits +#define EMS_THERMOSTAT_MAXWWC 2 // max number of warm water circuits #define EMS_THERMOSTAT_DEFAULTHC 1 // default heating circuit is 1 #define EMS_THERMOSTAT_WRITE_YES true #define EMS_THERMOSTAT_WRITE_NO false @@ -112,9 +113,10 @@ typedef enum { EMS_SYS_LOGGING_WATCH, // watch a specific type ID EMS_SYS_LOGGING_BASIC, // only basic read/write messages EMS_SYS_LOGGING_THERMOSTAT, // only telegrams sent from thermostat - EMS_SYS_LOGGING_SOLARMODULE, // only telegrams sent from thermostat + EMS_SYS_LOGGING_SOLARMODULE, // only telegrams sent from solarmodule EMS_SYS_LOGGING_VERBOSE, // everything - EMS_SYS_LOGGING_JABBER // lots of debug output... + EMS_SYS_LOGGING_JABBER, // lots of debug output... + EMS_SYS_LOGGING_DEVICE // watch the device ID } _EMS_SYS_LOGGING; // status/counters since last power on @@ -126,7 +128,7 @@ typedef struct { uint16_t emxCrcErr; // CRC errors bool emsPollEnabled; // flag enable the response to poll messages _EMS_SYS_LOGGING emsLogging; // logging - uint16_t emsLogging_typeID; // the typeID to watch + uint16_t emsLogging_ID; // the type or device ID to watch uint8_t emsRefreshedFlags; // fresh data, needs to be pushed out to MQTT bool emsBusConnected; // is there an active bus uint32_t emsRxTimestamp; // timestamp of last EMS message received @@ -344,6 +346,15 @@ typedef struct { uint8_t flowSetTemp; } _EMS_Mixing_HC; +// Mixing Module per WWC +typedef struct { + uint8_t wwc; // warm water circuit 1, 2 + bool active; // true if there is data for this WWC + uint16_t flowTemp; + uint8_t pumpMod; + uint8_t tempStatus; +} _EMS_Mixing_WWC; + // Mixer data typedef struct { uint8_t device_id; @@ -353,6 +364,7 @@ typedef struct { char version[10]; bool detected; _EMS_Mixing_HC hc[EMS_THERMOSTAT_MAXHC]; // array for the 4 heating circuits + _EMS_Mixing_WWC wwc[EMS_THERMOSTAT_MAXWWC]; // array for the 2 ww circuits } _EMS_Mixing; // Solar Module - SM10/SM100/SM200/ISM1 diff --git a/src/ems_devices.h b/src/ems_devices.h index c780b0c37..f44b414b7 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -46,7 +46,7 @@ #define EMS_OFFSET_UBAParameterWW_wwtemp 2 // WW Temperature #define EMS_OFFSET_UBAParameterWW_wwactivated 1 // WW Activated #define EMS_OFFSET_UBAParameterWW_wwOneTime 0x00 // WW OneTime loading -#define EMS_OFFSET_UBAParameterWW_wwCirulation 1 // WW circulation +#define EMS_OFFSET_UBAParameterWW_wwCirulation 1 // WW circulation #define EMS_OFFSET_UBAParameterWW_wwComfort 9 // WW is in comfort or eco mode #define EMS_VALUE_UBAParameterWW_wwComfort_Hot 0x00 // the value for hot #define EMS_VALUE_UBAParameterWW_wwComfort_Eco 0xD8 // the value for eco @@ -176,9 +176,14 @@ #define EMS_TYPE_MMPLUSStatusMessage_HC2 0x01D8 // mixer status HC2 #define EMS_TYPE_MMPLUSStatusMessage_HC3 0x01D9 // mixer status HC3 #define EMS_TYPE_MMPLUSStatusMessage_HC4 0x01DA // mixer status HC4 +#define EMS_TYPE_MMPLUSStatusMessage_WWC1 0x0231 // mixer status WWC1 +#define EMS_TYPE_MMPLUSStatusMessage_WWC2 0x0232 // mixer status WWC2 #define EMS_OFFSET_MMPLUSStatusMessage_flow_temp 3 // flow temperature #define EMS_OFFSET_MMPLUSStatusMessage_pump_mod 5 // pump modulation #define EMS_OFFSET_MMPLUSStatusMessage_valve_status 2 // valve in percent +#define EMS_OFFSET_MMPLUSStatusMessage_WW_flow_temp 0 // flow temperature +#define EMS_OFFSET_MMPLUSStatusMessage_WW_pump_mod 2 // pump on 6, off 0 +#define EMS_OFFSET_MMPLUSStatusMessage_WW_temp_status 11 // 0,1,2 // MM10 #define EMS_TYPE_MMStatusMessage 0xAB // mixer status diff --git a/src/version.h b/src/version.h index 32897e3e2..1cfb1f22a 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define APP_VERSION "1.9.5b17" +#define APP_VERSION "1.9.5b17m"