mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 16:29:51 +03:00
added mqtt for hot water & heating on/off
This commit is contained in:
@@ -61,7 +61,10 @@ uint8_t regularUpdatesCount = 0;
|
||||
|
||||
// boiler
|
||||
#define TOPIC_BOILER_DATA MQTT_BOILER "boiler_data" // for sending boiler values
|
||||
#define TOPIC_BOILER_ MQTT_BOILER "boiler_wwtemp" // warm water selected temp
|
||||
#define TOPIC_BOILER_WARM_WATER_SELECTED_TEMPERATURE MQTT_BOILER "boiler_wwtemp" // warm water selected temp
|
||||
#define TOPIC_BOILER_TAPWATER_ACTIVE MQTT_BOILER "tapwater_active" // if hot tap water is running
|
||||
#define TOPIC_BOILER_HEATING_ACTIVE MQTT_BOILER "heating_active" // if heating is on
|
||||
|
||||
// shower time
|
||||
#define TOPIC_SHOWERTIME MQTT_BOILER "showertime" // for sending shower time results
|
||||
@@ -95,7 +98,6 @@ const unsigned long SHOWER_COLDSHOT_DURATION = 5; // in seconds! how long for co
|
||||
const unsigned long SHOWER_OFFSET_TIME = 0; // 0 seconds grace time, to calibrate actual time under the shower
|
||||
#endif
|
||||
|
||||
const uint8_t SHOWER_BURNPOWER_MIN = 80;
|
||||
typedef struct {
|
||||
bool wifi_connected;
|
||||
bool boiler_online;
|
||||
@@ -106,7 +108,6 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
bool showerOn;
|
||||
bool hotWaterOn;
|
||||
unsigned long timerStart; // ms
|
||||
unsigned long timerPause; // ms
|
||||
unsigned long duration; // ms
|
||||
@@ -124,18 +125,18 @@ netInfo homeNet = {.mqttHost = MQTT_IP,
|
||||
ESPHelper myESP(&homeNet);
|
||||
|
||||
command_t PROGMEM project_cmds[] = {{"s", "show statistics"},
|
||||
{"h", "list supported EMS telegram type ids"},
|
||||
{"h", "list EMS telegram type ids with supported logic"},
|
||||
{"P", "publish all stat to MQTT"},
|
||||
{"v", "[n] set logging (0=none, 1=basic, 2=verbose)"},
|
||||
{"p", "poll ems response on/off (default is off)"},
|
||||
{"T", "thermostat monitoring on/off"},
|
||||
{"S", "shower timer on/off"},
|
||||
{"A", "shower alert on/off"},
|
||||
{"r", "[n] send EMS request (n=telegram type id. Use 'h' for list)"},
|
||||
{"t", "[n] set thermostat temperature to n"},
|
||||
{"p", "toggle EMS Poll response on/off"},
|
||||
{"T", "toggle Thermostat monitoring on/off"},
|
||||
{"S", "toggle Shower timer on/off"},
|
||||
{"A", "toggle shower Alert on/off"},
|
||||
{"r", "[n] send EMS request (n=any telegram type id. Use 'h' for suppported types)"},
|
||||
{"t", "[n] set thermostat temperature"},
|
||||
{"m", "[n] set thermostat mode (1=manual, 2=auto)"},
|
||||
{"w", "[n] set boiler warm water temperature to n (min 30)"},
|
||||
{"a", "[n] boiler warm water on (n=1) or off (n=0)"},
|
||||
{"w", "[n] set boiler warm water temperature (min 30)"},
|
||||
{"a", "[n] boiler warm water (1=on, 2=off)"},
|
||||
{"x", "[n] experimental (warning: for debugging only!)"}};
|
||||
|
||||
// calculates size of an 2d array at compile time
|
||||
@@ -163,6 +164,8 @@ unsigned long timestamp; // for internal timings, via millis()
|
||||
static int connectionStatus = NO_CONNECTION;
|
||||
bool startMQTTsent = false;
|
||||
|
||||
uint8_t last_boilerActive = 0xFF; // for remembering last setting of the tap water or heating on/off
|
||||
|
||||
// toggle for heartbeat LED
|
||||
bool heartbeatEnabled;
|
||||
|
||||
@@ -322,6 +325,10 @@ void showInfo() {
|
||||
|
||||
myDebug("\n\n%sBoiler stats:%s\n", COLOR_BOLD_ON, COLOR_BOLD_OFF);
|
||||
|
||||
// active stats
|
||||
myDebug(" Hot tap water is %s\n", (EMS_Boiler.tapwaterActive ? "running" : "off"));
|
||||
myDebug(" Central Heating is %s\n", (EMS_Boiler.heatingActive ? "active" : "off"));
|
||||
|
||||
// UBAParameterWW
|
||||
_renderBoolValue("Warm Water activated", EMS_Boiler.wWActivated);
|
||||
_renderBoolValue("Warm Water circulation pump available", EMS_Boiler.wWCircPump);
|
||||
@@ -348,7 +355,7 @@ void showInfo() {
|
||||
_renderBoolValue("Circulation pump", EMS_Boiler.wWCirc);
|
||||
_renderIntValue("Burner selected max power", "%", EMS_Boiler.selBurnPow);
|
||||
_renderIntValue("Burner current power", "%", EMS_Boiler.curBurnPow);
|
||||
_renderFloatValue("Flame current", "uA", EMS_Boiler.flameCurr);
|
||||
_renderFloatValue("Flame current", "mA", EMS_Boiler.flameCurr);
|
||||
_renderFloatValue("System pressure", "bar", EMS_Boiler.sysPress);
|
||||
|
||||
// UBAMonitorSlow
|
||||
@@ -392,15 +399,16 @@ void showInfo() {
|
||||
|
||||
// show the Shower Info
|
||||
if (Boiler_Status.shower_timer) {
|
||||
myDebug("\n%sShower stats:%s\n", COLOR_BOLD_ON, COLOR_BOLD_OFF);
|
||||
myDebug(" Hot water is %s\n", (Boiler_Shower.hotWaterOn ? "running" : "stopped"));
|
||||
myDebug(" Shower is %s\n", (Boiler_Shower.showerOn ? "on" : "off"));
|
||||
myDebug("\n%s Shower stats:%s\n", COLOR_BOLD_ON, COLOR_BOLD_OFF);
|
||||
myDebug(" Shower Timer is %s\n", (Boiler_Shower.showerOn ? "active" : "off"));
|
||||
}
|
||||
|
||||
myDebug("\n");
|
||||
}
|
||||
|
||||
// send values to HA via MQTT
|
||||
// a json object is created for the boiler and one for the thermostat
|
||||
// CRC check is done to see if there are changes in the values since the last send to avoid too much wifi traffic
|
||||
void publishValues(bool force) {
|
||||
char s[20]; // for formatting strings
|
||||
|
||||
@@ -435,7 +443,7 @@ void publishValues(bool force) {
|
||||
crc.update(data[i]);
|
||||
}
|
||||
uint32_t checksum = crc.finalize();
|
||||
//myDebug("HASH=%d %08x, len=%d, s=%s\n", checksum, checksum, len, data);
|
||||
//myDebug("Boiler HASH=%d %08x, len=%d, s=%s\n", checksum, checksum, len, data);
|
||||
|
||||
if ((previousBoilerPublishCRC != checksum) || force) {
|
||||
previousBoilerPublishCRC = checksum;
|
||||
@@ -447,6 +455,19 @@ void publishValues(bool force) {
|
||||
myESP.publish(TOPIC_BOILER_DATA, data);
|
||||
}
|
||||
|
||||
// see if the heating or hot tap water has changed, if so send
|
||||
// last_boilerActive stores heating in bit 1 and tap water in bit 2
|
||||
if (last_boilerActive != ((EMS_Boiler.tapwaterActive << 1) + EMS_Boiler.heatingActive)) {
|
||||
if (ems_getLogging() != EMS_SYS_LOGGING_NONE) {
|
||||
myDebug("Publishing hot water and heating state via MQTT\n");
|
||||
}
|
||||
myESP.publish(TOPIC_BOILER_TAPWATER_ACTIVE, EMS_Boiler.tapwaterActive == 1 ? "1" : "0");
|
||||
myESP.publish(TOPIC_BOILER_HEATING_ACTIVE, EMS_Boiler.heatingActive == 1 ? "1" : "0");
|
||||
|
||||
last_boilerActive = ((EMS_Boiler.tapwaterActive << 1) + EMS_Boiler.heatingActive); // remember last state
|
||||
}
|
||||
|
||||
|
||||
// handle the thermostat values separately
|
||||
if (EMS_Sys_Status.emsThermostatEnabled) {
|
||||
// only send thermostat values if we actually have them
|
||||
@@ -476,6 +497,7 @@ void publishValues(bool force) {
|
||||
crc.update(data[i]);
|
||||
}
|
||||
uint32_t checksum = crc.finalize();
|
||||
//myDebug("Thermostat HASH=%d %08x, len=%d, s=%s\n", checksum, checksum, len, data);
|
||||
|
||||
if ((previousThermostatPublishCRC != checksum) || force) {
|
||||
previousThermostatPublishCRC = checksum;
|
||||
@@ -517,7 +539,7 @@ void myDebugCallback() {
|
||||
ems_setPoll(b);
|
||||
break;
|
||||
case 'P':
|
||||
myESP.logger(LOG_HA, "Force publish values");
|
||||
//myESP.logger(LOG_HA, "Force publish values");
|
||||
publishValues(true);
|
||||
break;
|
||||
case 'r': // read command for Boiler or Thermostat
|
||||
@@ -751,6 +773,8 @@ void setup() {
|
||||
myESP.addSubscription(TOPIC_SHOWER_TIMER);
|
||||
myESP.addSubscription(TOPIC_SHOWER_ALERT);
|
||||
myESP.addSubscription(TOPIC_BOILER_WARM_WATER_SELECTED_TEMPERATURE);
|
||||
myESP.addSubscription(TOPIC_BOILER_TAPWATER_ACTIVE);
|
||||
myESP.addSubscription(TOPIC_BOILER_HEATING_ACTIVE);
|
||||
myESP.addSubscription(TOPIC_SHOWER_COLDSHOT);
|
||||
|
||||
myESP.consoleSetCallBackProjectCmds(project_cmds, ArraySize(project_cmds), myDebugCallback); // set up Telnet commands
|
||||
@@ -812,11 +836,8 @@ void regularUpdates() {
|
||||
// only do calls if the EMS is connected and alive
|
||||
if (Boiler_Status.boiler_online) {
|
||||
if ((cycle == 0) && Boiler_Status.thermostat_enabled) {
|
||||
// force get the thermostat mode which is not broadcasted
|
||||
// important! this is only configured for the RC20. Look up the correct telegram type for other thermostat versions
|
||||
if (EMS_ID_THERMOSTAT == 0x17) { // RC20 is type 0x17
|
||||
ems_doReadCommand(EMS_TYPE_RC20Temperature);
|
||||
}
|
||||
// force get the thermostat data which are not usually automatically broadcasted
|
||||
ems_getThermostatTemps();
|
||||
} else if (cycle == 1) {
|
||||
ems_doReadCommand(EMS_TYPE_UBAParameterWW); // get Warm Water values
|
||||
}
|
||||
@@ -880,10 +901,11 @@ void loop() {
|
||||
#endif
|
||||
}
|
||||
|
||||
// publish the values to MQTT (only if there are changes)
|
||||
// if we received new data and flagged for pushing, do it
|
||||
if (EMS_Sys_Status.emsRefreshed) {
|
||||
EMS_Sys_Status.emsRefreshed = false;
|
||||
publishValues(true);
|
||||
publishValues(false);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -892,13 +914,8 @@ void loop() {
|
||||
if (Boiler_Status.shower_timer) {
|
||||
// if already in cold mode, ignore all this logic until we're out of the cold blast
|
||||
if (!Boiler_Shower.doingColdShot) {
|
||||
// these values come from UBAMonitorFast - type 0x18) which is broadcasted every second so our timings are accurate enough
|
||||
// and no need to fetch the values from the boiler
|
||||
Boiler_Shower.hotWaterOn =
|
||||
((EMS_Boiler.selBurnPow >= SHOWER_BURNPOWER_MIN) && (EMS_Boiler.selFlowTemp == 0) && EMS_Boiler.burnGas);
|
||||
|
||||
// is the hot water running?
|
||||
if (Boiler_Shower.hotWaterOn) {
|
||||
if (EMS_Boiler.tapwaterActive) {
|
||||
// if heater was previously off, start the timer
|
||||
if (Boiler_Shower.timerStart == 0) {
|
||||
// hot water just started...
|
||||
|
||||
167
src/ems.cpp
167
src/ems.cpp
@@ -10,6 +10,16 @@
|
||||
#include <Arduino.h>
|
||||
#include <TimeLib.h>
|
||||
|
||||
// add you custom setings here like thermostat IDs and thresholds
|
||||
const uint8_t SHOWER_BURNPOWER_MIN = 80;
|
||||
|
||||
// define here the Thermostat type
|
||||
#define EMS_ID_THERMOSTAT EMS_ID_THERMOSTAT_RC20 // your thermostat ID
|
||||
|
||||
// define here the boiler power settings (selBurnPow) when hot tap water is running and the heating is on
|
||||
#define EMS_BOILER_BURNPOWER_TAPWATER 115
|
||||
#define EMS_BOILER_BURNPOWER_HEATING 75
|
||||
|
||||
// Check for ESPurna vs ESPHelper (standalone)
|
||||
#ifdef USE_CUSTOM_H
|
||||
#include "debug.h"
|
||||
@@ -41,21 +51,24 @@ bool _process_RC20Temperature(uint8_t * data, uint8_t length);
|
||||
bool _process_RCTempMessage(uint8_t * data, uint8_t length);
|
||||
bool _process_Version(uint8_t * data, uint8_t length);
|
||||
|
||||
const _EMS_Types EMS_Types[] =
|
||||
{{EMS_ID_BOILER, EMS_TYPE_UBAMonitorFast, "UBAMonitorFast", _process_UBAMonitorFast},
|
||||
{EMS_ID_BOILER, EMS_TYPE_UBAMonitorSlow, "UBAMonitorSlow", _process_UBAMonitorSlow},
|
||||
{EMS_ID_BOILER, EMS_TYPE_UBAMonitorWWMessage, "UBAMonitorWWMessage", _process_UBAMonitorWWMessage},
|
||||
{EMS_ID_BOILER, EMS_TYPE_UBAParameterWW, "UBAParameterWW", _process_UBAParameterWW},
|
||||
{EMS_ID_BOILER, EMS_TYPE_UBATotalUptimeMessage, "UBATotalUptimeMessage", NULL},
|
||||
{EMS_ID_BOILER, EMS_TYPE_UBAMaintenanceSettingsMessage, "UBAMaintenanceSettingsMessage", NULL},
|
||||
{EMS_ID_BOILER, EMS_TYPE_UBAParametersMessage, "UBAParametersMessage", NULL},
|
||||
{EMS_ID_BOILER, EMS_TYPE_UBAMaintenanceStatusMessage, "UBAMaintenanceStatusMessage", NULL},
|
||||
const _EMS_Types EMS_Types[] = {
|
||||
|
||||
{EMS_ID_THERMOSTAT, EMS_TYPE_RC20StatusMessage, "RC20StatusMessage", _process_RC20StatusMessage},
|
||||
{EMS_ID_THERMOSTAT, EMS_TYPE_RC20Time, "RC20Time", _process_RC20Time},
|
||||
{EMS_ID_THERMOSTAT, EMS_TYPE_RC20Temperature, "RC20Temperature", _process_RC20Temperature},
|
||||
{EMS_ID_THERMOSTAT, EMS_TYPE_RCTempMessage, "RCTempMessage", _process_RCTempMessage},
|
||||
{EMS_ID_THERMOSTAT, EMS_TYPE_Version, "Version", _process_Version}};
|
||||
{EMS_ID_BOILER, EMS_TYPE_UBAMonitorFast, "UBAMonitorFast", _process_UBAMonitorFast},
|
||||
{EMS_ID_BOILER, EMS_TYPE_UBAMonitorSlow, "UBAMonitorSlow", _process_UBAMonitorSlow},
|
||||
{EMS_ID_BOILER, EMS_TYPE_UBAMonitorWWMessage, "UBAMonitorWWMessage", _process_UBAMonitorWWMessage},
|
||||
{EMS_ID_BOILER, EMS_TYPE_UBAParameterWW, "UBAParameterWW", _process_UBAParameterWW},
|
||||
{EMS_ID_BOILER, EMS_TYPE_UBATotalUptimeMessage, "UBATotalUptimeMessage", NULL},
|
||||
{EMS_ID_BOILER, EMS_TYPE_UBAMaintenanceSettingsMessage, "UBAMaintenanceSettingsMessage", NULL},
|
||||
{EMS_ID_BOILER, EMS_TYPE_UBAParametersMessage, "UBAParametersMessage", NULL},
|
||||
{EMS_ID_BOILER, EMS_TYPE_UBAMaintenanceStatusMessage, "UBAMaintenanceStatusMessage", NULL},
|
||||
|
||||
{EMS_ID_THERMOSTAT, EMS_TYPE_RC20StatusMessage, "RC20StatusMessage", _process_RC20StatusMessage},
|
||||
{EMS_ID_THERMOSTAT, EMS_TYPE_RC20Time, "RC20Time", _process_RC20Time},
|
||||
{EMS_ID_THERMOSTAT, EMS_TYPE_RC20Temperature, "RC20Temperature", _process_RC20Temperature},
|
||||
{EMS_ID_THERMOSTAT, EMS_TYPE_RCTempMessage, "RCTempMessage", _process_RCTempMessage},
|
||||
{EMS_ID_THERMOSTAT, EMS_TYPE_Version, "Version", _process_Version}
|
||||
|
||||
};
|
||||
uint8_t _EMS_Types_max = ArraySize(EMS_Types); // number of defined types
|
||||
|
||||
// reserve space for the data we collect from the Boiler and Thermostat
|
||||
@@ -89,20 +102,21 @@ uint8_t emsLastRxCount; // used for retries when sending failed
|
||||
// uses -1 or 255 for values that haven't been set yet (EMS_VALUE_INT_NOTSET and EMS_VALUE_FLOAT_NOTSET)
|
||||
void ems_init() {
|
||||
// overall status
|
||||
EMS_Sys_Status.emsRxPgks = 0;
|
||||
EMS_Sys_Status.emsTxPkgs = 0;
|
||||
EMS_Sys_Status.emxCrcErr = 0;
|
||||
EMS_Sys_Status.emsRxStatus = EMS_RX_IDLE;
|
||||
EMS_Sys_Status.emsTxStatus = EMS_TX_IDLE;
|
||||
EMS_Sys_Status.emsLastPoll = 0;
|
||||
EMS_Sys_Status.emsLastRx = 0;
|
||||
EMS_Sys_Status.emsLastTx = 0;
|
||||
EMS_Sys_Status.emsRefreshed = false;
|
||||
|
||||
EMS_Sys_Status.emsRxPgks = 0;
|
||||
EMS_Sys_Status.emsTxPkgs = 0;
|
||||
EMS_Sys_Status.emxCrcErr = 0;
|
||||
EMS_Sys_Status.emsRxStatus = EMS_RX_IDLE;
|
||||
EMS_Sys_Status.emsTxStatus = EMS_TX_IDLE;
|
||||
EMS_Sys_Status.emsLastPoll = 0;
|
||||
EMS_Sys_Status.emsLastRx = 0;
|
||||
EMS_Sys_Status.emsLastTx = 0;
|
||||
EMS_Sys_Status.emsRefreshed = false;
|
||||
EMS_Sys_Status.emsPollEnabled = false; // start up with Poll disabled
|
||||
EMS_Sys_Status.emsThermostatEnabled = true; // there is a RCxx thermostat active as default
|
||||
EMS_Sys_Status.emsLogging = EMS_SYS_LOGGING_NONE; // Verbose logging is off
|
||||
|
||||
// thermostat
|
||||
EMS_Thermostat.type = EMS_ID_THERMOSTAT; // type, see ems.h
|
||||
EMS_Thermostat.hour = 0;
|
||||
EMS_Thermostat.minute = 0;
|
||||
EMS_Thermostat.second = 0;
|
||||
@@ -146,6 +160,9 @@ void ems_init() {
|
||||
EMS_Boiler.wWWorkM = EMS_VALUE_INT_NOTSET; // Warm Water # minutes
|
||||
EMS_Boiler.wWOneTime = EMS_VALUE_INT_NOTSET; // Warm Water one time function on/off
|
||||
|
||||
EMS_Boiler.tapwaterActive = EMS_VALUE_INT_NOTSET; // Hot tap water is on/off
|
||||
EMS_Boiler.heatingActive = EMS_VALUE_INT_NOTSET; // Central heating is on/off
|
||||
|
||||
// init the Tx package
|
||||
_initTxBuffer();
|
||||
}
|
||||
@@ -316,13 +333,18 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) {
|
||||
&& ((millis() - EMS_Sys_Status.emsLastTx) > RX_READ_TIMEOUT)) {
|
||||
if (emsLastRxCount++ >= RX_READ_TIMEOUT_COUNT) {
|
||||
// give up and reset tx
|
||||
myDebug("Error! Failed to send telegram, cancelling last write command.\n");
|
||||
if (EMS_Sys_Status.emsLogging != EMS_SYS_LOGGING_NONE) {
|
||||
myDebug("Error! Failed to send telegram, cancelling last write command.\n");
|
||||
}
|
||||
// re-initialise
|
||||
_initTxBuffer();
|
||||
} else {
|
||||
myDebug("Didn't receive acknowledgement from the 0x%02x, so resending (attempt #%d/%d)...\n",
|
||||
EMS_TxTelegram.type,
|
||||
emsLastRxCount,
|
||||
RX_READ_TIMEOUT_COUNT);
|
||||
if (EMS_Sys_Status.emsLogging != EMS_SYS_LOGGING_NONE) {
|
||||
myDebug("Didn't receive acknowledgement from the 0x%02x, so resending (attempt #%d/%d)...\n",
|
||||
EMS_TxTelegram.type,
|
||||
emsLastRxCount,
|
||||
RX_READ_TIMEOUT_COUNT);
|
||||
}
|
||||
EMS_Sys_Status.emsTxStatus = EMS_TX_PENDING; // set to pending will trigger sending the same package again
|
||||
}
|
||||
}
|
||||
@@ -415,10 +437,11 @@ void _processType(uint8_t * telegram, uint8_t length) {
|
||||
// we have a match
|
||||
typeFound = true;
|
||||
// call callback to fetch the values from the telegram
|
||||
// ignoring the return value for now
|
||||
// return value tells us if we need to force send values back to MQTT
|
||||
if ((EMS_Types[i].processType_cb) != (void *)NULL) {
|
||||
(void)EMS_Types[i].processType_cb(data, length);
|
||||
EMS_Sys_Status.emsRefreshed = EMS_Types[i].processType_cb(data, length);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
@@ -530,7 +553,7 @@ bool _checkWriteQueueFull() {
|
||||
myDebug("Delaying write command as there is already a telegram (type 0x%02x) in the queue\n",
|
||||
EMS_TxTelegram.type);
|
||||
}
|
||||
return true;
|
||||
return true; // something in queue
|
||||
}
|
||||
|
||||
return false; // nothing queue, we can do a write command
|
||||
@@ -538,7 +561,7 @@ bool _checkWriteQueueFull() {
|
||||
|
||||
/*
|
||||
* UBAParameterWW - type 0x33 - warm water parameters
|
||||
* received only after requested
|
||||
* received only after requested (not broadcasted)
|
||||
*/
|
||||
bool _process_UBAParameterWW(uint8_t * data, uint8_t length) {
|
||||
EMS_Boiler.wWSelTemp = data[2];
|
||||
@@ -546,9 +569,7 @@ bool _process_UBAParameterWW(uint8_t * data, uint8_t length) {
|
||||
EMS_Boiler.wWCircPump = (data[6] == 0xFF); // 0xFF means on
|
||||
EMS_Boiler.wWDesiredTemp = data[8];
|
||||
|
||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back to Home Assistant via MQTT
|
||||
|
||||
return true;
|
||||
return true; // triggers a send the values back to Home Assistant via MQTT
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -561,7 +582,7 @@ bool _process_UBAMonitorWWMessage(uint8_t * data, uint8_t length) {
|
||||
EMS_Boiler.wWWorkM = _toLong(10, data);
|
||||
EMS_Boiler.wWOneTime = bitRead(data[5], 1);
|
||||
|
||||
return true;
|
||||
return false; // no need to update mqtt
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -573,16 +594,23 @@ bool _process_UBAMonitorFast(uint8_t * data, uint8_t length) {
|
||||
EMS_Boiler.curFlowTemp = _toFloat(1, data);
|
||||
EMS_Boiler.retTemp = _toFloat(13, data);
|
||||
|
||||
uint8_t v = data[7];
|
||||
EMS_Boiler.burnGas = bitRead(v, 0);
|
||||
EMS_Boiler.fanWork = bitRead(v, 2);
|
||||
EMS_Boiler.ignWork = bitRead(v, 3);
|
||||
EMS_Boiler.heatPmp = bitRead(v, 5);
|
||||
EMS_Boiler.wWHeat = bitRead(v, 6);
|
||||
EMS_Boiler.wWCirc = bitRead(v, 7);
|
||||
|
||||
EMS_Boiler.selBurnPow = data[3]; // max power
|
||||
uint8_t v = data[7];
|
||||
EMS_Boiler.burnGas = bitRead(v, 0);
|
||||
EMS_Boiler.fanWork = bitRead(v, 2);
|
||||
EMS_Boiler.ignWork = bitRead(v, 3);
|
||||
EMS_Boiler.heatPmp = bitRead(v, 5);
|
||||
EMS_Boiler.wWHeat = bitRead(v, 6);
|
||||
EMS_Boiler.wWCirc = bitRead(v, 7);
|
||||
EMS_Boiler.curBurnPow = data[4];
|
||||
EMS_Boiler.selBurnPow = data[3]; // burn power max setting
|
||||
|
||||
// check if the boiler is providing hot water to the tap or hot water to the central heating
|
||||
// we use a quick hack:
|
||||
// the heating on, if burner selected max power = 75 (UBAMonitorFast:EMS_Boiler.selBurnPow)
|
||||
// hot tap water running, if burner selected max power=115 (UBAMonitorFast:EMS_Boiler.selBurnPow)
|
||||
// we could also add (EMS_Boiler.selFlowTemp == 0) && EMS_Boiler.burnGas) for more precision
|
||||
EMS_Boiler.tapwaterActive = ((EMS_Boiler.selBurnPow == EMS_BOILER_BURNPOWER_TAPWATER) ? 1 : 0);
|
||||
EMS_Boiler.heatingActive = ((EMS_Boiler.selBurnPow == EMS_BOILER_BURNPOWER_HEATING) ? 1 : 0);
|
||||
|
||||
EMS_Boiler.flameCurr = _toFloat(15, data);
|
||||
|
||||
@@ -592,7 +620,7 @@ bool _process_UBAMonitorFast(uint8_t * data, uint8_t length) {
|
||||
EMS_Boiler.sysPress = (((float)data[17]) / (float)10);
|
||||
}
|
||||
|
||||
return true;
|
||||
return false; // no need to update mqtt
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -607,9 +635,7 @@ bool _process_UBAMonitorSlow(uint8_t * data, uint8_t length) {
|
||||
EMS_Boiler.burnWorkMin = _toLong(13, data);
|
||||
EMS_Boiler.heatWorkMin = _toLong(19, data);
|
||||
|
||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back to Home Assistant via MQTT
|
||||
|
||||
return true;
|
||||
return true; // triggers a send the values back to Home Assistant via MQTT
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -620,9 +646,7 @@ bool _process_RC20StatusMessage(uint8_t * data, uint8_t length) {
|
||||
EMS_Thermostat.setpoint_roomTemp = ((float)data[1]) / (float)2;
|
||||
EMS_Thermostat.curr_roomTemp = _toFloat(2, data);
|
||||
|
||||
EMS_Sys_Status.emsRefreshed = true; // set the updated flag to trigger a send back to HA
|
||||
|
||||
return true;
|
||||
return true; // triggers a send the values back to Home Assistant via MQTT
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -642,13 +666,12 @@ bool _process_RC20Temperature(uint8_t * data, uint8_t length) {
|
||||
}
|
||||
|
||||
// and send the values back to HA (Home Assistant MQTT)
|
||||
EMS_Sys_Status.emsRefreshed = true;
|
||||
} else {
|
||||
// Process the whole telegram package
|
||||
EMS_Thermostat.mode = data[EMS_OFFSET_RC20Temperature_mode]; // get the mode
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
// Process the whole telegram package
|
||||
EMS_Thermostat.mode = data[EMS_OFFSET_RC20Temperature_mode]; // get the mode
|
||||
return false; // don't update mqtt
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -657,21 +680,24 @@ bool _process_RC20Temperature(uint8_t * data, uint8_t length) {
|
||||
bool _process_RCTempMessage(uint8_t * data, uint8_t length) {
|
||||
// add support here if you're reading external sensors
|
||||
|
||||
return true;
|
||||
return false; // don't update mqtt
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Version - type 0x02 - get the version of the Thermostat firmware
|
||||
* We don't bother storing these values anywhere
|
||||
* When a thermostat is connecting it will send out 0x02 messages too, which we'll ignore
|
||||
* We don't bother storing these values anywhere, just print
|
||||
*/
|
||||
bool _process_Version(uint8_t * data, uint8_t length) {
|
||||
uint8_t major = data[1];
|
||||
uint8_t minor = data[2];
|
||||
// ignore short messages
|
||||
if (length == 8) {
|
||||
uint8_t major = data[1];
|
||||
uint8_t minor = data[2];
|
||||
myDebug("Version %d.%d\n", major, minor);
|
||||
}
|
||||
|
||||
myDebug("Version %d.%d\n", major, minor);
|
||||
|
||||
return true;
|
||||
return false; // don't update mqtt
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -696,7 +722,7 @@ bool _process_RC20Time(uint8_t * data, uint8_t length) {
|
||||
EMS_Thermostat.year + 2000);
|
||||
*/
|
||||
|
||||
return true;
|
||||
return false; // don't update mqtt
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -720,6 +746,15 @@ void _buildTxTelegram(uint8_t data_value) {
|
||||
EMS_Sys_Status.emsTxStatus = EMS_TX_PENDING; // armed and ready to send
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic function to return temperature settings from the thermostat
|
||||
*/
|
||||
void ems_getThermostatTemps() {
|
||||
if (EMS_Thermostat.type == EMS_ID_THERMOSTAT_RC20) {
|
||||
ems_doReadCommand(EMS_TYPE_RC20Temperature);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a command to UART Tx to Read from another device
|
||||
* Read commands when sent must respond by the destination (target) immediately (or within 10ms)
|
||||
|
||||
42
src/ems.h
42
src/ems.h
@@ -21,8 +21,10 @@
|
||||
|
||||
#define EMS_TX_MAXBUFFERSIZE 128 // max size of the buffer. packets are 32 bits
|
||||
|
||||
// define here the Thermostat type
|
||||
#define EMS_ID_THERMOSTAT 0x17 // x17=RC20 (Moduline300), x10=RC30/RC35 (Moduline 400)
|
||||
#define EMS_ID_THERMOSTAT_RC20 0x17 // RC20 (older Moduline 300)
|
||||
#define EMS_ID_THERMOSTAT_RC30 0x10 // RC30 (Moduline 300)
|
||||
#define EMS_ID_THERMOSTAT_RC35 0x10 // RC35 (Moduline 400)
|
||||
#define EMS_ID_THERMOSTAT_EASY 0x18 // Nefit Easy
|
||||
|
||||
// define here the EMS telegram types you need
|
||||
|
||||
@@ -143,10 +145,16 @@ typedef struct {
|
||||
uint32_t wWStarts; // Warm Water # starts
|
||||
uint32_t wWWorkM; // Warm Water # minutes
|
||||
uint8_t wWOneTime; // Warm Water one time function on/off
|
||||
|
||||
// calculated values
|
||||
uint8_t tapwaterActive; // Hot tap water is on/off
|
||||
uint8_t heatingActive; // Central heating is on/off
|
||||
|
||||
} _EMS_Boiler;
|
||||
|
||||
// RC20 data
|
||||
// Thermostat data
|
||||
typedef struct {
|
||||
uint8_t type; // thermostat type (RC20, RC30, RC35 etc)
|
||||
float setpoint_roomTemp; // current set temp
|
||||
float curr_roomTemp; // current room temp
|
||||
uint8_t mode; // 0=low, 1=manual, 2=auto
|
||||
@@ -183,22 +191,26 @@ typedef struct {
|
||||
#define COLOR_BOLD_OFF "\x1B[21m"
|
||||
|
||||
// function definitions
|
||||
extern void ems_parseTelegram(uint8_t * telegram, uint8_t len);
|
||||
void ems_init();
|
||||
void ems_doReadCommand(uint8_t type);
|
||||
void ems_setThermostatTemp(float temp);
|
||||
void ems_setThermostatMode(uint8_t mode);
|
||||
void ems_setWarmWaterTemp(uint8_t temperature);
|
||||
void ems_setWarmWaterActivated(bool activated);
|
||||
void ems_setExperimental(uint8_t value);
|
||||
void ems_setPoll(bool b);
|
||||
extern void ems_parseTelegram(uint8_t * telegram, uint8_t len);
|
||||
void ems_init();
|
||||
void ems_doReadCommand(uint8_t type);
|
||||
|
||||
void ems_setThermostatTemp(float temp);
|
||||
void ems_setThermostatMode(uint8_t mode);
|
||||
void ems_setWarmWaterTemp(uint8_t temperature);
|
||||
void ems_setWarmWaterActivated(bool activated);
|
||||
void ems_setExperimental(uint8_t value);
|
||||
void ems_setPoll(bool b);
|
||||
void ems_setThermostatEnabled(bool b);
|
||||
void ems_setLogging(_EMS_SYS_LOGGING loglevel);
|
||||
|
||||
void ems_getThermostatTemps();
|
||||
bool ems_getPoll();
|
||||
bool ems_getThermostatEnabled();
|
||||
void ems_setThermostatEnabled(bool b);
|
||||
void ems_setLogging(_EMS_SYS_LOGGING loglevel);
|
||||
_EMS_SYS_LOGGING ems_getLogging();
|
||||
uint8_t ems_getEmsTypesCount();
|
||||
void ems_printAllTypes();
|
||||
|
||||
void ems_printAllTypes();
|
||||
|
||||
// private functions
|
||||
uint8_t _crcCalculator(uint8_t * data, uint8_t len);
|
||||
|
||||
Reference in New Issue
Block a user