mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 07:49:52 +03:00
added mqtt for hot water & heating on/off
This commit is contained in:
12
README.md
12
README.md
@@ -23,7 +23,7 @@ There are 3 parts to this project, first the design of the circuit, second the c
|
|||||||
- [EMS Reading and Writing](#ems-reading-and-writing)
|
- [EMS Reading and Writing](#ems-reading-and-writing)
|
||||||
- [The ESP8266 Source Code](#the-esp8266-source-code)
|
- [The ESP8266 Source Code](#the-esp8266-source-code)
|
||||||
- [Supported EMS Types](#supported-ems-types)
|
- [Supported EMS Types](#supported-ems-types)
|
||||||
- [Supporting A Type RC35 Thermostat](#supporting-a-type-rc35-thermostat)
|
- [Supporting other Thermostats types](#supporting-other-thermostats-types)
|
||||||
- [Customizing The Code](#customizing-the-code)
|
- [Customizing The Code](#customizing-the-code)
|
||||||
- [Using MQTT](#using-mqtt)
|
- [Using MQTT](#using-mqtt)
|
||||||
- [The Basic Shower Logic](#the-basic-shower-logic)
|
- [The Basic Shower Logic](#the-basic-shower-logic)
|
||||||
@@ -223,13 +223,13 @@ The code is built on the Arduino framework and is dependent on these external li
|
|||||||
|
|
||||||
In `boiler.ino` you can make calls to automatically send these read commands. See the function *regularUpdates()*
|
In `boiler.ino` you can make calls to automatically send these read commands. See the function *regularUpdates()*
|
||||||
|
|
||||||
#### Supporting A Type RC35 Thermostat
|
#### Supporting other Thermostats types
|
||||||
|
|
||||||
The code is designed for a Moduline300 (RC20) thermostat. To adjust for a RC35 first change `EMS_ID_THERMOSTAT` in `ems.h`. A RC35 thermostat has 4 heating circuits and to read the values use different Monitor type IDs (e.g. 0x3E, 0x48, etc). The mode (0=night, 1=day, 2=holiday) is the first byte of the telegram and the temperature is the value of the 2nd byte divided by 2.
|
The code is originally designed for a Moduline300 (RC20) thermostat.
|
||||||
|
|
||||||
Then to set temperature values use the Working Mode with type IDs (0x3D, 0x47,0x51 and 0x5B) respectively. Set the offset (byte 4 of the header) to determine which temperature you're changing; 1 for night, 2 for day and 3 for holiday. The data value is the desired temperature multiplied by 2 as a single byte.
|
To adjust for a RC35 first change `EMS_ID_THERMOSTAT` in `ems.cpp`. A RC35 thermostat has 4 heating circuits and to read the values use different Monitor type IDs (e.g. 0x3E, 0x48, etc). The mode (0=night, 1=day, 2=holiday) is the first byte of the telegram and the temperature is the value of the 2nd byte divided by 2. Then to set temperature values use the Working Mode with type IDs (0x3D, 0x47,0x51 and 0x5B) respectively. Set the offset (byte 4 of the header) to determine which temperature you're changing; 1 for night, 2 for day and 3 for holiday. The data value is the desired temperature multiplied by 2 as a single byte.
|
||||||
|
|
||||||
Consult the wiki documentation for the actual data format.
|
I will add further support for the other thermostats (such as the Nefit Easy) as soon as I can get my hands on a physical device. I do however welcome contribtions to this code repository which is essentially the purpose of GitHub. By inspecting the telegram packets and looking up the codes in the German wiki (and with lots of trial and error) it is possible to easily extend the existing functions to support other EMS devices.
|
||||||
|
|
||||||
### Customizing The Code
|
### Customizing The Code
|
||||||
|
|
||||||
@@ -243,7 +243,7 @@ Most of the changes will be done in `boiler.ino` and `ems.cpp`.
|
|||||||
|
|
||||||
When the ESP8266 boots it will send a start signal via MQTT. This is picked up by Home Assistant and sends a notification informing me that the device has booted. Useful for knowing when the ESP gets reset.
|
When the ESP8266 boots it will send a start signal via MQTT. This is picked up by Home Assistant and sends a notification informing me that the device has booted. Useful for knowing when the ESP gets reset.
|
||||||
|
|
||||||
I'm using the standard PubSubClient client so make sure you set `-DMQTT_MAX_PACKET_SIZE=300` as the default package size is 128 and our JSON messages are around 220 bytes.
|
I'm using the standard PubSubClient client so make sure you set `-DMQTT_MAX_PACKET_SIZE=400` as the default package size is 128 and our JSON messages are around 300 bytes.
|
||||||
|
|
||||||
I run Mosquitto on my Raspberry PI 3 as the MQTT broker.
|
I run Mosquitto on my Raspberry PI 3 as the MQTT broker.
|
||||||
|
|
||||||
|
|||||||
BIN
doc/ha/ha.png
BIN
doc/ha/ha.png
Binary file not shown.
|
Before Width: | Height: | Size: 149 KiB |
@@ -1,18 +0,0 @@
|
|||||||
thermostat_temp:
|
|
||||||
name: Set Temperature
|
|
||||||
icon: mdi:temperature-celsius
|
|
||||||
min: 10
|
|
||||||
max: 25
|
|
||||||
step: 0.5
|
|
||||||
unit_of_measurement: "°C"
|
|
||||||
mode: slider
|
|
||||||
|
|
||||||
boiler_wwtemp:
|
|
||||||
name: Warm Water temp
|
|
||||||
icon: mdi:temperature-celsius
|
|
||||||
min: 30
|
|
||||||
max: 60
|
|
||||||
step: 1
|
|
||||||
unit_of_measurement: "°C"
|
|
||||||
mode: slider
|
|
||||||
|
|
||||||
@@ -1,7 +1,3 @@
|
|||||||
##########################################################
|
|
||||||
## Boiler
|
|
||||||
##########################################################
|
|
||||||
|
|
||||||
- id: boiler_shower
|
- id: boiler_shower
|
||||||
alias: Alert shower time
|
alias: Alert shower time
|
||||||
trigger:
|
trigger:
|
||||||
@@ -43,31 +39,6 @@
|
|||||||
payload: >
|
payload: >
|
||||||
{{ now().strftime("%H:%M:%S %-d/%b/%Y") }}
|
{{ now().strftime("%H:%M:%S %-d/%b/%Y") }}
|
||||||
|
|
||||||
# Set thermostat temp
|
|
||||||
- id: thermostat_temp
|
|
||||||
alias: 'Adjust Theromostat Temperature'
|
|
||||||
trigger:
|
|
||||||
platform: state
|
|
||||||
entity_id: input_number.thermostat_temp
|
|
||||||
action:
|
|
||||||
service: mqtt.publish
|
|
||||||
data_template:
|
|
||||||
topic: 'home/boiler/thermostat_cmd_temp'
|
|
||||||
payload: >
|
|
||||||
{{ states.input_number.thermostat_temp.state }}
|
|
||||||
|
|
||||||
# See if thermostat_temp has changed in recent mqtt payload, then adjust input_number
|
|
||||||
- id: thermostat_temp_incoming
|
|
||||||
trigger:
|
|
||||||
platform: state
|
|
||||||
entity_id: sensor.current_set_temperature
|
|
||||||
action:
|
|
||||||
service: input_number.set_value
|
|
||||||
data_template:
|
|
||||||
entity_id: input_number.thermostat_temp
|
|
||||||
value: '{{ states.sensor.current_set_temperature.state }}'
|
|
||||||
|
|
||||||
|
|
||||||
# Boiler warm water temp
|
# Boiler warm water temp
|
||||||
- id: boiler_wwtemp
|
- id: boiler_wwtemp
|
||||||
trigger:
|
trigger:
|
||||||
12
doc/home assistant/binary_sensor.yaml
Normal file
12
doc/home assistant/binary_sensor.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
- platform: mqtt
|
||||||
|
name: 'Tap Water'
|
||||||
|
state_topic: 'home/boiler/tapwater_active'
|
||||||
|
payload_on: "1"
|
||||||
|
payload_off: "0"
|
||||||
|
|
||||||
|
- platform: mqtt
|
||||||
|
name: 'Heating'
|
||||||
|
state_topic: 'home/boiler/heating_active'
|
||||||
|
payload_on: "1"
|
||||||
|
payload_off: "0"
|
||||||
|
|
||||||
BIN
doc/home assistant/ha.png
Normal file
BIN
doc/home assistant/ha.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
9
doc/home assistant/input_number.yaml
Normal file
9
doc/home assistant/input_number.yaml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
boiler_wwtemp:
|
||||||
|
name: Warm Water temp
|
||||||
|
icon: mdi:temperature-celsius
|
||||||
|
min: 30
|
||||||
|
max: 60
|
||||||
|
step: 1
|
||||||
|
unit_of_measurement: "°C"
|
||||||
|
mode: slider
|
||||||
|
|
||||||
@@ -26,6 +26,16 @@
|
|||||||
name: 'Last shower duration'
|
name: 'Last shower duration'
|
||||||
force_update: true
|
force_update: true
|
||||||
|
|
||||||
|
- platform: mqtt
|
||||||
|
state_topic: 'home/boiler/boiler_data'
|
||||||
|
name: 'Tap Water'
|
||||||
|
value_template: '{{ value_json.tapwaterActive }}'
|
||||||
|
|
||||||
|
- platform: mqtt
|
||||||
|
state_topic: 'home/boiler/boiler_data'
|
||||||
|
name: 'Heating'
|
||||||
|
value_template: '{{ value_json.heatingActive }}'
|
||||||
|
|
||||||
- platform: mqtt
|
- platform: mqtt
|
||||||
state_topic: 'home/boiler/boiler_data'
|
state_topic: 'home/boiler/boiler_data'
|
||||||
name: 'Warm Water selected temperature'
|
name: 'Warm Water selected temperature'
|
||||||
@@ -51,13 +51,6 @@ views:
|
|||||||
|
|
||||||
- type: vertical-stack
|
- type: vertical-stack
|
||||||
cards:
|
cards:
|
||||||
- type: entities
|
|
||||||
title: Thermostat
|
|
||||||
show_header_toggle: true
|
|
||||||
entities:
|
|
||||||
- sensor.current_room_temperature
|
|
||||||
- sensor.current_mode
|
|
||||||
- input_number.thermostat_temp
|
|
||||||
- type: history-graph
|
- type: history-graph
|
||||||
entities:
|
entities:
|
||||||
- sensor.current_room_temperature
|
- sensor.current_room_temperature
|
||||||
@@ -245,7 +245,7 @@ void showInfo() {
|
|||||||
_renderBoolValue("Circulation pump", EMS_Boiler.wWCirc);
|
_renderBoolValue("Circulation pump", EMS_Boiler.wWCirc);
|
||||||
_renderIntValue("Burner selected max power", "%", EMS_Boiler.selBurnPow);
|
_renderIntValue("Burner selected max power", "%", EMS_Boiler.selBurnPow);
|
||||||
_renderIntValue("Burner current power", "%", EMS_Boiler.curBurnPow);
|
_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);
|
_renderFloatValue("System pressure", "bar", EMS_Boiler.sysPress);
|
||||||
|
|
||||||
// UBAMonitorSlow
|
// UBAMonitorSlow
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ env_default = nodemcuv2
|
|||||||
[common]
|
[common]
|
||||||
platform = espressif8266
|
platform = espressif8266
|
||||||
; optional flags are -DUSE_LED -DSHOWER_TEST -DDEBUG -DUSE_SERIAL -DNO_TX
|
; optional flags are -DUSE_LED -DSHOWER_TEST -DDEBUG -DUSE_SERIAL -DNO_TX
|
||||||
build_flags = -g -w -DMQTT_MAX_PACKET_SIZE=300
|
build_flags = -g -w -DMQTT_MAX_PACKET_SIZE=400
|
||||||
build_flags_custom = '-DWIFI_SSID="my_ssid"' '-DWIFI_PASSWORD="my_password"' '-DMQTT_IP="my_broker_ip"' '-DMQTT_USER="my_broker_username"' '-DMQTT_PASS="my_broker_password"'
|
build_flags_custom = '-DWIFI_SSID="my_ssid"' '-DWIFI_PASSWORD="my_password"' '-DMQTT_IP="my_broker_ip"' '-DMQTT_USER="my_broker_username"' '-DMQTT_PASS="my_broker_password"'
|
||||||
lib_deps =
|
lib_deps =
|
||||||
Time
|
Time
|
||||||
|
|||||||
@@ -61,7 +61,10 @@ uint8_t regularUpdatesCount = 0;
|
|||||||
|
|
||||||
// boiler
|
// boiler
|
||||||
#define TOPIC_BOILER_DATA MQTT_BOILER "boiler_data" // for sending boiler values
|
#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_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
|
// shower time
|
||||||
#define TOPIC_SHOWERTIME MQTT_BOILER "showertime" // for sending shower time results
|
#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
|
const unsigned long SHOWER_OFFSET_TIME = 0; // 0 seconds grace time, to calibrate actual time under the shower
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const uint8_t SHOWER_BURNPOWER_MIN = 80;
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool wifi_connected;
|
bool wifi_connected;
|
||||||
bool boiler_online;
|
bool boiler_online;
|
||||||
@@ -106,7 +108,6 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool showerOn;
|
bool showerOn;
|
||||||
bool hotWaterOn;
|
|
||||||
unsigned long timerStart; // ms
|
unsigned long timerStart; // ms
|
||||||
unsigned long timerPause; // ms
|
unsigned long timerPause; // ms
|
||||||
unsigned long duration; // ms
|
unsigned long duration; // ms
|
||||||
@@ -124,18 +125,18 @@ netInfo homeNet = {.mqttHost = MQTT_IP,
|
|||||||
ESPHelper myESP(&homeNet);
|
ESPHelper myESP(&homeNet);
|
||||||
|
|
||||||
command_t PROGMEM project_cmds[] = {{"s", "show statistics"},
|
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"},
|
{"P", "publish all stat to MQTT"},
|
||||||
{"v", "[n] set logging (0=none, 1=basic, 2=verbose)"},
|
{"v", "[n] set logging (0=none, 1=basic, 2=verbose)"},
|
||||||
{"p", "poll ems response on/off (default is off)"},
|
{"p", "toggle EMS Poll response on/off"},
|
||||||
{"T", "thermostat monitoring on/off"},
|
{"T", "toggle Thermostat monitoring on/off"},
|
||||||
{"S", "shower timer on/off"},
|
{"S", "toggle Shower timer on/off"},
|
||||||
{"A", "shower alert on/off"},
|
{"A", "toggle shower Alert on/off"},
|
||||||
{"r", "[n] send EMS request (n=telegram type id. Use 'h' for list)"},
|
{"r", "[n] send EMS request (n=any telegram type id. Use 'h' for suppported types)"},
|
||||||
{"t", "[n] set thermostat temperature to n"},
|
{"t", "[n] set thermostat temperature"},
|
||||||
{"m", "[n] set thermostat mode (1=manual, 2=auto)"},
|
{"m", "[n] set thermostat mode (1=manual, 2=auto)"},
|
||||||
{"w", "[n] set boiler warm water temperature to n (min 30)"},
|
{"w", "[n] set boiler warm water temperature (min 30)"},
|
||||||
{"a", "[n] boiler warm water on (n=1) or off (n=0)"},
|
{"a", "[n] boiler warm water (1=on, 2=off)"},
|
||||||
{"x", "[n] experimental (warning: for debugging only!)"}};
|
{"x", "[n] experimental (warning: for debugging only!)"}};
|
||||||
|
|
||||||
// calculates size of an 2d array at compile time
|
// 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;
|
static int connectionStatus = NO_CONNECTION;
|
||||||
bool startMQTTsent = false;
|
bool startMQTTsent = false;
|
||||||
|
|
||||||
|
uint8_t last_boilerActive = 0xFF; // for remembering last setting of the tap water or heating on/off
|
||||||
|
|
||||||
// toggle for heartbeat LED
|
// toggle for heartbeat LED
|
||||||
bool heartbeatEnabled;
|
bool heartbeatEnabled;
|
||||||
|
|
||||||
@@ -322,6 +325,10 @@ void showInfo() {
|
|||||||
|
|
||||||
myDebug("\n\n%sBoiler stats:%s\n", COLOR_BOLD_ON, COLOR_BOLD_OFF);
|
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
|
// UBAParameterWW
|
||||||
_renderBoolValue("Warm Water activated", EMS_Boiler.wWActivated);
|
_renderBoolValue("Warm Water activated", EMS_Boiler.wWActivated);
|
||||||
_renderBoolValue("Warm Water circulation pump available", EMS_Boiler.wWCircPump);
|
_renderBoolValue("Warm Water circulation pump available", EMS_Boiler.wWCircPump);
|
||||||
@@ -348,7 +355,7 @@ void showInfo() {
|
|||||||
_renderBoolValue("Circulation pump", EMS_Boiler.wWCirc);
|
_renderBoolValue("Circulation pump", EMS_Boiler.wWCirc);
|
||||||
_renderIntValue("Burner selected max power", "%", EMS_Boiler.selBurnPow);
|
_renderIntValue("Burner selected max power", "%", EMS_Boiler.selBurnPow);
|
||||||
_renderIntValue("Burner current power", "%", EMS_Boiler.curBurnPow);
|
_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);
|
_renderFloatValue("System pressure", "bar", EMS_Boiler.sysPress);
|
||||||
|
|
||||||
// UBAMonitorSlow
|
// UBAMonitorSlow
|
||||||
@@ -393,14 +400,15 @@ void showInfo() {
|
|||||||
// show the Shower Info
|
// show the Shower Info
|
||||||
if (Boiler_Status.shower_timer) {
|
if (Boiler_Status.shower_timer) {
|
||||||
myDebug("\n%s Shower stats:%s\n", COLOR_BOLD_ON, COLOR_BOLD_OFF);
|
myDebug("\n%s Shower stats:%s\n", COLOR_BOLD_ON, COLOR_BOLD_OFF);
|
||||||
myDebug(" Hot water is %s\n", (Boiler_Shower.hotWaterOn ? "running" : "stopped"));
|
myDebug(" Shower Timer is %s\n", (Boiler_Shower.showerOn ? "active" : "off"));
|
||||||
myDebug(" Shower is %s\n", (Boiler_Shower.showerOn ? "on" : "off"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
myDebug("\n");
|
myDebug("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// send values to HA via MQTT
|
// 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) {
|
void publishValues(bool force) {
|
||||||
char s[20]; // for formatting strings
|
char s[20]; // for formatting strings
|
||||||
|
|
||||||
@@ -435,7 +443,7 @@ void publishValues(bool force) {
|
|||||||
crc.update(data[i]);
|
crc.update(data[i]);
|
||||||
}
|
}
|
||||||
uint32_t checksum = crc.finalize();
|
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) {
|
if ((previousBoilerPublishCRC != checksum) || force) {
|
||||||
previousBoilerPublishCRC = checksum;
|
previousBoilerPublishCRC = checksum;
|
||||||
@@ -447,6 +455,19 @@ void publishValues(bool force) {
|
|||||||
myESP.publish(TOPIC_BOILER_DATA, data);
|
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
|
// handle the thermostat values separately
|
||||||
if (EMS_Sys_Status.emsThermostatEnabled) {
|
if (EMS_Sys_Status.emsThermostatEnabled) {
|
||||||
// only send thermostat values if we actually have them
|
// only send thermostat values if we actually have them
|
||||||
@@ -476,6 +497,7 @@ void publishValues(bool force) {
|
|||||||
crc.update(data[i]);
|
crc.update(data[i]);
|
||||||
}
|
}
|
||||||
uint32_t checksum = crc.finalize();
|
uint32_t checksum = crc.finalize();
|
||||||
|
//myDebug("Thermostat HASH=%d %08x, len=%d, s=%s\n", checksum, checksum, len, data);
|
||||||
|
|
||||||
if ((previousThermostatPublishCRC != checksum) || force) {
|
if ((previousThermostatPublishCRC != checksum) || force) {
|
||||||
previousThermostatPublishCRC = checksum;
|
previousThermostatPublishCRC = checksum;
|
||||||
@@ -517,7 +539,7 @@ void myDebugCallback() {
|
|||||||
ems_setPoll(b);
|
ems_setPoll(b);
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
myESP.logger(LOG_HA, "Force publish values");
|
//myESP.logger(LOG_HA, "Force publish values");
|
||||||
publishValues(true);
|
publishValues(true);
|
||||||
break;
|
break;
|
||||||
case 'r': // read command for Boiler or Thermostat
|
case 'r': // read command for Boiler or Thermostat
|
||||||
@@ -751,6 +773,8 @@ void setup() {
|
|||||||
myESP.addSubscription(TOPIC_SHOWER_TIMER);
|
myESP.addSubscription(TOPIC_SHOWER_TIMER);
|
||||||
myESP.addSubscription(TOPIC_SHOWER_ALERT);
|
myESP.addSubscription(TOPIC_SHOWER_ALERT);
|
||||||
myESP.addSubscription(TOPIC_BOILER_WARM_WATER_SELECTED_TEMPERATURE);
|
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.addSubscription(TOPIC_SHOWER_COLDSHOT);
|
||||||
|
|
||||||
myESP.consoleSetCallBackProjectCmds(project_cmds, ArraySize(project_cmds), myDebugCallback); // set up Telnet commands
|
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
|
// only do calls if the EMS is connected and alive
|
||||||
if (Boiler_Status.boiler_online) {
|
if (Boiler_Status.boiler_online) {
|
||||||
if ((cycle == 0) && Boiler_Status.thermostat_enabled) {
|
if ((cycle == 0) && Boiler_Status.thermostat_enabled) {
|
||||||
// force get the thermostat mode which is not broadcasted
|
// force get the thermostat data which are not usually automatically broadcasted
|
||||||
// important! this is only configured for the RC20. Look up the correct telegram type for other thermostat versions
|
ems_getThermostatTemps();
|
||||||
if (EMS_ID_THERMOSTAT == 0x17) { // RC20 is type 0x17
|
|
||||||
ems_doReadCommand(EMS_TYPE_RC20Temperature);
|
|
||||||
}
|
|
||||||
} else if (cycle == 1) {
|
} else if (cycle == 1) {
|
||||||
ems_doReadCommand(EMS_TYPE_UBAParameterWW); // get Warm Water values
|
ems_doReadCommand(EMS_TYPE_UBAParameterWW); // get Warm Water values
|
||||||
}
|
}
|
||||||
@@ -880,10 +901,11 @@ void loop() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// publish the values to MQTT (only if there are changes)
|
||||||
// if we received new data and flagged for pushing, do it
|
// if we received new data and flagged for pushing, do it
|
||||||
if (EMS_Sys_Status.emsRefreshed) {
|
if (EMS_Sys_Status.emsRefreshed) {
|
||||||
EMS_Sys_Status.emsRefreshed = false;
|
EMS_Sys_Status.emsRefreshed = false;
|
||||||
publishValues(true);
|
publishValues(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -892,13 +914,8 @@ void loop() {
|
|||||||
if (Boiler_Status.shower_timer) {
|
if (Boiler_Status.shower_timer) {
|
||||||
// if already in cold mode, ignore all this logic until we're out of the cold blast
|
// if already in cold mode, ignore all this logic until we're out of the cold blast
|
||||||
if (!Boiler_Shower.doingColdShot) {
|
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?
|
// is the hot water running?
|
||||||
if (Boiler_Shower.hotWaterOn) {
|
if (EMS_Boiler.tapwaterActive) {
|
||||||
// if heater was previously off, start the timer
|
// if heater was previously off, start the timer
|
||||||
if (Boiler_Shower.timerStart == 0) {
|
if (Boiler_Shower.timerStart == 0) {
|
||||||
// hot water just started...
|
// hot water just started...
|
||||||
|
|||||||
97
src/ems.cpp
97
src/ems.cpp
@@ -10,6 +10,16 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <TimeLib.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)
|
// Check for ESPurna vs ESPHelper (standalone)
|
||||||
#ifdef USE_CUSTOM_H
|
#ifdef USE_CUSTOM_H
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@@ -41,8 +51,9 @@ bool _process_RC20Temperature(uint8_t * data, uint8_t length);
|
|||||||
bool _process_RCTempMessage(uint8_t * data, uint8_t length);
|
bool _process_RCTempMessage(uint8_t * data, uint8_t length);
|
||||||
bool _process_Version(uint8_t * data, uint8_t length);
|
bool _process_Version(uint8_t * data, uint8_t length);
|
||||||
|
|
||||||
const _EMS_Types EMS_Types[] =
|
const _EMS_Types EMS_Types[] = {
|
||||||
{{EMS_ID_BOILER, EMS_TYPE_UBAMonitorFast, "UBAMonitorFast", _process_UBAMonitorFast},
|
|
||||||
|
{EMS_ID_BOILER, EMS_TYPE_UBAMonitorFast, "UBAMonitorFast", _process_UBAMonitorFast},
|
||||||
{EMS_ID_BOILER, EMS_TYPE_UBAMonitorSlow, "UBAMonitorSlow", _process_UBAMonitorSlow},
|
{EMS_ID_BOILER, EMS_TYPE_UBAMonitorSlow, "UBAMonitorSlow", _process_UBAMonitorSlow},
|
||||||
{EMS_ID_BOILER, EMS_TYPE_UBAMonitorWWMessage, "UBAMonitorWWMessage", _process_UBAMonitorWWMessage},
|
{EMS_ID_BOILER, EMS_TYPE_UBAMonitorWWMessage, "UBAMonitorWWMessage", _process_UBAMonitorWWMessage},
|
||||||
{EMS_ID_BOILER, EMS_TYPE_UBAParameterWW, "UBAParameterWW", _process_UBAParameterWW},
|
{EMS_ID_BOILER, EMS_TYPE_UBAParameterWW, "UBAParameterWW", _process_UBAParameterWW},
|
||||||
@@ -55,7 +66,9 @@ const _EMS_Types EMS_Types[] =
|
|||||||
{EMS_ID_THERMOSTAT, EMS_TYPE_RC20Time, "RC20Time", _process_RC20Time},
|
{EMS_ID_THERMOSTAT, EMS_TYPE_RC20Time, "RC20Time", _process_RC20Time},
|
||||||
{EMS_ID_THERMOSTAT, EMS_TYPE_RC20Temperature, "RC20Temperature", _process_RC20Temperature},
|
{EMS_ID_THERMOSTAT, EMS_TYPE_RC20Temperature, "RC20Temperature", _process_RC20Temperature},
|
||||||
{EMS_ID_THERMOSTAT, EMS_TYPE_RCTempMessage, "RCTempMessage", _process_RCTempMessage},
|
{EMS_ID_THERMOSTAT, EMS_TYPE_RCTempMessage, "RCTempMessage", _process_RCTempMessage},
|
||||||
{EMS_ID_THERMOSTAT, EMS_TYPE_Version, "Version", _process_Version}};
|
{EMS_ID_THERMOSTAT, EMS_TYPE_Version, "Version", _process_Version}
|
||||||
|
|
||||||
|
};
|
||||||
uint8_t _EMS_Types_max = ArraySize(EMS_Types); // number of defined types
|
uint8_t _EMS_Types_max = ArraySize(EMS_Types); // number of defined types
|
||||||
|
|
||||||
// reserve space for the data we collect from the Boiler and Thermostat
|
// reserve space for the data we collect from the Boiler and Thermostat
|
||||||
@@ -98,11 +111,12 @@ void ems_init() {
|
|||||||
EMS_Sys_Status.emsLastRx = 0;
|
EMS_Sys_Status.emsLastRx = 0;
|
||||||
EMS_Sys_Status.emsLastTx = 0;
|
EMS_Sys_Status.emsLastTx = 0;
|
||||||
EMS_Sys_Status.emsRefreshed = false;
|
EMS_Sys_Status.emsRefreshed = false;
|
||||||
|
|
||||||
EMS_Sys_Status.emsPollEnabled = false; // start up with Poll disabled
|
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.emsThermostatEnabled = true; // there is a RCxx thermostat active as default
|
||||||
EMS_Sys_Status.emsLogging = EMS_SYS_LOGGING_NONE; // Verbose logging is off
|
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.hour = 0;
|
||||||
EMS_Thermostat.minute = 0;
|
EMS_Thermostat.minute = 0;
|
||||||
EMS_Thermostat.second = 0;
|
EMS_Thermostat.second = 0;
|
||||||
@@ -146,6 +160,9 @@ void ems_init() {
|
|||||||
EMS_Boiler.wWWorkM = EMS_VALUE_INT_NOTSET; // Warm Water # minutes
|
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.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
|
// init the Tx package
|
||||||
_initTxBuffer();
|
_initTxBuffer();
|
||||||
}
|
}
|
||||||
@@ -316,13 +333,18 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) {
|
|||||||
&& ((millis() - EMS_Sys_Status.emsLastTx) > RX_READ_TIMEOUT)) {
|
&& ((millis() - EMS_Sys_Status.emsLastTx) > RX_READ_TIMEOUT)) {
|
||||||
if (emsLastRxCount++ >= RX_READ_TIMEOUT_COUNT) {
|
if (emsLastRxCount++ >= RX_READ_TIMEOUT_COUNT) {
|
||||||
// give up and reset tx
|
// give up and reset tx
|
||||||
|
if (EMS_Sys_Status.emsLogging != EMS_SYS_LOGGING_NONE) {
|
||||||
myDebug("Error! Failed to send telegram, cancelling last write command.\n");
|
myDebug("Error! Failed to send telegram, cancelling last write command.\n");
|
||||||
|
}
|
||||||
|
// re-initialise
|
||||||
_initTxBuffer();
|
_initTxBuffer();
|
||||||
} else {
|
} else {
|
||||||
|
if (EMS_Sys_Status.emsLogging != EMS_SYS_LOGGING_NONE) {
|
||||||
myDebug("Didn't receive acknowledgement from the 0x%02x, so resending (attempt #%d/%d)...\n",
|
myDebug("Didn't receive acknowledgement from the 0x%02x, so resending (attempt #%d/%d)...\n",
|
||||||
EMS_TxTelegram.type,
|
EMS_TxTelegram.type,
|
||||||
emsLastRxCount,
|
emsLastRxCount,
|
||||||
RX_READ_TIMEOUT_COUNT);
|
RX_READ_TIMEOUT_COUNT);
|
||||||
|
}
|
||||||
EMS_Sys_Status.emsTxStatus = EMS_TX_PENDING; // set to pending will trigger sending the same package again
|
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
|
// we have a match
|
||||||
typeFound = true;
|
typeFound = true;
|
||||||
// call callback to fetch the values from the telegram
|
// 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) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
@@ -530,7 +553,7 @@ bool _checkWriteQueueFull() {
|
|||||||
myDebug("Delaying write command as there is already a telegram (type 0x%02x) in the queue\n",
|
myDebug("Delaying write command as there is already a telegram (type 0x%02x) in the queue\n",
|
||||||
EMS_TxTelegram.type);
|
EMS_TxTelegram.type);
|
||||||
}
|
}
|
||||||
return true;
|
return true; // something in queue
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // nothing queue, we can do a write command
|
return false; // nothing queue, we can do a write command
|
||||||
@@ -538,7 +561,7 @@ bool _checkWriteQueueFull() {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* UBAParameterWW - type 0x33 - warm water parameters
|
* 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) {
|
bool _process_UBAParameterWW(uint8_t * data, uint8_t length) {
|
||||||
EMS_Boiler.wWSelTemp = data[2];
|
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.wWCircPump = (data[6] == 0xFF); // 0xFF means on
|
||||||
EMS_Boiler.wWDesiredTemp = data[8];
|
EMS_Boiler.wWDesiredTemp = data[8];
|
||||||
|
|
||||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back to Home Assistant via MQTT
|
return true; // triggers a send the values back to Home Assistant via MQTT
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -561,7 +582,7 @@ bool _process_UBAMonitorWWMessage(uint8_t * data, uint8_t length) {
|
|||||||
EMS_Boiler.wWWorkM = _toLong(10, data);
|
EMS_Boiler.wWWorkM = _toLong(10, data);
|
||||||
EMS_Boiler.wWOneTime = bitRead(data[5], 1);
|
EMS_Boiler.wWOneTime = bitRead(data[5], 1);
|
||||||
|
|
||||||
return true;
|
return false; // no need to update mqtt
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -580,9 +601,16 @@ bool _process_UBAMonitorFast(uint8_t * data, uint8_t length) {
|
|||||||
EMS_Boiler.heatPmp = bitRead(v, 5);
|
EMS_Boiler.heatPmp = bitRead(v, 5);
|
||||||
EMS_Boiler.wWHeat = bitRead(v, 6);
|
EMS_Boiler.wWHeat = bitRead(v, 6);
|
||||||
EMS_Boiler.wWCirc = bitRead(v, 7);
|
EMS_Boiler.wWCirc = bitRead(v, 7);
|
||||||
|
|
||||||
EMS_Boiler.selBurnPow = data[3]; // max power
|
|
||||||
EMS_Boiler.curBurnPow = data[4];
|
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);
|
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);
|
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.burnWorkMin = _toLong(13, data);
|
||||||
EMS_Boiler.heatWorkMin = _toLong(19, 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; // triggers a send the values back to Home Assistant via MQTT
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -620,9 +646,7 @@ bool _process_RC20StatusMessage(uint8_t * data, uint8_t length) {
|
|||||||
EMS_Thermostat.setpoint_roomTemp = ((float)data[1]) / (float)2;
|
EMS_Thermostat.setpoint_roomTemp = ((float)data[1]) / (float)2;
|
||||||
EMS_Thermostat.curr_roomTemp = _toFloat(2, data);
|
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; // triggers a send the values back to Home Assistant via MQTT
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -642,13 +666,12 @@ bool _process_RC20Temperature(uint8_t * data, uint8_t length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// and send the values back to HA (Home Assistant MQTT)
|
// and send the values back to HA (Home Assistant MQTT)
|
||||||
EMS_Sys_Status.emsRefreshed = true;
|
return true;
|
||||||
} else {
|
|
||||||
// Process the whole telegram package
|
|
||||||
EMS_Thermostat.mode = data[EMS_OFFSET_RC20Temperature_mode]; // get the mode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
bool _process_RCTempMessage(uint8_t * data, uint8_t length) {
|
||||||
// add support here if you're reading external sensors
|
// 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
|
* 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) {
|
bool _process_Version(uint8_t * data, uint8_t length) {
|
||||||
|
// ignore short messages
|
||||||
|
if (length == 8) {
|
||||||
uint8_t major = data[1];
|
uint8_t major = data[1];
|
||||||
uint8_t minor = data[2];
|
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);
|
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
|
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
|
* 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)
|
* Read commands when sent must respond by the destination (target) immediately (or within 10ms)
|
||||||
|
|||||||
22
src/ems.h
22
src/ems.h
@@ -21,8 +21,10 @@
|
|||||||
|
|
||||||
#define EMS_TX_MAXBUFFERSIZE 128 // max size of the buffer. packets are 32 bits
|
#define EMS_TX_MAXBUFFERSIZE 128 // max size of the buffer. packets are 32 bits
|
||||||
|
|
||||||
// define here the Thermostat type
|
#define EMS_ID_THERMOSTAT_RC20 0x17 // RC20 (older Moduline 300)
|
||||||
#define EMS_ID_THERMOSTAT 0x17 // x17=RC20 (Moduline300), x10=RC30/RC35 (Moduline 400)
|
#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
|
// define here the EMS telegram types you need
|
||||||
|
|
||||||
@@ -143,10 +145,16 @@ typedef struct {
|
|||||||
uint32_t wWStarts; // Warm Water # starts
|
uint32_t wWStarts; // Warm Water # starts
|
||||||
uint32_t wWWorkM; // Warm Water # minutes
|
uint32_t wWWorkM; // Warm Water # minutes
|
||||||
uint8_t wWOneTime; // Warm Water one time function on/off
|
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;
|
} _EMS_Boiler;
|
||||||
|
|
||||||
// RC20 data
|
// Thermostat data
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
uint8_t type; // thermostat type (RC20, RC30, RC35 etc)
|
||||||
float setpoint_roomTemp; // current set temp
|
float setpoint_roomTemp; // current set temp
|
||||||
float curr_roomTemp; // current room temp
|
float curr_roomTemp; // current room temp
|
||||||
uint8_t mode; // 0=low, 1=manual, 2=auto
|
uint8_t mode; // 0=low, 1=manual, 2=auto
|
||||||
@@ -186,18 +194,22 @@ typedef struct {
|
|||||||
extern void ems_parseTelegram(uint8_t * telegram, uint8_t len);
|
extern void ems_parseTelegram(uint8_t * telegram, uint8_t len);
|
||||||
void ems_init();
|
void ems_init();
|
||||||
void ems_doReadCommand(uint8_t type);
|
void ems_doReadCommand(uint8_t type);
|
||||||
|
|
||||||
void ems_setThermostatTemp(float temp);
|
void ems_setThermostatTemp(float temp);
|
||||||
void ems_setThermostatMode(uint8_t mode);
|
void ems_setThermostatMode(uint8_t mode);
|
||||||
void ems_setWarmWaterTemp(uint8_t temperature);
|
void ems_setWarmWaterTemp(uint8_t temperature);
|
||||||
void ems_setWarmWaterActivated(bool activated);
|
void ems_setWarmWaterActivated(bool activated);
|
||||||
void ems_setExperimental(uint8_t value);
|
void ems_setExperimental(uint8_t value);
|
||||||
void ems_setPoll(bool b);
|
void ems_setPoll(bool b);
|
||||||
bool ems_getPoll();
|
|
||||||
bool ems_getThermostatEnabled();
|
|
||||||
void ems_setThermostatEnabled(bool b);
|
void ems_setThermostatEnabled(bool b);
|
||||||
void ems_setLogging(_EMS_SYS_LOGGING loglevel);
|
void ems_setLogging(_EMS_SYS_LOGGING loglevel);
|
||||||
|
|
||||||
|
void ems_getThermostatTemps();
|
||||||
|
bool ems_getPoll();
|
||||||
|
bool ems_getThermostatEnabled();
|
||||||
_EMS_SYS_LOGGING ems_getLogging();
|
_EMS_SYS_LOGGING ems_getLogging();
|
||||||
uint8_t ems_getEmsTypesCount();
|
uint8_t ems_getEmsTypesCount();
|
||||||
|
|
||||||
void ems_printAllTypes();
|
void ems_printAllTypes();
|
||||||
|
|
||||||
// private functions
|
// private functions
|
||||||
|
|||||||
Reference in New Issue
Block a user