diff --git a/src/MyESP.h b/src/MyESP.h index 573b04e6f..25adf82aa 100644 --- a/src/MyESP.h +++ b/src/MyESP.h @@ -215,7 +215,7 @@ static_assert(sizeof(RtcmemData) <= (RTCMEM_BLOCKS * 4u), "RTCMEM struct is too typedef struct { bool set; // is it a set command? - char key[50]; + char key[55]; // longest is log (alternatively, the log command description could be shortened) char description[110]; } command_t; diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 8e026d0d5..f9fa985ff 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -107,7 +107,7 @@ static const command_t project_cmds[] PROGMEM = { {true, "master_thermostat [product id]", "set default thermostat to use. No argument lists 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"}, + {false, "log ", "logging: none, basic, thermo, solar, mixer, raw, jabber, verbose, watch a type or device"}, #ifdef TESTS {false, "test ", "insert a test telegram on to the EMS bus"}, @@ -231,6 +231,8 @@ void showInfo() { myDebug_P(PSTR(" System logging set to Thermostat only")); } else if (sysLog == EMS_SYS_LOGGING_SOLARMODULE) { myDebug_P(PSTR(" System logging set to Solar Module only")); + } else if (sysLog == EMS_SYS_LOGGING_MIXERMODULE) { + myDebug_P(PSTR(" System logging set to Mixer Module only")); } else if (sysLog == EMS_SYS_LOGGING_JABBER) { myDebug_P(PSTR(" System logging set to Jabber")); } else if (sysLog == EMS_SYS_LOGGING_WATCH) { @@ -299,6 +301,18 @@ void showInfo() { // UBAParameterWW _renderBoolValue("Warm Water activated", EMS_Boiler.wWActivated); _renderBoolValue("Warm Water circulation pump available", EMS_Boiler.wWCircPump); + myDebug_P(PSTR(" Warm Water circulation pump type: %s"), EMS_Boiler.wWCircPumpType ? "charge pump" : "3-way pump"); + if (EMS_Boiler.wWCircPumpMode == 7) { + myDebug_P(PSTR(" Warm Water circulation pump freq: continuous")); + } else { + char s[7]; + char buffer[2]; + buffer[0] = (EMS_Boiler.wWCircPumpMode % 10) + '0'; + buffer[1] = '\0'; + strlcpy(s, buffer, 3); + strlcat(s, "x3min", sizeof(s)); + myDebug_P(PSTR(" Warm Water circulation pump freq: %s"), s); + } if (EMS_Boiler.wWComfort == EMS_VALUE_UBAParameterWW_wwComfort_Hot) { myDebug_P(PSTR(" Warm Water comfort setting: Hot")); } else if (EMS_Boiler.wWComfort == EMS_VALUE_UBAParameterWW_wwComfort_Eco) { @@ -309,7 +323,7 @@ void showInfo() { _renderIntValue("Warm Water selected temperature", "C", EMS_Boiler.wWSelTemp); _renderIntValue("Warm Water desinfection temperature", "C", EMS_Boiler.wWDesinfectTemp); - _renderBoolValue("Warm Water Circulation active", EMS_Boiler.wWCirc); + _renderBoolValue("Warm Water circulation active", EMS_Boiler.wWCirc); // UBAMonitorWWMessage _renderUShortValue("Warm Water current temperature", "C", EMS_Boiler.wWCurTmp); @@ -635,7 +649,7 @@ bool publishSensorValues() { // publish Boiler data via MQTT bool publishEMSValues_boiler() { - const size_t capacity = JSON_OBJECT_SIZE(41); // must recalculate if more objects addded https://arduinojson.org/v6/assistant/ + const size_t capacity = JSON_OBJECT_SIZE(47); // must recalculate if more objects addded https://arduinojson.org/v6/assistant/ DynamicJsonDocument doc(capacity); JsonObject rootBoiler = doc.to(); @@ -670,6 +684,12 @@ bool publishEMSValues_boiler() { if (EMS_Boiler.wWCircPump != EMS_VALUE_BOOL_NOTSET) { rootBoiler["wWCircPump"] = EMS_Boiler.wWCircPump; } + if (EMS_Boiler.wWCircPumpType != EMS_VALUE_BOOL_NOTSET) { + rootBoiler["wWCiPuType"] = EMS_Boiler.wWCircPumpType; + } + if (EMS_Boiler.wWCircPumpMode != EMS_VALUE_INT_NOTSET) { + rootBoiler["wWCiPuMode"] = EMS_Boiler.wWCircPumpMode; + } if (EMS_Boiler.extTemp > EMS_VALUE_SHORT_NOTSET) { rootBoiler["outdoorTemp"] = (float)EMS_Boiler.extTemp / 10; } @@ -709,6 +729,18 @@ bool publishEMSValues_boiler() { if (EMS_Boiler.wWActivated != EMS_VALUE_BOOL_NOTSET) { rootBoiler["wWOnetime"] = _bool_to_char(s, EMS_Boiler.wWOneTime); } + if (EMS_Boiler.wWActivated != EMS_VALUE_BOOL_NOTSET) { + rootBoiler["wWDesinfecting"] = _bool_to_char(s, EMS_Boiler.wWDesinfecting); + } + if (EMS_Boiler.wWActivated != EMS_VALUE_BOOL_NOTSET) { + rootBoiler["wWReady"] = _bool_to_char(s, EMS_Boiler.wWReadiness); + } + if (EMS_Boiler.wWActivated != EMS_VALUE_BOOL_NOTSET) { + rootBoiler["wWRecharge"] = _bool_to_char(s, EMS_Boiler.wWRecharging); + } + if (EMS_Boiler.wWActivated != EMS_VALUE_BOOL_NOTSET) { + rootBoiler["wWTempOK"] = _bool_to_char(s, EMS_Boiler.wWTemperaturOK); + } if (EMS_Boiler.wWCirc != EMS_VALUE_BOOL_NOTSET) { rootBoiler["wWCirc"] = _bool_to_char(s, EMS_Boiler.wWCirc); } @@ -846,7 +878,19 @@ bool publishEMSValues_thermostat() { } else if (thermoMode == EMS_THERMOSTAT_MODE_NIGHT) { dataThermostat[THERMOSTAT_MODE] = "night"; } - + // Render Thermostat Mode2, only if its in Auto mode + if (thermoMode == EMS_THERMOSTAT_MODE_AUTO) { + thermoMode = _getThermostatMode2(hc_v); + if (thermoMode == EMS_THERMOSTAT_MODE_NIGHT) { + dataThermostat[THERMOSTAT_MODETYPE] = "night"; + } else if (thermoMode == EMS_THERMOSTAT_MODE_DAY) { + dataThermostat[THERMOSTAT_MODETYPE] = "day"; + } else if (thermoMode == EMS_THERMOSTAT_MODE_COMFORT) { + dataThermostat[THERMOSTAT_MODETYPE] = "comfort"; + } else if (thermoMode == EMS_THERMOSTAT_MODE_ECO) { + dataThermostat[THERMOSTAT_MODETYPE] = "eco"; + } + } // if its not nested, send immediately if (!myESP.mqttUseNestedJson()) { @@ -1542,6 +1586,9 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) { } else if (strcmp(second_cmd, "s") == 0) { ems_setLogging(EMS_SYS_LOGGING_SOLARMODULE); ok = true; + } else if (strcmp(second_cmd, "m") == 0) { + ems_setLogging(EMS_SYS_LOGGING_MIXERMODULE); + ok = true; } else if (strcmp(second_cmd, "r") == 0) { ems_setLogging(EMS_SYS_LOGGING_RAW); ok = true; diff --git a/src/ems.cpp b/src/ems.cpp index 3f92dd7ac..c103e18dc 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -145,6 +145,8 @@ void ems_init() { EMS_Boiler.wWActivated = EMS_VALUE_BOOL_NOTSET; // Warm Water activated EMS_Boiler.wWSelTemp = EMS_VALUE_INT_NOTSET; // Warm Water selected temperature EMS_Boiler.wWCircPump = EMS_VALUE_BOOL_NOTSET; // Warm Water circulation pump available + EMS_Boiler.wWCircPumpMode = EMS_VALUE_INT_NOTSET; // Warm Water circulation pump mode + EMS_Boiler.wWCircPumpType = EMS_VALUE_BOOL_NOTSET; // Warm Water circulation pump type EMS_Boiler.wWDesinfectTemp = EMS_VALUE_INT_NOTSET; // Warm Water desinfection temperature to prevent infection EMS_Boiler.wWComfort = EMS_VALUE_INT_NOTSET; // WW comfort mode @@ -182,6 +184,11 @@ void ems_init() { EMS_Boiler.wWStarts = EMS_VALUE_LONG_NOTSET; // Warm Water # starts EMS_Boiler.wWWorkM = EMS_VALUE_LONG_NOTSET; // Warm Water # minutes EMS_Boiler.wWOneTime = EMS_VALUE_INT_NOTSET; // Warm Water one time function on/off + EMS_Boiler.wWDesinfecting = EMS_VALUE_INT_NOTSET; // Warm Water desinfection on/off + EMS_Boiler.wWReadiness = EMS_VALUE_INT_NOTSET; // Warm Water readiness on/off + EMS_Boiler.wWRecharging = EMS_VALUE_INT_NOTSET; // Warm Water recharge on/off + EMS_Boiler.wWTemperaturOK = EMS_VALUE_INT_NOTSET; // Warm Water temperatur ok on/off + EMS_Boiler.wWCurFlow = EMS_VALUE_INT_NOTSET; // WW current flow temp // UBATotalUptimeMessage @@ -319,6 +326,8 @@ void ems_setLogging(_EMS_SYS_LOGGING loglevel, bool quiet) { myDebug_P(PSTR("System Logging set to Thermostat only")); } else if (loglevel == EMS_SYS_LOGGING_SOLARMODULE) { myDebug_P(PSTR("System Logging set to Solar Module only")); + } else if (loglevel == EMS_SYS_LOGGING_MIXERMODULE) { + myDebug_P(PSTR("System Logging set to Mixer Module only")); } else if (loglevel == EMS_SYS_LOGGING_RAW) { myDebug_P(PSTR("System Logging set to Raw mode")); } else if (loglevel == EMS_SYS_LOGGING_JABBER) { @@ -927,7 +936,7 @@ void _removeTxQueue() { /** * Check if hot tap water or heating is active - * using a quick hack for checking the heating. Selected Flow Temp >= 70 + * using a quick hack for checking the heating. Selected Flow Temp >= 30 */ void _checkActive() { // hot tap water, using flow to check instead of the burner power @@ -948,6 +957,8 @@ void _checkActive() { void _process_UBAParameterWW(_EMS_RxTelegram * EMS_RxTelegram) { _setValue(EMS_RxTelegram, &EMS_Boiler.wWActivated, 1); // 0xFF means on _setValue(EMS_RxTelegram, &EMS_Boiler.wWCircPump, 6); // 0xFF means on + _setValue(EMS_RxTelegram, &EMS_Boiler.wWCircPumpMode, 7); // 1=1x3min... 6=6x3min, 7=continuous + _setValue(EMS_RxTelegram, &EMS_Boiler.wWCircPumpType, 10); // 0 = charge pump, 0xff = 3-way valve _setValue(EMS_RxTelegram, &EMS_Boiler.wWSelTemp, 2); _setValue(EMS_RxTelegram, &EMS_Boiler.wWDesinfectTemp, 8); _setValue(EMS_RxTelegram, &EMS_Boiler.wWComfort, EMS_OFFSET_UBAParameterWW_wwComfort); @@ -979,6 +990,10 @@ void _process_UBAMonitorWWMessage(_EMS_RxTelegram * EMS_RxTelegram) { _setValue(EMS_RxTelegram, &EMS_Boiler.wWStarts, 13); _setValue(EMS_RxTelegram, &EMS_Boiler.wWWorkM, 10); _setValue(EMS_RxTelegram, &EMS_Boiler.wWOneTime, 5, 1); + _setValue(EMS_RxTelegram, &EMS_Boiler.wWDesinfecting, 5, 2); + _setValue(EMS_RxTelegram, &EMS_Boiler.wWReadiness, 5, 3); + _setValue(EMS_RxTelegram, &EMS_Boiler.wWRecharging, 5, 4); + _setValue(EMS_RxTelegram, &EMS_Boiler.wWTemperaturOK, 5, 5); _setValue(EMS_RxTelegram, &EMS_Boiler.wWCurFlow, 9); } @@ -1066,7 +1081,7 @@ void _process_UBAMonitorFast(_EMS_RxTelegram * EMS_RxTelegram) { } /** - * UBAMonitorFast2 - type 0xE4 - central heating monitor + * UBAMonitorFast2 - type 0xE4 - central heating monitor EMS+ */ void _process_UBAMonitorFast2(_EMS_RxTelegram * EMS_RxTelegram) { _setValue(EMS_RxTelegram, &EMS_Boiler.selFlowTemp, 6); @@ -1112,7 +1127,7 @@ void _process_UBAMonitorSlow(_EMS_RxTelegram * EMS_RxTelegram) { } /** - * UBAMonitorSlow2 - type 0xE5 - central heating monitor + * UBAMonitorSlow2 - type 0xE5 - central heating monitor EMS+ */ void _process_UBAMonitorSlow2(_EMS_RxTelegram * EMS_RxTelegram) { _setValue(EMS_RxTelegram, &EMS_Boiler.fanWork, 2, 2); @@ -1126,7 +1141,7 @@ void _process_UBAMonitorSlow2(_EMS_RxTelegram * EMS_RxTelegram) { } /** - * UBAOutdoorTemp - type 0xD1 - external temperature + * UBAOutdoorTemp - type 0xD1 - external temperature EMS+ */ void _process_UBAOutdoorTemp(_EMS_RxTelegram * EMS_RxTelegram) { _setValue(EMS_RxTelegram, &EMS_Boiler.extTemp, 0); @@ -1302,6 +1317,17 @@ void _process_MMStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { //_setValue(EMS_RxTelegram, &EMS_MixingModule.hc[hc].valveStatus, EMS_OFFSET_MMStatusMessage_valve_status); } +// Mixer Parameters - 0xAC +// We assume MM10 is on HC2 and WM10 is using HC1 +void _process_MM10ParameterMessage(_EMS_RxTelegram * EMS_RxTelegram) { + //uint8_t hc = 1; // fixed to HC2 + //EMS_MixingModule.hc[hc].active = true; + + //_setValue(EMS_RxTelegram, &EMS_MixingModule.hc[hc].flowTemp, EMS_OFFSET_MMStatusMessage_flow_temp); + //_setValue(EMS_RxTelegram, &EMS_MixingModule.hc[hc].pumpMod, EMS_OFFSET_MMStatusMessage_pump_mod); + //_setValue(EMS_RxTelegram, &EMS_MixingModule.hc[hc].flowSetTemp, EMS_OFFSET_MMStatusMessage_flow_set); +} + /** * type 0x01A5 - data from the Nefit RC1010/3000 thermostat (0x18) and RC300/310s on 0x10 * EMS+ messages may come in with different offsets so handle them here @@ -2930,9 +2956,8 @@ const _EMS_Type EMS_Types[] = { {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} - - + {EMS_DEVICE_UPDATE_FLAG_MIXING, EMS_TYPE_MMStatusMessage, "MMStatusMessage", _process_MMStatusMessage}, + {EMS_DEVICE_UPDATE_FLAG_MIXING, EMS_TYPE_MM10ParameterMessage, "MM10ParameterMessage", _process_MM10ParameterMessage} }; // calculate sizes of arrays at compile time @@ -3026,10 +3051,19 @@ void _printMessage(_EMS_RxTelegram * EMS_RxTelegram, const int8_t show_type) { _debugPrintTelegram(output_str, EMS_RxTelegram, color_s); } } else if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_SOLARMODULE) { - // only print ones to/from thermostat if logging is set to thermostat only + // only print ones to/from solar module if logging is set to solar module only 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_MIXERMODULE) { + // only print ones to/from mixer module if logging is set to mixer module only + if ((src == EMS_MixingModule.device_id) || (dest == EMS_MixingModule.device_id)) { + _debugPrintTelegram(output_str, EMS_RxTelegram, color_s); + // also analyse the sequence of instructions prior to instructions to/from mixer module + // typically: EMS_TYPE_MM10ParameterMessage(0xAC) - EMS_TYPE_UBASetPoints(0x1A) - EMS_TYPE_UBAFlags(0x35) + } else if ((type == EMS_TYPE_MMStatusMessage) || (type == EMS_TYPE_MM10ParameterMessage) || (type == EMS_TYPE_UBASetPoints) || (type == EMS_TYPE_UBAFlags)) { + _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)) { diff --git a/src/ems.h b/src/ems.h index 40a2b2dc0..b5e5d00cb 100644 --- a/src/ems.h +++ b/src/ems.h @@ -125,7 +125,8 @@ 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 solarmodule + EMS_SYS_LOGGING_SOLARMODULE, // only telegrams sent from solar module + EMS_SYS_LOGGING_MIXERMODULE, // only telegrams sent from mixer module EMS_SYS_LOGGING_VERBOSE, // everything EMS_SYS_LOGGING_JABBER, // lots of debug output... EMS_SYS_LOGGING_DEVICE // watch the device ID @@ -286,6 +287,8 @@ typedef struct { uint8_t wWActivated; // Warm Water activated uint8_t wWSelTemp; // Warm Water selected temperature uint8_t wWCircPump; // Warm Water circulation pump Available + uint8_t wWCircPumpMode; // Warm Water circulation pump mode (1 = 1x3min, ..., 6=6x3min, 7 continuous) + uint8_t wWCircPumpType; // Warm Water circulation pump type (0 = charge pump, 0xff = 3-way pump) uint8_t wWDesinfectTemp; // Warm Water desinfection temperature uint8_t wWComfort; // Warm water comfort or ECO mode @@ -323,6 +326,10 @@ typedef struct { uint32_t wWStarts; // Warm Water # starts uint32_t wWWorkM; // Warm Water # minutes uint8_t wWOneTime; // Warm Water one time function on/off + uint8_t wWDesinfecting; // Warm Water desinfection on/off + uint8_t wWReadiness; // Warm Water readiness on/off + uint8_t wWRecharging; // Warm Water recharge on/off + uint8_t wWTemperaturOK; // Warm Water temperatur ok on/off uint8_t wWCurFlow; // Warm Water current flow in l/min // UBATotalUptimeMessage diff --git a/src/ems_devices.h b/src/ems_devices.h index 75b6e2001..7960a0685 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -72,6 +72,7 @@ #define EMS_OFFSET_MMStatusMessage_flow_temp 1 // flow temperature #define EMS_OFFSET_MMStatusMessage_pump_mod 3 // pump modulation in percent #define EMS_OFFSET_MMStatusMessage_valve_status 4 // valve 0..255 +#define EMS_TYPE_MM10ParameterMessage 0xAC // mixer parameters // Solar Module // Assuming here that the SM200 behaves like SM100 diff --git a/src/my_config.h b/src/my_config.h index 91e1fdea0..2c4e574a8 100644 --- a/src/my_config.h +++ b/src/my_config.h @@ -32,6 +32,7 @@ #define THERMOSTAT_SELTEMP "seltemp" // selected temperature #define THERMOSTAT_HC "hc" // which heating circuit number #define THERMOSTAT_MODE "mode" // mode +#define THERMOSTAT_MODETYPE "modetype" // mode type #define THERMOSTAT_DAYTEMP "daytemp" // RC35 specific #define THERMOSTAT_NIGHTTEMP "nighttemp" // RC35 specific #define THERMOSTAT_HOLIDAYTEMP "holidayttemp" // RC35 specific