mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 16:29:51 +03:00
This commit is contained in:
@@ -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>();
|
||||
JsonObject rootSM = doc.to<JsonObject>();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
23
src/ems.cpp
23
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
|
||||
*/
|
||||
|
||||
12
src/ems.h
12
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
|
||||
|
||||
@@ -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...
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user