proddy
2019-05-03 16:56:28 +02:00
parent 0a95b2c034
commit a64dd34379
6 changed files with 88 additions and 45 deletions

View File

@@ -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);
}
}
}

View File

@@ -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
*/

View File

@@ -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

View File

@@ -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...

View File

@@ -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

View File

@@ -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
};