diff --git a/CHANGELOG.md b/CHANGELOG.md index d257e76e9..2e8bd4f69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- HeatPump (e.g. Nefit Enviline) - MM50 Mixer - tx_mode takes a value from 0 to 3 for the different Tx logic diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index d10774d31..477bca03e 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -110,6 +110,11 @@ command_t project_cmds[] = { {false, "info", "show data captured on the EMS bus"}, {false, "log ", "set logging mode to none, basic, thermostat only, raw or verbose"}, + +#ifdef TESTS + {false, "test ", "insert a test telegram on to the EMS bus"}, +#endif + {false, "publish", "publish all values to MQTT"}, {false, "refresh", "fetch values from the EMS devices"}, {false, "devices", "list all supported and detected EMS devices and types IDs"}, @@ -449,13 +454,21 @@ void showInfo() { if (EMS_Other.SM) { myDebug_P(PSTR("")); // newline myDebug_P(PSTR("%sSolar Module stats:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF); - _renderShortValue(" Collector temperature", "C", EMS_Other.SMcollectorTemp); - _renderShortValue(" Bottom temperature", "C", EMS_Other.SMbottomTemp); - _renderIntValue(" Pump modulation", "%", EMS_Other.SMpumpModulation); - _renderBoolValue(" Pump active", EMS_Other.SMpump); - _renderShortValue(" Energy Last Hour", "Wh", EMS_Other.SMEnergyLastHour, 1); // *10 - _renderShortValue(" Energy Today", "Wh", EMS_Other.SMEnergyToday, 0); - _renderShortValue(" Energy Total", "kWH", EMS_Other.SMEnergyTotal, 1); // *10 + _renderShortValue("Collector temperature", "C", EMS_Other.SMcollectorTemp); + _renderShortValue("Bottom temperature", "C", EMS_Other.SMbottomTemp); + _renderIntValue("Pump modulation", "%", EMS_Other.SMpumpModulation); + _renderBoolValue("Pump active", EMS_Other.SMpump); + _renderShortValue("Energy Last Hour", "Wh", EMS_Other.SMEnergyLastHour, 1); // *10 + _renderShortValue("Energy Today", "Wh", EMS_Other.SMEnergyToday, 0); + _renderShortValue("Energy Total", "kWH", EMS_Other.SMEnergyTotal, 1); // *10 + } + + // For HeatPumps + if (EMS_Other.HP) { + myDebug_P(PSTR("")); // newline + myDebug_P(PSTR("%sHeat Pump stats:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF); + _renderIntValue("Pump modulation", "%", EMS_Other.HPModulation); + _renderIntValue("Pump speed", "%", EMS_Other.HPSpeed); } // Thermostat stats @@ -567,6 +580,7 @@ void publishSensorValues() { // CRC check is done to see if there are changes in the values since the last send to avoid too much wifi traffic // a check is done against the previous values and if there are changes only then they are published. Unless force=true void publishValues(bool force) { + // don't send if MQTT is connected if (!myESP.isMQTTConnected()) { return; @@ -751,6 +765,7 @@ void publishValues(bool force) { } // handle the other values separately + // For SM10 and SM100 Solar Modules if (EMS_Other.SM) { // build new json object @@ -796,6 +811,27 @@ void publishValues(bool force) { myESP.mqttPublish(TOPIC_SM_DATA, data); } } + + // handle HeatPump + if (EMS_Other.HP) { + // build new json object + doc.clear(); + JsonObject rootSM = doc.to(); + + if (EMS_Other.HPModulation != EMS_VALUE_INT_NOTSET) + rootSM[HP_PUMPMODULATION] = EMS_Other.HPModulation; + + if (EMS_Other.HPSpeed != EMS_VALUE_INT_NOTSET) + rootSM[HP_PUMPSPEED] = EMS_Other.HPSpeed; + + data[0] = '\0'; // reset data for next package + serializeJson(doc, data, sizeof(data)); + + myDebugLog("Publishing HeatPump data via MQTT"); + + // send values via MQTT + myESP.mqttPublish(TOPIC_HP_DATA, data); + } } // sets the shower timer on/off @@ -977,7 +1013,7 @@ void runUnitTest(uint8_t test_num) { publishValuesTimer.detach(); systemCheckTimer.detach(); regularUpdatesTimer.detach(); - EMSESP_Status.listen_mode = true; // temporary go into listen mode to disable Tx + // EMSESP_Status.listen_mode = true; // temporary go into listen mode to disable Tx ems_testTelegram(test_num); } @@ -1092,7 +1128,7 @@ bool SettingsCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, c EMSESP_Status.listen_mode = false; ok = true; ems_setTxDisabled(false); - myDebug_P(PSTR("* out of listen mode. Tx is enabled.")); + myDebug_P(PSTR("* out of listen mode. Tx is now enabled.")); } else { myDebug_P(PSTR("Error. Usage: set listen_mode ")); } @@ -1451,7 +1487,6 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { if ((hc >= 1) && (hc <= 2)) { EMSESP_Status.heating_circuit = hc; ems_setThermostatHC(hc); - // TODO: save setting to SPIFFS?? } } diff --git a/src/ems.cpp b/src/ems.cpp index 42e9dee0c..9a39bfdc1 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -50,7 +50,6 @@ void _process_UBAMonitorWWMessage(_EMS_RxTelegram * EMS_RxTelegram); void _process_UBAParameterWW(_EMS_RxTelegram * EMS_RxTelegram); void _process_UBATotalUptimeMessage(_EMS_RxTelegram * EMS_RxTelegram); void _process_UBAParametersMessage(_EMS_RxTelegram * EMS_RxTelegram); - void _process_SetPoints(_EMS_RxTelegram * EMS_RxTelegram); // SM10 @@ -62,6 +61,10 @@ void _process_SM100Status(_EMS_RxTelegram * EMS_RxTelegram); void _process_SM100Status2(_EMS_RxTelegram * EMS_RxTelegram); void _process_SM100Energy(_EMS_RxTelegram * EMS_RxTelegram); +// HeatPump HP +void _process_HPMonitor1(_EMS_RxTelegram * EMS_RxTelegram); +void _process_HPMonitor2(_EMS_RxTelegram * EMS_RxTelegram); + // Common for most thermostats void _process_RCTime(_EMS_RxTelegram * EMS_RxTelegram); void _process_RCOutdoorTempMessage(_EMS_RxTelegram * EMS_RxTelegram); @@ -120,6 +123,8 @@ const _EMS_Type EMS_Types[] = { {EMS_MODEL_OTHER, EMS_TYPE_SM100Status, "SM100Status", _process_SM100Status}, {EMS_MODEL_OTHER, EMS_TYPE_SM100Status2, "SM100Status2", _process_SM100Status2}, {EMS_MODEL_OTHER, EMS_TYPE_SM100Energy, "SM100Energy", _process_SM100Energy}, + {EMS_MODEL_OTHER, EMS_TYPE_HPMonitor1, "HeatPumpMonitor1", _process_HPMonitor1}, + {EMS_MODEL_OTHER, EMS_TYPE_HPMonitor2, "HeatPumpMonitor2", _process_HPMonitor2}, // RC10 {EMS_MODEL_RC10, EMS_TYPE_RCTime, "RCTime", _process_RCTime}, @@ -299,6 +304,8 @@ void ems_init() { EMS_Other.SMEnergyLastHour = EMS_VALUE_SHORT_NOTSET; EMS_Other.SMEnergyToday = EMS_VALUE_SHORT_NOTSET; EMS_Other.SMEnergyTotal = EMS_VALUE_SHORT_NOTSET; + EMS_Other.HPModulation = EMS_VALUE_INT_NOTSET; + EMS_Other.HPSpeed = EMS_VALUE_INT_NOTSET; // calculated values EMS_Boiler.tapwaterActive = EMS_VALUE_INT_NOTSET; // Hot tap water is on/off @@ -315,6 +322,7 @@ void ems_init() { // set other types EMS_Other.SM = false; + EMS_Other.HP = false; // default logging is none ems_setLogging(EMS_SYS_LOGGING_DEFAULT); @@ -695,7 +703,6 @@ void _ems_readTelegram(uint8_t * telegram, uint8_t length) { // check first for a Poll for us // the poll has the MSB set - seems to work on both EMS and Junkers if (value == (EMS_ID_ME | 0x80)) { - EMS_Sys_Status.emsTxCapable = true; uint32_t timenow_microsecs = micros(); EMS_Sys_Status.emsPollFrequency = (timenow_microsecs - _last_emsPollFrequency); @@ -1427,10 +1434,9 @@ void _process_SM100Status2(_EMS_RxTelegram * EMS_RxTelegram) { /* * SM100Energy - type 0x028E EMS+ for energy readings + * e.g. 30 00 FF 00 02 8E 00 00 00 00 00 00 06 C5 00 00 76 35 */ void _process_SM100Energy(_EMS_RxTelegram * EMS_RxTelegram) { - // e.g. 30 00 FF 00 02 8E 00 00 00 00 00 00 06 C5 00 00 76 35 - EMS_Other.SMEnergyLastHour = _toShort(2); // last hour / 10 in Wh EMS_Other.SMEnergyToday = _toShort(6); // todays in Wh EMS_Other.SMEnergyTotal = _toShort(10); // total / 10 in kWh @@ -1439,6 +1445,26 @@ void _process_SM100Energy(_EMS_RxTelegram * EMS_RxTelegram) { EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } +/* + * Type 0xE3 - HeatPump Monitor 1 + */ +void _process_HPMonitor1(_EMS_RxTelegram * EMS_RxTelegram) { + EMS_Other.HPModulation = _toByte(14); // modulation % + + EMS_Other.HP = true; + EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT +} + +/* + * Type 0xE5 - HeatPump Monitor 2 + */ +void _process_HPMonitor2(_EMS_RxTelegram * EMS_RxTelegram) { + EMS_Other.HPSpeed = _toByte(25); // speed % + + EMS_Other.HP = true; + EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT +} + /** * UBASetPoint 0x1A */ @@ -1631,6 +1657,12 @@ void _process_Version(_EMS_RxTelegram * EMS_RxTelegram) { myDebug_P(PSTR("SM10 Solar Module support enabled.")); } + // see if this is a HeatPump + if (Other_Types[i].device_id == EMS_ID_HP) { + EMS_Other.HP = true; // we have detected a HP + myDebug_P(PSTR("HeatPump support enabled.")); + } + // fetch other values ems_getOtherValues(); return; diff --git a/src/ems.h b/src/ems.h index 447720ab4..d40d90dd4 100644 --- a/src/ems.h +++ b/src/ems.h @@ -18,6 +18,7 @@ #define EMS_ID_ME 0x0B // Fixed - our device, hardcoded as the "Service Key" #define EMS_ID_DEFAULT_BOILER 0x08 #define EMS_ID_SM 0x30 // Solar Module SM10 and SM100 +#define EMS_ID_HP 0x38 // HeatPump #define EMS_ID_GATEWAY 0x48 // KM200 Web Gateway #define EMS_MIN_TELEGRAM_LENGTH 6 // minimal length for a validation telegram, including CRC @@ -242,7 +243,8 @@ typedef struct { // UBAParameterWW // SM Solar Module - SM10Monitor/SM100Monitor typedef struct { - bool SM; // set true if there is a SM available + bool SM; // set true if there is a Solar Module available + bool HP; // set true if there is a Heat Pump available int16_t SMcollectorTemp; // collector temp int16_t SMbottomTemp; // bottom temp uint8_t SMpumpModulation; // modulation solar pump @@ -250,6 +252,8 @@ typedef struct { int16_t SMEnergyLastHour; int16_t SMEnergyToday; int16_t SMEnergyTotal; + uint8_t HPModulation; // heatpump modulation in % + uint8_t HPSpeed; // speed 0-100 % } _EMS_Other; // Thermostat data diff --git a/src/ems_devices.h b/src/ems_devices.h index 96261fb31..175749300 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -46,6 +46,8 @@ #define EMS_TYPE_SM100Status 0x0264 // SM100Status #define EMS_TYPE_SM100Status2 0x026A // SM100Status2 #define EMS_TYPE_SM100Energy 0x028E // SM100Energy +#define EMS_TYPE_HPMonitor1 0xE3 // HeatPump Monitor 1 +#define EMS_TYPE_HPMonitor2 0xE5 // HeatPump Monitor 2 /* * Thermostats... diff --git a/src/my_config.h b/src/my_config.h index b2713a2a0..c12218e00 100644 --- a/src/my_config.h +++ b/src/my_config.h @@ -58,6 +58,11 @@ #define SM_ENERGYTODAY "energytoday" // energy today #define SM_ENERGYTOTAL "energytotal" // energy total +// MQTT for HP (HeatPump) +#define TOPIC_HP_DATA "hp_data" // topic name +#define HP_PUMPMODULATION "pumpmodulation" // pump modulation +#define HP_PUMPSPEED "pumpspeed" // pump speed + // shower time #define TOPIC_SHOWERTIME "showertime" // for sending shower time results #define TOPIC_SHOWER_TIMER "shower_timer" // toggle switch for enabling the shower logic diff --git a/src/test_data.h b/src/test_data.h index 40b2b365c..30f9c3c31 100644 --- a/src/test_data.h +++ b/src/test_data.h @@ -46,7 +46,11 @@ static const char * TEST_DATA[] = { "10 48 F7 00 FF 01 A5 DF FF F7 7F 1F", // test 41 - gateway "30 00 FF 09 02 64 1E", // test 42 - SM100 "08 00 18 00 05 03 30 00 00 00 00 04 40 80 00 02 17 80 00 00 00 FF 30 48 00 CB 00 00 00", // test 43 - sys pressure - "90 00 FF 00 00 6F 03 01 00 BE 00 BF" // test 44 - FR10 + "90 00 FF 00 00 6F 03 01 00 BE 00 BF", // test 44 - FR10 + "08 00 E3 00 01 00 01 00 00 00 00 00 00 00 00 00 DF 00 64 55", // test 45 - heatpump Enviline + "08 00 E5 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0A", // test 46 - heatpump Enviline + "38 10 FF 00 03 2B 00 C7 07 C3 01" // test 47 - heatpump Enviline + }; diff --git a/src/version.h b/src/version.h index 7a47bf9cb..8b82bbcc1 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.0b5" +#define APP_VERSION "1.8.0b6" #define APP_HOSTNAME "ems-esp"