From a64dd3437960afa55cc96d490a64b82193ce37a8 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 3 May 2019 16:56:28 +0200 Subject: [PATCH] https://github.com/proddy/EMS-ESP/issues/96 --- src/ems-esp.cpp | 78 ++++++++++++++++++++++++++++------------------- src/ems.cpp | 23 ++++++++++++-- src/ems.h | 12 +++++--- src/ems_devices.h | 1 + src/my_config.h | 15 +++++---- src/test_data.h | 4 ++- 6 files changed, 88 insertions(+), 45 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 3d818d118..e1af1e483 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -172,39 +172,42 @@ char * _bool_to_char(char * s, uint8_t value) { return s; } -// convert short (two bytes) to text value +// convert short (two bytes) to text string +// decimals: 0 = no division, 1=divide value by 10, 10=divide value by 100 // negative values are assumed stored as 1-compliment (https://medium.com/@LeeJulija/how-integers-are-stored-in-memory-using-twos-complement-5ba04d61a56c) char * _short_to_char(char * s, int16_t value, uint8_t decimals = 1) { - // remove errors on invalid values + // remove errors or invalid values if (abs(value) >= EMS_VALUE_SHORT_NOTSET) { - strlcpy(s, "?", sizeof(s)); + strlcpy(s, "?", 10); return (s); } + // just print if (decimals == 0) { - itoa(value, s, 10); + ltoa(value, s, 10); return (s); } - // floating point - char s2[5] = {0}; + // do floating point + char s2[10] = {0}; // check for negative values if (value < 0) { - strlcpy(s, "-", 2); + strlcpy(s, "-", 10); value = abs(value); } - strlcpy(s, itoa(value / (decimals * 10), s2, 10), 5); - strlcat(s, ".", sizeof(s)); - strlcat(s, itoa(value % (decimals * 10), s2, 10), 5); + + strlcpy(s, ltoa(value / (decimals * 10), s2, 10), 10); + strlcat(s, ".", 10); + strlcat(s, ltoa(value % (decimals * 10), s2, 10), 10); return s; } // takes a short value (2 bytes), converts to a fraction -// most values stored a s short are either *10 or *100 +// decimals: 0 = no division, 1=divide value by 10, 10=divide value by 100 void _renderShortValue(const char * prefix, const char * postfix, int16_t value, uint8_t decimals = 1) { - char buffer[200] = {0}; - char s[20] = {0}; + static char buffer[200] = {0}; + static char s[20] = {0}; strlcpy(buffer, " ", sizeof(buffer)); strlcat(buffer, prefix, sizeof(buffer)); strlcat(buffer, ": ", sizeof(buffer)); @@ -226,7 +229,7 @@ char * _int_to_char(char * s, uint8_t value, uint8_t div = 1) { return (s); } - char s2[5] = {0}; + static char s2[5] = {0}; switch (div) { case 1: @@ -255,8 +258,8 @@ char * _int_to_char(char * s, uint8_t value, uint8_t div = 1) { // takes an int value (1 byte), converts to a fraction void _renderIntValue(const char * prefix, const char * postfix, uint8_t value, uint8_t div = 1) { - char buffer[200] = {0}; - char s[20] = {0}; + static char buffer[200] = {0}; + static char s[20] = {0}; strlcpy(buffer, " ", sizeof(buffer)); strlcat(buffer, prefix, sizeof(buffer)); strlcat(buffer, ": ", sizeof(buffer)); @@ -273,7 +276,7 @@ void _renderIntValue(const char * prefix, const char * postfix, uint8_t value, u // takes a long value at prints it to debug log void _renderLongValue(const char * prefix, const char * postfix, uint32_t value) { - char buffer[200] = {0}; + static char buffer[200] = {0}; strlcpy(buffer, " ", sizeof(buffer)); strlcat(buffer, prefix, sizeof(buffer)); strlcat(buffer, ": ", sizeof(buffer)); @@ -295,8 +298,8 @@ void _renderLongValue(const char * prefix, const char * postfix, uint32_t value) // takes a bool value at prints it to debug log void _renderBoolValue(const char * prefix, uint8_t value) { - char buffer[200] = {0}; - char s[20] = {0}; + static char buffer[200] = {0}; + static char s[20] = {0}; strlcpy(buffer, " ", sizeof(buffer)); strlcat(buffer, prefix, sizeof(buffer)); strlcat(buffer, ": ", sizeof(buffer)); @@ -310,7 +313,7 @@ void _renderBoolValue(const char * prefix, uint8_t value) { void showInfo() { // General stats from EMS bus - char buffer_type[128] = {0}; + static char buffer_type[128] = {0}; myDebug("%sEMS-ESP system stats:%s", COLOR_BOLD_ON, COLOR_BOLD_OFF); _EMS_SYS_LOGGING sysLog = ems_getLogging(); @@ -438,7 +441,7 @@ void showInfo() { myDebug(" Total UBA working time: %d days %d hours %d minutes", EMS_Boiler.UBAuptime / 1440, (EMS_Boiler.UBAuptime % 1440) / 60, EMS_Boiler.UBAuptime % 60); } - // For SM10 Solar Module + // For SM10/SM100 Solar Module if (EMS_Other.SM) { myDebug(""); // newline myDebug("%sSolar Module stats:%s", COLOR_BOLD_ON, COLOR_BOLD_OFF); @@ -446,6 +449,9 @@ void showInfo() { _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 } // Thermostat stats @@ -717,25 +723,33 @@ void publishValues(bool force) { } // handle the other values separately - // For SM10 Solar Module + // For SM10 and SM100 Solar Modules if (EMS_Other.SM) { // build new json object doc.clear(); - JsonObject rootSM10 = doc.to(); + JsonObject rootSM = doc.to(); - rootSM10[SM10_COLLECTORTEMP] = _short_to_char(s, EMS_Other.SMcollectorTemp); - rootSM10[SM10_BOTTOMTEMP] = _short_to_char(s, EMS_Other.SMbottomTemp); + rootSM[SM_COLLECTORTEMP] = _short_to_char(s, EMS_Other.SMcollectorTemp); + rootSM[SM_BOTTOMTEMP] = _short_to_char(s, EMS_Other.SMbottomTemp); if (abs(EMS_Other.SMcollectorTemp) < EMS_VALUE_SHORT_NOTSET) - rootSM10[SM10_COLLECTORTEMP] = (double)EMS_Other.SMcollectorTemp / 10; + rootSM[SM_COLLECTORTEMP] = (double)EMS_Other.SMcollectorTemp / 10; if (abs(EMS_Other.SMbottomTemp) < EMS_VALUE_SHORT_NOTSET) - rootSM10[SM10_BOTTOMTEMP] = (double)EMS_Other.SMbottomTemp / 10; - + rootSM[SM_BOTTOMTEMP] = (double)EMS_Other.SMbottomTemp / 10; if (EMS_Other.SMpumpModulation != EMS_VALUE_INT_NOTSET) - rootSM10[SM10_PUMPMODULATION] = EMS_Other.SMpumpModulation; + rootSM[SM_PUMPMODULATION] = EMS_Other.SMpumpModulation; - rootSM10[SM10_PUMP] = _bool_to_char(s, EMS_Other.SMpump); + rootSM[SM_PUMP] = _bool_to_char(s, EMS_Other.SMpump); + + if (abs(EMS_Other.SMEnergyLastHour) < EMS_VALUE_SHORT_NOTSET) + rootSM[SM_ENERGYLASTHOUR] = (double)EMS_Other.SMEnergyLastHour / 10; + + if (abs(EMS_Other.SMEnergyToday) < EMS_VALUE_SHORT_NOTSET) + rootSM[SM_ENERGYTODAY] = EMS_Other.SMEnergyToday; + + if (abs(EMS_Other.SMEnergyTotal) < EMS_VALUE_SHORT_NOTSET) + rootSM[SM_ENERGYTOTAL] = (double)EMS_Other.SMEnergyTotal / 10; data[0] = '\0'; // reset data for next package serializeJson(doc, data, sizeof(data)); @@ -748,10 +762,10 @@ void publishValues(bool force) { fchecksum = crc.finalize(); if ((previousOtherPublishCRC != fchecksum) || force) { previousOtherPublishCRC = fchecksum; - myDebugLog("Publishing SM10 data via MQTT"); + myDebugLog("Publishing SM data via MQTT"); // send values via MQTT - myESP.mqttPublish(TOPIC_SM10_DATA, data); + myESP.mqttPublish(TOPIC_SM_DATA, data); } } } diff --git a/src/ems.cpp b/src/ems.cpp index a4ea31da4..69f898ec5 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -42,7 +42,7 @@ std::list<_Generic_Type> Devices; // generic void _process_Version(_EMS_RxTelegram * EMS_RxTelegram); -// Boiler and Buderus devices +// EMS master/Boiler devices void _process_UBAMonitorFast(_EMS_RxTelegram * EMS_RxTelegram); void _process_UBAMonitorSlow(_EMS_RxTelegram * EMS_RxTelegram); void _process_UBAMonitorWWMessage(_EMS_RxTelegram * EMS_RxTelegram); @@ -59,6 +59,7 @@ void _process_SM10Monitor(_EMS_RxTelegram * EMS_RxTelegram); void _process_SM100Monitor(_EMS_RxTelegram * EMS_RxTelegram); void _process_SM100Status(_EMS_RxTelegram * EMS_RxTelegram); void _process_SM100Status2(_EMS_RxTelegram * EMS_RxTelegram); +void _process_SM100Energy(_EMS_RxTelegram * EMS_RxTelegram); // Common for most thermostats void _process_RCTime(_EMS_RxTelegram * EMS_RxTelegram); @@ -111,6 +112,7 @@ const _EMS_Type EMS_Types[] = { {EMS_MODEL_OTHER, EMS_TYPE_SM100Monitor, "SM100Monitor", _process_SM100Monitor}, {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}, // RC10 {EMS_MODEL_RC10, EMS_TYPE_RCTime, "RCTime", _process_RCTime}, @@ -280,6 +282,9 @@ void ems_init() { EMS_Other.SMbottomTemp = EMS_VALUE_SHORT_NOTSET; // bottom temp from SM10/SM100 EMS_Other.SMpumpModulation = EMS_VALUE_INT_NOTSET; // modulation solar pump SM10/SM100 EMS_Other.SMpump = EMS_VALUE_INT_NOTSET; // pump active + EMS_Other.SMEnergyLastHour = EMS_VALUE_SHORT_NOTSET; + EMS_Other.SMEnergyToday = EMS_VALUE_SHORT_NOTSET; + EMS_Other.SMEnergyTotal = EMS_VALUE_SHORT_NOTSET; // calculated values EMS_Boiler.tapwaterActive = EMS_VALUE_INT_NOTSET; // Hot tap water is on/off @@ -1330,13 +1335,27 @@ void _process_SM100Status(_EMS_RxTelegram * EMS_RxTelegram) { */ void _process_SM100Status2(_EMS_RxTelegram * EMS_RxTelegram) { if (EMS_RxTelegram->data_length == 1) { - EMS_Other.SMpump = _bitRead(0, 2); // 03=off 04=on + EMS_Other.SMpump = _bitRead(0, 2); // 03=off 04=on } EMS_Other.SM = true; EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } +/* + * SM100Energy - type 0x028E EMS+ for energy readings + */ +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 + + EMS_Other.SM = true; + EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT +} + /** * UBASetPoint 0x1A */ diff --git a/src/ems.h b/src/ems.h index 937b1624d..6a3159202 100644 --- a/src/ems.h +++ b/src/ems.h @@ -238,13 +238,17 @@ typedef struct { // UBAParameterWW /* * Telegram package defintions for Other EMS devices */ + +// SM Solar Module - SM10Monitor/SM100Monitor typedef struct { - // SM10 Solar Module - SM10Monitor - bool SM; // set true if there is a SM10 available - int16_t SMcollectorTemp; // collector temp from SM10 - int16_t SMbottomTemp; // bottom temp from SM10 + bool SM; // set true if there is a SM available + int16_t SMcollectorTemp; // collector temp + int16_t SMbottomTemp; // bottom temp uint8_t SMpumpModulation; // modulation solar pump uint8_t SMpump; // pump active + int16_t SMEnergyLastHour; + int16_t SMEnergyToday; + int16_t SMEnergyTotal; } _EMS_Other; // Thermostat data diff --git a/src/ems_devices.h b/src/ems_devices.h index 2e8096280..691022fef 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -45,6 +45,7 @@ #define EMS_TYPE_SM100Monitor 0x0262 // SM100Monitor #define EMS_TYPE_SM100Status 0x0264 // SM100Status #define EMS_TYPE_SM100Status2 0x026A // SM100Status2 +#define EMS_TYPE_SM100Energy 0x028E // SM100Energy /* * Thermostats... diff --git a/src/my_config.h b/src/my_config.h index be0accd05..7b507b8b7 100644 --- a/src/my_config.h +++ b/src/my_config.h @@ -48,12 +48,15 @@ #define TOPIC_BOILER_CMD_WWTEMP "boiler_cmd_wwtemp" // for received boiler wwtemp changes via MQTT #define TOPIC_BOILER_CMD_COMFORT "boiler_cmd_comfort" // for received boiler ww comfort setting via MQTT -// MQTT for SM10 Solar Module -#define TOPIC_SM10_DATA "sm10_data" // topic name -#define SM10_COLLECTORTEMP "temp" // collector temp -#define SM10_BOTTOMTEMP "bottomtemp" // bottom temp -#define SM10_PUMPMODULATION "pumpmodulation" // pump modulation -#define SM10_PUMP "pump" // pump active +// MQTT for SM10/SM100 Solar Module +#define TOPIC_SM_DATA "sm_data" // topic name +#define SM_COLLECTORTEMP "temp" // collector temp +#define SM_BOTTOMTEMP "bottomtemp" // bottom temp +#define SM_PUMPMODULATION "pumpmodulation" // pump modulation +#define SM_PUMP "pump" // pump active +#define SM_ENERGYLASTHOUR "energylasthour" // energy last hour +#define SM_ENERGYTODAY "energytoday" // energy today +#define SM_ENERGYTOTAL "energytotal" // energy total // shower time #define TOPIC_SHOWERTIME "showertime" // for sending shower time results diff --git a/src/test_data.h b/src/test_data.h index e6a2cdece..604362e5c 100644 --- a/src/test_data.h +++ b/src/test_data.h @@ -34,7 +34,9 @@ static const char * TEST_DATA[] = { "30 00 FF 0A 02 6A 03", // test 29 - SM100 pump off "48 90 02 00 01", // test 30 - version test "10 48 02 00 9E", // test 31 - version test - "48 88 02 00 0A" // test 32 - version test + "30 00 FF 00 02 8E 00 00 0C F3 00 00 06 02 00 00 76 33", // test 32 - SM100 energy + "30 00 FF 00 02 8E 00 00 07 9E 00 00 06 C5 00 00 76 35", // test 33 - SM100 energy + "30 00 FF 00 02 8E 00 00 00 00 00 00 06 C5 00 00 76 35" // test 34 - SM100 energy };