version 1.3.0

This commit is contained in:
proddy
2019-01-09 23:41:41 +01:00
parent 2d2ee1927d
commit 22823545da
28 changed files with 1730 additions and 758 deletions

View File

@@ -1,13 +1,15 @@
/*
* EMS-ESP-Boiler
* Paul Derbyshire - May 2018 - https://github.com/proddy/EMS-ESP-Boiler
* https://community.home-assistant.io/t/thermostat-and-boiler-controller-for-ems-based-boilers-nefit-buderus-bosch-using-esp/53382
* EMS-ESP
*
* Paul Derbyshire - https://github.com/proddy/EMS-ESP
*
* See README for Acknowledgments
* See ChangeLog.md for history
* See README.md for Acknowledgments
*/
// local libraries
#include "ems.h"
#include "ems_devices.h"
#include "emsuart.h"
#include "my_config.h"
#include "version.h"
@@ -45,6 +47,8 @@ uint8_t scanThermostat_count = 0;
Ticker showerColdShotStopTimer;
static unsigned long timestamp; // for internal timings, via millis()
// thermostat
#define TOPIC_THERMOSTAT_DATA "thermostat_data" // for sending thermostat values
#define TOPIC_THERMOSTAT_CMD_TEMP "thermostat_cmd_temp" // for received thermostat temp changes
@@ -65,19 +69,11 @@ Ticker showerColdShotStopTimer;
#define TOPIC_SHOWER_COLDSHOT "shower_coldshot" // used to trigger a coldshot from HA publish
#define SHOWER_ALARM "shower_alarm" // for notifying HA that shower time has reached its limit
// shower settings for DEBUGGING only
#ifdef SHOWER_TEST
#undef SHOWER_PAUSE_TIME
#undef SHOWER_MIN_DURATION
#undef SHOWER_MAX_DURATION
#undef SHOWER_COLDSHOT_DURATION
#undef SHOWER_OFFSET_TIME
const unsigned long SHOWER_PAUSE_TIME = 15000; // 15 seconds, max time if water is switched off & on during a shower
const unsigned long SHOWER_MIN_DURATION = 20000; // 20 secs, before recognizing its a shower
const unsigned long SHOWER_MAX_DURATION = 25000; // 25 secs, before trigger a shot of cold water
const unsigned long SHOWER_COLDSHOT_DURATION = 5; // in seconds! how long for cold water shot
const unsigned long SHOWER_OFFSET_TIME = 0; // 0 seconds grace time, to calibrate actual time under the shower
#endif
// if using the shower timer, change these settings
#define SHOWER_PAUSE_TIME 15000 // in ms. 15 seconds, max time if water is switched off & on during a shower
#define SHOWER_MIN_DURATION 120000 // in ms. 2 minutes, before recognizing its a shower
#define SHOWER_OFFSET_TIME 5000 // in ms. 5 seconds grace time, to calibrate actual time under the shower
#define SHOWER_COLDSHOT_DURATION 10 // in seconds. 10 seconds for cold water before turning back hot water
typedef struct {
bool shower_timer; // true if we want to report back on shower times
@@ -94,24 +90,23 @@ typedef struct {
command_t PROGMEM project_cmds[] = {
{"l [n]", "set logging (0=none, 1=raw, 2=basic, 3=thermostat only, 4=verbose)"},
{"s", "show statistics"},
{"D", "scan EMS connected Devices"},
{"h", "list supported EMS telegram type IDs"},
{"M", "publish to MQTT"},
{"Q", "print Tx Queue"},
{"U [n]", "do a deep scan of all thermostat message types, starting at n"},
{"P", "toggle EMS Poll response on/off"},
{"X", "toggle EMS Tx transmission on/off"},
{"S", "toggle Shower timer on/off"},
{"A", "toggle shower Alert on/off"},
{"r [s]", "send raw telegram in hex to EMS (s=XX XX XX...)"},
{"b [xx]", "send boiler read request (xx=telegram type ID in hex)"},
{"t [xx]", "send thermostat read request (xx=telegram type ID in hex)"},
{"w [n]", "set boiler warm water temperature (min 30)"},
{"a [n]", "set boiler warm tap water (0=off, 1=on)"},
{"T [n]", "set thermostat temperature"},
{"m [n]", "set thermostat mode (0=low/night, 1=manual/day, 2=auto)"}
{"info", "show the values"},
{"log <n | b | t | r | v>", "set logging mode to none, basic, thermostat only, raw or verbose"},
{"poll", "toggle EMS poll request on/off"},
{"tx", "toggle EMX Tx on/off"},
{"publish", "publish values to MQTT"},
{"types", "list supported EMS telegram type IDs"},
{"queue", "print the Tx queue"},
{"autodetect", "discover EMS devices and set boiler and thermostat automatically"},
{"shower <timer | alert>", "toggle either timer or alert on/off"},
{"send XX...", "send raw telegram data in hex to EMS bus"},
{"thermostat read <hex type ID>", "send read request to thermostat"},
{"thermostat temp <degrees>", "set current thermostat temperature"},
{"thermostat mode <mode>", "set mode (0=low/night, 1=manual/day, 2=auto)"},
{"thermostat scan <hex type ID>", "do a deep scan of all thermostat message types, starting at n"},
{"boiler read <hex type ID>", "send read request to boiler"},
{"boiler wwtemp <degrees>", "set warm water temperature"},
{"boiler tapwater <on | off>", "set warm tap water on or off"}
};
@@ -127,8 +122,6 @@ uint32_t previousThermostatPublishCRC = 0;
const unsigned long POLL_TIMEOUT_ERR = 10000; // if no signal from boiler for last 10 seconds, assume its offline
const unsigned long TX_HOLD_LED_TIME = 2000; // how long to hold the Tx LED because its so quick
unsigned long timestamp; // for internal timings, via millis()
uint8_t last_boilerActive = 0xFF; // for remembering last setting of the tap water or heating on/off
// logging messages with fixed strings
@@ -269,7 +262,7 @@ void _renderBoolValue(const char * prefix, uint8_t value) {
void showInfo() {
// General stats from EMS bus
myDebug("%sEMS-ESP-Boiler system stats:%s", COLOR_BOLD_ON, COLOR_BOLD_OFF);
myDebug("%sEMS-ESP System setstats:%s", COLOR_BOLD_ON, COLOR_BOLD_OFF);
_EMS_SYS_LOGGING sysLog = ems_getLogging();
if (sysLog == EMS_SYS_LOGGING_BASIC) {
myDebug(" System logging set to Basic");
@@ -519,116 +512,203 @@ void publishValues(bool force) {
// sets the shower timer on/off
void set_showerTimer() {
if (ems_getLogging() != EMS_SYS_LOGGING_NONE) {
myDebug("Shower timer is %s", Boiler_Status.shower_timer ? "enabled" : "disabled");
myDebug("Shower timer has been set to %s", Boiler_Status.shower_timer ? "enabled" : "disabled");
}
}
// sets the shower alert on/off
void set_showerAlert() {
if (ems_getLogging() != EMS_SYS_LOGGING_NONE) {
myDebug("Shower alert is %s", Boiler_Status.shower_alert ? "enabled" : "disabled");
myDebug("Shower alert has been set to %s", Boiler_Status.shower_alert ? "enabled" : "disabled");
}
}
// used to read the next string from an input buffer and convert to an 8 bit int
uint8_t _readIntNumber() {
char * numTextPtr = strtok(NULL, ", \n");
if (numTextPtr == nullptr) {
return 0;
}
return atoi(numTextPtr);
}
// used to read the next string from an input buffer as a hex value and convert to an 8 bit int
uint8_t _readHexNumber() {
char * numTextPtr = strtok(NULL, ", \n");
if (numTextPtr == nullptr) {
return 0;
}
return (uint8_t)strtol(numTextPtr, 0, 16);
}
// used to read the next string from an input buffer
char * _readWord() {
char * word = strtok(NULL, ", \n");
return word;
}
// initiate a force scan by sending type read requests from 0 to FF to the thermostat
// used to analyze repsonses for debugging
void startThermostatScan(uint8_t start) {
ems_setLogging(EMS_SYS_LOGGING_THERMOSTAT);
publishValuesTimer.detach();
systemCheckTimer.detach();
regularUpdatesTimer.detach();
scanThermostat_count = start;
myDebug("Starting a deep message scan on thermostat");
scanThermostat.attach(SCANTHERMOSTAT_TIME, do_scanThermostat);
}
// call back when a telnet client connects or disconnects
// we set the logging here
void TelnetCallback(uint8_t event) {
if (event == TELNET_EVENT_CONNECT) {
ems_setLogging(EMS_SYS_LOGGING_BASIC);
} else if (event == TELNET_EVENT_DISCONNECT) {
ems_setLogging(EMS_SYS_LOGGING_NONE);
}
}
// extra commands options for telnet debug window
void myDebugCallback() {
char * cmd = myESP.consoleGetLastCommand();
uint8_t len = strlen(cmd);
bool b;
// wc is the word count, i.e. number of arguments. Everything is in lower case.
void TelnetCommandCallback(uint8_t wc, const char * commandLine) {
bool ok = false;
// get first command argument
char * first_cmd = strtok((char *)commandLine, ", \n");
// look for single letter commands
if (len == 1) {
switch (cmd[0]) {
case 's':
showInfo();
break;
case 'P': // toggle Poll
b = !ems_getPoll();
ems_setPoll(b);
break;
case 'X': // toggle Tx
b = !ems_getTxEnabled();
ems_setTxEnabled(b);
break;
case 'M':
publishValues(true);
break;
case 'h': // show type handlers
ems_printAllTypes();
break;
case 'S': // toggle Shower timer support
Boiler_Status.shower_timer = !Boiler_Status.shower_timer;
myESP.mqttPublish(TOPIC_SHOWER_TIMER, Boiler_Status.shower_timer ? "1" : "0");
break;
case 'A': // toggle Shower alert
Boiler_Status.shower_alert = !Boiler_Status.shower_alert;
myESP.mqttPublish(TOPIC_SHOWER_ALERT, Boiler_Status.shower_alert ? "1" : "0");
break;
case 'Q': // print Tx Queue
ems_printTxQueue();
break;
case 'D': // Auto detect EMS devices
ems_scanDevices();
break;
default:
myDebug("Unknown command. Use ? for help.");
break;
if (strcmp(first_cmd, "info") == 0) {
showInfo();
ok = true;
}
if (strcmp(first_cmd, "poll") == 0) {
bool b = !ems_getPoll();
ems_setPoll(b);
ok = true;
}
if (strcmp(first_cmd, "tx") == 0) {
bool b = !ems_getTxEnabled();
ems_setTxEnabled(b);
ok = true;
}
if (strcmp(first_cmd, "publish") == 0) {
publishValues(true);
ok = true;
}
if (strcmp(first_cmd, "types") == 0) {
ems_printAllTypes();
ok = true;
}
if (strcmp(first_cmd, "queue") == 0) {
ems_printTxQueue();
ok = true;
}
if (strcmp(first_cmd, "autodetect") == 0) {
ems_scanDevices();
ok = true;
}
// shower settings
if (strcmp(first_cmd, "shower") == 0) {
if (wc == 2) {
char * second_cmd = _readWord();
if (strcmp(second_cmd, "timer") == 0) {
Boiler_Status.shower_timer = !Boiler_Status.shower_timer;
myESP.mqttPublish(TOPIC_SHOWER_TIMER, Boiler_Status.shower_timer ? "1" : "0");
ok = true;
} else if (strcmp(second_cmd, "alert") == 0) {
Boiler_Status.shower_alert = !Boiler_Status.shower_alert;
myESP.mqttPublish(TOPIC_SHOWER_ALERT, Boiler_Status.shower_alert ? "1" : "0");
ok = true;
}
}
return;
}
// for commands with parameters, assume command is just a single letter followed by a space
switch (cmd[0]) {
case 'T': // set thermostat temp
ems_setThermostatTemp(strtof(&cmd[2], 0));
break;
case 'm': // set thermostat mode
ems_setThermostatMode(cmd[2] - '0');
break;
case 'w': // set warm water temp
ems_setWarmWaterTemp((uint8_t)strtol(&cmd[2], 0, 10));
break;
case 'l': // logging
ems_setLogging((_EMS_SYS_LOGGING)(cmd[2] - '0'));
break;
case 'a': // set ww activate on or off
if ((cmd[2] - '0') == 1)
ems_setWarmTapWaterActivated(true);
else if ((cmd[2] - '0') == 0)
ems_setWarmTapWaterActivated(false);
break;
case 'b': // boiler read command
ems_doReadCommand((uint8_t)strtol(&cmd[2], 0, 16), EMS_Boiler.type_id);
break;
case 't': // thermostat command
ems_doReadCommand((uint8_t)strtol(&cmd[2], 0, 16), EMS_Thermostat.type_id);
break;
case 'r': // send raw data
ems_sendRawTelegram(&cmd[2]);
break;
case 'x': // experimental, not displayed!
myDebug("Calling experimental...");
ems_setLogging(EMS_SYS_LOGGING_VERBOSE);
ems_setExperimental((uint8_t)strtol(&cmd[2], 0, 16)); // takes HEX param
break;
case 'U': // thermostat scan
ems_setLogging(EMS_SYS_LOGGING_THERMOSTAT);
publishValuesTimer.detach();
systemCheckTimer.detach();
regularUpdatesTimer.detach();
scanThermostat_count = (uint8_t)strtol(&cmd[2], 0, 16);
myDebug("Starting a deep message scan on thermometer");
scanThermostat.attach(SCANTHERMOSTAT_TIME, do_scanThermostat);
break;
default:
myDebug("Unknown command. Use ? for help.");
break;
// logging
if (strcmp(first_cmd, "log") == 0) {
if (wc == 2) {
char * second_cmd = _readWord();
if (strcmp(second_cmd, "v") == 0) {
ems_setLogging(EMS_SYS_LOGGING_VERBOSE);
ok = true;
} else if (strcmp(second_cmd, "b") == 0) {
ems_setLogging(EMS_SYS_LOGGING_BASIC);
ok = true;
} else if (strcmp(second_cmd, "t") == 0) {
ems_setLogging(EMS_SYS_LOGGING_THERMOSTAT);
ok = true;
} else if (strcmp(second_cmd, "r") == 0) {
ems_setLogging(EMS_SYS_LOGGING_RAW);
ok = true;
} else if (strcmp(second_cmd, "n") == 0) {
ems_setLogging(EMS_SYS_LOGGING_NONE);
ok = true;
}
}
}
// thermostat commands
if (strcmp(first_cmd, "thermostat") == 0) {
if (wc == 3) {
char * second_cmd = _readWord();
if (strcmp(second_cmd, "temp") == 0) {
ems_setThermostatTemp(_readIntNumber());
ok = true;
} else if (strcmp(second_cmd, "mode") == 0) {
ems_setThermostatMode(_readIntNumber());
ok = true;
} else if (strcmp(second_cmd, "read") == 0) {
ems_doReadCommand(_readHexNumber(), EMS_Thermostat.type_id);
ok = true;
} else if (strcmp(second_cmd, "scan") == 0) {
startThermostatScan(_readIntNumber());
ok = true;
}
}
}
// boiler commands
if (strcmp(first_cmd, "boiler") == 0) {
if (wc == 3) {
char * second_cmd = _readWord();
if (strcmp(second_cmd, "wwtemp") == 0) {
ems_setWarmWaterTemp(_readIntNumber());
ok = true;
} else if (strcmp(second_cmd, "read") == 0) {
ems_doReadCommand(_readHexNumber(), EMS_Boiler.type_id);
ok = true;
} else if (strcmp(second_cmd, "tapwater") == 0) {
char * third_cmd = _readWord();
if (strcmp(third_cmd, "on") == 0) {
ems_setWarmTapWaterActivated(true);
ok = true;
} else if (strcmp(third_cmd, "off") == 0) {
ems_setWarmTapWaterActivated(false);
ok = true;
}
}
}
}
// send raw
if (strcmp(first_cmd, "send") == 0) {
ems_sendRawTelegram((char *)&commandLine[5]);
ok = true;
}
// check for invalid command
if (!ok) {
myDebug("Unknown command. Use ? for help.");
}
return;
}
// MQTT Callback to handle incoming/outgoing changes
void MQTTcallback(unsigned int type, const char * topic, const char * message) {
void MQTTCallback(unsigned int type, const char * topic, const char * message) {
// we're connected. lets subscribe to some topics
if (type == MQTT_CONNECT_EVENT) {
myESP.mqttSubscribe(TOPIC_THERMOSTAT_CMD_TEMP);
@@ -708,7 +788,7 @@ void WIFICallback() {
// Initialize the boiler settings
void initShower() {
// default showr settings
// default shower settings
Boiler_Status.shower_timer = BOILER_SHOWER_TIMER;
Boiler_Status.shower_alert = BOILER_SHOWER_ALERT;
Boiler_Shower.timerStart = 0;
@@ -719,7 +799,10 @@ void initShower() {
// call PublishValues without forcing, so using CRC to see if we really need to publish
void do_publishValues() {
publishValues(false);
// don't publish if we're not connected to the EMS bus
if (ems_getBusConnected()) {
publishValues(false);
}
}
// callback to light up the LED, called via Ticker every second
@@ -745,16 +828,20 @@ void do_scanThermostat() {
// do a system health check every now and then to see if we all connections
void do_systemCheck() {
if (!ems_getBusConnected()) {
myDebug("Error! Unable to connect to EMS bus. Please make sure you're not in DEBUG_SUPPORT mode. Retrying in %d seconds...",
myDebug("Error! Unable to connect to EMS bus. Check connection and make sure you're not in DEBUG_SUPPORT mode. Retrying in %d "
"seconds...",
SYSTEMCHECK_TIME);
}
}
// force calls to get data from EMS for the types that aren't sent as broadcasts
// only if we have a EMS connection
void do_regularUpdates() {
myDebugLog("Calling scheduled data refresh from EMS devices..");
ems_getThermostatValues(); // get Thermostat temps (if supported)
ems_getBoilerValues();
if (ems_getBusConnected()) {
myDebugLog("Calling scheduled data refresh from EMS devices..");
ems_getThermostatValues(); // get Thermostat temps (if supported)
ems_getBoilerValues();
}
}
// turn off hot water to send a shot of cold
@@ -860,16 +947,20 @@ void setup() {
regularUpdatesTimer.attach(REGULARUPDATES_TIME, do_regularUpdates); // regular reads from the EMS
// set up myESP for Wifi, MQTT, MDNS and Telnet
// with callbacks
myESP.setup(APP_HOSTNAME, APP_NAME, APP_VERSION, WIFI_SSID, WIFI_PASSWORD, MQTT_IP, MQTT_USER, MQTT_PASS);
myESP.consoleSetCallBackProjectCmds(project_cmds, ArraySize(project_cmds), myDebugCallback); // set up Telnet commands
myESP.setTelnetCommands(project_cmds, ArraySize(project_cmds), TelnetCommandCallback); // set up Telnet commands
myESP.setConnection(WIFI_SSID, WIFI_PASSWORD, MQTT_IP, MQTT_USER, MQTT_PASS); // optional
myESP.begin(APP_HOSTNAME, APP_NAME, APP_VERSION);
myESP.setMQTTbase(MQTT_BASE);
// callbacks
myESP.setWIFICallback(WIFICallback);
myESP.setMQTTCallback(MQTTcallback);
myESP.setMQTTCallback(MQTTCallback);
myESP.setTelnetCallback(TelnetCallback);
// init Shower specific parameters
initShower();
ems_setLogging(BOILER_DEFAULT_LOGGING); // set default logging. see my_config.h
ems_setLogging(EMS_SYS_LOGGING_NONE); // set default logging to none
// init the EMS bus
// call ems.cpp's init function to set all the internal params
@@ -892,7 +983,7 @@ void loop() {
ems_setEmsRefreshed(false);
}
// do shower logic if it is enabled
// do shower logic, if enabled
if (Boiler_Status.shower_timer) {
showerCheck();
}

View File

@@ -1,10 +1,18 @@
/**
* ems.cpp
*
* handles all the processing of the EMS messages
* Paul Derbyshire - https://github.com/proddy/EMS-ESP-Boiler
*
* Paul Derbyshire - https://github.com/proddy/EMS-ESP
*/
#include "ems.h"
#include "ems_devices.h"
#include "emsuart.h"
#include <Arduino.h>
#include <CircularBuffer.h> // https://github.com/rlogiacco/CircularBuffer
#include <MyESP.h>
#include <list> // std::list
// myESP
#define myDebug(...) myESP.myDebug(__VA_ARGS__)
@@ -42,42 +50,9 @@ void _process_RC35StatusMessage(uint8_t * data, uint8_t length);
// Easy
void _process_EasyStatusMessage(uint8_t * data, uint8_t length);
// EMS types for known Buderus devices
// Note: This is still incomplete
const _Model_Type Model_Types[] = {
// me
{EMS_MODEL_SERVICEKEY, 999, 0x0B, "Service Key"},
// various boilers and buderus type devices
{EMS_MODEL_UBA, 123, 0x08, "MC10/UBA3 Boiler"}, // verified
{EMS_MODEL_BK15, 64, 0x08, "Sieger BK15 Boiler"}, // verified
{EMS_MODEL_BC10, 190, 0x09, "BC10 Base Controller"}, // verified
{EMS_MODEL_MM10, 125, 0x21, "MM10 Mixer Module"}, // warning, fake product id!
{EMS_MODEL_WM10, 126, 0x11, "WM10 Switch Module"}, // warning, fake product id!
// controllers and thermostats
{EMS_MODEL_ES73, 76, 0x10, "Sieger ES73"},
{EMS_MODEL_RC20, 77, 0x17, "RC20 (Nefit Moduline 300)"},
{EMS_MODEL_RC30, 78, 0x10, "RC30 (Nefit Moduline 400)"},
{EMS_MODEL_RC35, 86, 0x10, "RC35 (or compatible"},
{EMS_MODEL_EASY, 202, 0x18, "TC100 (Nefit Easy/CT100)"}
};
/*
* Known thermostat types and their abilities
* Recognized EMS types and the functions they call to process the telegrams
*/
const _Thermostat_Type Thermostat_Types[] = {
{EMS_MODEL_RC20, EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
{EMS_MODEL_RC30, EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
{EMS_MODEL_RC35, EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
{EMS_MODEL_EASY, EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_NO},
{EMS_MODEL_ES73, EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES}
};
const _EMS_Type EMS_Types[] = {
// common
@@ -93,13 +68,19 @@ const _EMS_Type EMS_Types[] = {
{EMS_MODEL_UBA, EMS_TYPE_UBAParametersMessage, "UBAParametersMessage", NULL},
{EMS_MODEL_UBA, EMS_TYPE_UBAMaintenanceStatusMessage, "UBAMaintenanceStatusMessage", NULL},
// RC20
// RC20 and RC20F
{EMS_MODEL_RC20, EMS_TYPE_RCOutdoorTempMessage, "RCOutdoorTempMessage", _process_RCOutdoorTempMessage},
{EMS_MODEL_RC20, EMS_TYPE_RCTime, "RCTime", _process_RCTime},
{EMS_MODEL_RC20, EMS_TYPE_RC20Set, "RC20Set", _process_RC20Set},
{EMS_MODEL_RC20, EMS_TYPE_RC20StatusMessage, "RC20StatusMessage", _process_RC20StatusMessage},
{EMS_MODEL_RC20, EMS_TYPE_UBASetPoints, "UBASetPoints", _process_SetPoints},
{EMS_MODEL_RC20F, EMS_TYPE_RCOutdoorTempMessage, "RCOutdoorTempMessage", _process_RCOutdoorTempMessage},
{EMS_MODEL_RC20F, EMS_TYPE_RCTime, "RCTime", _process_RCTime},
{EMS_MODEL_RC20F, EMS_TYPE_RC20Set, "RC20Set", _process_RC20Set},
{EMS_MODEL_RC20F, EMS_TYPE_RC20StatusMessage, "RC20StatusMessage", _process_RC20StatusMessage},
{EMS_MODEL_RC20F, EMS_TYPE_UBASetPoints, "UBASetPoints", _process_SetPoints},
// RC30
{EMS_MODEL_RC30, EMS_TYPE_RCOutdoorTempMessage, "RCOutdoorTempMessage", _process_RCOutdoorTempMessage},
{EMS_MODEL_RC30, EMS_TYPE_RCTime, "RCTime", _process_RCTime},
@@ -125,7 +106,6 @@ const _EMS_Type EMS_Types[] = {
{EMS_MODEL_EASY, EMS_TYPE_EasyStatusMessage, "EasyStatusMessage", _process_EasyStatusMessage},
{EMS_MODEL_EASY, EMS_TYPE_UBASetPoints, "UBASetPoints", _process_SetPoints}
};
// calculate sizes of arrays
@@ -163,7 +143,7 @@ uint8_t _last_TxTelgramCRC; // CRC of last Tx sent, for checking duplicates
// init stats and counters and buffers
// uses -255 or 255 for values that haven't been set yet (EMS_VALUE_INT_NOTSET and EMS_VALUE_FLOAT_NOTSET)
void ems_init(_EMS_MODEL_ID boiler_modelid, _EMS_MODEL_ID thermostat_modelid) {
void ems_init(uint8_t boiler_modelid, uint8_t thermostat_modelid) {
// overall status
EMS_Sys_Status.emsRxPgks = 0;
EMS_Sys_Status.emsTxPkgs = 0;
@@ -816,7 +796,7 @@ void _processType(uint8_t * telegram, uint8_t length) {
// there is a match, so write must have been successful
EMS_TxQueue.shift(); // remove validate from queue
if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_BASIC) {
myDebug("Write to 0x%02X successful.", EMS_TxTelegram.dest);
myDebug("Write to 0x%02X was successful", EMS_TxTelegram.dest);
}
ems_doReadCommand(EMS_TxTelegram.comparisonPostRead,
EMS_TxTelegram.dest,
@@ -1102,7 +1082,7 @@ void _process_Version(uint8_t * data, uint8_t length) {
ems_getThermostatValues(); // get Thermostat values (if supported)
}
} else {
// otherwise assume its a boiler
// otherwise assume its a boiler or some other EMS device
if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_BASIC) {
myDebug("Boiler recognized. Model %s with TypeID 0x%02X, Product ID %d, Version %s",
Model_Types[i].model_string,
@@ -1125,7 +1105,7 @@ void _process_Version(uint8_t * data, uint8_t length) {
* Given a MODEL_ID, look up its data and set either a Thermostat or Boiler
* return false if not found or no need to set
*/
bool _ems_setModel(_EMS_MODEL_ID model_id) {
bool _ems_setModel(uint8_t model_id) {
if (model_id == EMS_MODEL_NONE) {
return false; // invalid model_id
}
@@ -1301,8 +1281,8 @@ void ems_getThermostatValues() {
return;
}
_EMS_MODEL_ID model_id = EMS_Thermostat.model_id;
uint8_t type = EMS_Thermostat.type_id;
uint8_t model_id = EMS_Thermostat.model_id;
uint8_t type = EMS_Thermostat.type_id;
if (model_id == EMS_MODEL_RC20) {
ems_doReadCommand(EMS_TYPE_RC20StatusMessage, type); // to get the setpoint temp
@@ -1332,7 +1312,7 @@ void ems_getBoilerValues() {
// return pointer to Model details
int _ems_findModel(_EMS_MODEL_ID model_id) {
int _ems_findModel(uint8_t model_id) {
uint8_t i = 0;
bool found = false;
@@ -1351,7 +1331,7 @@ int _ems_findModel(_EMS_MODEL_ID model_id) {
return i;
}
char * _ems_buildModelString(char * buffer, uint8_t size, _EMS_MODEL_ID model_id) {
char * _ems_buildModelString(char * buffer, uint8_t size, uint8_t model_id) {
int i = _ems_findModel(model_id);
if (i != -1) {
char tmp[6] = {0};
@@ -1394,12 +1374,12 @@ char * ems_getBoilerType(char * buffer) {
}
// returns the model type for a thermostat
_EMS_MODEL_ID ems_getThermostatModel() {
uint8_t ems_getThermostatModel() {
return (EMS_Thermostat.model_id);
}
// returns the model type for a boiler
_EMS_MODEL_ID ems_getBoilerModel() {
uint8_t ems_getBoilerModel() {
return (EMS_Boiler.model_id);
}
@@ -1407,7 +1387,11 @@ _EMS_MODEL_ID ems_getBoilerModel() {
* Find the versions of our connected devices
*/
void ems_scanDevices() {
myDebug("Scanning EMS bus for devices. This may take a few seconds.");
if (!ems_getBusConnected()) {
return;
}
myDebug("Scanning EMS bus for devices. This may take a few seconds...");
// copy over the IDs from Model-type to a list
std::list<uint8_t> Device_Ids;
@@ -1430,7 +1414,7 @@ void ems_scanDevices() {
* Print out all handled types
*/
void ems_printAllTypes() {
myDebug("These %d telegram TypeIDs are recognized currently:", _EMS_Types_max);
myDebug("These %d telegram TypeIDs are recognized:", _EMS_Types_max);
uint8_t i;
for (i = 0; i < _EMS_Types_max; i++) {
@@ -1444,7 +1428,7 @@ void ems_printAllTypes() {
}
}
myDebug("\nThese %d thermostats are natively supported:", _Thermostat_Types_max);
myDebug("\nThese %d thermostats models are supported:", _Thermostat_Types_max);
for (i = 0; i < _Thermostat_Types_max; i++) {
// find the model's details
for (int j = 0; j < _Model_Types_max; j++) {
@@ -1503,6 +1487,7 @@ void ems_doReadCommand(uint8_t type, uint8_t dest, bool forceRefresh) {
/**
* Send a raw telegram to the bus
* telegram is a string of hex values
*/
void ems_sendRawTelegram(char * telegram) {
uint8_t count = 0;
@@ -1558,8 +1543,8 @@ void ems_setThermostatTemp(float temperature) {
_EMS_TxTelegram EMS_TxTelegram = EMS_TX_TELEGRAM_NEW; // create new Tx
EMS_TxTelegram.timestamp = millis(); // set timestamp
_EMS_MODEL_ID model_id = EMS_Thermostat.model_id;
uint8_t type = EMS_Thermostat.type_id;
uint8_t model_id = EMS_Thermostat.model_id;
uint8_t type = EMS_Thermostat.type_id;
EMS_TxTelegram.action = EMS_TX_TELEGRAM_WRITE;
EMS_TxTelegram.dest = type;
@@ -1606,8 +1591,8 @@ void ems_setThermostatMode(uint8_t mode) {
return;
}
_EMS_MODEL_ID model_id = EMS_Thermostat.model_id;
uint8_t type = EMS_Thermostat.type_id;
uint8_t model_id = EMS_Thermostat.model_id;
uint8_t type = EMS_Thermostat.type_id;
myDebug("Setting thermostat mode to %d", mode);
@@ -1756,33 +1741,3 @@ void ems_setWarmTapWaterActivated(bool activated) {
EMS_TxQueue.push(EMS_TxTelegram); // add to queue
}
/**
* experimental code for debugging - not in production
*/
void ems_setExperimental(uint8_t value) {
/*
_EMS_TxTelegram EMS_TxTelegram = EMS_TX_TELEGRAM_NEW; // create new Tx
EMS_TxTelegram.timestamp = millis(); // set timestamp
EMS_TxTelegram.action = EMS_TX_TELEGRAM_READ; // read command
EMS_TxTelegram.dest = EMS_Thermostat.type; // set 8th bit to indicate a read
EMS_TxTelegram.offset = 0; // 0 for all data
EMS_TxTelegram.length = 8;
EMS_TxTelegram.type = 0xF0;
EMS_TxTelegram.type_validate = EMS_ID_NONE;
// EMS Plus test
// Sending read to 0x18: telegram: 0B 98 F0 00 01 B9 63 DB (len 8)
EMS_TxTelegram.data[0] = EMS_ID_ME; // src
EMS_TxTelegram.data[1] = EMS_TxTelegram.dest; // dest
EMS_TxTelegram.data[2] = 0xF0; // marker
EMS_TxTelegram.data[3] = EMS_TxTelegram.offset; // offset
EMS_TxTelegram.data[4] = 0x01; // hi byte
EMS_TxTelegram.data[5] = 0xB9; // low byte
EMS_TxTelegram.data[6] = 99; // max length
EMS_TxQueue.push(EMS_TxTelegram);
*/
}

211
src/ems.h
View File

@@ -1,25 +1,15 @@
/*
* Header file for EMS.cpp
* Header file for ems.cpp
*
*/
#pragma once
#include "emsuart.h"
#include "my_config.h" // include custom configuration settings
#include <Arduino.h>
#include <CircularBuffer.h> // https://github.com/rlogiacco/CircularBuffer
#include <MyESP.h>
#include <list>
#include <vector>
// EMS IDs
#define EMS_ID_NONE 0x00 // Fixed - used as a dest in broadcast messages and empty type IDs
#define EMS_ID_ME 0x0B // Fixed - our device, hardcoded as "Service Key"
//#define EMS_ID_THERMOSTAT 0xFF // Fixed - to recognize a Thermostat
//#define EMS_ID_BOILER 0x08 // Fixed - also known as MC10.
#define EMS_ID_ME 0x0B // Fixed - our device, hardcoded as the "Service Key"
#define EMS_MIN_TELEGRAM_LENGTH 6 // minimal length for a validation telegram, including CRC
@@ -27,70 +17,9 @@
// This can differs per firmware version and typically 32 is the max
#define EMS_MAX_TELEGRAM_LENGTH 99
// define here the EMS telegram types you need
// Common for all EMS devices
#define EMS_TYPE_Version 0x02 // version of the UBA controller (boiler)
/*
* Boiler...
*/
#define EMS_TYPE_UBAMonitorFast 0x18 // is an automatic monitor broadcast
#define EMS_TYPE_UBAMonitorSlow 0x19 // is an automatic monitor broadcast
#define EMS_TYPE_UBAMonitorWWMessage 0x34 // is an automatic monitor broadcast
#define EMS_TYPE_UBAMaintenanceStatusMessage 0x1C // is an automatic monitor broadcast
#define EMS_TYPE_UBAParameterWW 0x33
#define EMS_TYPE_UBATotalUptimeMessage 0x14
#define EMS_TYPE_UBAMaintenanceSettingsMessage 0x15
#define EMS_TYPE_UBAParametersMessage 0x16
#define EMS_TYPE_UBASetPoints 0x1A
#define EMS_TYPE_UBAFunctionTest 0x1D
#define EMS_OFFSET_UBAParameterWW_wwtemp 2 // WW Temperature
#define EMS_OFFSET_UBAParameterWW_wwactivated 1 // WW Activated
#define EMS_OFFSET_UBAParameterWW_wwComfort 9 // WW is in comfort or eco mode
#define EMS_VALUE_UBAParameterWW_wwComfort_Comfort 0x00 // the value for comfort
#define EMS_VALUE_UBAParameterWW_wwComfort_Eco 0xD8 // the value for eco
/*
* Thermostat...
*/
// Common for all thermostats
#define EMS_TYPE_RCTime 0x06 // is an automatic thermostat broadcast
#define EMS_TYPE_RCOutdoorTempMessage 0xA3 // is an automatic thermostat broadcast, outdoor external temp
// RC20 specific
#define EMS_TYPE_RC20StatusMessage 0x91 // is an automatic thermostat broadcast giving us temps
#define EMS_TYPE_RC20Set 0xA8 // for setting values like temp and mode
#define EMS_OFFSET_RC20Set_mode 23 // position of thermostat mode
#define EMS_OFFSET_RC20Set_temp 28 // position of thermostat setpoint temperature
#define EMS_TYPE_RC20StatusMessage_setpoint 1 // setpoint temp
#define EMS_TYPE_RC20StatusMessage_curr 2 // current temp
// RC30 specific
#define EMS_TYPE_RC30StatusMessage 0x41 // is an automatic thermostat broadcast giving us temps
#define EMS_TYPE_RC30Set 0xA7 // for setting values like temp and mode
#define EMS_OFFSET_RC30Set_mode 23 // position of thermostat mode
#define EMS_OFFSET_RC30Set_temp 28 // position of thermostat setpoint temperature
#define EMS_TYPE_RC30StatusMessage_setpoint 1 // setpoint temp
#define EMS_TYPE_RC30StatusMessage_curr 2 // current temp
// RC35 specific
#define EMS_TYPE_RC35StatusMessage 0x3E // is an automatic thermostat broadcast giving us temps
#define EMS_TYPE_RC35StatusMessage_setpoint 2 // desired temp
#define EMS_TYPE_RC35StatusMessage_curr 3 // current temp
#define EMS_TYPE_RC35Set 0x3D // for setting values like temp and mode (Working mode HC1)
#define EMS_OFFSET_RC35Set_mode 7 // position of thermostat mode
#define EMS_OFFSET_RC35Set_temp_day 2 // position of thermostat setpoint temperature for day time
#define EMS_OFFSET_RC35Set_temp_night 1 // position of thermostat setpoint temperature for night time
// Easy specific
#define EMS_TYPE_EasyStatusMessage 0x0A // reading values on an Easy Thermostat
#define EMS_TYPE_EasyStatusMessage_setpoint 10 // setpoint temp
#define EMS_TYPE_EasyStatusMessage_curr 8 // current temp
// default values
#define EMS_VALUE_INT_ON 1 // boolean true
#define EMS_VALUE_INT_OFF 0 // boolean false
@@ -98,6 +27,34 @@
#define EMS_VALUE_LONG_NOTSET 0xFFFFFF // for 3-byte longs
#define EMS_VALUE_FLOAT_NOTSET -255 // float unset
#define EMS_THERMOSTAT_READ_YES true
#define EMS_THERMOSTAT_READ_NO false
#define EMS_THERMOSTAT_WRITE_YES true
#define EMS_THERMOSTAT_WRITE_NO false
// ANSI Colors
#define COLOR_RESET "\x1B[0m"
#define COLOR_BLACK "\x1B[0;30m"
#define COLOR_RED "\x1B[0;31m"
#define COLOR_GREEN "\x1B[0;32m"
#define COLOR_YELLOW "\x1B[0;33m"
#define COLOR_BLUE "\x1B[0;34m"
#define COLOR_MAGENTA "\x1B[0;35m"
#define COLOR_CYAN "\x1B[0;36m"
#define COLOR_WHITE "\x1B[0;37m"
#define COLOR_BOLD_ON "\x1B[1m"
#define COLOR_BOLD_OFF "\x1B[21m"
// trigger settings to determine if hot tap water or the heating is active
#define EMS_BOILER_BURNPOWER_TAPWATER 100
#define EMS_BOILER_SELFLOWTEMP_HEATING 70
//define maximum settable tapwater temperature, not every installation supports 90 degrees
#define EMS_BOILER_TAPWATER_TEMPERATURE_MAX 60
#define EMS_TX_TELEGRAM_QUEUE_MAX 50 // max size of Tx FIFO queue
/* EMS UART transfer status */
typedef enum {
EMS_RX_IDLE,
@@ -160,8 +117,6 @@ typedef struct {
uint8_t data[EMS_MAX_TELEGRAM_LENGTH];
} _EMS_TxTelegram;
#define EMS_TX_TELEGRAM_QUEUE_MAX 20 // max size of Tx FIFO queue
// default empty Tx
const _EMS_TxTelegram EMS_TX_TELEGRAM_NEW = {
EMS_TX_TELEGRAM_INIT, // action
@@ -179,35 +134,11 @@ const _EMS_TxTelegram EMS_TX_TELEGRAM_NEW = {
{0x00} // data
};
// Known Buderus non-Thermostat types
typedef enum {
EMS_MODEL_NONE,
EMS_MODEL_ALL, // common for all devices
// service key
EMS_MODEL_SERVICEKEY, // this is us
// main buderus boiler type devices
EMS_MODEL_BK15,
EMS_MODEL_UBA,
EMS_MODEL_BC10,
EMS_MODEL_MM10,
EMS_MODEL_WM10,
// thermostats
EMS_MODEL_ES73,
EMS_MODEL_RC20,
EMS_MODEL_RC30,
EMS_MODEL_RC35,
EMS_MODEL_EASY
} _EMS_MODEL_ID;
typedef struct {
_EMS_MODEL_ID model_id;
uint8_t product_id;
uint8_t type_id;
char model_string[50];
uint8_t model_id;
uint8_t product_id;
uint8_t type_id;
char model_string[50];
} _Model_Type;
/*
@@ -259,39 +190,34 @@ typedef struct { // UBAParameterWW
uint8_t heatingActive; // Central heating is on/off
// settings
char version[10];
uint8_t type_id;
_EMS_MODEL_ID model_id;
char version[10];
uint8_t type_id;
uint8_t model_id;
} _EMS_Boiler;
// Definition for thermostat type
typedef struct {
_EMS_MODEL_ID model_id;
bool read_supported;
bool write_supported;
uint8_t model_id;
bool read_supported;
bool write_supported;
} _Thermostat_Type;
#define EMS_THERMOSTAT_READ_YES true
#define EMS_THERMOSTAT_READ_NO false
#define EMS_THERMOSTAT_WRITE_YES true
#define EMS_THERMOSTAT_WRITE_NO false
// Thermostat data
typedef struct {
uint8_t type_id; // the type ID of the thermostat
_EMS_MODEL_ID model_id; // which Thermostat type
bool read_supported;
bool write_supported;
char version[10];
float setpoint_roomTemp; // current set temp
float curr_roomTemp; // current room temp
uint8_t mode; // 0=low, 1=manual, 2=auto
uint8_t hour;
uint8_t minute;
uint8_t second;
uint8_t day;
uint8_t month;
uint8_t year;
uint8_t type_id; // the type ID of the thermostat
uint8_t model_id; // which Thermostat type
bool read_supported;
bool write_supported;
char version[10];
float setpoint_roomTemp; // current set temp
float curr_roomTemp; // current room temp
uint8_t mode; // 0=low, 1=manual, 2=auto
uint8_t hour;
uint8_t minute;
uint8_t second;
uint8_t day;
uint8_t month;
uint8_t year;
} _EMS_Thermostat;
// call back function signature
@@ -299,28 +225,15 @@ typedef void (*EMS_processType_cb)(uint8_t * data, uint8_t length);
// Definition for each EMS type, including the relative callback function
typedef struct {
_EMS_MODEL_ID model_id;
uint8_t model_id;
uint8_t type;
const char typeString[50];
EMS_processType_cb processType_cb;
} _EMS_Type;
// ANSI Colors
#define COLOR_RESET "\x1B[0m"
#define COLOR_BLACK "\x1B[0;30m"
#define COLOR_RED "\x1B[0;31m"
#define COLOR_GREEN "\x1B[0;32m"
#define COLOR_YELLOW "\x1B[0;33m"
#define COLOR_BLUE "\x1B[0;34m"
#define COLOR_MAGENTA "\x1B[0;35m"
#define COLOR_CYAN "\x1B[0;36m"
#define COLOR_WHITE "\x1B[0;37m"
#define COLOR_BOLD_ON "\x1B[1m"
#define COLOR_BOLD_OFF "\x1B[21m"
// function definitions
extern void ems_parseTelegram(uint8_t * telegram, uint8_t len);
void ems_init(_EMS_MODEL_ID boiler_modelid, _EMS_MODEL_ID thermostat_modelid);
void ems_init(uint8_t boiler_modelid, uint8_t thermostat_modelid);
void ems_doReadCommand(uint8_t type, uint8_t dest, bool forceRefresh = false);
void ems_sendRawTelegram(char * telegram);
@@ -329,7 +242,6 @@ void ems_setThermostatMode(uint8_t mode);
void ems_setWarmWaterTemp(uint8_t temperature);
void ems_setWarmWaterActivated(bool activated);
void ems_setWarmTapWaterActivated(bool activated);
void ems_setExperimental(uint8_t value);
void ems_setPoll(bool b);
void ems_setTxEnabled(bool b);
void ems_setLogging(_EMS_SYS_LOGGING loglevel);
@@ -348,8 +260,8 @@ bool ems_getBusConnected();
_EMS_SYS_LOGGING ems_getLogging();
uint8_t ems_getEmsTypesCount();
bool ems_getEmsRefreshed();
_EMS_MODEL_ID ems_getThermostatModel();
_EMS_MODEL_ID ems_getBoilerModel();
uint8_t ems_getThermostatModel();
uint8_t ems_getBoilerModel();
void ems_scanDevices();
void ems_printAllTypes();
@@ -362,10 +274,9 @@ uint8_t _crcCalculator(uint8_t * data, uint8_t len);
void _processType(uint8_t * telegram, uint8_t length);
void _debugPrintPackage(const char * prefix, uint8_t * data, uint8_t len, const char * color);
void _ems_clearTxData();
int _ems_findModel(_EMS_MODEL_ID model_id);
char * _ems_buildModelString(char * buffer, uint8_t size, _EMS_MODEL_ID model_id);
bool _ems_setModel(_EMS_MODEL_ID model_id);
int _ems_findModel(uint8_t model_id);
char * _ems_buildModelString(char * buffer, uint8_t size, uint8_t model_id);
bool _ems_setModel(uint8_t model_id);
// global so can referenced in other classes
extern _EMS_Sys_Status EMS_Sys_Status;

132
src/ems_devices.h Normal file
View File

@@ -0,0 +1,132 @@
/*
* General information about known EMS devices
*
*/
#pragma once
#include "ems.h"
/*
* Boiler...
*/
#define EMS_TYPE_UBAMonitorFast 0x18 // is an automatic monitor broadcast
#define EMS_TYPE_UBAMonitorSlow 0x19 // is an automatic monitor broadcast
#define EMS_TYPE_UBAMonitorWWMessage 0x34 // is an automatic monitor broadcast
#define EMS_TYPE_UBAMaintenanceStatusMessage 0x1C // is an automatic monitor broadcast
#define EMS_TYPE_UBAParameterWW 0x33
#define EMS_TYPE_UBATotalUptimeMessage 0x14
#define EMS_TYPE_UBAMaintenanceSettingsMessage 0x15
#define EMS_TYPE_UBAParametersMessage 0x16
#define EMS_TYPE_UBASetPoints 0x1A
#define EMS_TYPE_UBAFunctionTest 0x1D
#define EMS_OFFSET_UBAParameterWW_wwtemp 2 // WW Temperature
#define EMS_OFFSET_UBAParameterWW_wwactivated 1 // WW Activated
#define EMS_OFFSET_UBAParameterWW_wwComfort 9 // WW is in comfort or eco mode
#define EMS_VALUE_UBAParameterWW_wwComfort_Comfort 0x00 // the value for comfort
#define EMS_VALUE_UBAParameterWW_wwComfort_Eco 0xD8 // the value for eco
/*
* Thermostat...
*/
// Common for all thermostats
#define EMS_TYPE_RCTime 0x06 // is an automatic thermostat broadcast
#define EMS_TYPE_RCOutdoorTempMessage 0xA3 // is an automatic thermostat broadcast, outdoor external temp
// RC20 specific
#define EMS_TYPE_RC20StatusMessage 0x91 // is an automatic thermostat broadcast giving us temps
#define EMS_TYPE_RC20Set 0xA8 // for setting values like temp and mode
#define EMS_OFFSET_RC20Set_mode 23 // position of thermostat mode
#define EMS_OFFSET_RC20Set_temp 28 // position of thermostat setpoint temperature
#define EMS_TYPE_RC20StatusMessage_setpoint 1 // setpoint temp
#define EMS_TYPE_RC20StatusMessage_curr 2 // current temp
// RC30 specific
#define EMS_TYPE_RC30StatusMessage 0x41 // is an automatic thermostat broadcast giving us temps
#define EMS_TYPE_RC30Set 0xA7 // for setting values like temp and mode
#define EMS_OFFSET_RC30Set_mode 23 // position of thermostat mode
#define EMS_OFFSET_RC30Set_temp 28 // position of thermostat setpoint temperature
#define EMS_TYPE_RC30StatusMessage_setpoint 1 // setpoint temp
#define EMS_TYPE_RC30StatusMessage_curr 2 // current temp
// RC35 specific
#define EMS_TYPE_RC35StatusMessage 0x3E // is an automatic thermostat broadcast giving us temps
#define EMS_TYPE_RC35StatusMessage_setpoint 2 // desired temp
#define EMS_TYPE_RC35StatusMessage_curr 3 // current temp
#define EMS_TYPE_RC35Set 0x3D // for setting values like temp and mode (Working mode HC1)
#define EMS_OFFSET_RC35Set_mode 7 // position of thermostat mode
#define EMS_OFFSET_RC35Set_temp_day 2 // position of thermostat setpoint temperature for day time
#define EMS_OFFSET_RC35Set_temp_night 1 // position of thermostat setpoint temperature for night time
// Easy specific
#define EMS_TYPE_EasyStatusMessage 0x0A // reading values on an Easy Thermostat
#define EMS_TYPE_EasyStatusMessage_setpoint 10 // setpoint temp
#define EMS_TYPE_EasyStatusMessage_curr 8 // current temp
// Known EMS types
typedef enum {
EMS_MODEL_NONE,
EMS_MODEL_ALL, // common for all devices
// service key
EMS_MODEL_SERVICEKEY, // this is us
// main buderus boiler type devices
EMS_MODEL_BK15,
EMS_MODEL_UBA,
EMS_MODEL_BC10,
EMS_MODEL_BC25,
EMS_MODEL_MM10,
EMS_MODEL_WM10,
EMS_MODEL_RFM20,
// thermostats
EMS_MODEL_ES73,
EMS_MODEL_RC20,
EMS_MODEL_RC20F,
EMS_MODEL_RC30,
EMS_MODEL_RC35,
EMS_MODEL_EASY
} _EMS_MODEL_ID;
// EMS types for known Buderus devices. This list will be extended when new devices are recognized.
// format is MODEL_ID, PRODUCT ID, TYPE_ID, DESCRIPTION
const _Model_Type Model_Types[] = {
// me
{EMS_MODEL_SERVICEKEY, 999, 0x0B, "Service Key"},
// various boilers and buderus type devices
{EMS_MODEL_UBA, 123, 0x08, "MC10/UBA3 Boiler"},
{EMS_MODEL_BK15, 64, 0x08, "Sieger BK15 Boiler"},
{EMS_MODEL_BC10, 190, 0x09, "BC10 Base Controller"},
{EMS_MODEL_BC25, 125, 0x09, "BC25 Base Controller"},
{EMS_MODEL_RFM20, 68, 0x09, "RFM20 RC20F Receiver"},
{EMS_MODEL_MM10, 251, 0x21, "MM10 Mixer Module"}, // warning, fake product id!
{EMS_MODEL_WM10, 250, 0x11, "WM10 Switch Module"}, // warning, fake product id!
// controllers and thermostats
{EMS_MODEL_ES73, 76, 0x10, "Sieger ES73"},
{EMS_MODEL_RC20, 77, 0x17, "RC20 (e.g. Nefit Moduline 300)"},
{EMS_MODEL_RC20F, 93, 0x18, "RC20F"},
{EMS_MODEL_RC30, 78, 0x10, "RC30 (e.g. Nefit Moduline 400)"},
{EMS_MODEL_RC35, 86, 0x10, "RC35 (or compatible"},
{EMS_MODEL_EASY, 202, 0x18, "TC100 (e.g. Nefit Easy or CT100)"}
};
/*
* Known thermostat types and their abilities
*/
const _Thermostat_Type Thermostat_Types[] = {
{EMS_MODEL_RC20, EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
{EMS_MODEL_RC20F, EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
{EMS_MODEL_RC30, EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
{EMS_MODEL_RC35, EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
{EMS_MODEL_EASY, EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_NO},
{EMS_MODEL_ES73, EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES}
};

View File

@@ -2,7 +2,7 @@
* emsuart.cpp
*
* The low level UART code for ESP8266 to read and write to the EMS bus via uart
* Paul Derbyshire - https://github.com/proddy/EMS-ESP-Boiler
* Paul Derbyshire - https://github.com/proddy/EMS-ESP
*/
#include "emsuart.h"

View File

@@ -1,7 +1,7 @@
/*
* emsuart.h
* Header file for emsuart.cpp
* Paul Derbyshire - https://github.com/proddy/EMS-ESP-Boiler
* Paul Derbyshire - https://github.com/proddy/EMS-ESP
*/
#pragma once

View File

@@ -1,57 +1,43 @@
/*
* my_config.h
*
* All configurations and customization's go here
*
* Paul Derbyshire - https://github.com/proddy/EMS-ESP-Boiler
* Paul Derbyshire - https://github.com/proddy/EMS-ESP
*/
#pragma once
// these are set as -D build flags during compilation
// they can be set in platformio.ini or alternatively hard coded here
/*
#define WIFI_SSID "<my_ssid>"
#define WIFI_PASSWORD "<my_password>"
#define MQTT_IP "<broker_ip>"
#define MQTT_USER "<broker_username>"
#define MQTT_PASS "<broker_password>"
*/
#include "ems.h"
// Set your wifi and mqtt params
// If set to NULL (default) you'll need to set them in AP mode using the 'set' command
// as these values are stored in SPIFFs for persisted
#define WIFI_SSID NULL
#define WIFI_PASSWORD NULL
#define MQTT_IP NULL
#define MQTT_USER NULL
#define MQTT_PASS NULL
// All MQTT topics are prefixed with the following string
#define MQTT_BASE "home"
// default values for shower logic on/off
#define BOILER_SHOWER_TIMER 1 // monitors how long a shower has taken
#define BOILER_SHOWER_ALERT 0 // send alert if showetime exceeded
#define BOILER_SHOWER_TIMER 1 // enable (1) to monitor shower time
#define BOILER_SHOWER_ALERT 0 // enable (1) to send alert of cold watewr when shower time limit has exceeded
#define SHOWER_MAX_DURATION 420000 // in ms. 7 minutes, before trigger a shot of cold water
// trigger settings to determine if hot tap water or the heating is active
#define EMS_BOILER_BURNPOWER_TAPWATER 100
#define EMS_BOILER_SELFLOWTEMP_HEATING 70
//define maximum settable tapwater temperature, not every installation supports 90 degrees
#define EMS_BOILER_TAPWATER_TEMPERATURE_MAX 60
// if using the shower timer, change these settings
#define SHOWER_PAUSE_TIME 15000 // in ms. 15 seconds, max time if water is switched off & on during a shower
#define SHOWER_MIN_DURATION 120000 // in ms. 2 minutes, before recognizing its a shower
#define SHOWER_MAX_DURATION 420000 // in ms. 7 minutes, before trigger a shot of cold water
#define SHOWER_OFFSET_TIME 5000 // in ms. 5 seconds grace time, to calibrate actual time under the shower
#define SHOWER_COLDSHOT_DURATION 10 // in seconds. 10 seconds for cold water before turning back hot water
// The LED for showing connection errors, either onboard or via an external pull-up LED
// can be disabled using -DNO_LED build flag in platformio.ini
// Set LED pin used for showing ems bus connection status. Solid is connected, Flashing is error
// can be either the onboard LED on the ESP8266 or external via an external pull-up LED (e.g. D1)
// note: can be disabled completely using -DNO_LED build flag in platformio.ini
#define BOILER_LED LED_BUILTIN // LED_BULLETIN for onboard LED
//#define BOILER_LED D1 // for external LED like on the latest bbqkees boards
// set this if using an external temperature sensor like a DS18B20
#define TEMPERATURE_SENSOR_PIN D7
// logging - EMS_SYS_LOGGING_VERBOSE, EMS_SYS_LOGGING_NONE, EMS_SYS_LOGGING_BASIC (see ems.h)
// this can be changed via the Telnet console using the 'l' command
#define BOILER_DEFAULT_LOGGING EMS_SYS_LOGGING_NONE
//#define BOILER_DEFAULT_LOGGING EMS_SYS_LOGGING_VERBOSE
//#define BOILER_DEFAULT_LOGGING EMS_SYS_LOGGING_BASIC
// By default the EMS bus will be scanned for known devices. You can override this here
// by fixing the Boiler and Thermostat types
// Options are in ems.h and include..
// By default the EMS bus will be scanned for known devices (EMS_MODEL_NONE).
// You can override this here by fixing the Boiler and Thermostat types.
// See ems.h for the list of recognized types. For example:
// boilers: EMS_MODEL_BK15, EMS_MODEL_UBA, EMS_MODEL_BC10, EMS_MODEL_MM10, EMS_MODEL_WM10
// thermostats: EMS_MODEL_ES73, EMS_MODEL_RC20, EMS_MODEL_RC30, EMS_MODEL_RC35, EMS_MODEL_EASY
#define MY_BOILER_MODELID EMS_MODEL_NONE

View File

@@ -1,5 +1,5 @@
#pragma once
#define APP_NAME "EMS-ESP-Boiler"
#define APP_VERSION "1.2.4"
#define APP_HOSTNAME "boiler"
#define APP_NAME "EMS-ESP Interface"
#define APP_VERSION "1.3.0"
#define APP_HOSTNAME "ems-esp"