From 9e3f5700e16c95541863c4e81b5adfa3344deea7 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 11 Nov 2019 23:54:59 +0100 Subject: [PATCH] code optimizations on EMS device library --- CHANGELOG.md | 1 + src/ems-esp.cpp | 93 +++-- src/ems.cpp | 894 ++++++++++++++-------------------------------- src/ems.h | 186 ++++++---- src/ems_devices.h | 209 +++++------ src/version.h | 2 +- 6 files changed, 501 insertions(+), 884 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 366310c8f..c7f7a1675 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ There are breaking changes in this release. See `publish_time` below and make su - Keeping Thermostat day/night modes separate from off/auto/manual, and setting this for the Junkers FR50 - Removed `publish_always` and use `publish_time`. For automatic mode you will need to change `publish_time` to 0 which will send MQTT every time data has changed (every 10 seconds). - Changed NTP interval from 1 hour to 12 hours +- Refactored EMS device library to make it support multi-EMS devices easier (e.g. multiple thermostats) ### Removed diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index b7f70d5d5..a3e37ff7e 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -102,7 +102,7 @@ static const command_t project_cmds[] PROGMEM = { {true, "publish_time ", "set frequency for publishing data to MQTT (0=automatic)"}, {true, "tx_mode ", "changes Tx logic. 1=EMS generic, 2=EMS+, 3=HT3"}, - {false, "info", "show current captured on the devices"}, + {false, "info", "show current values deciphered from the EMS messages"}, {false, "log ", "set logging mode to none, basic, thermostat only, solar module only, raw, jabber or verbose"}, #ifdef TESTS @@ -111,7 +111,7 @@ static const command_t project_cmds[] PROGMEM = { {false, "publish", "publish all values to MQTT"}, {false, "refresh", "fetch values from the EMS devices"}, - {false, "devices [all]", "list all supported and detected EMS devices"}, + {false, "devices", "list detected EMS devices"}, {false, "queue", "show current Tx queue"}, {false, "autodetect [quick]", "detect EMS devices and attempt to automatically set boiler and thermostat types"}, {false, "send XX ...", "send raw telegram data to EMS bus (XX are hex values)"}, @@ -143,11 +143,11 @@ void myDebugLog(const char * s) { // hc_num is 1 to 4 _EMS_THERMOSTAT_MODE _getThermostatMode(uint8_t hc_num) { _EMS_THERMOSTAT_MODE thermoMode = EMS_THERMOSTAT_MODE_UNKNOWN; - uint8_t model = ems_getThermostatModel(); - uint8_t mode = EMS_Thermostat.hc[hc_num - 1].mode; + uint8_t mode = EMS_Thermostat.hc[hc_num - 1].mode; + uint8_t model = ems_getThermostatModel(); - if (model == EMS_MODEL_RC20) { + if (model == EMS_DEVICE_FLAG_RC20) { if (mode == 0) { thermoMode = EMS_THERMOSTAT_MODE_OFF; } else if (mode == 1) { @@ -155,13 +155,13 @@ _EMS_THERMOSTAT_MODE _getThermostatMode(uint8_t hc_num) { } else if (mode == 2) { thermoMode = EMS_THERMOSTAT_MODE_AUTO; } - } else if (model == EMS_MODEL_RC300) { + } else if (model == EMS_DEVICE_FLAG_RC300) { if (mode == 0) { thermoMode = EMS_THERMOSTAT_MODE_MANUAL; } else if (mode == 1) { thermoMode = EMS_THERMOSTAT_MODE_AUTO; } - } else if (model == EMS_MODEL_FR10 || model == EMS_MODEL_FR50 || model == EMS_MODEL_FR100) { + } else if (model == EMS_DEVICE_FLAG_JUNKERS) { if (mode == 1) { thermoMode = EMS_THERMOSTAT_MODE_MANUAL; } else if (mode == 2) { @@ -181,7 +181,7 @@ _EMS_THERMOSTAT_MODE _getThermostatMode(uint8_t hc_num) { } // figures out the thermostat day/night mode depending on the thermostat type -// returns {EMS_THERMOSTAT_MODE_UNKNOWN, EMS_THERMOSTAT_MODE_OFF, EMS_THERMOSTAT_MODE_MANUAL, EMS_THERMOSTAT_MODE_AUTO, EMS_THERMOSTAT_MODE_NIGHT, EMS_THERMOSTAT_MODE_DAY} +// returns {EMS_THERMOSTAT_MODE_NIGHT, EMS_THERMOSTAT_MODE_DAY} // hc_num is 1 to 4 _EMS_THERMOSTAT_MODE _getThermostatDayMode(uint8_t hc_num) { _EMS_THERMOSTAT_MODE thermoMode = EMS_THERMOSTAT_MODE_UNKNOWN; @@ -189,19 +189,19 @@ _EMS_THERMOSTAT_MODE _getThermostatDayMode(uint8_t hc_num) { uint8_t mode = EMS_Thermostat.hc[hc_num - 1].day_mode; - if (model == EMS_MODEL_FW100 || model == EMS_MODEL_FW120 || model == EMS_MODEL_FR10 || model == EMS_MODEL_FR100 || model == EMS_MODEL_FR50) { + if (model == EMS_DEVICE_FLAG_JUNKERS) { if (mode == 3) { thermoMode = EMS_THERMOSTAT_MODE_DAY; } else if (mode == 2) { thermoMode = EMS_THERMOSTAT_MODE_NIGHT; } - } else if (model == EMS_MODEL_RC35 || model == EMS_MODEL_ES73) { + } else if (model == EMS_DEVICE_FLAG_RC35) { if (mode == 0) { thermoMode = EMS_THERMOSTAT_MODE_NIGHT; } else if (mode == 1) { thermoMode = EMS_THERMOSTAT_MODE_DAY; } - } else if (model == EMS_MODEL_RC100 || model == EMS_MODEL_RC300) { + } else if (model == EMS_DEVICE_FLAG_RC300) { if (mode == 0) { thermoMode = EMS_THERMOSTAT_MODE_NIGHT; } else if (mode == 1) { @@ -271,7 +271,7 @@ void showInfo() { myDebug_P(PSTR("%sBoiler stats:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF); // version details - myDebug_P(PSTR(" Boiler: %s"), ems_getBoilerDescription(buffer_type)); + myDebug_P(PSTR(" Boiler: %s"), ems_getDeviceDescription(EMS_DEVICE_TYPE_BOILER, buffer_type)); // active stats if (ems_getBusConnected()) { @@ -364,7 +364,7 @@ void showInfo() { if (ems_getSolarModuleEnabled()) { myDebug_P(PSTR("")); // newline myDebug_P(PSTR("%sSolar Module stats:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF); - myDebug_P(PSTR(" Solar module: %s"), ems_getSolarModuleDescription(buffer_type)); + myDebug_P(PSTR(" Solar module: %s"), ems_getDeviceDescription(EMS_DEVICE_TYPE_SOLAR, buffer_type)); _renderShortValue("Collector temperature", "C", EMS_SolarModule.collectorTemp); _renderShortValue("Bottom temperature", "C", EMS_SolarModule.bottomTemp); _renderIntValue("Pump modulation", "%", EMS_SolarModule.pumpModulation); @@ -384,7 +384,7 @@ void showInfo() { if (ems_getHeatPumpEnabled()) { myDebug_P(PSTR("")); // newline myDebug_P(PSTR("%sHeat Pump stats:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF); - myDebug_P(PSTR(" Heat Pump module: %s"), ems_getHeatPumpDescription(buffer_type)); + myDebug_P(PSTR(" Heat Pump module: %s"), ems_getDeviceDescription(EMS_DEVICE_TYPE_HEATPUMP, buffer_type)); _renderIntValue("Pump modulation", "%", EMS_HeatPump.HPModulation); _renderIntValue("Pump speed", "%", EMS_HeatPump.HPSpeed); } @@ -393,24 +393,21 @@ void showInfo() { if (ems_getThermostatEnabled()) { myDebug_P(PSTR("")); // newline myDebug_P(PSTR("%sThermostat stats:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF); - myDebug_P(PSTR(" Thermostat: %s"), ems_getThermostatDescription(buffer_type, false)); + myDebug_P(PSTR(" Thermostat: %s"), ems_getDeviceDescription(EMS_DEVICE_TYPE_THERMOSTAT, buffer_type, false)); // Render Thermostat Date & Time uint8_t model = ems_getThermostatModel(); - if ((model != EMS_MODEL_EASY)) { + if ((model != EMS_DEVICE_FLAG_EASY)) { myDebug_P(PSTR(" Thermostat time is %s"), EMS_Thermostat.datetime); } uint8_t _m_setpoint, _m_curr; switch (model) { - case EMS_MODEL_EASY: + case EMS_DEVICE_FLAG_EASY: _m_setpoint = 10; // *100 _m_curr = 10; // *100 break; - case EMS_MODEL_FR10: - case EMS_MODEL_FR50: - case EMS_MODEL_FW100: - case EMS_MODEL_FW120: + case EMS_DEVICE_FLAG_JUNKERS: _m_setpoint = 1; // *10 _m_curr = 1; // *10 break; @@ -430,7 +427,7 @@ void showInfo() { // Render Day/Night/Holiday Temperature on RC35s // there is no single setpoint temp, but one for day, night and vacation - if (model == EMS_MODEL_RC35) { + if (model == EMS_DEVICE_FLAG_RC35) { if (EMS_Thermostat.hc[hc_num - 1].summer_mode) { myDebug_P(PSTR(" Program is set to Summer mode")); } else if (EMS_Thermostat.hc[hc_num - 1].holiday_mode) { @@ -732,15 +729,15 @@ void publishEMSValues(bool force) { strlcpy(hc, THERMOSTAT_HC, sizeof(hc)); strlcat(hc, _int_to_char(s, thermostat->hc), sizeof(hc)); JsonObject dataThermostat = rootThermostat.createNestedObject(hc); + uint8_t model = ems_getThermostatModel(); // different logic depending on thermostat types - if (ems_getThermostatModel() == EMS_MODEL_EASY) { + if (model == EMS_DEVICE_FLAG_EASY) { if (thermostat->setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET) dataThermostat[THERMOSTAT_SELTEMP] = (float)thermostat->setpoint_roomTemp / 100; if (thermostat->curr_roomTemp != EMS_VALUE_SHORT_NOTSET) dataThermostat[THERMOSTAT_CURRTEMP] = (float)thermostat->curr_roomTemp / 100; - } else if ((ems_getThermostatModel() == EMS_MODEL_FR10) || (ems_getThermostatModel() == EMS_MODEL_FR50) - || (ems_getThermostatModel() == EMS_MODEL_FW100) || (ems_getThermostatModel() == EMS_MODEL_FW120)) { + } else if (model == EMS_DEVICE_FLAG_JUNKERS) { if (thermostat->setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET) dataThermostat[THERMOSTAT_SELTEMP] = (float)thermostat->setpoint_roomTemp / 10; if (thermostat->curr_roomTemp != EMS_VALUE_SHORT_NOTSET) @@ -1264,14 +1261,7 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) { } if (strcmp(first_cmd, "devices") == 0) { - if (wc == 2) { - char * second_cmd = _readWord(); - if (strcmp(second_cmd, "all") == 0) { - ems_printAllDevices(); // verbose - } - } else { - ems_printDevices(); - } + ems_printDevices(); ok = true; } @@ -1714,23 +1704,32 @@ void WebCallback(JsonObject root) { // send over EMS devices JsonArray list = emsbus.createNestedArray("devices"); + char buffer[50]; + + for (std::list<_Detected_Device>::iterator it = Devices.begin(); it != Devices.end(); ++it) { + JsonObject item = list.createNestedObject(); + + (void)ems_getDeviceTypeDescription((it)->device_id, buffer); + item["type"] = buffer; + + if ((it)->known) { + item["model"] = EMS_Devices[(it)->device_index].device_desc; + } else { + item["model"] = EMS_MODELTYPE_UNKNOWN_STRING; + } - for (std::list<_Generic_Device>::iterator it = Devices.begin(); it != Devices.end(); ++it) { - JsonObject item = list.createNestedObject(); - item["type"] = (it)->model_type; - item["model"] = (it)->model_string; item["version"] = (it)->version; item["productid"] = (it)->product_id; - char buffer[10]; + char tmp_hex[10]; // copy of my _hextoa() function from ems.cpp, to convert device_id into a 0xNN hex value string - char * p = buffer; + char * p = tmp_hex; byte nib1 = ((it)->device_id >> 4) & 0x0F; byte nib2 = ((it)->device_id >> 0) & 0x0F; *p++ = nib1 < 0xA ? '0' + nib1 : 'A' + nib1 - 0xA; *p++ = nib2 < 0xA ? '0' + nib2 : 'A' + nib2 - 0xA; *p = '\0'; // null terminate just in case - item["deviceid"] = buffer; + item["deviceid"] = tmp_hex; } // send over Thermostat data @@ -1740,18 +1739,18 @@ void WebCallback(JsonObject root) { thermostat["ok"] = true; char buffer[200]; - thermostat["tm"] = ems_getThermostatDescription(buffer, true); + thermostat["tm"] = ems_getDeviceDescription(EMS_DEVICE_TYPE_THERMOSTAT, buffer, true); uint8_t hc_num = EMS_THERMOSTAT_DEFAULTHC; // default to HC1 + uint8_t model = ems_getThermostatModel(); // Render Current & Setpoint Room Temperature - if (ems_getThermostatModel() == EMS_MODEL_EASY) { + if (model == EMS_DEVICE_FLAG_EASY) { if (EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET) thermostat["ts"] = (float)EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp / 100; if (EMS_Thermostat.hc[hc_num - 1].curr_roomTemp != EMS_VALUE_SHORT_NOTSET) thermostat["tc"] = (float)EMS_Thermostat.hc[hc_num - 1].curr_roomTemp / 100; - } else if ((ems_getThermostatModel() == EMS_MODEL_FR10) || (ems_getThermostatModel() == EMS_MODEL_FR50) || (ems_getThermostatModel() == EMS_MODEL_FW100) - || (ems_getThermostatModel() == EMS_MODEL_FW120)) { + } else if (model == EMS_DEVICE_FLAG_JUNKERS) { if (EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET) thermostat["ts"] = (float)EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp / 10; if (EMS_Thermostat.hc[hc_num - 1].curr_roomTemp != EMS_VALUE_SHORT_NOTSET) @@ -1781,7 +1780,7 @@ void WebCallback(JsonObject root) { boiler["ok"] = true; char buffer[200]; - boiler["bm"] = ems_getBoilerDescription(buffer, true); + boiler["bm"] = ems_getDeviceDescription(EMS_DEVICE_TYPE_BOILER, buffer, true); boiler["b1"] = (EMS_Boiler.tapwaterActive ? "running" : "off"); boiler["b2"] = (EMS_Boiler.heatingActive ? "active" : "off"); @@ -1808,7 +1807,7 @@ void WebCallback(JsonObject root) { sm["ok"] = true; char buffer[200]; - sm["sm"] = ems_getSolarModuleDescription(buffer, true); + sm["sm"] = ems_getDeviceDescription(EMS_DEVICE_TYPE_SOLAR, buffer, true); if (EMS_SolarModule.collectorTemp != EMS_VALUE_SHORT_NOTSET) sm["sm1"] = (float)EMS_SolarModule.collectorTemp / 10; // Collector temperature oC @@ -1841,7 +1840,7 @@ void WebCallback(JsonObject root) { if (ems_getHeatPumpEnabled()) { hp["ok"] = true; char buffer[200]; - hp["hm"] = ems_getHeatPumpDescription(buffer, true); + hp["hm"] = ems_getDeviceDescription(EMS_DEVICE_TYPE_HEATPUMP, buffer, true); if (EMS_HeatPump.HPModulation != EMS_VALUE_INT_NOTSET) hp["hp1"] = EMS_HeatPump.HPModulation; // Pump modulation % diff --git a/src/ems.cpp b/src/ems.cpp index ebea04632..79636428a 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -23,7 +23,7 @@ _EMS_Sys_Status EMS_Sys_Status; // EMS Status CircularBuffer<_EMS_TxTelegram, EMS_TX_TELEGRAM_QUEUE_MAX> EMS_TxQueue; // FIFO queue for Tx send buffer // for storing all detected EMS devices -std::list<_Generic_Device> Devices; +std::list<_Detected_Device> Devices; // macros used in the _process* functions #define _toByte(i) (EMS_RxTelegram->data[i]) @@ -101,105 +101,84 @@ void _process_MMPLUSStatusMessage(_EMS_RxTelegram * EMS_RxTelegram); /** * Recognized EMS types and the functions they call to process the telegrams - * Format: MODEL ID, TYPE ID, Description, function, emsplus */ const _EMS_Type EMS_Types[] = { // common - {EMS_MODEL_ALL, EMS_TYPE_Version, "Version", _process_Version}, - {EMS_MODEL_ALL, EMS_TYPE_UBADevices, "UBADevices", _process_UBADevices}, + {EMS_TYPE_Version, "Version", _process_Version}, + {EMS_TYPE_UBADevices, "UBADevices", _process_UBADevices}, + {EMS_TYPE_RCTime, "RCTime", _process_RCTime}, + {EMS_TYPE_RCOutdoorTempMessage, "RCOutdoorTempMessage", _process_RCOutdoorTempMessage}, - // Boiler commands - {EMS_MODEL_UBA, EMS_TYPE_UBAMonitorFast, "UBAMonitorFast", _process_UBAMonitorFast}, - {EMS_MODEL_UBA, EMS_TYPE_UBAMonitorSlow, "UBAMonitorSlow", _process_UBAMonitorSlow}, - {EMS_MODEL_UBA, EMS_TYPE_UBAMonitorWWMessage, "UBAMonitorWWMessage", _process_UBAMonitorWWMessage}, - {EMS_MODEL_UBA, EMS_TYPE_UBAParameterWW, "UBAParameterWW", _process_UBAParameterWW}, - {EMS_MODEL_UBA, EMS_TYPE_UBATotalUptimeMessage, "UBATotalUptimeMessage", _process_UBATotalUptimeMessage}, - {EMS_MODEL_UBA, EMS_TYPE_UBAMaintenanceSettingsMessage, "UBAMaintenanceSettingsMessage", nullptr}, - {EMS_MODEL_UBA, EMS_TYPE_UBAParametersMessage, "UBAParametersMessage", _process_UBAParametersMessage}, - {EMS_MODEL_UBA, EMS_TYPE_UBASetPoints, "UBASetPoints", _process_SetPoints}, + // UBA/Boiler + {EMS_TYPE_UBAMonitorFast, "UBAMonitorFast", _process_UBAMonitorFast}, + {EMS_TYPE_UBAMonitorSlow, "UBAMonitorSlow", _process_UBAMonitorSlow}, + {EMS_TYPE_UBAMonitorWWMessage, "UBAMonitorWWMessage", _process_UBAMonitorWWMessage}, + {EMS_TYPE_UBAParameterWW, "UBAParameterWW", _process_UBAParameterWW}, + {EMS_TYPE_UBATotalUptimeMessage, "UBATotalUptimeMessage", _process_UBATotalUptimeMessage}, + {EMS_TYPE_UBAMaintenanceSettingsMessage, "UBAMaintenanceSettingsMessage", nullptr}, + {EMS_TYPE_UBAParametersMessage, "UBAParametersMessage", _process_UBAParametersMessage}, + {EMS_TYPE_UBASetPoints, "UBASetPoints", _process_SetPoints}, - // SM devices - {EMS_MODEL_SM, EMS_TYPE_SM10Monitor, "SM10Monitor", _process_SM10Monitor}, - {EMS_MODEL_SM, EMS_TYPE_SM100Monitor, "SM100Monitor", _process_SM100Monitor}, - {EMS_MODEL_SM, EMS_TYPE_SM100Status, "SM100Status", _process_SM100Status}, - {EMS_MODEL_SM, EMS_TYPE_SM100Status2, "SM100Status2", _process_SM100Status2}, - {EMS_MODEL_SM, EMS_TYPE_SM100Energy, "SM100Energy", _process_SM100Energy}, - {EMS_MODEL_SM, EMS_TYPE_ISM1StatusMessage, "ISM1StatusMessage", _process_ISM1StatusMessage}, - {EMS_MODEL_SM, EMS_TYPE_ISM1Set, "ISM1Set", _process_ISM1Set}, + // Solar Module devices + {EMS_TYPE_SM10Monitor, "SM10Monitor", _process_SM10Monitor}, + {EMS_TYPE_SM100Monitor, "SM100Monitor", _process_SM100Monitor}, + {EMS_TYPE_SM100Status, "SM100Status", _process_SM100Status}, + {EMS_TYPE_SM100Status2, "SM100Status2", _process_SM100Status2}, + {EMS_TYPE_SM100Energy, "SM100Energy", _process_SM100Energy}, + {EMS_TYPE_ISM1StatusMessage, "ISM1StatusMessage", _process_ISM1StatusMessage}, + {EMS_TYPE_ISM1Set, "ISM1Set", _process_ISM1Set}, - // heatpunps - {EMS_MODEL_HP, EMS_TYPE_HPMonitor1, "HeatPumpMonitor1", _process_HPMonitor1}, - {EMS_MODEL_HP, EMS_TYPE_HPMonitor2, "HeatPumpMonitor2", _process_HPMonitor2}, + // heatpumps + {EMS_TYPE_HPMonitor1, "HeatPumpMonitor1", _process_HPMonitor1}, + {EMS_TYPE_HPMonitor2, "HeatPumpMonitor2", _process_HPMonitor2}, // RC10 - {EMS_MODEL_RC10, EMS_TYPE_RCTime, "RCTime", _process_RCTime}, - {EMS_MODEL_RC10, EMS_TYPE_RC10Set, "RC10Set", _process_RC10Set}, - {EMS_MODEL_RC10, EMS_TYPE_RC10StatusMessage, "RC10StatusMessage", _process_RC10StatusMessage}, + {EMS_TYPE_RC10Set, "RC10Set", _process_RC10Set}, + {EMS_TYPE_RC10StatusMessage, "RC10StatusMessage", _process_RC10StatusMessage}, // RC20 and RC20RF - {EMS_MODEL_RC20, EMS_TYPE_RCOutdoorTempMessage, "RCOutdoorTempMessage", _process_RCOutdoorTempMessage}, - {EMS_MODEL_RC20, EMS_TYPE_RCTime, "RCTime", _process_RCTime}, - {EMS_MODEL_RC20, EMS_TYPE_RC20Set, "RC20Set", _process_RC20Set}, - {EMS_MODEL_RC20, EMS_TYPE_RC20StatusMessage, "RC20StatusMessage", _process_RC20StatusMessage}, - - {EMS_MODEL_RC20RF, EMS_TYPE_RCOutdoorTempMessage, "RCOutdoorTempMessage", _process_RCOutdoorTempMessage}, - {EMS_MODEL_RC20RF, EMS_TYPE_RCTime, "RCTime", _process_RCTime}, - {EMS_MODEL_RC20RF, EMS_TYPE_RC20Set, "RC20Set", _process_RC20Set}, - {EMS_MODEL_RC20RF, EMS_TYPE_RC20StatusMessage, "RC20StatusMessage", _process_RC20StatusMessage}, + {EMS_TYPE_RC20Set, "RC20Set", _process_RC20Set}, + {EMS_TYPE_RC20StatusMessage, "RC20StatusMessage", _process_RC20StatusMessage}, // RC30 - {EMS_MODEL_RC30, EMS_TYPE_RCOutdoorTempMessage, "RCOutdoorTempMessage", _process_RCOutdoorTempMessage}, - {EMS_MODEL_RC30, EMS_TYPE_RCTime, "RCTime", _process_RCTime}, - {EMS_MODEL_RC30, EMS_TYPE_RC30Set, "RC30Set", _process_RC30Set}, - {EMS_MODEL_RC30, EMS_TYPE_RC30StatusMessage, "RC30StatusMessage", _process_RC30StatusMessage}, + {EMS_TYPE_RC30Set, "RC30Set", _process_RC30Set}, + {EMS_TYPE_RC30StatusMessage, "RC30StatusMessage", _process_RC30StatusMessage}, - // RC35 - {EMS_MODEL_RC35, EMS_TYPE_RCOutdoorTempMessage, "RCOutdoorTempMessage", _process_RCOutdoorTempMessage}, - {EMS_MODEL_RC35, EMS_TYPE_RCTime, "RCTime", _process_RCTime}, - {EMS_MODEL_RC35, EMS_TYPE_RC35Set_HC1, "RC35Set_HC1", _process_RC35Set}, - {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}, - {EMS_MODEL_ES73, EMS_TYPE_RCTime, "RCTime", _process_RCTime}, - {EMS_MODEL_ES73, EMS_TYPE_RC35Set_HC1, "RC35Set", _process_RC35Set}, - {EMS_MODEL_ES73, EMS_TYPE_RC35StatusMessage_HC1, "RC35StatusMessage", _process_RC35StatusMessage}, + // RC35 and ES71 + {EMS_TYPE_RC35Set_HC1, "RC35Set_HC1", _process_RC35Set}, + {EMS_TYPE_RC35StatusMessage_HC1, "RC35StatusMessage_HC1", _process_RC35StatusMessage}, + {EMS_TYPE_RC35Set_HC2, "RC35Set_HC2", _process_RC35Set}, + {EMS_TYPE_RC35StatusMessage_HC2, "RC35StatusMessage_HC2", _process_RC35StatusMessage}, + {EMS_TYPE_RC35Set_HC3, "RC35Set_HC2", _process_RC35Set}, + {EMS_TYPE_RC35StatusMessage_HC3, "RC35StatusMessage_HC3", _process_RC35StatusMessage}, + {EMS_TYPE_RC35Set_HC4, "RC35Set_HC4", _process_RC35Set}, + {EMS_TYPE_RC35StatusMessage_HC4, "RC35StatusMessage_HC4", _process_RC35StatusMessage}, // Easy - {EMS_MODEL_EASY, EMS_TYPE_EasyStatusMessage, "EasyStatusMessage", _process_EasyStatusMessage}, + {EMS_TYPE_EasyStatusMessage, "EasyStatusMessage", _process_EasyStatusMessage}, // Nefit 1010, RC300, RC310 (EMS Plus) - {EMS_MODEL_ALL, EMS_TYPE_RCPLUSStatusMessage_HC1, "RCPLUSStatusMessage_HC1", _process_RCPLUSStatusMessage}, - {EMS_MODEL_ALL, EMS_TYPE_RCPLUSStatusMessage_HC2, "RCPLUSStatusMessage_HC2", _process_RCPLUSStatusMessage}, - {EMS_MODEL_ALL, EMS_TYPE_RCPLUSStatusMessage_HC3, "RCPLUSStatusMessage_HC3", _process_RCPLUSStatusMessage}, - {EMS_MODEL_ALL, EMS_TYPE_RCPLUSStatusMessage_HC4, "RCPLUSStatusMessage_HC4", _process_RCPLUSStatusMessage}, - {EMS_MODEL_ALL, EMS_TYPE_RCPLUSSet, "RCPLUSSetMessage", _process_RCPLUSSetMessage}, - {EMS_MODEL_ALL, EMS_TYPE_RCPLUSStatusMode, "RCPLUSStatusMode", _process_RCPLUSStatusMode}, + {EMS_TYPE_RCPLUSStatusMessage_HC1, "RCPLUSStatusMessage_HC1", _process_RCPLUSStatusMessage}, + {EMS_TYPE_RCPLUSStatusMessage_HC2, "RCPLUSStatusMessage_HC2", _process_RCPLUSStatusMessage}, + {EMS_TYPE_RCPLUSStatusMessage_HC3, "RCPLUSStatusMessage_HC3", _process_RCPLUSStatusMessage}, + {EMS_TYPE_RCPLUSStatusMessage_HC4, "RCPLUSStatusMessage_HC4", _process_RCPLUSStatusMessage}, + {EMS_TYPE_RCPLUSSet, "RCPLUSSetMessage", _process_RCPLUSSetMessage}, + {EMS_TYPE_RCPLUSStatusMode, "RCPLUSStatusMode", _process_RCPLUSStatusMode}, // Junkers FR10 - {EMS_MODEL_ALL, EMS_TYPE_JunkersStatusMessage, "JunkersStatusMessage", _process_JunkersStatusMessage}, + {EMS_TYPE_JunkersStatusMessage, "JunkersStatusMessage", _process_JunkersStatusMessage}, // Mixing devices - {EMS_MODEL_MM, EMS_TYPE_MMPLUSStatusMessage_HC1, "MMPLUSStatusMessage_HC1", _process_MMPLUSStatusMessage}, - {EMS_MODEL_MM, EMS_TYPE_MMPLUSStatusMessage_HC2, "MMPLUSStatusMessage_HC2", _process_MMPLUSStatusMessage}, + {EMS_TYPE_MMPLUSStatusMessage_HC1, "MMPLUSStatusMessage_HC1", _process_MMPLUSStatusMessage}, + {EMS_TYPE_MMPLUSStatusMessage_HC2, "MMPLUSStatusMessage_HC2", _process_MMPLUSStatusMessage} }; -// calculate sizes of arrays at compile -uint8_t _EMS_Types_max = ArraySize(EMS_Types); // number of defined types -uint8_t _Boiler_Devices_max = ArraySize(Boiler_Devices); // number of boiler models -uint8_t _SolarModule_Devices_max = ArraySize(SolarModule_Devices); // number of solar module types -uint8_t _Other_Devices_max = ArraySize(Other_Devices); // number of other ems devices -uint8_t _Thermostat_Devices_max = ArraySize(Thermostat_Devices); // number of defined thermostat types -uint8_t _HeatPump_Devices_max = ArraySize(HeatPump_Devices); // number of defined heatpump types -uint8_t _Mixing_Devices_max = ArraySize(Mixing_Devices); // number of mixing device types +// calculate sizes of arrays at compile time +uint8_t _EMS_Types_max = ArraySize(EMS_Types); +uint8_t _EMS_Devices_max = ArraySize(EMS_Devices); +uint8_t _EMS_Devices_Types_max = ArraySize(EMS_Devices_Types); // these structs contain the data we store from the specific EMS devices _EMS_Boiler EMS_Boiler; // for boiler @@ -207,7 +186,6 @@ _EMS_Thermostat EMS_Thermostat; // for thermostat _EMS_SolarModule EMS_SolarModule; // for solar modules _EMS_HeatPump EMS_HeatPump; // for heatpumps _EMS_Mixing EMS_Mixing; // for mixing devices -_EMS_Other EMS_Other; // for other known EMS devices // CRC lookup table with poly 12 for faster checking const uint8_t ems_crc_table[] = {0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, 0x20, 0x22, 0x24, 0x26, @@ -279,7 +257,6 @@ void ems_init() { EMS_Mixing.hc[i].pumpMod = EMS_VALUE_INT_NOTSET; EMS_Mixing.hc[i].valveStatus = EMS_VALUE_INT_NOTSET; EMS_Mixing.hc[i].device_id = EMS_ID_NONE; - EMS_Mixing.hc[i].model_id = EMS_MODEL_NONE; EMS_Mixing.hc[i].product_id = EMS_ID_NONE; } @@ -339,7 +316,6 @@ void ems_init() { EMS_SolarModule.EnergyToday = EMS_VALUE_USHORT_NOTSET; EMS_SolarModule.EnergyTotal = EMS_VALUE_USHORT_NOTSET; EMS_SolarModule.device_id = EMS_ID_NONE; - EMS_SolarModule.model_id = EMS_MODEL_NONE; EMS_SolarModule.product_id = EMS_ID_NONE; EMS_SolarModule.pumpWorkMin = EMS_VALUE_LONG_NOTSET; EMS_SolarModule.setpoint_maxBottomTemp = EMS_VALUE_SHORT_NOTSET; @@ -348,7 +324,6 @@ void ems_init() { EMS_HeatPump.HPModulation = EMS_VALUE_INT_NOTSET; EMS_HeatPump.HPSpeed = EMS_VALUE_INT_NOTSET; EMS_HeatPump.device_id = EMS_ID_NONE; - EMS_HeatPump.model_id = EMS_MODEL_NONE; EMS_HeatPump.product_id = EMS_ID_NONE; // calculated values @@ -360,7 +335,6 @@ void ems_init() { strlcpy(EMS_Boiler.version, "?", sizeof(EMS_Boiler.version)); // set thermostat model - EMS_Thermostat.model_id = EMS_MODEL_NONE; EMS_Thermostat.product_id = EMS_ID_NONE; strlcpy(EMS_Thermostat.version, "?", sizeof(EMS_Thermostat.version)); @@ -407,11 +381,11 @@ bool ems_getHeatPumpEnabled() { } uint8_t ems_getThermostatModel() { - return (EMS_Thermostat.model_id); + return (EMS_Thermostat.device_flags & 0x7F); // strip 7th bit } uint8_t ems_getSolarModuleModel() { - return (EMS_SolarModule.model_id); + return (EMS_SolarModule.device_flags); } void ems_setTxDisabled(bool b) { @@ -500,7 +474,7 @@ uint8_t _crcCalculator(uint8_t * data, uint8_t len) { * Find the pointer to the EMS_Types array for a given type ID * or -1 if not found */ -int _ems_findType(uint16_t type) { +int8_t _ems_findType(uint16_t type) { uint8_t i = 0; bool typeFound = false; // scan through known ID types @@ -612,14 +586,6 @@ void _ems_sendTelegram() { // we don't remove from the queue yet _EMS_TxTelegram EMS_TxTelegram = EMS_TxQueue.first(); - /* - // if there is no destination, also delete it from the queue - if (EMS_TxTelegram.dest == EMS_ID_NONE) { - EMS_TxQueue.shift(); // remove from queue - return; - } - */ - // if we're in raw mode just fire and forget if (EMS_TxTelegram.action == EMS_TX_TELEGRAM_RAW) { EMS_TxTelegram.data[EMS_TxTelegram.length - 1] = _crcCalculator(EMS_TxTelegram.data, EMS_TxTelegram.length); // add the CRC @@ -717,7 +683,6 @@ void _ems_sendTelegram() { } } - /** * Takes the last write command and turns into a validate request * placing it on the Tx queue @@ -770,16 +735,6 @@ void ems_dumpBuffer(const char * prefix, uint8_t * telegram, uint8_t length) { static char output_str[200] = {0}; static char buffer[16] = {0}; - /* - // we only care about known devices - if (length) { - uint8_t dev = telegram[0] & 0x7F; - if (!((dev == 0x04)||(dev == 0x08)||(dev == 0x09)||(dev == 0x0a) - ||(dev == 0x01)||(dev == 0x0b)||(dev == 0x10))) - return; - } -*/ - strlcpy(output_str, "(", sizeof(output_str)); strlcat(output_str, COLOR_CYAN, sizeof(output_str)); strlcat(output_str, _smallitoa((uint8_t)((timestamp / 3600000) % 24), buffer), sizeof(output_str)); @@ -801,7 +756,6 @@ void ems_dumpBuffer(const char * prefix, uint8_t * telegram, uint8_t length) { strlcat(output_str, _hextoa(EMS_Sys_Status.emsTxStatus, buffer), sizeof(output_str)); strlcat(output_str, ": ", sizeof(output_str)); - // print whole buffer, don't interpret any data for (int i = 0; i < (length); i++) { strlcat(output_str, _hextoa(telegram[i], buffer), sizeof(output_str)); @@ -839,7 +793,7 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) { } /* - * It may happen that we where interrupted (for instance by WIFI activity) and the + * It may happen that we were interrupted (for instance by WIFI activity) and the * buffer isn't valid anymore, so we must not answer at all... */ if (EMS_Sys_Status.emsRxStatus != EMS_RX_STATUS_IDLE) { @@ -982,51 +936,23 @@ void _printMessage(_EMS_RxTelegram * EMS_RxTelegram) { char output_str[200] = {0}; char buffer[16] = {0}; char color_s[20] = {0}; + char type_s[30]; // source - if (src == EMS_Boiler.device_id) { - strlcpy(output_str, "Boiler", sizeof(output_str)); - } else if (src == EMS_Thermostat.device_id) { - strlcpy(output_str, "Thermostat", sizeof(output_str)); - } else if (src == EMS_ID_SM) { - strlcpy(output_str, "SM", sizeof(output_str)); - } else if (src == EMS_ID_HP) { - strlcpy(output_str, "HP", sizeof(output_str)); - } else if (src == EMS_ID_GATEWAY) { - strlcpy(output_str, "Gateway", sizeof(output_str)); - } else { - strlcpy(output_str, "0x", sizeof(output_str)); - strlcat(output_str, _hextoa(src, buffer), sizeof(output_str)); - } - + ems_getDeviceTypeDescription(src, type_s); + strlcpy(output_str, type_s, sizeof(output_str)); strlcat(output_str, " -> ", sizeof(output_str)); // destination + (void)ems_getDeviceTypeDescription(dest, type_s); + strlcat(output_str, type_s, sizeof(output_str)); + if (dest == EMS_ID_ME) { - strlcat(output_str, "me", sizeof(output_str)); - strlcpy(color_s, COLOR_YELLOW, sizeof(color_s)); + strlcpy(color_s, COLOR_YELLOW, sizeof(color_s)); // me } else if (dest == EMS_ID_NONE) { - strlcat(output_str, "all", sizeof(output_str)); - strlcpy(color_s, COLOR_GREEN, sizeof(color_s)); - } else if (dest == EMS_Boiler.device_id) { - strlcat(output_str, "Boiler", sizeof(output_str)); - strlcpy(color_s, COLOR_MAGENTA, sizeof(color_s)); - } else if (dest == EMS_ID_SM) { - strlcat(output_str, "SM", sizeof(output_str)); - strlcpy(color_s, COLOR_MAGENTA, sizeof(color_s)); - } else if (dest == EMS_ID_HP) { - strlcat(output_str, "HP", sizeof(output_str)); - strlcpy(color_s, COLOR_MAGENTA, sizeof(color_s)); - } else if (dest == EMS_ID_GATEWAY) { - strlcat(output_str, "Gateway", sizeof(output_str)); - strlcpy(color_s, COLOR_MAGENTA, sizeof(color_s)); - } else if (dest == EMS_Thermostat.device_id) { - strlcat(output_str, "Thermostat", sizeof(output_str)); - strlcpy(color_s, COLOR_MAGENTA, sizeof(color_s)); + strlcpy(color_s, COLOR_GREEN, sizeof(color_s)); // broadcast } else { - strlcat(output_str, "0x", sizeof(output_str)); - strlcat(output_str, _hextoa(dest, buffer), sizeof(output_str)); - strlcpy(color_s, COLOR_MAGENTA, sizeof(color_s)); + strlcpy(color_s, COLOR_MAGENTA, sizeof(color_s)); // everything else } if (length) { @@ -1086,8 +1012,7 @@ void _ems_processTelegram(_EMS_RxTelegram * EMS_RxTelegram) { while (i < _EMS_Types_max) { if (EMS_Types[i].type == type) { - // is it a broadcast or something sent to us? - // we don't really care where it is from + // is it a broadcast (dest=0x00) or something sent to us (dest=0x08)? if ((dest == EMS_ID_NONE) || (dest == EMS_ID_ME)) { typeFound = true; break; @@ -1882,7 +1807,7 @@ void _process_SetPoints(_EMS_RxTelegram * EMS_RxTelegram) { * common for all thermostats */ void _process_RCTime(_EMS_RxTelegram * EMS_RxTelegram) { - if ((EMS_Thermostat.model_id == EMS_MODEL_EASY)) { + if ((EMS_Thermostat.device_flags == EMS_DEVICE_FLAG_EASY)) { return; // not supported } @@ -1918,84 +1843,54 @@ void ems_clearDeviceList() { /* * add an EMS device to our list of detected devices if its unique - * model_type : 1=boiler, 2=thermostat, 3=sm, 4=other, 5=unknown + * returns true if already in list */ -void _addDevice(uint8_t model_type, uint8_t src, uint8_t product_id, char * version, uint8_t i) { - _Generic_Device device; +bool _addDevice(_EMS_DEVICE_TYPE device_type, uint8_t product_id, uint8_t device_id, uint8_t device_index, const char * version, const char * device_desc) { + _Detected_Device device; // check for duplicates - bool found = false; - for (std::list<_Generic_Device>::iterator it = Devices.begin(); it != Devices.end(); ++it) { - if (((it)->product_id == product_id) && ((it)->device_id == src)) { - found = true; // it already exists in the list + // a combi of product_id and device_id make it unique + for (std::list<_Detected_Device>::iterator it = Devices.begin(); it != Devices.end(); ++it) { + if (((it)->product_id == product_id) && ((it)->device_id == device_id)) { + return (true); // it already exists in the list, don't add } } - char device_type[500]; - strlcpy(device_type, "EMS Device recognized as ", sizeof(device_type)); + // create a new record and add it to list + device.device_type = device_type; + device.product_id = product_id; + device.device_id = device_id; + device.device_index = device_index; // where it is in the EMS_Devices table + strlcpy(device.version, version, sizeof(device.version)); + device.known = (device_type != EMS_DEVICE_TYPE_UNKNOWN); + Devices.push_back(device); - switch (model_type) { - case EMS_MODELTYPE_BOILER: - strlcat(device_type, "Boiler", sizeof(device_type)); - strlcpy(device.model_string, Boiler_Devices[i].model_string, sizeof(device.model_string)); - break; - case EMS_MODELTYPE_THERMOSTAT: - strlcat(device_type, "Thermostat", sizeof(device_type)); - strlcpy(device.model_string, Thermostat_Devices[i].model_string, sizeof(device.model_string)); - break; - case EMS_MODELTYPE_SM: - strlcat(device_type, "Solar Module", sizeof(device_type)); - strlcpy(device.model_string, SolarModule_Devices[i].model_string, sizeof(device.model_string)); - break; - case EMS_MODELTYPE_HP: - strlcat(device_type, "Heat Pump", sizeof(device_type)); - strlcpy(device.model_string, HeatPump_Devices[i].model_string, sizeof(device.model_string)); - break; - case EMS_MODELTYPE_MIXING: - strlcat(device_type, "Mixing Device", sizeof(device_type)); - strlcpy(device.model_string, Mixing_Devices[i].model_string, sizeof(device.model_string)); - break; - case EMS_MODELTYPE_OTHER: - strlcat(device_type, "Other", sizeof(device_type)); - strlcpy(device.model_string, Other_Devices[i].model_string, sizeof(device.model_string)); - break; - case EMS_MODELTYPE_UNKNOWN: - default: - strlcat(device_type, "?", sizeof(device_type)); - strlcpy(device.model_string, EMS_MODELTYPE_UNKNOWN_STRING, sizeof(device.model_string)); - break; + char line[500]; + strlcpy(line, "New EMS Device recognized as a", sizeof(line)); + + // get type as a string + char type_s[50]; + if (ems_getDeviceTypeDescription(device_id, type_s)) { + strlcat(line, type_s, sizeof(line)); + } else { + strlcat(line, "?", sizeof(line)); } char tmp[6] = {0}; // for formatting numbers - strlcat(device_type, ": ", sizeof(device_type)); - strlcat(device_type, device.model_string, sizeof(device_type)); - strlcat(device_type, " (DeviceID:0x", sizeof(device_type)); - strlcat(device_type, _hextoa(src, tmp), sizeof(device_type)); + strlcat(line, ": ", sizeof(line)); + strlcat(line, device_desc, sizeof(line)); + strlcat(line, " (DeviceID:0x", sizeof(line)); + strlcat(line, _hextoa(device_id, tmp), sizeof(line)); + strlcat(line, " ProductID:", sizeof(line)); + strlcat(line, itoa(product_id, tmp, 10), sizeof(line)); + strlcat(line, " Version:", sizeof(line)); + strlcat(line, version, sizeof(line)); + strlcat(line, ")", sizeof(line)); - strlcat(device_type, " ProductID:", sizeof(device_type)); - strlcat(device_type, itoa(product_id, tmp, 10), sizeof(device_type)); + myDebug(line); // print it - strlcat(device_type, " Version:", sizeof(device_type)); - strlcat(device_type, version, sizeof(device_type)); - - strlcat(device_type, ")", sizeof(device_type)); - - // if already exists mention it - if (found) { - strlcat(device_type, " **already active**", sizeof(device_type)); - myDebug(device_type); // print it - return; // exit - } - - myDebug(device_type); // print it - - // create a new record and add it to list - device.model_type = model_type; - device.product_id = product_id; - device.device_id = src; - strlcpy(device.version, version, sizeof(device.version)); - Devices.push_back(device); + return false; // added, wasn't a duplicate } /** @@ -2038,7 +1933,7 @@ void _process_UBADevices(_EMS_RxTelegram * EMS_RxTelegram) { } /** - * type 0x02 - get the firmware version and type of an EMS device + * type 0x02 - get the version and type of an EMS device * look up known devices via the product id and make it active if not already setup */ void _process_Version(_EMS_RxTelegram * EMS_RxTelegram) { @@ -2060,167 +1955,76 @@ void _process_Version(_EMS_RxTelegram * EMS_RxTelegram) { } } - uint8_t product_id = _toByte(offset); + uint8_t device_id = EMS_RxTelegram->src; // device ID - // print version as "%02d.%02d" + // get version as XX.XX char version[10] = {0}; char buf[6] = {0}; strlcpy(version, _smallitoa(_toByte(offset + 1), buf), sizeof(version)); strlcat(version, ".", sizeof(version)); strlcat(version, _smallitoa(_toByte(offset + 2), buf), sizeof(version)); - // see if its a known boiler - int i = 0; - bool typeFound = false; - while (i < _Boiler_Devices_max) { - if ((Boiler_Devices[i].product_id == product_id) && ((EMS_RxTelegram->src & 0x7F) == EMS_ID_BOILER)) { + // scan through known devices matching the productid + uint8_t product_id = _toByte(offset); + uint8_t i = 0; + bool typeFound = false; + while (i < _EMS_Devices_max) { + if (EMS_Devices[i].product_id == product_id) { typeFound = true; // we have a matching product id. i is the index. break; } i++; } - if (typeFound) { - // its a boiler, add to list - _addDevice(EMS_MODELTYPE_BOILER, EMS_RxTelegram->src, product_id, version, i); // type 1 = boiler - - // if its a boiler set it, unless it already has been set by checking for a productID - // it will take the first one found in the list - if ((EMS_Boiler.device_id == EMS_ID_NONE) || ((EMS_Boiler.device_id == EMS_ID_BOILER) && EMS_Boiler.product_id == EMS_ID_NONE)) { - /* - myDebug_P(PSTR("* Setting Boiler to model %s (DeviceID:0x%02X ProductID:%d Version:%s)"), - Boiler_Devices[i].model_string, - EMS_ID_BOILER, - product_id, - version); - */ - - EMS_Boiler.device_id = EMS_ID_BOILER; - EMS_Boiler.product_id = Boiler_Devices[i].product_id; - strlcpy(EMS_Boiler.version, version, sizeof(EMS_Boiler.version)); - - ems_getBoilerValues(); // get Boiler values that we would usually have to wait for - } + // if not found, just add it + if (!typeFound) { + (void)_addDevice(EMS_DEVICE_TYPE_UNKNOWN, product_id, device_id, 0xFF, version, EMS_MODELTYPE_UNKNOWN_STRING); // use device_index of 255 return; } - // its not a boiler, maybe its a known thermostat? - i = 0; - while (i < _Thermostat_Devices_max) { - if (Thermostat_Devices[i].product_id == product_id) { - typeFound = true; // we have a matching product id. i is the index. - break; - } - i++; + // we recognized it, see if we already have it in our recognized list + if (_addDevice(EMS_Devices[i].type, product_id, device_id, i, version, EMS_Devices[i].device_desc)) { + return; // already in list } - if (typeFound) { - // its a known thermostat, add to list - _addDevice(EMS_MODELTYPE_THERMOSTAT, EMS_RxTelegram->src, product_id, version, i); + // its a new entry, set the specifics + uint8_t flags = EMS_Devices[i].flags; - // if we don't have a thermostat set, use this one. it will pick the first one. - if (((EMS_Thermostat.device_id == EMS_ID_NONE) || (EMS_Thermostat.model_id == EMS_MODEL_NONE) - || (EMS_Thermostat.device_id == Thermostat_Devices[i].device_id)) - && EMS_Thermostat.product_id == EMS_ID_NONE) { - /* - myDebug_P(PSTR("* Setting Thermostat to %s (DeviceID:0x%02X ProductID:%d Version:%s)"), - Thermostat_Devices[i].model_string, - Thermostat_Devices[i].device_id, - product_id, - version); - */ - - EMS_Thermostat.model_id = Thermostat_Devices[i].model_id; - EMS_Thermostat.device_id = EMS_RxTelegram->src; - EMS_Thermostat.write_supported = Thermostat_Devices[i].write_supported; - EMS_Thermostat.product_id = product_id; - strlcpy(EMS_Thermostat.version, version, sizeof(EMS_Thermostat.version)); - - // get Thermostat values (if supported) - ems_getThermostatValues(); - } - return; - } - - - // look for Solar Modules - i = 0; - while (i < _SolarModule_Devices_max) { - if (SolarModule_Devices[i].product_id == product_id) { - typeFound = true; // we have a matching product id. i is the index. - break; - } - i++; - } - - if (typeFound) { - // its a known SM, add to list - _addDevice(EMS_MODELTYPE_SM, EMS_RxTelegram->src, product_id, version, i); - - // myDebug_P(PSTR("Solar Module support enabled.")); - EMS_SolarModule.device_id = EMS_ID_SM; - EMS_SolarModule.product_id = product_id; + if (EMS_Devices[i].type == EMS_DEVICE_TYPE_BOILER) { + EMS_Boiler.device_id = device_id; + EMS_Boiler.product_id = product_id; + EMS_Boiler.device_flags = flags; + EMS_Boiler.device_index = i; + strlcpy(EMS_Boiler.version, version, sizeof(EMS_Boiler.version)); + ems_getBoilerValues(); // get Boiler values that we would usually have to wait for + } else if (EMS_Devices[i].type == EMS_DEVICE_TYPE_THERMOSTAT) { + EMS_Thermostat.device_id = device_id; + EMS_Thermostat.device_flags = (flags & 0x7F); // remove 7th bit + EMS_Thermostat.write_supported = (flags & EMS_DEVICE_FLAG_NO_WRITE) == 0; + EMS_Thermostat.product_id = product_id; + EMS_Thermostat.device_index = i; + strlcpy(EMS_Thermostat.version, version, sizeof(EMS_Thermostat.version)); + ems_getThermostatValues(); // get Thermostat values + } else if (EMS_Devices[i].type == EMS_DEVICE_TYPE_SOLAR) { + EMS_SolarModule.device_id = device_id; + EMS_SolarModule.product_id = product_id; + EMS_SolarModule.device_flags = flags; + EMS_SolarModule.device_index = i; strlcpy(EMS_SolarModule.version, version, sizeof(EMS_SolarModule.version)); - - // fetch Solar Module values - ems_getSolarModuleValues(); - return; - } - - // look for heatpumps - i = 0; - while (i < _HeatPump_Devices_max) { - if (HeatPump_Devices[i].product_id == product_id) { - typeFound = true; // we have a matching product id. i is the index. - break; - } - i++; - } - - if (typeFound) { - // its a known SM, add to list - _addDevice(EMS_MODELTYPE_HP, EMS_RxTelegram->src, product_id, version, i); - - // myDebug_P(PSTR("Heat Pump support enabled.")); - EMS_HeatPump.device_id = EMS_ID_HP; - EMS_HeatPump.product_id = product_id; + ems_getSolarModuleValues(); // fetch Solar Module values + } else if (EMS_Devices[i].type == EMS_DEVICE_TYPE_HEATPUMP) { + EMS_HeatPump.device_id = device_id; + EMS_HeatPump.product_id = product_id; + EMS_HeatPump.device_flags = flags; + EMS_HeatPump.device_index = i; strlcpy(EMS_HeatPump.version, version, sizeof(EMS_HeatPump.version)); - return; - } - - // look for mixing devices - i = 0; - while (i < _Mixing_Devices_max) { - if (Mixing_Devices[i].product_id == product_id) { - typeFound = true; - break; - } - i++; - } - - if (typeFound) { - _addDevice(EMS_MODELTYPE_MIXING, EMS_RxTelegram->src, product_id, version, i); - ems_doReadCommand(EMS_TYPE_MMPLUSStatusMessage_HC1, EMS_RxTelegram->src); - EMS_Mixing.detected = true; - return; - } - - // finally look for the other EMS devices - i = 0; - while (i < _Other_Devices_max) { - if (Other_Devices[i].product_id == product_id) { - typeFound = true; // we have a matching product id. i is the index. - break; - } - i++; - } - - if (typeFound) { - // its a known other device, add to list - _addDevice(EMS_MODELTYPE_OTHER, EMS_RxTelegram->src, product_id, version, i); - } else { - // didn't recognize, add to list anyway - _addDevice(EMS_MODELTYPE_UNKNOWN, EMS_RxTelegram->src, product_id, version, 0); + } else if (EMS_Devices[i].type == EMS_DEVICE_TYPE_MIXING) { + EMS_Mixing.device_id = device_id; + EMS_Mixing.product_id = product_id; + EMS_Mixing.device_index = i; + EMS_Mixing.device_flags = flags; + EMS_Mixing.detected = true; + ems_doReadCommand(EMS_TYPE_MMPLUSStatusMessage_HC1, device_id); // fetch MM values } } @@ -2296,24 +2100,23 @@ void ems_getThermostatValues() { return; } - uint8_t model_id = EMS_Thermostat.model_id; - uint8_t device_id = EMS_Thermostat.device_id; + uint8_t device_flags = EMS_Thermostat.device_flags; + uint8_t device_id = EMS_Thermostat.device_id; uint8_t statusMsg, opMode; - switch (model_id) { - case EMS_MODEL_RC20: + switch (device_flags) { + case EMS_DEVICE_FLAG_RC20: ems_doReadCommand(EMS_TYPE_RC20StatusMessage, device_id); // to get the temps ems_doReadCommand(EMS_TYPE_RC20Set, device_id); // to get the mode break; - case EMS_MODEL_RC30: + case EMS_DEVICE_FLAG_RC30: ems_doReadCommand(EMS_TYPE_RC30StatusMessage, device_id); // to get the temps ems_doReadCommand(EMS_TYPE_RC30Set, device_id); // to get the mode break; - case EMS_MODEL_EASY: + case EMS_DEVICE_FLAG_EASY: ems_doReadCommand(EMS_TYPE_EasyStatusMessage, device_id); break; - case EMS_MODEL_RC35: - case EMS_MODEL_ES73: + case EMS_DEVICE_FLAG_RC35: for (uint8_t hc_num = 1; hc_num <= EMS_THERMOSTAT_MAXHC; hc_num++) { if (hc_num == 1) { statusMsg = EMS_TYPE_RC35StatusMessage_HC1; @@ -2332,7 +2135,7 @@ void ems_getThermostatValues() { ems_doReadCommand(opMode, device_id); // to get the mode } break; - case EMS_MODEL_RC300: + case EMS_DEVICE_FLAG_RC300: ems_doReadCommand(EMS_TYPE_RCPLUSStatusMessage_HC1, device_id); ems_doReadCommand(EMS_TYPE_RCPLUSStatusMessage_HC2, device_id); ems_doReadCommand(EMS_TYPE_RCPLUSStatusMessage_HC3, device_id); @@ -2360,189 +2163,96 @@ void ems_getBoilerValues() { */ void ems_getSolarModuleValues() { if (ems_getSolarModuleEnabled()) { - if (EMS_SolarModule.product_id == EMS_PRODUCTID_SM10) { + if (EMS_SolarModule.device_flags == EMS_DEVICE_FLAG_SM10) { ems_doReadCommand(EMS_TYPE_SM10Monitor, EMS_ID_SM); // fetch all from SM10Monitor - } else if ((EMS_SolarModule.product_id == EMS_PRODUCTID_SM100) || (EMS_SolarModule.product_id == EMS_PRODUCTID_SM50)) { + } else if (EMS_SolarModule.device_flags == EMS_DEVICE_FLAG_SM100) { ems_doReadCommand(EMS_TYPE_SM100Monitor, EMS_ID_SM); // fetch all from SM100Monitor } } } /** - * returns current thermostat type as a string - * by looking up the product_id + * takes a device_id and tries to find the corresponding type name (e.g. Boiler) + * If it can't find it, it will use the hex value and function returns false */ -char * ems_getThermostatDescription(char * buffer, bool name_only) { - uint8_t size = 128; - if (!ems_getThermostatEnabled()) { - strlcpy(buffer, "", size); - } else { - int i = 0; - bool found = false; - char tmp[6] = {0}; +bool ems_getDeviceTypeDescription(uint8_t device_id, char * buffer) { + uint8_t i = 0; + bool typeFound = false; - // scan through known ID types - while (i < _Thermostat_Devices_max) { - if (Thermostat_Devices[i].product_id == EMS_Thermostat.product_id) { - found = true; // we have a match - break; - } - i++; + // scan through known ID types + while (i < _EMS_Devices_Types_max) { + if (EMS_Devices_Types[i].device_id == device_id) { + typeFound = true; // we have a match + break; } - - if (found) { - strlcpy(buffer, Thermostat_Devices[i].model_string, size); - if (name_only) { - return buffer; // only interested in the model name - } - } else { - strlcpy(buffer, "DeviceID:0x", size); - strlcat(buffer, _hextoa(EMS_Thermostat.device_id, tmp), size); - } - - strlcat(buffer, " (ProductID:", size); - if (EMS_Thermostat.product_id == EMS_ID_NONE) { - strlcat(buffer, "?", size); - } else { - strlcat(buffer, itoa(EMS_Thermostat.product_id, tmp, 10), size); - } - strlcat(buffer, " Version:", size); - strlcat(buffer, EMS_Thermostat.version, size); - strlcat(buffer, ")", size); + i++; } - return buffer; + if (typeFound) { + strlcpy(buffer, EMS_Devices_Types[i].device_type_string, 30); + return true; + } else { + // print as hex value + char hexbuffer[16] = {0}; + strlcpy(buffer, "0x", 30); + strlcat(buffer, _hextoa(device_id, hexbuffer), 30); + return false; + } } -/** - * returns current boiler type as a string - */ -char * ems_getBoilerDescription(char * buffer, bool name_only) { - uint8_t size = 128; - if (!ems_getBoilerEnabled()) { - strlcpy(buffer, "", size); - } else { - int i = 0; - bool found = false; - char tmp[6] = {0}; - - // scan through known ID types - while (i < _Boiler_Devices_max) { - if (Boiler_Devices[i].product_id == EMS_Boiler.product_id) { - found = true; // we have a match - break; - } - i++; - } - if (found) { - strlcpy(buffer, Boiler_Devices[i].model_string, size); - if (name_only) { - return buffer; // only interested in the model name - } - } else { - strlcpy(buffer, "DeviceID:0x", size); - strlcat(buffer, _hextoa(EMS_Boiler.device_id, tmp), size); - } - - strlcat(buffer, " (ProductID:", size); - if (EMS_Boiler.product_id == EMS_ID_NONE) { - strlcat(buffer, "?", size); - } else { - strlcat(buffer, itoa(EMS_Boiler.product_id, tmp, 10), size); - } - strlcat(buffer, " Version:", size); - strlcat(buffer, EMS_Boiler.version, size); - strlcat(buffer, ")", size); - } - - return buffer; -} /** - * returns current Solar Module type as a string + * returns current device details as a string for known thermostat,boiler,solar and heatpump */ -char * ems_getSolarModuleDescription(char * buffer, bool name_only) { - uint8_t size = 128; - if (!ems_getSolarModuleEnabled()) { - strlcpy(buffer, "", size); - } else { - int i = 0; - bool found = false; - char tmp[6] = {0}; +char * ems_getDeviceDescription(_EMS_DEVICE_TYPE device_type, char * buffer, bool name_only) { + const uint8_t size = 128; + bool enabled = false; + uint8_t device_id; + uint8_t device_index = 0; + char * version; - // scan through known ID types - while (i < _SolarModule_Devices_max) { - if (SolarModule_Devices[i].product_id == EMS_SolarModule.product_id) { - found = true; // we have a match - break; - } - i++; - } - if (found) { - strlcpy(buffer, SolarModule_Devices[i].model_string, size); - if (name_only) { - return buffer; // only interested in the model name - } - } else { - strlcpy(buffer, "DeviceID:0x", size); - strlcat(buffer, _hextoa(EMS_SolarModule.device_id, tmp), size); - } - - strlcat(buffer, " (ProductID:", size); - if (EMS_SolarModule.product_id == EMS_ID_NONE) { - strlcat(buffer, "?", size); - } else { - strlcat(buffer, itoa(EMS_SolarModule.product_id, tmp, 10), size); - } - strlcat(buffer, " Version:", size); - strlcat(buffer, EMS_SolarModule.version, size); - strlcat(buffer, ")", size); + if (device_type == EMS_DEVICE_TYPE_THERMOSTAT) { + enabled = ems_getThermostatEnabled(); + device_id = EMS_Thermostat.device_id; + device_index = EMS_Thermostat.device_index; + version = EMS_Thermostat.version; + } else if (device_type == EMS_DEVICE_TYPE_BOILER) { + enabled = ems_getBoilerEnabled(); + device_id = EMS_Boiler.device_id; + device_index = EMS_Boiler.device_index; + version = EMS_Boiler.version; + } else if (device_type == EMS_DEVICE_TYPE_SOLAR) { + enabled = ems_getSolarModuleEnabled(); + device_id = EMS_SolarModule.device_id; + device_index = EMS_SolarModule.device_index; + version = EMS_SolarModule.version; + } else if (device_type == EMS_DEVICE_TYPE_HEATPUMP) { + enabled = ems_getHeatPumpEnabled(); + device_id = EMS_HeatPump.device_id; + device_index = EMS_HeatPump.device_index; + version = EMS_HeatPump.version; } - return buffer; -} - -/** - * returns current Heat Pump type as a string - */ -char * ems_getHeatPumpDescription(char * buffer, bool name_only) { - uint8_t size = 128; - if (!ems_getHeatPumpEnabled()) { + if (!enabled) { strlcpy(buffer, "", size); - } else { - int i = 0; - bool found = false; - char tmp[6] = {0}; - - // scan through known ID types - while (i < _HeatPump_Devices_max) { - if (HeatPump_Devices[i].product_id == EMS_HeatPump.product_id) { - found = true; // we have a match - break; - } - i++; - } - if (found) { - strlcpy(buffer, HeatPump_Devices[i].model_string, size); - if (name_only) { - return buffer; // only interested in the model name - } - } else { - strlcpy(buffer, "DeviceID:0x", size); - strlcat(buffer, _hextoa(EMS_HeatPump.device_id, tmp), size); - } - - strlcat(buffer, " (ProductID:", size); - if (EMS_HeatPump.product_id == EMS_ID_NONE) { - strlcat(buffer, "?", size); - } else { - strlcat(buffer, itoa(EMS_HeatPump.product_id, tmp, 10), size); - } - strlcat(buffer, " Version:", size); - strlcat(buffer, EMS_HeatPump.version, size); - strlcat(buffer, ")", size); + return buffer; } + // get device description + strlcpy(buffer, EMS_Devices[device_index].device_desc, size); + if (name_only) { + return buffer; // only interested in the model name + } + + strlcat(buffer, " (DeviceID:0x", size); + char tmp[6] = {0}; + strlcat(buffer, _hextoa(device_id, tmp), size); + strlcat(buffer, " ProductID:", size); + strlcat(buffer, itoa(EMS_Devices[device_index].product_id, tmp, 10), size); + strlcat(buffer, " Version:", size); + strlcat(buffer, version, size); + strlcat(buffer, ")", size); + return buffer; } @@ -2554,25 +2264,21 @@ void ems_scanDevices() { std::list Device_Ids; // create a new list - - Device_Ids.push_back(EMS_ID_BOILER); // add boiler device_id which is always 0x08 - Device_Ids.push_back(EMS_ID_HP); // add heat pump - Device_Ids.push_back(EMS_ID_SM); // add solar module - - // copy over thermostats - for (_Thermostat_Device tt : Thermostat_Devices) { - Device_Ids.push_back(tt.device_id); - } - - // copy over others - for (_Other_Device ot : Other_Devices) { - Device_Ids.push_back(ot.device_id); - } + Device_Ids.push_back(EMS_ID_BOILER); // UBAMaster/Boilers - 0x08 + Device_Ids.push_back(EMS_ID_HP); // HeatPump - 0x38 + Device_Ids.push_back(EMS_ID_SM); // Solar Module - 0x30 + Device_Ids.push_back(0x09); // Controllers - 0x09 + Device_Ids.push_back(0x02); // Connect - 0x02 + Device_Ids.push_back(0x48); // Gateway - 0x48 + Device_Ids.push_back(0x20); // Mixing Devices - 0x20, 0x21 + Device_Ids.push_back(0x21); // Mixing Devices - 0x20, 0x21 + Device_Ids.push_back(0x10); // Thermostats - 0x10, 0x17, 0x18 + Device_Ids.push_back(0x17); // Thermostats - 0x10, 0x17, 0x18 + Device_Ids.push_back(0x18); // Thermostats - 0x10, 0x17, 0x18 // remove duplicates and reserved IDs (like our own device) Device_Ids.sort(); - Device_Ids.unique(); - Device_Ids.remove(EMS_MODEL_NONE); + // Device_Ids.unique(); // send the read command with Version command for (uint8_t device_id : Device_Ids) { @@ -2580,81 +2286,10 @@ void ems_scanDevices() { } } -/** - * Print out all handled types - */ -void ems_printAllDevices() { - uint8_t i; - - myDebug_P(PSTR("\nThese %d devices are supported as boiler units:"), _Boiler_Devices_max); - for (i = 0; i < _Boiler_Devices_max; i++) { - myDebug_P(PSTR(" %s%s%s (DeviceID:0x%02X ProductID:%d)"), - COLOR_BOLD_ON, - Boiler_Devices[i].model_string, - COLOR_BOLD_OFF, - EMS_ID_BOILER, - Boiler_Devices[i].product_id); - } - - myDebug_P(PSTR("\nThese %d devices are supported under solar module devices:"), _SolarModule_Devices_max); - for (i = 0; i < _SolarModule_Devices_max; i++) { - myDebug_P(PSTR(" %s%s%s (DeviceID:0x%02X ProductID:%d)"), - COLOR_BOLD_ON, - SolarModule_Devices[i].model_string, - COLOR_BOLD_OFF, - EMS_ID_SM, - SolarModule_Devices[i].product_id); - } - - myDebug_P(PSTR("\nThese %d devices are supported under heat pump devices:"), _HeatPump_Devices_max); - for (i = 0; i < _HeatPump_Devices_max; i++) { - myDebug_P(PSTR(" %s%s%s (DeviceID:0x%02X ProductID:%d)"), - COLOR_BOLD_ON, - HeatPump_Devices[i].model_string, - COLOR_BOLD_OFF, - EMS_ID_HP, - HeatPump_Devices[i].product_id); - } - - myDebug_P(PSTR("\nThese %d devices are supported as other EMS devices:"), _Other_Devices_max); - for (i = 0; i < _Other_Devices_max; i++) { - myDebug_P(PSTR(" %s%s%s (DeviceID:0x%02X ProductID:%d)"), - COLOR_BOLD_ON, - Other_Devices[i].model_string, - COLOR_BOLD_OFF, - Other_Devices[i].device_id, - Other_Devices[i].product_id); - } - - myDebug_P(PSTR("\nThe following telegram type IDs are supported:")); - for (i = 0; i < _EMS_Types_max; i++) { - if ((EMS_Types[i].model_id == EMS_MODEL_ALL) || (EMS_Types[i].model_id == EMS_MODEL_UBA)) { - myDebug_P(PSTR(" type 0x%04X (%s)"), EMS_Types[i].type, EMS_Types[i].typeString); - } - } - - myDebug_P(PSTR("\nThese %d thermostat devices are supported:"), _Thermostat_Devices_max); - for (i = 0; i < _Thermostat_Devices_max; i++) { - myDebug_P(PSTR(" %s%s%s (DeviceID:0x%02X ProductID:%d) can write:%c"), - COLOR_BOLD_ON, - Thermostat_Devices[i].model_string, - COLOR_BOLD_OFF, - Thermostat_Devices[i].device_id, - Thermostat_Devices[i].product_id, - (Thermostat_Devices[i].write_supported) ? 'y' : 'n'); - } - - // print out known devices - ems_printDevices(); - - myDebug_P(PSTR("")); // newline -} - /** * print out contents of the device list that was captured */ void ems_printDevices() { - // print out the device map, which is sent from the UBA master and shows all the connected IDs char s[100]; char buffer[16] = {0}; @@ -2684,28 +2319,31 @@ void ems_printDevices() { // print out the ones we recognized if (!Devices.empty()) { - bool unknown = false; + bool have_unknowns = false; + char device_name[200]; myDebug_P(PSTR("and %d were recognized by EMS-ESP as:"), Devices.size()); - for (std::list<_Generic_Device>::iterator it = Devices.begin(); it != Devices.end(); ++it) { + for (std::list<_Detected_Device>::iterator it = Devices.begin(); it != Devices.end(); ++it) { + if ((it)->known) { + strlcpy(device_name, EMS_Devices[(it)->device_index].device_desc, sizeof(device_name)); + } else { + strlcpy(device_name, EMS_MODELTYPE_UNKNOWN_STRING, sizeof(device_name)); // Unknown + have_unknowns = true; + } + myDebug_P(PSTR(" %s%s%s (DeviceID:0x%02X ProductID:%d Version:%s)"), COLOR_BOLD_ON, - (it)->model_string, + device_name, COLOR_BOLD_OFF, (it)->device_id, (it)->product_id, (it)->version); - // check for unknowns - if (strcmp((it)->model_string, EMS_MODELTYPE_UNKNOWN_STRING) == 0) { - unknown = true; - } } myDebug_P(PSTR("")); // newline - if (unknown) { + if (have_unknowns) { myDebug_P(PSTR("You have a device is that is not known by EMS-ESP. Please report this as a GitHub issue so we can expand the EMS device library.")); } - } else { myDebug_P(PSTR("No were devices recognized. This may be because Tx is disabled or failing.")); } @@ -2736,7 +2374,7 @@ void ems_doReadCommand(uint16_t type, uint8_t dest, bool forceRefresh) { EMS_Sys_Status.txRetryCount = 0; // reset retry counter // see if its a known type - int i = _ems_findType(type); + int8_t i = _ems_findType(type); if ((ems_getLogging() == EMS_SYS_LOGGING_BASIC) || (ems_getLogging() == EMS_SYS_LOGGING_VERBOSE)) { if (i == -1) { @@ -2838,7 +2476,7 @@ void ems_setThermostatTemp(float temperature, uint8_t hc_num, uint8_t temptype) EMS_TxTelegram.timestamp = millis(); // set timestamp EMS_Sys_Status.txRetryCount = 0; // reset retry counter - uint8_t model_id = EMS_Thermostat.model_id; + uint8_t model = ems_getThermostatModel(); uint8_t device_id = EMS_Thermostat.device_id; EMS_TxTelegram.action = EMS_TX_TELEGRAM_WRITE; @@ -2850,25 +2488,25 @@ void ems_setThermostatTemp(float temperature, uint8_t hc_num, uint8_t temptype) hc_num, temptype); - if (model_id == EMS_MODEL_RC20) { + if (model == EMS_DEVICE_FLAG_RC20) { EMS_TxTelegram.type = EMS_TYPE_RC20Set; EMS_TxTelegram.offset = EMS_OFFSET_RC20Set_temp; EMS_TxTelegram.comparisonPostRead = EMS_TYPE_RC20StatusMessage; EMS_TxTelegram.type_validate = EMS_TxTelegram.type; - } else if (model_id == EMS_MODEL_RC10) { + } else if (model == EMS_DEVICE_FLAG_RC10) { EMS_TxTelegram.type = EMS_TYPE_RC10Set; EMS_TxTelegram.offset = EMS_OFFSET_RC10Set_temp; EMS_TxTelegram.comparisonPostRead = EMS_TYPE_RC10StatusMessage; EMS_TxTelegram.type_validate = EMS_TxTelegram.type; - } else if (model_id == EMS_MODEL_RC30) { + } else if (model == EMS_DEVICE_FLAG_RC30) { EMS_TxTelegram.type = EMS_TYPE_RC30Set; EMS_TxTelegram.offset = EMS_OFFSET_RC30Set_temp; EMS_TxTelegram.comparisonPostRead = EMS_TYPE_RC30StatusMessage; EMS_TxTelegram.type_validate = EMS_TxTelegram.type; - } else if (model_id == EMS_MODEL_RC300) { + } else if (model == EMS_DEVICE_FLAG_RC300) { // check mode to determine offset if (EMS_Thermostat.hc[hc_num - 1].mode == 1) { // auto EMS_TxTelegram.offset = 0x08; // auto offset @@ -2892,7 +2530,7 @@ void ems_setThermostatTemp(float temperature, uint8_t hc_num, uint8_t temptype) EMS_TxTelegram.type_validate = EMS_ID_NONE; // validate by reading from a different telegram - } else if ((model_id == EMS_MODEL_RC35) || (model_id == EMS_MODEL_ES73)) { + } else if (model == EMS_DEVICE_FLAG_RC35) { switch (temptype) { case 1: // change the night temp EMS_TxTelegram.offset = EMS_OFFSET_RC35Set_temp_night; @@ -2960,12 +2598,12 @@ void ems_setThermostatMode(uint8_t mode, uint8_t hc_num) { return; } - uint8_t model_id = EMS_Thermostat.model_id; + uint8_t model = ems_getThermostatModel(); uint8_t device_id = EMS_Thermostat.device_id; uint8_t set_mode; // RC300/1000/3000 have different settings - if (model_id == EMS_MODEL_RC300) { + if (model == EMS_DEVICE_FLAG_RC300) { if (mode == 1) { set_mode = 0; // manual } else { @@ -2994,19 +2632,19 @@ void ems_setThermostatMode(uint8_t mode, uint8_t hc_num) { EMS_TxTelegram.dataValue = set_mode; // handle different thermostat types - if (model_id == EMS_MODEL_RC20) { + if (model == EMS_DEVICE_FLAG_RC20) { EMS_TxTelegram.type = EMS_TYPE_RC20Set; EMS_TxTelegram.offset = EMS_OFFSET_RC20Set_mode; EMS_TxTelegram.type_validate = EMS_TYPE_RC20Set; EMS_TxTelegram.comparisonPostRead = EMS_TYPE_RC20StatusMessage; - } else if (model_id == EMS_MODEL_RC30) { + } else if (model == EMS_DEVICE_FLAG_RC30) { EMS_TxTelegram.type = EMS_TYPE_RC30Set; EMS_TxTelegram.offset = EMS_OFFSET_RC30Set_mode; EMS_TxTelegram.type_validate = EMS_TYPE_RC30Set; EMS_TxTelegram.comparisonPostRead = EMS_TYPE_RC30StatusMessage; - } else if ((model_id == EMS_MODEL_RC35) || (model_id == EMS_MODEL_ES73)) { + } else if (model == EMS_DEVICE_FLAG_RC35) { if (hc_num == 1) { EMS_TxTelegram.type = EMS_TYPE_RC35Set_HC1; EMS_TxTelegram.comparisonPostRead = EMS_TYPE_RC35StatusMessage_HC1; @@ -3023,7 +2661,7 @@ void ems_setThermostatMode(uint8_t mode, uint8_t hc_num) { EMS_TxTelegram.offset = EMS_OFFSET_RC35Set_mode; EMS_TxTelegram.type_validate = EMS_TxTelegram.type; - } else if (model_id == EMS_MODEL_RC300) { + } else if (model == EMS_DEVICE_FLAG_RC300) { EMS_TxTelegram.offset = EMS_OFFSET_RCPLUSSet_mode; if (hc_num == 1) { diff --git a/src/ems.h b/src/ems.h index 87f53a936..c38916cbd 100644 --- a/src/ems.h +++ b/src/ems.h @@ -20,17 +20,19 @@ #define EMS_ID_NONE 0x00 // used as a dest in broadcast messages and empty device IDs // Fixed EMS IDs -#define EMS_ID_ME 0x0B // our device, hardcoded as the "Service Key" -#define EMS_ID_BOILER 0x08 // all UBA Boilers have 0x08 -#define EMS_ID_SM 0x30 // Solar Module SM10, SM100 and ISM1 -#define EMS_ID_HP 0x38 // HeatPump -#define EMS_ID_GATEWAY 0x48 // KM200 Web Gateway - -// Product IDs -#define EMS_PRODUCTID_SM10 73 // SM10 solar module -#define EMS_PRODUCTID_SM50 162 // SM50 solar module -#define EMS_PRODUCTID_SM100 163 // SM100 solar module -#define EMS_PRODUCTID_ISM1 101 // Junkers ISM1 solar module +#define EMS_ID_ME 0x0B // our device, hardcoded as the "Service Key" +#define EMS_ID_BOILER 0x08 // all UBA Boilers have 0x08 +#define EMS_ID_SM 0x30 // Solar Module SM10, SM100 and ISM1 +#define EMS_ID_HP 0x38 // HeatPump +#define EMS_ID_GATEWAY 0x48 // e.g. KM200 Web Gateway +#define EMS_ID_MIXING1 0x20 // Mixing +#define EMS_ID_MIXING2 0x21 // Mixing +#define EMS_ID_SWITCH 0x11 // Switch +#define EMS_ID_CONTROLLER 0x09 // Controller +#define EMS_ID_CONNECT 0x02 // Connect +#define EMS_ID_THERMOSTAT1 0x10 // Thermostat +#define EMS_ID_THERMOSTAT2 0x17 // Thermostat +#define EMS_ID_THERMOSTAT3 0x18 // Thermostat #define EMS_MIN_TELEGRAM_LENGTH 6 // minimal length for a validation telegram, including CRC #define EMS_MAX_TELEGRAM_LENGTH 32 // max length of a telegram, including CRC, for Rx and Tx. @@ -191,50 +193,81 @@ const _EMS_TxTelegram EMS_TX_TELEGRAM_NEW = { {0x00} // data }; -// where defintions are stored -typedef struct { - uint8_t product_id; - char model_string[100]; -} _Boiler_Device; +typedef enum { + EMS_DEVICE_TYPE_NONE, + EMS_DEVICE_TYPE_SERVICEKEY, + EMS_DEVICE_TYPE_BOILER, + EMS_DEVICE_TYPE_THERMOSTAT, + EMS_DEVICE_TYPE_MIXING, + EMS_DEVICE_TYPE_SOLAR, + EMS_DEVICE_TYPE_HEATPUMP, + EMS_DEVICE_TYPE_GATEWAY, + EMS_DEVICE_TYPE_OTHER, + EMS_DEVICE_TYPE_SWITCH, + EMS_DEVICE_TYPE_CONTROLLER, + EMS_DEVICE_TYPE_CONNECT, + EMS_DEVICE_TYPE_UNKNOWN +} _EMS_DEVICE_TYPE; +// to store all know EMS devices typedef struct { - uint8_t product_id; - char model_string[50]; -} _SolarModule_Device; + uint8_t product_id; + _EMS_DEVICE_TYPE type; + char device_desc[100]; + uint8_t flags; +} _EMS_Device; +// to store mapping of device_ids to their string name typedef struct { - uint8_t product_id; - uint8_t device_id; - char model_string[50]; -} _Other_Device; + uint8_t device_id; + _EMS_DEVICE_TYPE device_type; + char device_type_string[30]; +} _EMS_Device_Types; +// mapping for EMS_Devices_Type +const _EMS_Device_Types EMS_Devices_Types[] = { + + {EMS_ID_BOILER, EMS_DEVICE_TYPE_BOILER, "UBAMaster"}, + {EMS_ID_THERMOSTAT1, EMS_DEVICE_TYPE_THERMOSTAT, "Thermostat"}, + {EMS_ID_THERMOSTAT2, EMS_DEVICE_TYPE_THERMOSTAT, "Thermostat"}, + {EMS_ID_THERMOSTAT3, EMS_DEVICE_TYPE_THERMOSTAT, "Thermostat"}, + {EMS_ID_SM, EMS_DEVICE_TYPE_SOLAR, "Solar Module"}, + {EMS_ID_HP, EMS_DEVICE_TYPE_HEATPUMP, "Heat Pump"}, + {EMS_ID_GATEWAY, EMS_DEVICE_TYPE_GATEWAY, "Gateway"}, + {EMS_ID_ME, EMS_DEVICE_TYPE_SERVICEKEY, "Me"}, + {EMS_ID_NONE, EMS_DEVICE_TYPE_NONE, "All"}, + {EMS_ID_MIXING1, EMS_DEVICE_TYPE_MIXING, "Mixing Module"}, + {EMS_ID_MIXING2, EMS_DEVICE_TYPE_MIXING, "Mixing Module"}, + {EMS_ID_SWITCH, EMS_DEVICE_TYPE_SWITCH, "Switching Module"}, + {EMS_ID_CONTROLLER, EMS_DEVICE_TYPE_CONTROLLER, "Controller"}, + {EMS_ID_CONNECT, EMS_DEVICE_TYPE_CONNECT, "Connect"} + +}; + +// for storing all recognised EMS devices typedef struct { - uint8_t product_id; - char model_string[50]; -} _HeatPump_Device; + _EMS_DEVICE_TYPE device_type; // type + uint8_t product_id; // product id for looking up details in _EMS_Devices + uint8_t device_id; // the device_id + uint8_t device_index; // where it is in the EMS_Devices table + char version[10]; // the version number XX.XX + bool known; // is this a known device? +} _Detected_Device; -typedef struct { - uint8_t model_id; - uint8_t product_id; - uint8_t device_id; - char model_string[50]; - bool write_supported; -} _Thermostat_Device; +#define EMS_DEVICE_FLAG_NONE 0 // no flags set -typedef struct { - uint8_t product_id; - char model_string[50]; -} _Mixing_Device; - -// for consolidating all types -typedef struct { - uint8_t model_type; // 1=boiler, 2=thermostat, 3=sm, 4=other, 5=unknown - uint8_t product_id; - uint8_t device_id; - char version[10]; - char model_string[50]; -} _Generic_Device; +#define EMS_DEVICE_FLAG_SM10 10 +#define EMS_DEVICE_FLAG_SM100 11 +// group flags for thermostats +#define EMS_DEVICE_FLAG_NO_WRITE 0x80 // top bit set if can't write yet +#define EMS_DEVICE_FLAG_EASY 1 +#define EMS_DEVICE_FLAG_RC10 2 +#define EMS_DEVICE_FLAG_RC20 3 +#define EMS_DEVICE_FLAG_RC30 4 +#define EMS_DEVICE_FLAG_RC35 5 +#define EMS_DEVICE_FLAG_RC300 6 +#define EMS_DEVICE_FLAG_JUNKERS 7 /* * Telegram package defintions @@ -242,6 +275,8 @@ typedef struct { typedef struct { // settings uint8_t device_id; // this is typically always 0x08 + uint8_t device_flags; + uint8_t device_index; uint8_t product_id; char version[10]; @@ -304,29 +339,22 @@ typedef struct { */ typedef struct { uint8_t device_id; // the device ID of the Heat Pump (e.g. 0x30) - uint8_t model_id; // Solar Module / Heat Pump model + uint8_t device_flags; + uint8_t device_index; uint8_t product_id; char version[10]; - uint8_t HPModulation; // heatpump modulation in % uint8_t HPSpeed; // speed 0-100 % } _EMS_HeatPump; typedef struct { - uint8_t device_id; - uint8_t model_id; - uint8_t product_id; - char version[10]; -} _EMS_Other; - -typedef struct { - uint8_t device_id; - uint8_t model_id; - uint8_t product_id; - char version[10]; - uint8_t hc; // heating circuit 1, 2, 3 or 4 - bool active; // true if there is data for this HC - + uint8_t device_id; + uint8_t device_flags; + uint8_t device_index; + uint8_t product_id; + char version[10]; + uint8_t hc; // heating circuit 1, 2, 3 or 4 + bool active; // true if there is data for this HC uint16_t flowTemp; uint8_t pumpMod; uint8_t valveStatus; @@ -334,17 +362,21 @@ typedef struct { // Mixer data typedef struct { + uint8_t device_id; + uint8_t device_flags; + uint8_t device_index; + uint8_t product_id; bool detected; _EMS_Mixing_HC hc[EMS_THERMOSTAT_MAXHC]; // array for the 4 heating circuits } _EMS_Mixing; // 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]; - + uint8_t device_id; // the device ID of the Solar Module + uint8_t device_flags; // Solar Module flags + uint8_t device_index; + uint8_t product_id; + char version[10]; int16_t collectorTemp; // collector temp int16_t bottomTemp; // bottom temp uint8_t pumpModulation; // modulation solar pump @@ -375,8 +407,9 @@ typedef struct { // Thermostat data typedef struct { - uint8_t device_id; // the device ID of the thermostat - uint8_t model_id; // thermostat model + uint8_t device_id; // the device ID of the thermostat + uint8_t device_flags; // thermostat model flags + uint8_t device_index; uint8_t product_id; char version[10]; char datetime[25]; // HH:MM:SS DD/MM/YYYY @@ -389,9 +422,8 @@ typedef void (*EMS_processType_cb)(_EMS_RxTelegram * EMS_RxTelegram); // Definition for each EMS type, including the relative callback function typedef struct { - uint8_t model_id; - uint16_t type; // long to support EMS+ types - const char typeString[50]; + uint16_t type; + const char typeString[30]; EMS_processType_cb processType_cb; } _EMS_Type; @@ -402,7 +434,6 @@ void ems_init(); void ems_doReadCommand(uint16_t type, uint8_t dest, bool forceRefresh = false); void ems_sendRawTelegram(char * telegram); void ems_scanDevices(); -void ems_printAllDevices(); void ems_printDevices(); uint8_t ems_printDevices_s(char * buffer, uint16_t len); void ems_printTxQueue(); @@ -428,10 +459,8 @@ 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); -char * ems_getHeatPumpDescription(char * buffer, bool name_only = false); +char * ems_getDeviceDescription(_EMS_DEVICE_TYPE device_type, char * buffer, bool name_only = false); +bool ems_getDeviceTypeDescription(uint8_t device_id, char * buffer); void ems_getThermostatValues(); void ems_getBoilerValues(); void ems_getSolarModuleValues(); @@ -465,7 +494,6 @@ extern _EMS_Boiler EMS_Boiler; extern _EMS_Thermostat EMS_Thermostat; extern _EMS_SolarModule EMS_SolarModule; extern _EMS_HeatPump EMS_HeatPump; -extern _EMS_Other EMS_Other; extern _EMS_Mixing EMS_Mixing; -extern std::list<_Generic_Device> Devices; +extern std::list<_Detected_Device> Devices; diff --git a/src/ems_devices.h b/src/ems_devices.h index 19948c23e..d0d5d289e 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -155,155 +155,106 @@ #define EMS_OFFSET_MMPLUSStatusMessage_pump_mod 5 // pump modulation #define EMS_OFFSET_MMPLUSStatusMessage_valve_status 2 // valve in percent - -// Known EMS devices -typedef enum { - EMS_MODEL_NONE, // unset - EMS_MODEL_ALL, // common for all devices - - EMS_MODEL_HP, // heatpump - EMS_MODEL_SM, // solar module - EMS_MODEL_MM, // mixer module - EMS_MODEL_UBA, // boiler - - // and the various thermostats - EMS_MODEL_ES73, - EMS_MODEL_RC10, - EMS_MODEL_RC20, - EMS_MODEL_RC20RF, - EMS_MODEL_RC30, - EMS_MODEL_RC35, - EMS_MODEL_EASY, - EMS_MODEL_RC300, - EMS_MODEL_CW100, - EMS_MODEL_RC100, - EMS_MODEL_OT, - EMS_MODEL_FW100, - EMS_MODEL_FR10, - EMS_MODEL_FR50, - EMS_MODEL_FR100, - EMS_MODEL_FR110, - EMS_MODEL_FW120, - EMS_MODEL_FW200, - EMS_MODEL_FR120 - -} _EMS_MODEL_ID; - -// EMS types for known boilers. This list will be extended when new devices are recognized. -// The device_id is always 0x08 -// format is PRODUCT ID, DESCRIPTION -const _Boiler_Device Boiler_Devices[] = { - - {72, "MC10 Module"}, - {123, "Buderus GBx72/Nefit Trendline/Junkers Cerapur/Worcester Greenstar Si/27i"}, - {133, "Buderus GB125/Logamatic MC110"}, - {115, "Nefit Topline/Buderus GB162"}, - {203, "Buderus Logamax U122/Junkers Cerapur"}, - {208, "Buderus Logamax plus/GB192/Bosch Condens GC9000"}, - {64, "Sieger BK13,BK15/Nefit Smartline/Buderus GB1x2"}, - {234, "Buderus Logamax Plus GB122"}, - {95, "Bosch Condens 2500/Buderus Logamax GB062/Junkers Cerapur Top/Worcester Greenstar i/Generic HT3"}, - {122, "Nefit Proline"}, - {170, "Buderus Logano GB212"}, - {172, "Nefit Enviline"} - -}; - /* - * Known Solar Module types, device id is 0x30 - * format is PRODUCT ID, DESCRIPTION + * Table of all known EMS Devices + * ProductID, DeviceType, Description, Flags */ -const _SolarModule_Device SolarModule_Devices[] = { +const _EMS_Device EMS_Devices[] = { - {EMS_PRODUCTID_SM10, "SM10 Solar Module"}, - {EMS_PRODUCTID_SM100, "SM100 Solar Module"}, - {EMS_PRODUCTID_ISM1, "Junkers ISM1 Solar Module"}, - {EMS_PRODUCTID_SM50, "SM50 Solar Module"} + // + // UBA Masters - typically with device_id of 0x08 + // -}; + {72, EMS_DEVICE_TYPE_BOILER, "MC10 Module", EMS_DEVICE_FLAG_NONE}, + {123, EMS_DEVICE_TYPE_BOILER, "Buderus GBx72/Nefit Trendline/Junkers Cerapur/Worcester Greenstar Si/27i", EMS_DEVICE_FLAG_NONE}, + {133, EMS_DEVICE_TYPE_BOILER, "Buderus GB125/Logamatic MC110", EMS_DEVICE_FLAG_NONE}, + {115, EMS_DEVICE_TYPE_BOILER, "Nefit Topline/Buderus GB162", EMS_DEVICE_FLAG_NONE}, + {203, EMS_DEVICE_TYPE_BOILER, "Buderus Logamax U122/Junkers Cerapur", EMS_DEVICE_FLAG_NONE}, + {208, EMS_DEVICE_TYPE_BOILER, "Buderus Logamax plus/GB192/Bosch Condens GC9000", EMS_DEVICE_FLAG_NONE}, + {64, EMS_DEVICE_TYPE_BOILER, "Sieger BK13,BK15/Nefit Smartline/Buderus GB1x2", EMS_DEVICE_FLAG_NONE}, + {234, EMS_DEVICE_TYPE_BOILER, "Buderus Logamax Plus GB122", EMS_DEVICE_FLAG_NONE}, + {95, EMS_DEVICE_TYPE_BOILER, "Bosch Condens 2500/Buderus Logamax GB062/Junkers Cerapur Top/Worcester Greenstar i/Generic HT3", EMS_DEVICE_FLAG_NONE}, + {122, EMS_DEVICE_TYPE_BOILER, "Nefit Proline", EMS_DEVICE_FLAG_NONE}, + {170, EMS_DEVICE_TYPE_BOILER, "Buderus Logano GB212", EMS_DEVICE_FLAG_NONE}, + {172, EMS_DEVICE_TYPE_BOILER, "Nefit Enviline", EMS_DEVICE_FLAG_NONE}, -/* - * Mixing Units - * Typically device id is 0x20 or 0x21 - * format is PRODUCT ID, DESCRIPTION - */ -const _Mixing_Device Mixing_Devices[] = { + // + // Solar Modules - type 0x30 + // - {160, "MM100 Mixing Module"}, - {161, "MM200 Mixing Module"}, - {69, "MM10 Mixer Module"}, - {159, "MM50 Mixing Module"}, - {79, "MM100 Mixer Module"}, - {80, "MM200 Mixer Module"}, - {78, "MM400 Mixer Module"} + {73, EMS_DEVICE_TYPE_SOLAR, "SM10 Solar Module", EMS_DEVICE_FLAG_SM10}, + {163, EMS_DEVICE_TYPE_SOLAR, "SM100 Solar Module", EMS_DEVICE_FLAG_SM100}, + {101, EMS_DEVICE_TYPE_SOLAR, "Junkers ISM1 Solar Module", EMS_DEVICE_FLAG_SM100}, + {162, EMS_DEVICE_TYPE_SOLAR, "SM50 Solar Module", EMS_DEVICE_FLAG_SM100}, -}; + // + // Mixing Devices - type 0x20 or 0x21 + // -// Other EMS devices which are not considered boilers, thermostats or solar modules -// format is PRODUCT ID, DEVICE ID, DESCRIPTION -const _Other_Device Other_Devices[] = { + {160, EMS_DEVICE_TYPE_MIXING, "MM100 Mixing Module", EMS_DEVICE_FLAG_NONE}, + {161, EMS_DEVICE_TYPE_MIXING, "MM200 Mixing Module", EMS_DEVICE_FLAG_NONE}, + {69, EMS_DEVICE_TYPE_MIXING, "MM10 Mixer Module", EMS_DEVICE_FLAG_NONE}, + {159, EMS_DEVICE_TYPE_MIXING, "MM50 Mixing Module", EMS_DEVICE_FLAG_NONE}, + {79, EMS_DEVICE_TYPE_MIXING, "MM100 Mixer Module", EMS_DEVICE_FLAG_NONE}, + {80, EMS_DEVICE_TYPE_MIXING, "MM200 Mixer Module", EMS_DEVICE_FLAG_NONE}, + {78, EMS_DEVICE_TYPE_MIXING, "MM400 Mixer Module", EMS_DEVICE_FLAG_NONE}, - {71, 0x11, "WM10 Switch Module"}, + // + // HeatPump - type 0x38 + // - {68, 0x09, "BC10/RFM20 Receiver"}, - {190, 0x09, "BC10 Base Controller"}, - {114, 0x09, "BC10 Base Controller"}, - {125, 0x09, "BC25 Base Controller"}, - {169, 0x09, "BC40 Base Controller"}, - {152, 0x09, "Controller"}, - {95, 0x09, "HT3 Controller"}, - {230, 0x09, "BC Base Controller"}, + {252, EMS_DEVICE_TYPE_HEATPUMP, "HeatPump Module", EMS_DEVICE_FLAG_NONE}, + {200, EMS_DEVICE_TYPE_HEATPUMP, "HeatPump Module", EMS_DEVICE_FLAG_NONE}, - {205, 0x02, "Nefit Moduline Easy Connect"}, - {206, 0x02, "Bosch Easy Connect"}, - {171, 0x02, "EMS-OT OpenTherm converter"}, + // + // Other devices, like 0x11 for Switching, 0x09 for controllers, 0x02 for Connect, 0x48 for Gateway + // - {189, EMS_ID_GATEWAY, "Web Gateway KM200"} + {71, EMS_DEVICE_TYPE_SWITCH, "WM10 Switch Module", EMS_DEVICE_FLAG_NONE}, // 0x11 + {68, EMS_DEVICE_TYPE_CONTROLLER, "BC10/RFM20 Receiver", EMS_DEVICE_FLAG_NONE}, // 0x09 + {190, EMS_DEVICE_TYPE_CONTROLLER, "BC10 Base Controller", EMS_DEVICE_FLAG_NONE}, // 0x09 + {114, EMS_DEVICE_TYPE_CONTROLLER, "BC10 Base Controller", EMS_DEVICE_FLAG_NONE}, // 0x09 + {125, EMS_DEVICE_TYPE_CONTROLLER, "BC25 Base Controller", EMS_DEVICE_FLAG_NONE}, // 0x09 + {169, EMS_DEVICE_TYPE_CONTROLLER, "BC40 Base Controller", EMS_DEVICE_FLAG_NONE}, // 0x09 + {152, EMS_DEVICE_TYPE_CONTROLLER, "Controller", EMS_DEVICE_FLAG_NONE}, // 0x09 + {95, EMS_DEVICE_TYPE_CONTROLLER, "HT3 Controller", EMS_DEVICE_FLAG_NONE}, // 0x09 + {230, EMS_DEVICE_TYPE_CONTROLLER, "BC Base Controller", EMS_DEVICE_FLAG_NONE}, // 0x09 + {205, EMS_DEVICE_TYPE_CONNECT, "Nefit Moduline Easy Connect", EMS_DEVICE_FLAG_NONE}, // 0x02 + {206, EMS_DEVICE_TYPE_CONNECT, "Bosch Easy Connect", EMS_DEVICE_FLAG_NONE}, // 0x02 + {171, EMS_DEVICE_TYPE_CONNECT, "EMS-OT OpenTherm converter", EMS_DEVICE_FLAG_NONE}, // 0x02 + {189, EMS_DEVICE_TYPE_GATEWAY, "Web Gateway KM200", EMS_DEVICE_FLAG_NONE}, // 0x48 -}; - -// heatpump, device ID 0x38 -// format is PRODUCT ID, DEVICE ID, DESCRIPTION -const _HeatPump_Device HeatPump_Devices[] = { - - {252, "HeatPump Module"}, - {200, "HeatPump Module"} - -}; - -/* - * Known thermostat types and their capabilities - * format is MODEL_ID, PRODUCT ID, DEVICE ID, DESCRIPTION - * Typically on DeviceID 0x10 or 0x18 - */ -const _Thermostat_Device Thermostat_Devices[] = { + // + // Thermostats, typically device id of 0x10, 0x17 and 0x18 + // // Easy devices - not currently supporting write operations - {EMS_MODEL_EASY, 202, 0x18, "Logamatic TC100/Nefit Moduline Easy", EMS_THERMOSTAT_WRITE_NO}, - {EMS_MODEL_EASY, 203, 0x18, "Bosch EasyControl CT200", EMS_THERMOSTAT_WRITE_NO}, - {EMS_MODEL_CW100, 157, 0x18, "Buderus RC200/Bosch CW100/Junkers CW100", EMS_THERMOSTAT_WRITE_NO}, + {202, EMS_DEVICE_TYPE_THERMOSTAT, "Logamatic TC100/Nefit Moduline Easy", EMS_DEVICE_FLAG_EASY & EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write + {203, EMS_DEVICE_TYPE_THERMOSTAT, "Bosch EasyControl CT200", EMS_DEVICE_FLAG_EASY & EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write + {157, EMS_DEVICE_TYPE_THERMOSTAT, "Buderus RC200/Bosch CW100/Junkers CW100", EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write // Buderus/Nefit - {EMS_MODEL_RC10, 79, 0x17, "RC10/Moduline 100", EMS_THERMOSTAT_WRITE_YES}, - {EMS_MODEL_RC20, 77, 0x17, "RC20/Moduline 300", EMS_THERMOSTAT_WRITE_YES}, - {EMS_MODEL_RC20RF, 93, 0x18, "RC20RF", EMS_THERMOSTAT_WRITE_YES}, - {EMS_MODEL_RC30, 67, 0x10, "RC30", EMS_THERMOSTAT_WRITE_YES}, - {EMS_MODEL_RC30, 78, 0x10, "RC30/Moduline 400", EMS_THERMOSTAT_WRITE_YES}, - {EMS_MODEL_RC35, 86, 0x10, "RC35", EMS_THERMOSTAT_WRITE_YES}, - {EMS_MODEL_RC300, 158, 0x10, "RC300/RC310/Moduline 3000/Bosch CW400", EMS_THERMOSTAT_WRITE_YES}, - {EMS_MODEL_RC100, 165, 0x18, "RC100/Moduline 1010", EMS_THERMOSTAT_WRITE_NO}, + {79, EMS_DEVICE_TYPE_THERMOSTAT, "RC10/Moduline 100", EMS_DEVICE_FLAG_RC10}, // 0x17 + {77, EMS_DEVICE_TYPE_THERMOSTAT, "RC20/Moduline 300", EMS_DEVICE_FLAG_RC20}, // 0x17 + {93, EMS_DEVICE_TYPE_THERMOSTAT, "RC20RF", EMS_DEVICE_FLAG_RC20}, // 0x18 + {67, EMS_DEVICE_TYPE_THERMOSTAT, "RC30", EMS_DEVICE_FLAG_RC30}, // 0x10 + {78, EMS_DEVICE_TYPE_THERMOSTAT, "RC30/Moduline 400", EMS_DEVICE_FLAG_RC30}, // 0x10 + {86, EMS_DEVICE_TYPE_THERMOSTAT, "RC35", EMS_DEVICE_FLAG_RC35}, // 0x10 + {158, EMS_DEVICE_TYPE_THERMOSTAT, "RC300/RC310/Moduline 3000/Bosch CW400", EMS_DEVICE_FLAG_RC300}, // 0x10 + {165, EMS_DEVICE_TYPE_THERMOSTAT, "RC100/Moduline 1010", EMS_DEVICE_FLAG_RC300 & EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write // Sieger - {EMS_MODEL_ES73, 76, 0x10, "Sieger ES73", EMS_THERMOSTAT_WRITE_YES}, + {076, EMS_DEVICE_TYPE_THERMOSTAT, "Sieger ES73", EMS_DEVICE_FLAG_RC35}, // 0x10 // Junkers - {EMS_MODEL_FW100, 105, 0x10, "Junkers FW100", EMS_THERMOSTAT_WRITE_NO}, - {EMS_MODEL_FW200, 106, 0x10, "Junkers FW200", EMS_THERMOSTAT_WRITE_NO}, - {EMS_MODEL_FR100, 107, 0x18, "Junkers FR100", EMS_THERMOSTAT_WRITE_NO}, - {EMS_MODEL_FR110, 108, 0x18, "Junkers FR110", EMS_THERMOSTAT_WRITE_NO}, - {EMS_MODEL_FR10, 111, 0x18, "Junkers FR10", EMS_THERMOSTAT_WRITE_NO}, - {EMS_MODEL_FR120, 191, 0x10, "Junkers FR120", EMS_THERMOSTAT_WRITE_NO}, - {EMS_MODEL_FW120, 192, 0x10, "Junkers FW120", EMS_THERMOSTAT_WRITE_NO}, - {EMS_MODEL_FR50, 147, 0x10, "Junkers FR50", EMS_THERMOSTAT_WRITE_NO} + {105, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FW100", EMS_DEVICE_FLAG_JUNKERS & EMS_DEVICE_FLAG_NO_WRITE}, // 0x10, cannot write + {106, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FW200", EMS_DEVICE_FLAG_JUNKERS & EMS_DEVICE_FLAG_NO_WRITE}, // 0x10, cannot write + {107, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FR100", EMS_DEVICE_FLAG_JUNKERS & EMS_DEVICE_FLAG_NO_WRITE}, // 0x10, cannot write + {108, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FR110", EMS_DEVICE_FLAG_JUNKERS & EMS_DEVICE_FLAG_NO_WRITE}, // 0x10, cannot write + {111, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FR10", EMS_DEVICE_FLAG_JUNKERS & EMS_DEVICE_FLAG_NO_WRITE}, // 0x10, cannot write + {191, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FR120", EMS_DEVICE_FLAG_JUNKERS & EMS_DEVICE_FLAG_NO_WRITE}, // 0x10, cannot write + {192, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FW120", EMS_DEVICE_FLAG_JUNKERS & EMS_DEVICE_FLAG_NO_WRITE}, // 0x10, cannot write + {147, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FR50", EMS_DEVICE_FLAG_JUNKERS & EMS_DEVICE_FLAG_NO_WRITE} // 0x10, cannot write + }; diff --git a/src/version.h b/src/version.h index 5ede72e09..8d57dc8c4 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define APP_VERSION "1.9.4b10" +#define APP_VERSION "1.9.4b11"