From 7253299469a28c3b8b93a49fc360ad8656be16d3 Mon Sep 17 00:00:00 2001 From: ypaindaveine Date: Sun, 22 Mar 2020 20:02:22 +0100 Subject: [PATCH] Added retrieving settings (0xA5) (validated on RC30N), and MQTT cmd to set display, building type and language. --- src/ems-esp.cpp | 206 +++++++++++++++++++++++++++++++++++++++++++++- src/ems.cpp | 152 ++++++++++++++++++++++++++++++++++ src/ems.h | 17 +++- src/ems_devices.h | 29 +++++++ src/my_config.h | 8 ++ 5 files changed, 408 insertions(+), 4 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 44d113c04..cdafbc789 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -45,6 +45,9 @@ Ticker systemCheckTimer; #define REGULARUPDATES_TIME 60 // every minute a call is made to fetch data from EMS devices manually Ticker regularUpdatesTimer; +#define DAILYUPDATES_TIME 86400 // every day a call is made to fetch data from EMS devices manually +Ticker dailyUpdatesTimer; + #define LEDCHECK_TIME 500 // every 1/2 second blink the heartbeat LED Ticker ledcheckTimer; @@ -433,6 +436,58 @@ void showInfo() { myDebug_P(PSTR(" Thermostat time is %s"), EMS_Thermostat.datetime); } + // settings parameters + if (EMS_Thermostat.ibaMainDisplay != EMS_VALUE_INT_NOTSET) { + if (EMS_Thermostat.ibaMainDisplay == EMS_VALUE_IBASettings_DISPLAY_INTTEMP) { + myDebug_P(PSTR(" Display: internal temperature")); + } else if (EMS_Thermostat.ibaMainDisplay == EMS_VALUE_IBASettings_DISPLAY_INTSETPOINT) { + myDebug_P(PSTR(" Display: internal setpoint")); + } else if (EMS_Thermostat.ibaMainDisplay == EMS_VALUE_IBASettings_DISPLAY_EXTTEMP) { + myDebug_P(PSTR(" Display: external temperature")); + } else if (EMS_Thermostat.ibaMainDisplay == EMS_VALUE_IBASettings_DISPLAY_BURNERTEMP) { + myDebug_P(PSTR(" Display: burner temperature")); + } else if (EMS_Thermostat.ibaMainDisplay == EMS_VALUE_IBASettings_DISPLAY_WWTEMP) { + myDebug_P(PSTR(" Display: WW temperature")); + } else if (EMS_Thermostat.ibaMainDisplay == EMS_VALUE_IBASettings_DISPLAY_FUNCMODE) { + myDebug_P(PSTR(" Display: functioning mode")); + } else if (EMS_Thermostat.ibaMainDisplay == EMS_VALUE_IBASettings_DISPLAY_TIME) { + myDebug_P(PSTR(" Display: time")); + } else if (EMS_Thermostat.ibaMainDisplay == EMS_VALUE_IBASettings_DISPLAY_DATE) { + myDebug_P(PSTR(" Display: date")); + } else if (EMS_Thermostat.ibaMainDisplay == EMS_VALUE_IBASettings_DISPLAY_SMOKETEMP) { + myDebug_P(PSTR(" Display: smoke temperature")); + } + } + if (EMS_Thermostat.ibaLanguage != EMS_VALUE_INT_NOTSET) { + if (EMS_Thermostat.ibaLanguage == EMS_VALUE_IBASettings_LANG_GERMAN) { + myDebug_P(PSTR(" Language: German")); + } else if (EMS_Thermostat.ibaLanguage == EMS_VALUE_IBASettings_LANG_DUTCH) { + myDebug_P(PSTR(" Language: Dutch")); + } else if (EMS_Thermostat.ibaLanguage == EMS_VALUE_IBASettings_LANG_FRENCH) { + myDebug_P(PSTR(" Language: French")); + } else if (EMS_Thermostat.ibaLanguage == EMS_VALUE_IBASettings_LANG_ITALIAN) { + myDebug_P(PSTR(" Language: Italian")); + } + } + if (EMS_Thermostat.ibaCalIntTemperature != EMS_VALUE_INT_NOTSET) { + _renderIntValue("Offset int. temperature", "K", EMS_Thermostat.ibaCalIntTemperature, 10); // offset int. temperature sensor, by * 0.1 Kelvin + } + if (EMS_Thermostat.ibaMinExtTemperature != EMS_VALUE_SHORT_NOTSET) { + _renderShortValue("Min ext. temperature", "C", EMS_Thermostat.ibaMinExtTemperature, 0); // min ext temp for heating curve, in deg. + } + if (EMS_Thermostat.ibaBuildingType != EMS_VALUE_INT_NOTSET) { + if (EMS_Thermostat.ibaBuildingType == EMS_VALUE_IBASettings_BUILDING_LIGHT) { + myDebug_P(PSTR(" Building: light")); + } else if (EMS_Thermostat.ibaBuildingType == EMS_VALUE_IBASettings_BUILDING_MEDIUM) { + myDebug_P(PSTR(" Building: medium")); + } else if (EMS_Thermostat.ibaBuildingType == EMS_VALUE_IBASettings_BUILDING_HEAVY) { + myDebug_P(PSTR(" Building: heavy")); + } + } + if (EMS_Thermostat.ibaClockOffset != EMS_VALUE_INT_NOTSET) { + _renderIntValue("Offset clock", "s", EMS_Thermostat.ibaClockOffset); // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s + } + uint8_t _m_setpoint, _m_curr; switch (model) { case EMS_DEVICE_FLAG_EASY: @@ -580,7 +635,7 @@ void scanDallas() { // send all dallas sensor values as a JSON package to MQTT bool publishSensorValues() { - // don't send if MQTT is connected + // don't send if MQTT is not connected if (!myESP.isMQTTConnected() || (EMSESP_Settings.publish_time == -1)) { return false; } @@ -914,6 +969,65 @@ bool publishEMSValues_thermostat() { return (has_data); } +// publish Settings parameters via MQTT +bool publishEMSValues_settings() { + const size_t capacity = JSON_OBJECT_SIZE(5); // must recalculate if more objects added https://arduinojson.org/v6/assistant/ + DynamicJsonDocument doc(capacity); + JsonObject rootSettings = doc.to(); + + if (EMS_Thermostat.ibaMainDisplay != EMS_VALUE_INT_NOTSET) { + if (EMS_Thermostat.ibaMainDisplay == EMS_VALUE_IBASettings_DISPLAY_INTTEMP) { + rootSettings["display"] = "int. temperature"; + } else if (EMS_Thermostat.ibaMainDisplay == EMS_VALUE_IBASettings_DISPLAY_INTSETPOINT) { + rootSettings["display"] = "int. setpoint"; + } else if (EMS_Thermostat.ibaMainDisplay == EMS_VALUE_IBASettings_DISPLAY_EXTTEMP) { + rootSettings["display"] = "ext. temperature"; + } else if (EMS_Thermostat.ibaMainDisplay == EMS_VALUE_IBASettings_DISPLAY_BURNERTEMP) { + rootSettings["display"] = "burner temperature"; + } else if (EMS_Thermostat.ibaMainDisplay == EMS_VALUE_IBASettings_DISPLAY_WWTEMP) { + rootSettings["display"] = "WW temperature"; + } else if (EMS_Thermostat.ibaMainDisplay == EMS_VALUE_IBASettings_DISPLAY_FUNCMODE) { + rootSettings["display"] = "functioning mode"; + } else if (EMS_Thermostat.ibaMainDisplay == EMS_VALUE_IBASettings_DISPLAY_TIME) { + rootSettings["display"] = "time"; + } else if (EMS_Thermostat.ibaMainDisplay == EMS_VALUE_IBASettings_DISPLAY_DATE) { + rootSettings["display"] = "date"; + } else if (EMS_Thermostat.ibaMainDisplay == EMS_VALUE_IBASettings_DISPLAY_SMOKETEMP) { + rootSettings["display"] = "smoke temperature"; + } + } + if (EMS_Thermostat.ibaLanguage != EMS_VALUE_INT_NOTSET) { + if (EMS_Thermostat.ibaLanguage == EMS_VALUE_IBASettings_LANG_GERMAN) { + rootSettings["language"] = "German"; + } else if (EMS_Thermostat.ibaLanguage == EMS_VALUE_IBASettings_LANG_DUTCH) { + rootSettings["language"] = "Dutch"; + } else if (EMS_Thermostat.ibaLanguage == EMS_VALUE_IBASettings_LANG_FRENCH) { + rootSettings["language"] = "French"; + } else if (EMS_Thermostat.ibaLanguage == EMS_VALUE_IBASettings_LANG_ITALIAN) { + rootSettings["language"] = "Italian"; + } + } + if (EMS_Thermostat.ibaCalIntTemperature != EMS_VALUE_INT_NOTSET) { + rootSettings["CalIntTemperature"] = (float)EMS_Thermostat.ibaCalIntTemperature / 10; // offset int. temperature sensor, by * 0.1 Kelvin + } + if (EMS_Thermostat.ibaMinExtTemperature != EMS_VALUE_SHORT_NOTSET) { + rootSettings["MinExtTemperature"] = EMS_Thermostat.ibaMinExtTemperature; // min ext temp for heating curve, in deg., 0xF6=-10, 0x0 = 0, 0xFF=-1 + } + if (EMS_Thermostat.ibaBuildingType != EMS_VALUE_INT_NOTSET) { + if (EMS_Thermostat.ibaBuildingType == EMS_VALUE_IBASettings_BUILDING_LIGHT) { + rootSettings["building"] = "light"; + } else if (EMS_Thermostat.ibaBuildingType == EMS_VALUE_IBASettings_BUILDING_MEDIUM) { + rootSettings["building"] = "medium"; + } else if (EMS_Thermostat.ibaBuildingType == EMS_VALUE_IBASettings_BUILDING_HEAVY) { + rootSettings["building"] = "heavy"; + } + } + if (EMS_Thermostat.ibaClockOffset != EMS_VALUE_INT_NOTSET) { + rootSettings["clockOffset"] = EMS_Thermostat.ibaClockOffset; // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s + } + return (myESP.mqttPublish(TOPIC_SETTINGS_DATA, doc)); +} + // publish mixing data // only sending if we have an active hc bool publishEMSValues_mixing() { @@ -1059,6 +1173,7 @@ bool publishEMSValues(bool force) { bool thermo = false; bool boiler = false; + bool settings = false; bool mixing = false; bool solar = false; bool heatpump = false; @@ -1073,6 +1188,12 @@ bool publishEMSValues(bool force) { ems_Device_remove_flags(EMS_DEVICE_UPDATE_FLAG_BOILER); // unset flag } + if (ems_getBoilerEnabled() && (ems_Device_has_flags(EMS_DEVICE_UPDATE_FLAG_SETTINGS))) { + // never force publication of settings + settings = publishEMSValues_settings(); + ems_Device_remove_flags(EMS_DEVICE_UPDATE_FLAG_SETTINGS); // unset flag + } + if (ems_getMixingModuleEnabled() && (ems_Device_has_flags(EMS_DEVICE_UPDATE_FLAG_MIXING) || force)) { mixing = publishEMSValues_mixing(); ems_Device_remove_flags(EMS_DEVICE_UPDATE_FLAG_MIXING); // unset flag @@ -1093,7 +1214,7 @@ bool publishEMSValues(bool force) { } // print - char log_s[50]; + char log_s[60]; strlcpy(log_s, "Publishing MQTT data for:", sizeof(log_s)); if (thermo) { strlcat(log_s, " thermostat", sizeof(log_s)); @@ -1101,6 +1222,9 @@ bool publishEMSValues(bool force) { if (boiler) { strlcat(log_s, " boiler", sizeof(log_s)); } + if (settings) { + strlcat(log_s, " settings", sizeof(log_s)); + } if (mixing) { strlcat(log_s, " mixing", sizeof(log_s)); } @@ -1167,6 +1291,16 @@ void do_regularUpdates() { } } +// force low-frequency (daily) calls to get data from EMS for the types that aren't sent as broadcasts +// only if we have a EMS connection +// which will cause the values to get published +void do_dailyUpdates() { + if (ems_getBusConnected() && !ems_getTxDisabled()) { + myDebugLog("Fetching settings data"); + ems_getSettingsValues(); + } +} + // turn back on the hot water for the shower void _showerColdShotStop() { if (EMSESP_Shower.doingColdShot) { @@ -1194,6 +1328,7 @@ void runUnitTest(uint8_t test_num) { publishValuesTimer.detach(); systemCheckTimer.detach(); regularUpdatesTimer.detach(); + dailyUpdatesTimer.detach(); // EMSESP_Settings.listen_mode = true; // temporary go into listen mode to disable Tx ems_testTelegram(test_num); } @@ -1527,6 +1662,7 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) { if (strcmp(first_cmd, "refresh") == 0) { do_regularUpdates(); + do_dailyUpdates(); ok = true; } @@ -1775,12 +1911,15 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { // this is used for example for comfort, flowtemp myESP.mqttSubscribe(TOPIC_BOILER_CMD); - // these three need to be unique topics + // these need to be unique topics myESP.mqttSubscribe(TOPIC_BOILER_CMD_WWACTIVATED); myESP.mqttSubscribe(TOPIC_BOILER_CMD_WWONETIME); myESP.mqttSubscribe(TOPIC_BOILER_CMD_WWCIRCULATION); myESP.mqttSubscribe(TOPIC_BOILER_CMD_WWTEMP); + // generic incoming MQTT command for Settings + myESP.mqttSubscribe(TOPIC_SETTINGS_CMD); + // generic incoming MQTT command for EMS-ESP // this is used for example for shower_coldshot myESP.mqttSubscribe(TOPIC_GENERIC_CMD); @@ -1936,6 +2075,66 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { return; } + // check for settings commands + if (strcmp(topic, TOPIC_SETTINGS_CMD) == 0) { + // convert JSON and get the command + StaticJsonDocument<100> doc; + DeserializationError error = deserializeJson(doc, message); // Deserialize the JSON document + if (error) { + myDebug_P(PSTR("[MQTT] Invalid command from topic %s, payload %s, error %s"), topic, message, error.c_str()); + return; + } + const char * command = doc["cmd"]; + if (command == nullptr) { + return; + } + + // language setting + if (strcmp(command, TOPIC_SETTINGS_CMD_LANGUAGE) == 0) { + const char * data = doc["data"]; + if (data == nullptr) { + return; + } + if (strcasecmp((char *)data, "french") == 0) { + ems_setSettingsLanguage(EMS_VALUE_IBASettings_LANG_FRENCH); + } else if (strcasecmp((char *)data, "german") == 0) { + ems_setSettingsLanguage(EMS_VALUE_IBASettings_LANG_GERMAN); + } else if (strcasecmp((char *)data, "italian") == 0) { + ems_setSettingsLanguage(EMS_VALUE_IBASettings_LANG_ITALIAN); + } + return; + } + // building setting + if (strcmp(command, TOPIC_SETTINGS_CMD_BUILDING) == 0) { + const char * data = doc["data"]; + if (data == nullptr) { + return; + } + if (strcasecmp((char *)data, "light") == 0) { + ems_setSettingsBuilding(EMS_VALUE_IBASettings_BUILDING_LIGHT); + } else if (strcasecmp((char *)data, "medium") == 0) { + ems_setSettingsBuilding(EMS_VALUE_IBASettings_BUILDING_MEDIUM); + } else if (strcasecmp((char *)data, "heavy") == 0) { + ems_setSettingsBuilding(EMS_VALUE_IBASettings_BUILDING_HEAVY); + } + return; + } + // display setting + if (strcmp(command, TOPIC_SETTINGS_CMD_DISPLAY) == 0) { + const char * data = doc["data"]; + if (data == nullptr) { + return; + } + uint8_t t = atoi((char *)data); + if (t) { + ems_setSettingsDisplay(t-1); + } + return; + } + return; // unknown settings command + } + + uint8_t hc; // thermostat temp changes hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_TEMP_HA, topic); @@ -2427,6 +2626,7 @@ void setup() { // enable regular checks to fetch data and publish using Tx (unless listen_mode is enabled) if (!EMSESP_Settings.listen_mode) { regularUpdatesTimer.attach(REGULARUPDATES_TIME, do_regularUpdates); // regular reads from the EMS + dailyUpdatesTimer.attach(DAILYUPDATES_TIME, do_dailyUpdates); // daily reads from the EMS } // set timers for MQTT publish diff --git a/src/ems.cpp b/src/ems.cpp index 72cf98114..bf1e7df8c 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -103,6 +103,13 @@ void ems_init() { strlcpy(EMS_Thermostat.datetime, "?", sizeof(EMS_Thermostat.datetime)); EMS_Thermostat.write_supported = false; EMS_Thermostat.device_id = EMS_ID_NONE; + // settings + EMS_Thermostat.ibaMainDisplay = EMS_VALUE_INT_NOTSET; // display on Thermostat: 0 int. temp, 1 int. setpoint, 2 ext. temp., 3 boiler temp., 4 ww temp, 5 functioning mode, 6 time, 7 data, 9 smoke temp + EMS_Thermostat.ibaLanguage = EMS_VALUE_INT_NOTSET; // language on Thermostat: 0 german, 1 dutch, 2 french, 3 italian + EMS_Thermostat.ibaCalIntTemperature = EMS_VALUE_INT_NOTSET; // offset int. temperature sensor, by * 0.1 Kelvin + EMS_Thermostat.ibaMinExtTemperature = EMS_VALUE_SHORT_NOTSET; // min ext temp for heating curve, in deg., 0xF6=-10, 0x0 = 0, 0xFF=-1 + EMS_Thermostat.ibaBuildingType = EMS_VALUE_INT_NOTSET; // building type: 0 = light, 1 = medium, 2 = heavy + EMS_Thermostat.ibaClockOffset = EMS_VALUE_INT_NOTSET; // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s // init all heating circuits for (uint8_t i = 0; i < EMS_THERMOSTAT_MAXHC; i++) { @@ -1286,6 +1293,33 @@ void _process_EasyStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { _setValue(EMS_RxTelegram, &EMS_Thermostat.hc[hc].setpoint_roomTemp, EMS_OFFSET_EasyStatusMessage_setpoint); // is * 100 } +// Settings Parameters - 0xA5 +void _process_IBASettingsMessage(_EMS_RxTelegram * EMS_RxTelegram) { + // thermostat compatible with this settings message, checked by in ems_getSettingsValues() + + // at init, and every 24h, send read request for settings parameters message, done with Ticker on do_dailyUpdates() + // send 0B 90 A5 00 20: + // 10 0B A5 00 00 02 00 00 FF F6 01 06 00 01 0D 03 03 + // 00 01 02 03 04 05 06 07 08 09 10 11 12 + + // values validated for RC30N + uint8_t extTemp = 100; // Min. ext temperature is coded as int8, 0xF6=-10, 0x0 = 0, 0xFF=-1. 100 is out of permissible range + + _setValue(EMS_RxTelegram, &EMS_Thermostat.ibaMainDisplay, EMS_OFFSET_IBASettings_Display); // display on Thermostat: 0 int. temp, 1 int. setpoint, 2 ext. temp., 3 burner temp., 4 ww temp, 5 functioning mode, 6 time, 7 data, 9 smoke temp + _setValue(EMS_RxTelegram, &EMS_Thermostat.ibaLanguage, EMS_OFFSET_IBASettings_Language); // language on Thermostat: 0 german, 1 dutch, 2 french, 3 italian + _setValue(EMS_RxTelegram, &EMS_Thermostat.ibaBuildingType, EMS_OFFSET_IBASettings_Building); // building type: 0 = light, 1 = medium, 2 = heavy + _setValue(EMS_RxTelegram, &EMS_Thermostat.ibaCalIntTemperature, EMS_OFFSET_IBASettings_CalIntTemp); // offset int. temperature sensor, by * 0.1 Kelvin + _setValue(EMS_RxTelegram, &extTemp, EMS_OFFSET_IBASettings_MinExtTemp); // min ext temp for heating curve, in deg., 0xF6=-10, 0x0 = 0, 0xFF=-1 + if (extTemp != 100) { + // code as signed short, to benefit from negative value rendering + EMS_Thermostat.ibaMinExtTemperature = (int16_t)(extTemp > 127) ? (extTemp-256) : extTemp; + } + _setValue(EMS_RxTelegram, &EMS_Thermostat.ibaClockOffset, EMS_OFFSET_IBASettings_ClockOffset); // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s + + // publish settings to mqtt (assuming this is a very low frequency message), done in publishEMSValues_settings() + ems_Device_add_flags(EMS_DEVICE_UPDATE_FLAG_SETTINGS); +} + // Mixing module - 0x01D7, 0x01D8 void _process_MMPLUSStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { uint8_t hc = (EMS_RxTelegram->type - EMS_TYPE_MMPLUSStatusMessage_HC1); // 0 to 3 @@ -2075,6 +2109,24 @@ void ems_getBoilerValues() { ems_doReadCommand(EMS_TYPE_UBATotalUptimeMessage, EMS_Boiler.device_id); // get uptime from boiler } +void ems_getSettingsValues() { + if (!ems_getThermostatEnabled()) { + return; + } + + uint8_t device_flags = EMS_Thermostat.device_flags; + uint8_t device_id = EMS_Thermostat.device_id; + + // for the moment, only validated on RC30 + switch (device_flags) { + case EMS_DEVICE_FLAG_RC30N: + ems_doReadCommand(EMS_TYPE_IBASettingsMessage, device_id); + break; + default: + break; + } +} + /* * Get solar values from EMS devices */ @@ -2753,6 +2805,103 @@ void ems_setThermostatMode(_EMS_THERMOSTAT_MODE mode, uint8_t hc) { EMS_TxQueue.push(EMS_TxTelegram); } +/** + * Set the language settings + * to 0xA5 + */ +void ems_setSettingsLanguage(uint8_t lg) { + _EMS_TxTelegram EMS_TxTelegram = EMS_TX_TELEGRAM_NEW; // create new Tx + EMS_TxTelegram.timestamp = millis(); // set timestamp + EMS_Sys_Status.txRetryCount = 0; // reset retry counter + + switch(lg) { + case EMS_VALUE_IBASettings_LANG_FRENCH: + case EMS_VALUE_IBASettings_LANG_GERMAN: + case EMS_VALUE_IBASettings_LANG_DUTCH: + case EMS_VALUE_IBASettings_LANG_ITALIAN: + myDebug_P(PSTR("Setting language to %d"),lg); + EMS_TxTelegram.dataValue = lg; + break; + default: + return; // invalid value + } + + EMS_TxTelegram.action = EMS_TX_TELEGRAM_WRITE; + EMS_TxTelegram.dest = EMS_Thermostat.device_id; + EMS_TxTelegram.type = EMS_TYPE_IBASettingsMessage; + EMS_TxTelegram.offset = EMS_OFFSET_IBASettings_Language; + EMS_TxTelegram.length = EMS_MIN_TELEGRAM_LENGTH; + EMS_TxTelegram.type_validate = EMS_ID_NONE; // don't validate + + EMS_TxQueue.push(EMS_TxTelegram); +} + +/** + * Set the building settings + * to 0xA5 + */ +void ems_setSettingsBuilding(uint8_t bg) { + _EMS_TxTelegram EMS_TxTelegram = EMS_TX_TELEGRAM_NEW; // create new Tx + EMS_TxTelegram.timestamp = millis(); // set timestamp + EMS_Sys_Status.txRetryCount = 0; // reset retry counter + + switch(bg) { + case EMS_VALUE_IBASettings_BUILDING_LIGHT: + case EMS_VALUE_IBASettings_BUILDING_MEDIUM: + case EMS_VALUE_IBASettings_BUILDING_HEAVY: + myDebug_P(PSTR("Setting building to %d"),bg); + EMS_TxTelegram.dataValue = bg; + break; + default: + return; // invalid value + } + + EMS_TxTelegram.action = EMS_TX_TELEGRAM_WRITE; + EMS_TxTelegram.dest = EMS_Thermostat.device_id; + EMS_TxTelegram.type = EMS_TYPE_IBASettingsMessage; + EMS_TxTelegram.offset = EMS_OFFSET_IBASettings_Building; + EMS_TxTelegram.length = EMS_MIN_TELEGRAM_LENGTH; + EMS_TxTelegram.type_validate = EMS_ID_NONE; // don't validate + + EMS_TxQueue.push(EMS_TxTelegram); +} + +/** + * Set the display settings + * to 0xA5 + */ +void ems_setSettingsDisplay(uint8_t ds) { + _EMS_TxTelegram EMS_TxTelegram = EMS_TX_TELEGRAM_NEW; // create new Tx + EMS_TxTelegram.timestamp = millis(); // set timestamp + EMS_Sys_Status.txRetryCount = 0; // reset retry counter + + switch(ds) { + case EMS_VALUE_IBASettings_DISPLAY_INTTEMP: + case EMS_VALUE_IBASettings_DISPLAY_INTSETPOINT: + case EMS_VALUE_IBASettings_DISPLAY_EXTTEMP: + case EMS_VALUE_IBASettings_DISPLAY_BURNERTEMP: + case EMS_VALUE_IBASettings_DISPLAY_WWTEMP: + case EMS_VALUE_IBASettings_DISPLAY_FUNCMODE: + case EMS_VALUE_IBASettings_DISPLAY_TIME: + case EMS_VALUE_IBASettings_DISPLAY_DATE: + case EMS_VALUE_IBASettings_DISPLAY_SMOKETEMP: + myDebug_P(PSTR("Setting display to %d"),ds); + EMS_TxTelegram.dataValue = ds; + break; + default: + return; // invalid value + } + + EMS_TxTelegram.action = EMS_TX_TELEGRAM_WRITE; + EMS_TxTelegram.dest = EMS_Thermostat.device_id; + EMS_TxTelegram.type = EMS_TYPE_IBASettingsMessage; + EMS_TxTelegram.offset = EMS_OFFSET_IBASettings_Display; + EMS_TxTelegram.length = EMS_MIN_TELEGRAM_LENGTH; + EMS_TxTelegram.type_validate = EMS_ID_NONE; // don't validate + + EMS_TxQueue.push(EMS_TxTelegram); +} + /** * Set the warm water temperature 0x33 */ @@ -3083,6 +3232,9 @@ const _EMS_Type EMS_Types[] = { {EMS_DEVICE_UPDATE_FLAG_THERMOSTAT, EMS_TYPE_JunkersStatusMessage_HC3, "JunkersStatusMessage_HC3", _process_JunkersStatusMessage}, {EMS_DEVICE_UPDATE_FLAG_THERMOSTAT, EMS_TYPE_JunkersStatusMessage_HC4, "JunkersStatusMessage_HC4", _process_JunkersStatusMessage}, + // settings + {EMS_DEVICE_UPDATE_FLAG_THERMOSTAT, EMS_TYPE_IBASettingsMessage, "IBASettingsMessage", _process_IBASettingsMessage}, + // 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}, diff --git a/src/ems.h b/src/ems.h index 4f08ef7ed..88434ead8 100644 --- a/src/ems.h +++ b/src/ems.h @@ -204,7 +204,8 @@ typedef enum : uint8_t { EMS_DEVICE_UPDATE_FLAG_THERMOSTAT = (1 << 1), EMS_DEVICE_UPDATE_FLAG_MIXING = (1 << 2), EMS_DEVICE_UPDATE_FLAG_SOLAR = (1 << 3), - EMS_DEVICE_UPDATE_FLAG_HEATPUMP = (1 << 4) + EMS_DEVICE_UPDATE_FLAG_HEATPUMP = (1 << 4), + EMS_DEVICE_UPDATE_FLAG_SETTINGS = (1 << 5) } _EMS_DEVICE_UPDATE_FLAG; typedef enum : uint8_t { @@ -430,6 +431,15 @@ typedef struct { char version[10]; char datetime[25]; // HH:MM:SS DD/MM/YYYY bool write_supported; + + // Installation parameters (tested on RC30) + uint8_t ibaMainDisplay; // 00, display on Thermostat: 0 int. temp, 1 int. setpoint, 2 ext. temp., 3 burner temp., 4 ww temp, 5 functioning mode, 6 time, 7 data, 9 smoke temp + uint8_t ibaLanguage; // 01, language on Thermostat: 0 german, 1 dutch, 2 french, 3 italian + uint8_t ibaCalIntTemperature; // 02, offset int. temperature sensor, by * 0.1 Kelvin + int16_t ibaMinExtTemperature; // 05, min ext temp for heating curve, in deg., 0xF6=-10, 0x0 = 0, 0xFF=-1 (actually a int8_t, coded as int16_t to benefit from negative value rendering) + uint8_t ibaBuildingType; // 06, building type: 0 = light, 1 = medium, 2 = heavy + uint8_t ibaClockOffset; // 12, offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s + _EMS_Thermostat_HC hc[EMS_THERMOSTAT_MAXHC]; // array for the 4 heating circuits } _EMS_Thermostat; @@ -483,6 +493,10 @@ void ems_testTelegram(uint8_t test_num); void ems_startupTelegrams(); bool ems_checkEMSBUSAlive(); +void ems_setSettingsLanguage(uint8_t lg); +void ems_setSettingsBuilding(uint8_t bg); +void ems_setSettingsDisplay(uint8_t ds); + void ems_setThermostatTemp(float temperature, uint8_t hc, _EMS_THERMOSTAT_MODE temptype); void ems_setThermostatTemp(float temperature, uint8_t hc, const char * mode_s); void ems_setThermostatMode(_EMS_THERMOSTAT_MODE mode, uint8_t hc); @@ -509,6 +523,7 @@ char * ems_getDeviceTypeName(_EMS_DEVICE_TYPE device_type, char * _EMS_THERMOSTAT_MODE ems_getThermostatMode(const char * mode_s); void ems_getThermostatValues(); void ems_getBoilerValues(); +void ems_getSettingsValues(); void ems_getSolarModuleValues(); void ems_getMixingModuleValues(); char * ems_getThermostatModeString(_EMS_THERMOSTAT_MODE mode, char * mode_str); diff --git a/src/ems_devices.h b/src/ems_devices.h index e9ffbe6a1..cf8151cc0 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -52,6 +52,34 @@ #define EMS_OFFSET_UBASetPoints_flowtemp 0 // flow temp +// Installation settings +#define EMS_TYPE_IBASettingsMessage 0xA5 // installation settings +#define EMS_OFFSET_IBASettings_Display 0 // display +#define EMS_OFFSET_IBASettings_Language 1 // language +#define EMS_OFFSET_IBASettings_MinExtTemp 5 // min. ext. temperature +#define EMS_OFFSET_IBASettings_Building 6 // building +#define EMS_OFFSET_IBASettings_CalIntTemp 2 // cal. int. temperature +#define EMS_OFFSET_IBASettings_ClockOffset 12 // clock offset + +#define EMS_VALUE_IBASettings_LANG_GERMAN 0 +#define EMS_VALUE_IBASettings_LANG_DUTCH 1 +#define EMS_VALUE_IBASettings_LANG_FRENCH 2 +#define EMS_VALUE_IBASettings_LANG_ITALIAN 3 + +#define EMS_VALUE_IBASettings_BUILDING_LIGHT 0 +#define EMS_VALUE_IBASettings_BUILDING_MEDIUM 1 +#define EMS_VALUE_IBASettings_BUILDING_HEAVY 2 + +#define EMS_VALUE_IBASettings_DISPLAY_INTTEMP 0 +#define EMS_VALUE_IBASettings_DISPLAY_INTSETPOINT 1 +#define EMS_VALUE_IBASettings_DISPLAY_EXTTEMP 2 +#define EMS_VALUE_IBASettings_DISPLAY_BURNERTEMP 3 +#define EMS_VALUE_IBASettings_DISPLAY_WWTEMP 4 +#define EMS_VALUE_IBASettings_DISPLAY_FUNCMODE 5 +#define EMS_VALUE_IBASettings_DISPLAY_TIME 6 +#define EMS_VALUE_IBASettings_DISPLAY_DATE 7 +#define EMS_VALUE_IBASettings_DISPLAY_SMOKETEMP 9 + // Mixing Modules // MM100/MM200 (EMS Plus) #define EMS_TYPE_MMPLUSStatusMessage_HC1 0x01D7 // mixing status HC1 @@ -66,6 +94,7 @@ #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 // mixing status #define EMS_OFFSET_MMStatusMessage_flow_set 0 // flow setpoint diff --git a/src/my_config.h b/src/my_config.h index ccd09358f..0dc1ab297 100644 --- a/src/my_config.h +++ b/src/my_config.h @@ -59,6 +59,14 @@ #define TOPIC_BOILER_CMD_COMFORT "comfort" // ww comfort setting via MQTT #define TOPIC_BOILER_CMD_FLOWTEMP "flowtemp" // flowtemp value via MQTT +// MQTT for settings +#define TOPIC_SETTINGS_DATA "settings_data" // for sending settings values to MQTT +#define TOPIC_SETTINGS_CMD "settings_cmd" // for receiving settings commands via MQTT +#define TOPIC_SETTINGS_CMD_DISPLAY "display" // change display +#define TOPIC_SETTINGS_CMD_LANGUAGE "language" // change language +#define TOPIC_SETTINGS_CMD_BUILDING "building" // change building +#define TOPIC_SETTINGS_CMD_MINEXTTEMP "minextTemp" // change min. ext. temp. + // MQTT for mixing device #define TOPIC_MIXING_DATA "mixing_data" // for sending mixing device values to MQTT