mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-08 00:39:50 +03:00
@@ -112,3 +112,4 @@ build_flags = ${common.build_flags} ${common.custom_flags}
|
||||
extra_scripts =
|
||||
pre:scripts/pre_script.py
|
||||
scripts/main_script.py
|
||||
|
||||
|
||||
179
src/ems-esp.cpp
179
src/ems-esp.cpp
@@ -103,8 +103,8 @@ static const command_t project_cmds[] PROGMEM = {
|
||||
{true, "master_thermostat [product id]", "set default thermostat to use. Omit [product id] to show options."},
|
||||
|
||||
{false, "info", "show current values deciphered from the EMS messages"},
|
||||
{false, "log <n | b | t | s | r | j | v | w [type ID]", "set logging to none, basic, thermostat, solar module, raw, jabber, verbose or watch a specific type"},
|
||||
|
||||
{false, "log <n | b | t | s | r | j | v | w [ID] | d [ID]>", "logging: none, basic, thermo, solar, raw, jabber, verbose, watch a type or device"},
|
||||
|
||||
#ifdef TESTS
|
||||
{false, "test <n>", "insert a test telegram on to the EMS bus"},
|
||||
#endif
|
||||
@@ -120,6 +120,7 @@ static const command_t project_cmds[] PROGMEM = {
|
||||
{false, "thermostat mode [hc] <mode>", "set mode (0=off, 1=manual, 2=auto) for heating circuit hc 1-4"},
|
||||
{false, "boiler read <type ID>", "send read request to boiler"},
|
||||
{false, "boiler wwtemp <degrees>", "set boiler warm water temperature"},
|
||||
{false, "boiler wwactive <on | off>", "set boiler warm water on/off"},
|
||||
{false, "boiler tapwater <on | off>", "set boiler warm tap water on/off"},
|
||||
{false, "boiler flowtemp <degrees>", "set boiler flow temperature"},
|
||||
{false, "boiler comfort <hot | eco | intelligent>", "set boiler warm water comfort setting"}
|
||||
@@ -230,6 +231,8 @@ void showInfo() {
|
||||
myDebug_P(PSTR(" System logging set to Jabber"));
|
||||
} else if (sysLog == EMS_SYS_LOGGING_WATCH) {
|
||||
myDebug_P(PSTR(" System logging set to Watch"));
|
||||
} else if (sysLog == EMS_SYS_LOGGING_DEVICE) {
|
||||
myDebug_P(PSTR(" System logging set to device"));
|
||||
} else {
|
||||
myDebug_P(PSTR(" System logging set to None"));
|
||||
}
|
||||
@@ -299,6 +302,7 @@ void showInfo() {
|
||||
|
||||
_renderIntValue("Warm Water selected temperature", "C", EMS_Boiler.wWSelTemp);
|
||||
_renderIntValue("Warm Water desinfection temperature", "C", EMS_Boiler.wWDesinfectTemp);
|
||||
_renderBoolValue("Warm Water Circulation active",EMS_Boiler.wWCirc);
|
||||
|
||||
// UBAMonitorWWMessage
|
||||
_renderUShortValue("Warm Water current temperature", "C", EMS_Boiler.wWCurTmp);
|
||||
@@ -337,7 +341,7 @@ void showInfo() {
|
||||
_renderIntValue("Boiler circuit pump modulation min power", "%", EMS_Boiler.pump_mod_min);
|
||||
|
||||
// UBAMonitorSlow
|
||||
if (EMS_Boiler.extTemp != EMS_VALUE_SHORT_NOTSET) {
|
||||
if (EMS_Boiler.extTemp > EMS_VALUE_SHORT_NOTSET) {
|
||||
_renderShortValue("Outside temperature", "C", EMS_Boiler.extTemp);
|
||||
}
|
||||
_renderUShortValue("Boiler temperature", "C", EMS_Boiler.boilTemp);
|
||||
@@ -442,6 +446,8 @@ void showInfo() {
|
||||
_renderIntValue(" Night temperature", "C", EMS_Thermostat.hc[hc_num - 1].nighttemp, 2); // convert to a single byte * 2
|
||||
_renderIntValue(" Vacation temperature", "C", EMS_Thermostat.hc[hc_num - 1].holidaytemp, 2); // convert to a single byte * 2
|
||||
}
|
||||
if (EMS_Thermostat.hc[hc_num - 1].circuitcalctemp < EMS_VALUE_USHORT_NOTSET)
|
||||
_renderIntValue(" Calculatet flow temperature", "C",EMS_Thermostat.hc[hc_num - 1].circuitcalctemp);
|
||||
|
||||
// Render Thermostat Mode
|
||||
_EMS_THERMOSTAT_MODE thermoMode;
|
||||
@@ -473,19 +479,34 @@ void showInfo() {
|
||||
if (ems_getMixingDeviceEnabled()) {
|
||||
myDebug_P(PSTR("")); // newline
|
||||
myDebug_P(PSTR("%sMixing module data:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF);
|
||||
_renderUShortValue("Switch temperature", "C", EMS_Boiler.switchTemp);
|
||||
// myDebug_P(PSTR(" Mixing: %s"), ems_getDeviceDescription(EMS_DEVICE_TYPE_MIXING, buffer_type,false));
|
||||
if (EMS_Boiler.switchTemp < EMS_VALUE_USHORT_NOTSET)
|
||||
_renderUShortValue("Switch temperature", "C", EMS_Boiler.switchTemp);
|
||||
|
||||
for (uint8_t hc_num = 1; hc_num <= EMS_THERMOSTAT_MAXHC; hc_num++) {
|
||||
if (EMS_Mixing.hc[hc_num - 1].active) {
|
||||
myDebug_P(PSTR(" Mixing Circuit %d"), hc_num);
|
||||
_renderUShortValue(" Current flow temperature", "C", EMS_Mixing.hc[hc_num - 1].flowTemp);
|
||||
if (EMS_Mixing.hc[hc_num - 1].flowTemp < EMS_VALUE_USHORT_NOTSET)
|
||||
_renderUShortValue(" Current flow temperature", "C", EMS_Mixing.hc[hc_num - 1].flowTemp);
|
||||
if (EMS_Mixing.hc[hc_num - 1].flowSetTemp != EMS_VALUE_INT_NOTSET)
|
||||
_renderIntValue(" Setpoint flow temperature", "C", EMS_Mixing.hc[hc_num - 1].flowSetTemp);
|
||||
_renderIntValue(" Current pump modulation", "%", EMS_Mixing.hc[hc_num - 1].pumpMod);
|
||||
if (EMS_Mixing.hc[hc_num - 1].pumpMod != EMS_VALUE_INT_NOTSET)
|
||||
_renderIntValue(" Current pump modulation", "%", EMS_Mixing.hc[hc_num - 1].pumpMod);
|
||||
if (EMS_Mixing.hc[hc_num - 1].valveStatus != EMS_VALUE_INT_NOTSET)
|
||||
_renderIntValue(" Current valve status", "", EMS_Mixing.hc[hc_num - 1].valveStatus);
|
||||
}
|
||||
}
|
||||
for (uint8_t wwc_num = 1; wwc_num <= EMS_THERMOSTAT_MAXWWC; wwc_num++) {
|
||||
if (EMS_Mixing.wwc[wwc_num - 1].active) {
|
||||
myDebug_P(PSTR(" Warm Water Circuit %d"), wwc_num);
|
||||
if (EMS_Mixing.wwc[wwc_num - 1].flowTemp < EMS_VALUE_USHORT_NOTSET)
|
||||
_renderUShortValue(" Current warm water temperature", "C", EMS_Mixing.wwc[wwc_num - 1].flowTemp);
|
||||
if (EMS_Mixing.wwc[wwc_num - 1].pumpMod != EMS_VALUE_INT_NOTSET)
|
||||
_renderIntValue(" Current pump status", "", EMS_Mixing.wwc[wwc_num - 1].pumpMod);
|
||||
if (EMS_Mixing.wwc[wwc_num - 1].tempStatus != EMS_VALUE_INT_NOTSET)
|
||||
_renderIntValue(" Current temp status", "", EMS_Mixing.wwc[wwc_num - 1].tempStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dallas external temp sensors
|
||||
@@ -592,23 +613,23 @@ void publishEMSValues(bool force) {
|
||||
if (EMS_Boiler.wWCircPump != EMS_VALUE_BOOL_NOTSET)
|
||||
rootBoiler["wWCircPump"] = EMS_Boiler.wWCircPump;
|
||||
|
||||
if (EMS_Boiler.extTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
if (EMS_Boiler.extTemp > EMS_VALUE_SHORT_NOTSET)
|
||||
rootBoiler["outdoorTemp"] = (float)EMS_Boiler.extTemp / 10;
|
||||
if (EMS_Boiler.wWCurTmp != EMS_VALUE_USHORT_NOTSET)
|
||||
if (EMS_Boiler.wWCurTmp < EMS_VALUE_USHORT_NOTSET)
|
||||
rootBoiler["wWCurTmp"] = (float)EMS_Boiler.wWCurTmp / 10;
|
||||
if (EMS_Boiler.wWCurFlow != EMS_VALUE_INT_NOTSET)
|
||||
rootBoiler["wWCurFlow"] = (float)EMS_Boiler.wWCurFlow / 10;
|
||||
if (EMS_Boiler.curFlowTemp != EMS_VALUE_USHORT_NOTSET)
|
||||
if (EMS_Boiler.curFlowTemp < EMS_VALUE_USHORT_NOTSET)
|
||||
rootBoiler["curFlowTemp"] = (float)EMS_Boiler.curFlowTemp / 10;
|
||||
if (EMS_Boiler.retTemp != EMS_VALUE_USHORT_NOTSET)
|
||||
if (EMS_Boiler.retTemp < EMS_VALUE_USHORT_NOTSET)
|
||||
rootBoiler["retTemp"] = (float)EMS_Boiler.retTemp / 10;
|
||||
if (EMS_Boiler.switchTemp != EMS_VALUE_USHORT_NOTSET)
|
||||
if (EMS_Boiler.switchTemp < EMS_VALUE_USHORT_NOTSET)
|
||||
rootBoiler["switchTemp"] = (float)EMS_Boiler.switchTemp / 10;
|
||||
if (EMS_Boiler.sysPress != EMS_VALUE_INT_NOTSET)
|
||||
rootBoiler["sysPress"] = (float)EMS_Boiler.sysPress / 10;
|
||||
if (EMS_Boiler.boilTemp != EMS_VALUE_USHORT_NOTSET)
|
||||
if (EMS_Boiler.boilTemp < EMS_VALUE_USHORT_NOTSET)
|
||||
rootBoiler["boilTemp"] = (float)EMS_Boiler.boilTemp / 10;
|
||||
if (EMS_Boiler.exhaustTemp != EMS_VALUE_USHORT_NOTSET)
|
||||
if (EMS_Boiler.exhaustTemp < EMS_VALUE_USHORT_NOTSET)
|
||||
rootBoiler["exhaustTemp"] = (float)EMS_Boiler.exhaustTemp / 10;
|
||||
if (EMS_Boiler.wWActivated != EMS_VALUE_BOOL_NOTSET)
|
||||
rootBoiler["wWActivated"] = _bool_to_char(s, EMS_Boiler.wWActivated);
|
||||
@@ -616,10 +637,13 @@ void publishEMSValues(bool force) {
|
||||
if (EMS_Boiler.wWActivated != EMS_VALUE_BOOL_NOTSET)
|
||||
rootBoiler["wWOnetime"] = _bool_to_char(s, EMS_Boiler.wWOneTime);
|
||||
|
||||
if (EMS_Boiler.wWCirc != EMS_VALUE_BOOL_NOTSET)
|
||||
rootBoiler["wWCirc"] = _bool_to_char(s, EMS_Boiler.wWCirc);
|
||||
|
||||
if (EMS_Boiler.burnGas != EMS_VALUE_BOOL_NOTSET)
|
||||
rootBoiler["burnGas"] = _bool_to_char(s, EMS_Boiler.burnGas);
|
||||
|
||||
if (EMS_Boiler.flameCurr != EMS_VALUE_USHORT_NOTSET)
|
||||
if (EMS_Boiler.flameCurr < EMS_VALUE_USHORT_NOTSET)
|
||||
rootBoiler["flameCurr"] = (float)(int16_t)EMS_Boiler.flameCurr / 10;
|
||||
|
||||
if (EMS_Boiler.heatPmp != EMS_VALUE_BOOL_NOTSET)
|
||||
@@ -631,9 +655,6 @@ void publishEMSValues(bool force) {
|
||||
if (EMS_Boiler.ignWork != EMS_VALUE_BOOL_NOTSET)
|
||||
rootBoiler["ignWork"] = _bool_to_char(s, EMS_Boiler.ignWork);
|
||||
|
||||
if (EMS_Boiler.wWCirc != EMS_VALUE_BOOL_NOTSET)
|
||||
rootBoiler["wWCirc"] = _bool_to_char(s, EMS_Boiler.wWCirc);
|
||||
|
||||
if (EMS_Boiler.heating_temp != EMS_VALUE_INT_NOTSET)
|
||||
rootBoiler["heating_temp"] = EMS_Boiler.heating_temp;
|
||||
if (EMS_Boiler.pump_mod_max != EMS_VALUE_INT_NOTSET)
|
||||
@@ -700,19 +721,19 @@ void publishEMSValues(bool force) {
|
||||
|
||||
// different logic depending on thermostat types
|
||||
if (model == EMS_DEVICE_FLAG_EASY) {
|
||||
if (thermostat->setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
if (thermostat->setpoint_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
||||
dataThermostat[THERMOSTAT_SELTEMP] = (float)thermostat->setpoint_roomTemp / 100;
|
||||
if (thermostat->curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
if (thermostat->curr_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
||||
dataThermostat[THERMOSTAT_CURRTEMP] = (float)thermostat->curr_roomTemp / 100;
|
||||
} else if (model == EMS_DEVICE_FLAG_JUNKERS) {
|
||||
if (thermostat->setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
if (thermostat->setpoint_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
||||
dataThermostat[THERMOSTAT_SELTEMP] = (float)thermostat->setpoint_roomTemp / 10;
|
||||
if (thermostat->curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
if (thermostat->curr_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
||||
dataThermostat[THERMOSTAT_CURRTEMP] = (float)thermostat->curr_roomTemp / 10;
|
||||
} else {
|
||||
if (thermostat->setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
if (thermostat->setpoint_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
||||
dataThermostat[THERMOSTAT_SELTEMP] = (float)thermostat->setpoint_roomTemp / 2;
|
||||
if (thermostat->curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
if (thermostat->curr_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
||||
dataThermostat[THERMOSTAT_CURRTEMP] = (float)thermostat->curr_roomTemp / 10;
|
||||
|
||||
if (thermostat->daytemp != EMS_VALUE_INT_NOTSET)
|
||||
@@ -767,8 +788,7 @@ void publishEMSValues(bool force) {
|
||||
strlcpy(hc, THERMOSTAT_HC, sizeof(hc));
|
||||
strlcat(hc, _int_to_char(s, mixing->hc), sizeof(hc));
|
||||
JsonObject dataMixing = rootMixing.createNestedObject(hc);
|
||||
|
||||
if (mixing->flowTemp != EMS_VALUE_USHORT_NOTSET)
|
||||
if (mixing->flowTemp < EMS_VALUE_USHORT_NOTSET)
|
||||
dataMixing["flowTemp"] = (float)mixing->flowTemp / 10;
|
||||
if (mixing->flowSetTemp != EMS_VALUE_INT_NOTSET)
|
||||
dataMixing["setflowTemp"] = mixing->flowSetTemp;
|
||||
@@ -778,6 +798,23 @@ void publishEMSValues(bool force) {
|
||||
dataMixing["valveStatus"] = mixing->valveStatus;
|
||||
}
|
||||
}
|
||||
for (uint8_t wwc_v = 1; wwc_v <= EMS_THERMOSTAT_MAXWWC; wwc_v++) {
|
||||
_EMS_Mixing_WWC * mixing = &EMS_Mixing.wwc[wwc_v - 1];
|
||||
// only send if we have an active Warm water Circuit with real data
|
||||
if (mixing->active) {
|
||||
// build new json object
|
||||
char wwc[10]; // wc{1-2}
|
||||
strlcpy(wwc, "wwc", sizeof(wwc));
|
||||
strlcat(wwc, _int_to_char(s, mixing->wwc), sizeof(wwc));
|
||||
JsonObject dataMixing = rootMixing.createNestedObject(wwc);
|
||||
if (mixing->flowTemp < EMS_VALUE_USHORT_NOTSET)
|
||||
dataMixing["wwTemp"] = (float)mixing->flowTemp / 10;
|
||||
if (mixing->pumpMod != EMS_VALUE_INT_NOTSET)
|
||||
dataMixing["pumpStatus"] = mixing->pumpMod;
|
||||
if (mixing->tempStatus != EMS_VALUE_INT_NOTSET)
|
||||
dataMixing["tempStatus"] = mixing->tempStatus;
|
||||
}
|
||||
}
|
||||
|
||||
data[0] = '\0'; // reset data for next package
|
||||
serializeJson(doc, data, sizeof(data));
|
||||
@@ -792,10 +829,10 @@ void publishEMSValues(bool force) {
|
||||
doc.clear();
|
||||
JsonObject rootSM = doc.to<JsonObject>();
|
||||
|
||||
if (EMS_SolarModule.collectorTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
if (EMS_SolarModule.collectorTemp > EMS_VALUE_SHORT_NOTSET)
|
||||
rootSM[SM_COLLECTORTEMP] = (float)EMS_SolarModule.collectorTemp / 10;
|
||||
|
||||
if (EMS_SolarModule.bottomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
if (EMS_SolarModule.bottomTemp > EMS_VALUE_SHORT_NOTSET)
|
||||
rootSM[SM_BOTTOMTEMP] = (float)EMS_SolarModule.bottomTemp / 10;
|
||||
|
||||
if (EMS_SolarModule.pumpModulation != EMS_VALUE_INT_NOTSET)
|
||||
@@ -809,13 +846,13 @@ void publishEMSValues(bool force) {
|
||||
rootSM[SM_PUMPWORKMIN] = (float)EMS_SolarModule.pumpWorkMin;
|
||||
}
|
||||
|
||||
if (EMS_SolarModule.EnergyLastHour != EMS_VALUE_USHORT_NOTSET)
|
||||
if (EMS_SolarModule.EnergyLastHour < EMS_VALUE_USHORT_NOTSET)
|
||||
rootSM[SM_ENERGYLASTHOUR] = (float)EMS_SolarModule.EnergyLastHour / 10;
|
||||
|
||||
if (EMS_SolarModule.EnergyToday != EMS_VALUE_USHORT_NOTSET)
|
||||
if (EMS_SolarModule.EnergyToday < EMS_VALUE_USHORT_NOTSET)
|
||||
rootSM[SM_ENERGYTODAY] = EMS_SolarModule.EnergyToday;
|
||||
|
||||
if (EMS_SolarModule.EnergyTotal != EMS_VALUE_USHORT_NOTSET)
|
||||
if (EMS_SolarModule.EnergyTotal < EMS_VALUE_USHORT_NOTSET)
|
||||
rootSM[SM_ENERGYTOTAL] = (float)EMS_SolarModule.EnergyTotal / 10;
|
||||
|
||||
data[0] = '\0'; // reset data for next package
|
||||
@@ -1271,6 +1308,9 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) {
|
||||
} else if ((strcmp(second_cmd, "w") == 0) && (wc == 3)) {
|
||||
ems_setLogging(EMS_SYS_LOGGING_WATCH, _readHexNumber()); // get type_id
|
||||
ok = true;
|
||||
} else if ((strcmp(second_cmd, "d") == 0) && (wc == 3)) {
|
||||
ems_setLogging(EMS_SYS_LOGGING_DEVICE, _readHexNumber()); // get device_id
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1330,6 +1370,15 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) {
|
||||
} else if (strcmp(second_cmd, "flowtemp") == 0) {
|
||||
ems_setFlowTemp(_readIntNumber());
|
||||
ok = true;
|
||||
} else if (strcmp(second_cmd, "wwactive") == 0) {
|
||||
char * third_cmd = _readWord();
|
||||
if (strcmp(third_cmd, "on") == 0) {
|
||||
ems_setWarmWaterActivated(true);
|
||||
ok = true;
|
||||
} else if (strcmp(third_cmd, "off") == 0) {
|
||||
ems_setWarmWaterActivated(false);
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1398,13 +1447,16 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
|
||||
char topic_s[50];
|
||||
char buffer[4];
|
||||
for (uint8_t hc = 1; hc <= EMS_THERMOSTAT_MAXHC; hc++) {
|
||||
strlcpy(topic_s, TOPIC_THERMOSTAT_CMD_TEMP_HA, sizeof(topic_s));
|
||||
strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s));
|
||||
myESP.mqttSubscribe(topic_s);
|
||||
// subscribe onlyto active hc
|
||||
if(EMS_Thermostat.hc[hc - 1].active) {
|
||||
strlcpy(topic_s, TOPIC_THERMOSTAT_CMD_TEMP_HA, sizeof(topic_s));
|
||||
strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s));
|
||||
myESP.mqttSubscribe(topic_s);
|
||||
|
||||
strlcpy(topic_s, TOPIC_THERMOSTAT_CMD_MODE_HA, sizeof(topic_s));
|
||||
strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s));
|
||||
myESP.mqttSubscribe(topic_s);
|
||||
strlcpy(topic_s, TOPIC_THERMOSTAT_CMD_MODE_HA, sizeof(topic_s));
|
||||
strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s));
|
||||
myESP.mqttSubscribe(topic_s);
|
||||
}
|
||||
}
|
||||
|
||||
// generic incoming MQTT command for Thermostat
|
||||
@@ -1418,6 +1470,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
|
||||
// these three need to be unique topics
|
||||
myESP.mqttSubscribe(TOPIC_BOILER_CMD_WWACTIVATED);
|
||||
myESP.mqttSubscribe(TOPIC_BOILER_CMD_WWONETIME);
|
||||
myESP.mqttSubscribe(TOPIC_BOILER_CMD_WWCIRCULATION);
|
||||
myESP.mqttSubscribe(TOPIC_BOILER_CMD_WWTEMP);
|
||||
|
||||
// generic incoming MQTT command for EMS-ESP
|
||||
@@ -1547,6 +1600,16 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
|
||||
return;
|
||||
}
|
||||
|
||||
// wwCirculation
|
||||
if (strcmp(topic, TOPIC_BOILER_CMD_WWCIRCULATION) == 0) {
|
||||
if (message[0] == '1' || strcmp(message, "on") == 0) {
|
||||
ems_setWarmWaterCirculation(true);
|
||||
} else if (message[0] == '0' || strcmp(message, "off") == 0) {
|
||||
ems_setWarmWaterCirculation(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// boiler wwtemp changes
|
||||
if (strcmp(topic, TOPIC_BOILER_CMD_WWTEMP) == 0) {
|
||||
uint8_t t = atoi((char *)message);
|
||||
@@ -1558,7 +1621,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
|
||||
uint8_t hc;
|
||||
// thermostat temp changes
|
||||
hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_TEMP_HA, topic);
|
||||
if (hc) {
|
||||
if (hc && EMS_Thermostat.hc[hc - 1].active) {
|
||||
float f = strtof((char *)message, 0);
|
||||
ems_setThermostatTemp(f, hc);
|
||||
publishEMSValues(true); // publish back immediately
|
||||
@@ -1567,7 +1630,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
|
||||
|
||||
// thermostat mode changes
|
||||
hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_MODE_HA, topic);
|
||||
if (hc) {
|
||||
if (hc && EMS_Thermostat.hc[hc - 1].active) {
|
||||
if (strncmp(message, "auto", 4) == 0) {
|
||||
ems_setThermostatMode(2, hc);
|
||||
} else if ((strncmp(message, "day", 4) == 0) || (strncmp(message, "manual", 6) == 0) || (strncmp(message, "heat", 4) == 0)) {
|
||||
@@ -1591,7 +1654,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
|
||||
|
||||
// thermostat temp changes
|
||||
hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_TEMP, command);
|
||||
if (hc) {
|
||||
if (hc && EMS_Thermostat.hc[hc - 1].active) {
|
||||
float f = doc["data"];
|
||||
ems_setThermostatTemp(f, hc);
|
||||
publishEMSValues(true); // publish back immediately
|
||||
@@ -1600,7 +1663,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
|
||||
|
||||
// thermostat mode changes
|
||||
hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_MODE, command);
|
||||
if (hc) {
|
||||
if (hc && EMS_Thermostat.hc[hc - 1].active) {
|
||||
const char * data_cmd = doc["data"];
|
||||
if (strncmp(data_cmd, "auto", 4) == 0) {
|
||||
ems_setThermostatMode(2, hc);
|
||||
@@ -1614,7 +1677,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
|
||||
|
||||
// set night temp value
|
||||
hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_NIGHTTEMP, command);
|
||||
if (hc) {
|
||||
if (hc && EMS_Thermostat.hc[hc - 1].active) {
|
||||
float f = doc["data"];
|
||||
ems_setThermostatTemp(f, hc, 1); // night
|
||||
return;
|
||||
@@ -1622,7 +1685,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
|
||||
|
||||
// set daytemp value
|
||||
hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_DAYTEMP, command);
|
||||
if (hc) {
|
||||
if (hc && EMS_Thermostat.hc[hc - 1].active) {
|
||||
float f = doc["data"];
|
||||
ems_setThermostatTemp(f, hc, 2); // day
|
||||
return;
|
||||
@@ -1630,7 +1693,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
|
||||
|
||||
// set holiday value
|
||||
hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_HOLIDAYTEMP, command);
|
||||
if (hc) {
|
||||
if (hc && EMS_Thermostat.hc[hc - 1].active) {
|
||||
float f = doc["data"];
|
||||
ems_setThermostatTemp(f, hc, 3); // holiday
|
||||
return;
|
||||
@@ -1709,24 +1772,24 @@ void WebCallback(JsonObject root) {
|
||||
char buffer[200];
|
||||
thermostat["tm"] = ems_getDeviceDescription(EMS_DEVICE_TYPE_THERMOSTAT, buffer, true);
|
||||
|
||||
uint8_t hc_num = EMS_THERMOSTAT_DEFAULTHC; // default to HC1
|
||||
uint8_t hc_num = 1; // default to HC1
|
||||
uint8_t model = ems_getThermostatModel();
|
||||
|
||||
while (hc_num < EMS_THERMOSTAT_MAXHC && !EMS_Thermostat.hc[hc_num - 1].active) hc_num++; // first active hc
|
||||
// Render Current & Setpoint Room Temperature
|
||||
if (model == EMS_DEVICE_FLAG_EASY) {
|
||||
if (EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
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)
|
||||
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 (model == EMS_DEVICE_FLAG_JUNKERS) {
|
||||
if (EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
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)
|
||||
if (EMS_Thermostat.hc[hc_num - 1].curr_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
||||
thermostat["tc"] = (float)EMS_Thermostat.hc[hc_num - 1].curr_roomTemp / 10;
|
||||
} else {
|
||||
if (EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
if (EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
||||
thermostat["ts"] = (float)EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp / 2;
|
||||
if (EMS_Thermostat.hc[hc_num - 1].curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
if (EMS_Thermostat.hc[hc_num - 1].curr_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
||||
thermostat["tc"] = (float)EMS_Thermostat.hc[hc_num - 1].curr_roomTemp / 10;
|
||||
}
|
||||
|
||||
@@ -1763,10 +1826,10 @@ void WebCallback(JsonObject root) {
|
||||
if (EMS_Boiler.curFlowTemp != EMS_VALUE_INT_NOTSET)
|
||||
boiler["b4"] = EMS_Boiler.curFlowTemp / 10;
|
||||
|
||||
if (EMS_Boiler.boilTemp != EMS_VALUE_USHORT_NOTSET)
|
||||
if (EMS_Boiler.boilTemp < EMS_VALUE_USHORT_NOTSET)
|
||||
boiler["b5"] = (float)EMS_Boiler.boilTemp / 10;
|
||||
|
||||
if (EMS_Boiler.retTemp != EMS_VALUE_USHORT_NOTSET)
|
||||
if (EMS_Boiler.retTemp < EMS_VALUE_USHORT_NOTSET)
|
||||
boiler["b6"] = (float)EMS_Boiler.retTemp / 10;
|
||||
|
||||
} else {
|
||||
@@ -1781,10 +1844,10 @@ void WebCallback(JsonObject root) {
|
||||
char buffer[200];
|
||||
sm["sm"] = ems_getDeviceDescription(EMS_DEVICE_TYPE_SOLAR, buffer, true);
|
||||
|
||||
if (EMS_SolarModule.collectorTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
if (EMS_SolarModule.collectorTemp > EMS_VALUE_SHORT_NOTSET)
|
||||
sm["sm1"] = (float)EMS_SolarModule.collectorTemp / 10; // Collector temperature oC
|
||||
|
||||
if (EMS_SolarModule.bottomTemp != EMS_VALUE_SHORT_NOTSET)
|
||||
if (EMS_SolarModule.bottomTemp > EMS_VALUE_SHORT_NOTSET)
|
||||
sm["sm2"] = (float)EMS_SolarModule.bottomTemp / 10; // Bottom temperature oC
|
||||
|
||||
if (EMS_SolarModule.pumpModulation != EMS_VALUE_INT_NOTSET)
|
||||
@@ -1795,13 +1858,13 @@ void WebCallback(JsonObject root) {
|
||||
sm["sm4"] = _bool_to_char(s, EMS_SolarModule.pump); // Pump active on/off
|
||||
}
|
||||
|
||||
if (EMS_SolarModule.EnergyLastHour != EMS_VALUE_USHORT_NOTSET)
|
||||
if (EMS_SolarModule.EnergyLastHour < EMS_VALUE_USHORT_NOTSET)
|
||||
sm["sm5"] = (float)EMS_SolarModule.EnergyLastHour / 10; // Energy last hour Wh
|
||||
|
||||
if (EMS_SolarModule.EnergyToday != EMS_VALUE_USHORT_NOTSET) // Energy today Wh
|
||||
if (EMS_SolarModule.EnergyToday < EMS_VALUE_USHORT_NOTSET) // Energy today Wh
|
||||
sm["sm6"] = EMS_SolarModule.EnergyToday;
|
||||
|
||||
if (EMS_SolarModule.EnergyTotal != EMS_VALUE_USHORT_NOTSET) // Energy total KWh
|
||||
if (EMS_SolarModule.EnergyTotal < EMS_VALUE_USHORT_NOTSET) // Energy total KWh
|
||||
sm["sm7"] = (float)EMS_SolarModule.EnergyTotal / 10;
|
||||
} else {
|
||||
sm["ok"] = false;
|
||||
|
||||
75
src/ems.cpp
75
src/ems.cpp
@@ -128,6 +128,12 @@ void ems_init() {
|
||||
EMS_Mixing.hc[i].valveStatus = EMS_VALUE_INT_NOTSET;
|
||||
EMS_Mixing.hc[i].flowSetTemp = EMS_VALUE_INT_NOTSET;
|
||||
}
|
||||
for (uint8_t i = 0; i < EMS_THERMOSTAT_MAXWWC; i++) {
|
||||
EMS_Mixing.wwc[i].wwc = i + 1;
|
||||
EMS_Mixing.wwc[i].flowTemp = EMS_VALUE_USHORT_NOTSET;
|
||||
EMS_Mixing.wwc[i].pumpMod = EMS_VALUE_INT_NOTSET;
|
||||
EMS_Mixing.wwc[i].tempStatus = EMS_VALUE_INT_NOTSET;
|
||||
}
|
||||
|
||||
// UBAParameterWW
|
||||
EMS_Boiler.wWActivated = EMS_VALUE_BOOL_NOTSET; // Warm Water activated
|
||||
@@ -161,6 +167,7 @@ void ems_init() {
|
||||
EMS_Boiler.burnStarts = EMS_VALUE_LONG_NOTSET; // # burner restarts
|
||||
EMS_Boiler.burnWorkMin = EMS_VALUE_LONG_NOTSET; // Total burner operating time
|
||||
EMS_Boiler.heatWorkMin = EMS_VALUE_LONG_NOTSET; // Total heat operating time
|
||||
EMS_Boiler.switchTemp = EMS_VALUE_USHORT_NOTSET;
|
||||
|
||||
// UBAMonitorWWMessage
|
||||
EMS_Boiler.wWCurTmp = EMS_VALUE_USHORT_NOTSET; // Warm Water current temperature
|
||||
@@ -280,9 +287,9 @@ _EMS_SYS_LOGGING ems_getLogging() {
|
||||
return EMS_Sys_Status.emsLogging;
|
||||
}
|
||||
|
||||
void ems_setLogging(_EMS_SYS_LOGGING loglevel, uint16_t type_id) {
|
||||
EMS_Sys_Status.emsLogging_typeID = type_id;
|
||||
ems_setLogging(EMS_SYS_LOGGING_WATCH, false);
|
||||
void ems_setLogging(_EMS_SYS_LOGGING loglevel, uint16_t id) {
|
||||
EMS_Sys_Status.emsLogging_ID = id;
|
||||
ems_setLogging(loglevel, false);
|
||||
}
|
||||
|
||||
void ems_setLogging(_EMS_SYS_LOGGING loglevel, bool quiet) {
|
||||
@@ -308,6 +315,8 @@ void ems_setLogging(_EMS_SYS_LOGGING loglevel, bool quiet) {
|
||||
myDebug_P(PSTR("System Logging set to Jabber mode"));
|
||||
} else if (loglevel == EMS_SYS_LOGGING_WATCH) {
|
||||
myDebug_P(PSTR("System Logging set to Watch mode"));
|
||||
} else if (loglevel == EMS_SYS_LOGGING_DEVICE) {
|
||||
myDebug_P(PSTR("System Logging set to Device mode"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -851,8 +860,11 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) {
|
||||
// but still continue to process it
|
||||
if ((EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_RAW)) {
|
||||
_debugPrintTelegram("", &EMS_RxTelegram, COLOR_WHITE, true);
|
||||
} else if ((EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_WATCH) && (EMS_RxTelegram.type == EMS_Sys_Status.emsLogging_typeID)) {
|
||||
} else if ((EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_WATCH) && (EMS_RxTelegram.type == EMS_Sys_Status.emsLogging_ID)) {
|
||||
_debugPrintTelegram("", &EMS_RxTelegram, COLOR_WHITE, true);
|
||||
// raw printout for log d [id] disabled, moved to _printMessage()
|
||||
// } else if ((EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_DEVICE) && ((EMS_RxTelegram.src == EMS_Sys_Status.emsLogging_ID) || (EMS_RxTelegram.dest == EMS_Sys_Status.emsLogging_ID))) {
|
||||
// _debugPrintTelegram("", &EMS_RxTelegram, COLOR_WHITE, true);
|
||||
}
|
||||
|
||||
// Assume at this point we have something that vaguely resembles a telegram in the format [src] [dest] [type] [offset] [data] [crc]
|
||||
@@ -930,6 +942,11 @@ void _printMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
if ((src == EMS_SolarModule.device_id) || (dest == EMS_SolarModule.device_id)) {
|
||||
_debugPrintTelegram(output_str, EMS_RxTelegram, color_s);
|
||||
}
|
||||
} else if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_DEVICE) {
|
||||
// only print ones to/from DeviceID
|
||||
if ((src == EMS_Sys_Status.emsLogging_ID) || (dest == EMS_Sys_Status.emsLogging_ID)) {
|
||||
_debugPrintTelegram(output_str, EMS_RxTelegram, color_s);
|
||||
}
|
||||
} else {
|
||||
// always print
|
||||
_debugPrintTelegram(output_str, EMS_RxTelegram, color_s);
|
||||
@@ -1024,6 +1041,27 @@ void ems_setWarmWaterOnetime(bool activated) {
|
||||
|
||||
EMS_TxQueue.push(EMS_TxTelegram);
|
||||
}
|
||||
/**
|
||||
* Activate / De-activate circulation of warm water 0x35
|
||||
* true = on, false = off
|
||||
*/
|
||||
void ems_setWarmWaterCirculation(bool activated) {
|
||||
myDebug_P(PSTR("Setting boiler warm water circulation %s"), activated ? "on" : "off");
|
||||
|
||||
_EMS_TxTelegram EMS_TxTelegram = EMS_TX_TELEGRAM_NEW; // create new Tx
|
||||
EMS_TxTelegram.timestamp = millis(); // set timestamp
|
||||
EMS_Sys_Status.txRetryCount = 0; // reset retry counter
|
||||
|
||||
EMS_TxTelegram.action = EMS_TX_TELEGRAM_WRITE;
|
||||
EMS_TxTelegram.dest = EMS_Boiler.device_id;
|
||||
EMS_TxTelegram.type = EMS_TYPE_UBAFlags;
|
||||
EMS_TxTelegram.offset = EMS_OFFSET_UBAParameterWW_wwCirulation;
|
||||
EMS_TxTelegram.length = EMS_MIN_TELEGRAM_LENGTH;
|
||||
EMS_TxTelegram.type_validate = EMS_ID_NONE; // don't validate
|
||||
EMS_TxTelegram.dataValue = (activated ? 0x22 : 0x02);
|
||||
|
||||
EMS_TxQueue.push(EMS_TxTelegram);
|
||||
}
|
||||
|
||||
/**
|
||||
* UBAMonitorFast - type 0x18 - central heating monitor part 1 (25 bytes long)
|
||||
@@ -1249,10 +1287,23 @@ void _process_MMPLUSStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
_setValue(EMS_RxTelegram, &EMS_Mixing.hc[hc].pumpMod, EMS_OFFSET_MMPLUSStatusMessage_pump_mod);
|
||||
_setValue(EMS_RxTelegram, &EMS_Mixing.hc[hc].valveStatus, EMS_OFFSET_MMPLUSStatusMessage_valve_status);
|
||||
}
|
||||
// Mixer warm water loading - 0x0231, 0x0232
|
||||
|
||||
void _process_MMPLUSStatusMessageWW(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
uint8_t wwc = (EMS_RxTelegram->type - EMS_TYPE_MMPLUSStatusMessage_WWC1); // 0 to 3
|
||||
if (wwc >= EMS_THERMOSTAT_MAXWWC) {
|
||||
return; // invalid type
|
||||
}
|
||||
EMS_Mixing.wwc[wwc].active = true;
|
||||
|
||||
_setValue(EMS_RxTelegram, &EMS_Mixing.wwc[wwc].flowTemp, EMS_OFFSET_MMPLUSStatusMessage_WW_flow_temp);
|
||||
_setValue(EMS_RxTelegram, &EMS_Mixing.wwc[wwc].pumpMod, EMS_OFFSET_MMPLUSStatusMessage_WW_pump_mod);
|
||||
_setValue(EMS_RxTelegram, &EMS_Mixing.wwc[wwc].tempStatus, EMS_OFFSET_MMPLUSStatusMessage_WW_temp_status);
|
||||
}
|
||||
|
||||
// Mixer - 0xAB
|
||||
void _process_MMStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
uint8_t hc = 0; // fixed, for 0xAB (HC1 only)
|
||||
uint8_t hc = 1; // fixed, for 0xAB
|
||||
EMS_Mixing.hc[hc].active = true;
|
||||
|
||||
_setValue(EMS_RxTelegram, &EMS_Mixing.hc[hc].flowTemp, EMS_OFFSET_MMStatusMessage_flow_temp);
|
||||
@@ -1812,6 +1863,7 @@ void _process_Version(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||
EMS_Mixing.device_desc_p = device_desc_p;
|
||||
EMS_Mixing.device_flags = flags;
|
||||
EMS_Mixing.detected = true;
|
||||
strlcpy(EMS_Mixing.version, version, sizeof(EMS_Mixing.version));
|
||||
ems_doReadCommand(EMS_TYPE_MMPLUSStatusMessage_HC1, device_id); // fetch MM values
|
||||
}
|
||||
}
|
||||
@@ -2056,6 +2108,12 @@ char * ems_getDeviceDescription(_EMS_DEVICE_TYPE device_type, char * buffer, boo
|
||||
product_id = EMS_HeatPump.product_id;
|
||||
device_desc_p = EMS_HeatPump.device_desc_p;
|
||||
version = EMS_HeatPump.version;
|
||||
} else if (device_type == EMS_DEVICE_TYPE_MIXING) {
|
||||
enabled = ems_getMixingDeviceEnabled();
|
||||
device_id = EMS_Mixing.device_id;
|
||||
product_id = EMS_Mixing.product_id;
|
||||
device_desc_p = EMS_Mixing.device_desc_p;
|
||||
version = EMS_Mixing.version;
|
||||
}
|
||||
|
||||
if (!enabled) {
|
||||
@@ -2812,7 +2870,7 @@ const _EMS_Type EMS_Types[] = {
|
||||
{EMS_DEVICE_UPDATE_FLAG_THERMOSTAT, EMS_TYPE_RC35StatusMessage_HC1, "RC35StatusMessage_HC1", _process_RC35StatusMessage},
|
||||
{EMS_DEVICE_UPDATE_FLAG_THERMOSTAT, EMS_TYPE_RC35Set_HC2, "RC35Set_HC2", _process_RC35Set},
|
||||
{EMS_DEVICE_UPDATE_FLAG_THERMOSTAT, EMS_TYPE_RC35StatusMessage_HC2, "RC35StatusMessage_HC2", _process_RC35StatusMessage},
|
||||
{EMS_DEVICE_UPDATE_FLAG_THERMOSTAT, EMS_TYPE_RC35Set_HC3, "RC35Set_HC2", _process_RC35Set},
|
||||
{EMS_DEVICE_UPDATE_FLAG_THERMOSTAT, EMS_TYPE_RC35Set_HC3, "RC35Set_HC3", _process_RC35Set},
|
||||
{EMS_DEVICE_UPDATE_FLAG_THERMOSTAT, EMS_TYPE_RC35StatusMessage_HC3, "RC35StatusMessage_HC3", _process_RC35StatusMessage},
|
||||
{EMS_DEVICE_UPDATE_FLAG_THERMOSTAT, EMS_TYPE_RC35Set_HC4, "RC35Set_HC4", _process_RC35Set},
|
||||
{EMS_DEVICE_UPDATE_FLAG_THERMOSTAT, EMS_TYPE_RC35StatusMessage_HC4, "RC35StatusMessage_HC4", _process_RC35StatusMessage},
|
||||
@@ -2837,8 +2895,11 @@ const _EMS_Type EMS_Types[] = {
|
||||
// Mixing devices MM10 - MM400
|
||||
{EMS_DEVICE_UPDATE_FLAG_MIXING, EMS_TYPE_MMPLUSStatusMessage_HC1, "MMPLUSStatusMessage_HC1", _process_MMPLUSStatusMessage},
|
||||
{EMS_DEVICE_UPDATE_FLAG_MIXING, EMS_TYPE_MMPLUSStatusMessage_HC2, "MMPLUSStatusMessage_HC2", _process_MMPLUSStatusMessage},
|
||||
{EMS_DEVICE_UPDATE_FLAG_MIXING, EMS_TYPE_MMPLUSStatusMessage_HC3, "MMPLUSStatusMessage_HC3", _process_MMPLUSStatusMessage},
|
||||
{EMS_DEVICE_UPDATE_FLAG_MIXING, EMS_TYPE_MMPLUSStatusMessage_HC4, "MMPLUSStatusMessage_HC4", _process_MMPLUSStatusMessage},
|
||||
{EMS_DEVICE_UPDATE_FLAG_MIXING, EMS_TYPE_MMPLUSStatusMessage_WWC1, "MMPLUSStatusMessage_WWC1", _process_MMPLUSStatusMessageWW},
|
||||
{EMS_DEVICE_UPDATE_FLAG_MIXING, EMS_TYPE_MMPLUSStatusMessage_WWC2, "MMPLUSStatusMessage_WWC2", _process_MMPLUSStatusMessageWW},
|
||||
{EMS_DEVICE_UPDATE_FLAG_MIXING, EMS_TYPE_MMStatusMessage, "MMStatusMessage", _process_MMStatusMessage}
|
||||
|
||||
};
|
||||
|
||||
// calculate sizes of arrays at compile time
|
||||
|
||||
23
src/ems.h
23
src/ems.h
@@ -27,13 +27,14 @@
|
||||
#define EMS_VALUE_BOOL_ON2 0xFF // boolean true, EMS sometimes uses 0xFF for TRUE
|
||||
#define EMS_VALUE_BOOL_OFF 0x00 // boolean false
|
||||
#define EMS_VALUE_INT_NOTSET 0xFF // for 8-bit unsigned ints/bytes
|
||||
#define EMS_VALUE_SHORT_NOTSET -32768 // for 2-byte signed shorts
|
||||
#define EMS_VALUE_USHORT_NOTSET 0x8000 // for 2-byte unsigned shorts
|
||||
#define EMS_VALUE_SHORT_NOTSET -32000 // was -32768 for 2-byte signed shorts
|
||||
#define EMS_VALUE_USHORT_NOTSET 32000 // was 0x8000 for 2-byte unsigned shorts
|
||||
#define EMS_VALUE_LONG_NOTSET 0xFFFFFF // for 3-byte longs
|
||||
#define EMS_VALUE_BOOL_NOTSET 0xFE // random number that's not 0, 1 or FF
|
||||
|
||||
// thermostat specific
|
||||
#define EMS_THERMOSTAT_MAXHC 4 // max number of heating circuits
|
||||
#define EMS_THERMOSTAT_MAXWWC 2 // max number of warm water circuits
|
||||
#define EMS_THERMOSTAT_DEFAULTHC 1 // default heating circuit is 1
|
||||
#define EMS_THERMOSTAT_WRITE_YES true
|
||||
#define EMS_THERMOSTAT_WRITE_NO false
|
||||
@@ -112,9 +113,10 @@ typedef enum {
|
||||
EMS_SYS_LOGGING_WATCH, // watch a specific type ID
|
||||
EMS_SYS_LOGGING_BASIC, // only basic read/write messages
|
||||
EMS_SYS_LOGGING_THERMOSTAT, // only telegrams sent from thermostat
|
||||
EMS_SYS_LOGGING_SOLARMODULE, // only telegrams sent from thermostat
|
||||
EMS_SYS_LOGGING_SOLARMODULE, // only telegrams sent from solarmodule
|
||||
EMS_SYS_LOGGING_VERBOSE, // everything
|
||||
EMS_SYS_LOGGING_JABBER // lots of debug output...
|
||||
EMS_SYS_LOGGING_JABBER, // lots of debug output...
|
||||
EMS_SYS_LOGGING_DEVICE // watch the device ID
|
||||
} _EMS_SYS_LOGGING;
|
||||
|
||||
// status/counters since last power on
|
||||
@@ -126,7 +128,7 @@ typedef struct {
|
||||
uint16_t emxCrcErr; // CRC errors
|
||||
bool emsPollEnabled; // flag enable the response to poll messages
|
||||
_EMS_SYS_LOGGING emsLogging; // logging
|
||||
uint16_t emsLogging_typeID; // the typeID to watch
|
||||
uint16_t emsLogging_ID; // the type or device ID to watch
|
||||
uint8_t emsRefreshedFlags; // fresh data, needs to be pushed out to MQTT
|
||||
bool emsBusConnected; // is there an active bus
|
||||
uint32_t emsRxTimestamp; // timestamp of last EMS message received
|
||||
@@ -344,6 +346,15 @@ typedef struct {
|
||||
uint8_t flowSetTemp;
|
||||
} _EMS_Mixing_HC;
|
||||
|
||||
// Mixing Module per WWC
|
||||
typedef struct {
|
||||
uint8_t wwc; // warm water circuit 1, 2
|
||||
bool active; // true if there is data for this WWC
|
||||
uint16_t flowTemp;
|
||||
uint8_t pumpMod;
|
||||
uint8_t tempStatus;
|
||||
} _EMS_Mixing_WWC;
|
||||
|
||||
// Mixer data
|
||||
typedef struct {
|
||||
uint8_t device_id;
|
||||
@@ -353,6 +364,7 @@ typedef struct {
|
||||
char version[10];
|
||||
bool detected;
|
||||
_EMS_Mixing_HC hc[EMS_THERMOSTAT_MAXHC]; // array for the 4 heating circuits
|
||||
_EMS_Mixing_WWC wwc[EMS_THERMOSTAT_MAXWWC]; // array for the 2 ww circuits
|
||||
} _EMS_Mixing;
|
||||
|
||||
// Solar Module - SM10/SM100/SM200/ISM1
|
||||
@@ -432,6 +444,7 @@ void ems_setWarmWaterTemp(uint8_t temperature);
|
||||
void ems_setFlowTemp(uint8_t temperature);
|
||||
void ems_setWarmWaterActivated(bool activated);
|
||||
void ems_setWarmWaterOnetime(bool activated);
|
||||
void ems_setWarmWaterCirculation(bool activated);
|
||||
void ems_setWarmTapWaterActivated(bool activated);
|
||||
void ems_setPoll(bool b);
|
||||
void ems_setLogging(_EMS_SYS_LOGGING loglevel, uint16_t type_id);
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#define EMS_OFFSET_UBAParameterWW_wwtemp 2 // WW Temperature
|
||||
#define EMS_OFFSET_UBAParameterWW_wwactivated 1 // WW Activated
|
||||
#define EMS_OFFSET_UBAParameterWW_wwOneTime 0x00 // WW OneTime loading
|
||||
#define EMS_OFFSET_UBAParameterWW_wwCirulation 1 // WW circulation
|
||||
#define EMS_OFFSET_UBAParameterWW_wwComfort 9 // WW is in comfort or eco mode
|
||||
#define EMS_VALUE_UBAParameterWW_wwComfort_Hot 0x00 // the value for hot
|
||||
#define EMS_VALUE_UBAParameterWW_wwComfort_Eco 0xD8 // the value for eco
|
||||
@@ -175,9 +176,14 @@
|
||||
#define EMS_TYPE_MMPLUSStatusMessage_HC2 0x01D8 // mixer status HC2
|
||||
#define EMS_TYPE_MMPLUSStatusMessage_HC3 0x01D9 // mixer status HC3
|
||||
#define EMS_TYPE_MMPLUSStatusMessage_HC4 0x01DA // mixer status HC4
|
||||
#define EMS_TYPE_MMPLUSStatusMessage_WWC1 0x0231 // mixer status WWC1
|
||||
#define EMS_TYPE_MMPLUSStatusMessage_WWC2 0x0232 // mixer status WWC2
|
||||
#define EMS_OFFSET_MMPLUSStatusMessage_flow_temp 3 // flow temperature
|
||||
#define EMS_OFFSET_MMPLUSStatusMessage_pump_mod 5 // pump modulation
|
||||
#define EMS_OFFSET_MMPLUSStatusMessage_valve_status 2 // valve in percent
|
||||
#define EMS_OFFSET_MMPLUSStatusMessage_WW_flow_temp 0 // flow temperature
|
||||
#define EMS_OFFSET_MMPLUSStatusMessage_WW_pump_mod 2 // pump on 6, off 0
|
||||
#define EMS_OFFSET_MMPLUSStatusMessage_WW_temp_status 11 // 0,1,2
|
||||
|
||||
// MM10
|
||||
#define EMS_TYPE_MMStatusMessage 0xAB // mixer status
|
||||
|
||||
@@ -40,7 +40,7 @@ char * _bool_to_char(char * s, uint8_t value) {
|
||||
// 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) {
|
||||
// remove errors or invalid values
|
||||
if (value == EMS_VALUE_SHORT_NOTSET) {
|
||||
if (value <= EMS_VALUE_SHORT_NOTSET) {
|
||||
strlcpy(s, "?", 10);
|
||||
return (s);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#define TOPIC_BOILER_CMD "boiler_cmd" // for receiving boiler commands via MQTT
|
||||
#define TOPIC_BOILER_CMD_WWACTIVATED "boiler_cmd_wwactivated" // change water on/off
|
||||
#define TOPIC_BOILER_CMD_WWONETIME "boiler_cmd_wwonetime" // warm warter one time loading
|
||||
#define TOPIC_BOILER_CMD_WWCIRCULATION "boiler_cmd_wwcirculation" // start warm warter circulation
|
||||
#define TOPIC_BOILER_CMD_WWTEMP "boiler_cmd_wwtemp" // wwtemp changes via MQTT
|
||||
#define TOPIC_BOILER_CMD_COMFORT "comfort" // ww comfort setting via MQTT
|
||||
#define TOPIC_BOILER_CMD_FLOWTEMP "flowtemp" // flowtemp value via MQTT
|
||||
|
||||
Reference in New Issue
Block a user