version 1.3.2. See changelog

This commit is contained in:
proddy
2019-01-23 20:30:36 +01:00
parent a18580c997
commit d2618bfcdb
8 changed files with 383 additions and 367 deletions

View File

@@ -5,6 +5,27 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.3.2] 2019-01-23
### Fixed
- Handle thermostats that don't have builtin temperature sensors when showing current temperature (https://github.com/proddy/EMS-ESP/issues/18#issuecomment-451012963)
### Changed
- Improved way to identify if the EMS bus is connected
- Improved 'types' command to show more details
- Improved auto detect of thermostat types
### Added
- Some more devices like the Nefit Topline & RC310 thermostat recognition
- Added a check to see Tx is possible. See 'Tx Capable' under the 'info' screen
### Removed
- Removed `MY_BOILER_MODELID` from `my_config.h`. It's always hardcoded.
## [1.3.1] 2019-01-12
### Fixed

View File

@@ -31,7 +31,7 @@
#define PUBLISHVALUES_TIME 120 // every 2 minutes post MQTT values
Ticker publishValuesTimer;
#define SYSTEMCHECK_TIME 10 // every 10 seconds check if Boiler is online and execute other requests
#define SYSTEMCHECK_TIME 20 // every 20 seconds check if Boiler is online
Ticker systemCheckTimer;
#define REGULARUPDATES_TIME 60 // every minute a call is made to fetch data from EMS devices manually
@@ -252,7 +252,7 @@ void _renderBoolValue(const char * prefix, uint8_t value) {
void showInfo() {
// General stats from EMS bus
myDebug("%sEMS-ESP System setstats:%s", COLOR_BOLD_ON, COLOR_BOLD_OFF);
myDebug("%sEMS-ESP System stats:%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");
@@ -266,8 +266,6 @@ void showInfo() {
myDebug(" LED is %s", EMSESP_Status.led_enabled ? "on" : "off");
myDebug(" # EMS type handlers: %d", ems_getEmsTypesCount());
myDebug(" Thermostat is %s, Boiler is %s, Poll is %s, Tx is %s, Shower Timer is %s, Shower Alert is %s",
(ems_getThermostatEnabled() ? "enabled" : "disabled"),
(ems_getBoilerEnabled() ? "enabled" : "disabled"),
@@ -276,7 +274,9 @@ void showInfo() {
((EMSESP_Status.shower_timer) ? "enabled" : "disabled"),
((EMSESP_Status.shower_alert) ? "enabled" : "disabled"));
myDebug(" EMS Bus Stats: Connected=%s, # Rx telegrams=%d, # Tx telegrams=%d, # Crc Errors=%d",
myDebug("\n%sEMS Bus Stats:%s", COLOR_BOLD_ON, COLOR_BOLD_OFF);
myDebug(" Bus Connected=%s, Tx Capable=%s, # Rx telegrams=%d, # Tx telegrams=%d, # Crc Errors=%d",
(ems_getTxCapable() ? "yes" : "no"),
(ems_getBusConnected() ? "yes" : "no"),
EMS_Sys_Status.emsRxPgks,
EMS_Sys_Status.emsTxPkgs,
@@ -288,7 +288,7 @@ void showInfo() {
// version details
char buffer_type[64];
myDebug(" Boiler type: %s", ems_getBoilerType(buffer_type));
myDebug(" Boiler type: %s", ems_getBoilerDescription(buffer_type));
// active stats
myDebug(" Hot tap water is %s", (EMS_Boiler.tapwaterActive ? "running" : "off"));
@@ -357,7 +357,7 @@ void showInfo() {
// Thermostat stats
if (ems_getThermostatEnabled()) {
myDebug("%sThermostat stats:%s", COLOR_BOLD_ON, COLOR_BOLD_OFF);
myDebug(" Thermostat type: %s", ems_getThermostatType(buffer_type));
myDebug(" Thermostat type: %s", ems_getThermostatDescription(buffer_type));
_renderFloatValue("Setpoint room temperature", "C", EMS_Thermostat.setpoint_roomTemp);
_renderFloatValue("Current room temperature", "C", EMS_Thermostat.curr_roomTemp);
if (ems_getThermostatModel() != EMS_MODEL_EASY) {
@@ -448,7 +448,7 @@ void publishValues(bool force) {
// 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)) || force) {
myDebugLog("Publishing hot water and heating state via MQTT");
myDebugLog("Publishing hot water and heating states via MQTT");
myESP.mqttPublish(TOPIC_BOILER_TAPWATER_ACTIVE, EMS_Boiler.tapwaterActive == 1 ? "1" : "0");
myESP.mqttPublish(TOPIC_BOILER_HEATING_ACTIVE, EMS_Boiler.heatingActive == 1 ? "1" : "0");
@@ -570,17 +570,18 @@ void FSCallback(MYESP_FSACTION action, JsonObject & json) {
// callback for custom settings
// wc is number of arguments after the 'set' command
bool SettingsCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, const char * value) {
bool ok = false;
if (action == MYESP_FSACTION_SET) {
if ((strcmp(setting, "led") == 0) && (wc == 2)) {
if (strcmp(value, "on") == 0) {
EMSESP_Status.led_enabled = true;
ok = true;
} else if (strcmp(value, "off") == 0) {
EMSESP_Status.led_enabled = false;
ok = true;
// let's make sure LED is really off
digitalWrite(BOILER_LED, (BOILER_LED == LED_BUILTIN) ? HIGH : LOW); // light off. For onboard high=off
} else {
// unknown command
return false;
}
}
}
@@ -589,7 +590,7 @@ bool SettingsCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, c
myDebug(" led=%s", EMSESP_Status.led_enabled ? "on" : "off");
}
return true;
return ok;
}
// call back when a telnet client connects or disconnects
@@ -762,7 +763,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
// handle incoming MQTT publish events
if (type == MQTT_MESSAGE_EVENT) {
// handle response from a start message
// for HA, it gets sent the bootime
// for example with HA it sends the system time from the server
if (strcmp(topic, MQTT_TOPIC_START) == 0) {
myDebug("Received boottime: %s", message);
myESP.setBoottime(message);
@@ -828,9 +829,10 @@ void WIFICallback() {
myDebug("[UART] Opened Rx/Tx connection");
#endif
// now that we're connected, check to see if we boiler and thermostat set
// otherwise this will initiate a self scan
ems_setModels();
// now that we're connected, set up the boiler and thermostat
// the boiler's version will be requested and if there is no thermostat hardcoded it will try
// and find the first one
ems_discoverModels();
}
// Initialize the boiler settings and shower settings
@@ -879,20 +881,16 @@ 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. Check connection and make sure you're not in DEBUG_SUPPORT mode. Retrying in %d "
"seconds...",
SYSTEMCHECK_TIME);
myDebug("Error! Unable to read from EMS bus. 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() {
if (ems_getBusConnected()) {
myDebugLog("Calling scheduled data refresh from EMS devices..");
ems_getThermostatValues();
ems_getBoilerValues();
}
myDebugLog("Calling scheduled data refresh from EMS devices..");
ems_getThermostatValues();
ems_getBoilerValues();
}
// turn off hot water to send a shot of cold
@@ -1010,7 +1008,7 @@ void setup() {
// init the EMS bus
// call ems.cpp's init function to set all the internal params
ems_init(MY_BOILER_MODELID, MY_THERMOSTAT_MODELID);
ems_init(MY_THERMOSTAT_MODELID);
}
//

View File

@@ -1,7 +1,7 @@
/**
* ems.cpp
*
* handles all the processing of the EMS messages
* Handles all the processing of the EMS messages
*
* Paul Derbyshire - https://github.com/proddy/EMS-ESP
*/
@@ -52,6 +52,7 @@ void _process_EasyStatusMessage(uint8_t * data, uint8_t length);
/*
* Recognized EMS types and the functions they call to process the telegrams
* Format: MODEL ID, TYPE ID, Description, function
*/
const _EMS_Type EMS_Types[] = {
@@ -67,50 +68,45 @@ const _EMS_Type EMS_Types[] = {
{EMS_MODEL_UBA, EMS_TYPE_UBAMaintenanceSettingsMessage, "UBAMaintenanceSettingsMessage", NULL},
{EMS_MODEL_UBA, EMS_TYPE_UBAParametersMessage, "UBAParametersMessage", NULL},
{EMS_MODEL_UBA, EMS_TYPE_UBAMaintenanceStatusMessage, "UBAMaintenanceStatusMessage", NULL},
{EMS_MODEL_UBA, EMS_TYPE_UBASetPoints, "UBASetPoints", _process_SetPoints},
// 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},
{EMS_MODEL_RC30, EMS_TYPE_RC30Set, "RC30Set", _process_RC30Set},
{EMS_MODEL_RC30, EMS_TYPE_RC30StatusMessage, "RC30StatusMessage", _process_RC30StatusMessage},
{EMS_MODEL_RC30, EMS_TYPE_UBASetPoints, "UBASetPoints", _process_SetPoints},
// RC35
{EMS_MODEL_RC35, EMS_TYPE_RCOutdoorTempMessage, "RCOutdoorTempMessage", _process_RCOutdoorTempMessage},
{EMS_MODEL_RC35, EMS_TYPE_RCTime, "RCTime", _process_RCTime},
{EMS_MODEL_RC35, EMS_TYPE_RC35Set, "RC35Set", _process_RC35Set},
{EMS_MODEL_RC35, EMS_TYPE_RC35StatusMessage, "RC35StatusMessage", _process_RC35StatusMessage},
{EMS_MODEL_RC35, EMS_TYPE_UBASetPoints, "UBASetPoints", _process_SetPoints},
// ES73
{EMS_MODEL_ES73, EMS_TYPE_RCOutdoorTempMessage, "RCOutdoorTempMessage", _process_RCOutdoorTempMessage},
{EMS_MODEL_ES73, EMS_TYPE_RCTime, "RCTime", _process_RCTime},
{EMS_MODEL_ES73, EMS_TYPE_RC35Set, "RC35Set", _process_RC35Set},
{EMS_MODEL_ES73, EMS_TYPE_RC35StatusMessage, "RC35StatusMessage", _process_RC35StatusMessage},
{EMS_MODEL_ES73, EMS_TYPE_UBASetPoints, "UBASetPoints", _process_SetPoints},
// Easy
{EMS_MODEL_EASY, EMS_TYPE_EasyStatusMessage, "EasyStatusMessage", _process_EasyStatusMessage},
{EMS_MODEL_EASY, EMS_TYPE_UBASetPoints, "UBASetPoints", _process_SetPoints}
};
// calculate sizes of arrays
uint8_t _EMS_Types_max = ArraySize(EMS_Types); // number of defined types
uint8_t _Model_Types_max = ArraySize(Model_Types); // number of models
uint8_t _Boiler_Types_max = ArraySize(Boiler_Types); // number of models
uint8_t _Thermostat_Types_max = ArraySize(Thermostat_Types); // number of defined thermostat types
// these structs contain the data we store from the Boiler and Thermostat
@@ -134,8 +130,9 @@ const uint8_t ems_crc_table[] = {0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,
0xCD, 0xCF, 0xC1, 0xC3, 0xC5, 0xC7, 0xF9, 0xFB, 0xFD, 0xFF, 0xF1, 0xF3, 0xF5, 0xF7, 0xE9, 0xEB, 0xED, 0xEF,
0xE1, 0xE3, 0xE5, 0xE7};
const uint8_t TX_WRITE_TIMEOUT_COUNT = 3; // 3 retries before timeout
const unsigned long EMS_BUS_TIMEOUT = 5000; // timeout in ms before recognizing the ems bus is offline (5 seconds)
const uint8_t TX_WRITE_TIMEOUT_COUNT = 3; // 3 retries before timeout
const unsigned long EMS_BUS_TIMEOUT = 15000; // timeout in ms before recognizing the ems bus is offline (15 seconds)
const unsigned long EMS_POLL_TIMEOUT = 5000; // timeout in ms before recognizing the ems bus is offline (5 seconds)
uint8_t _emsTxRetryCount; // used for retries when sending failed
uint8_t _ems_PollCount; // not used, but can be used to slow down sending on faster chips
@@ -143,17 +140,20 @@ 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(uint8_t boiler_modelid, uint8_t thermostat_modelid) {
void ems_init(uint8_t thermostat_modelid) {
// 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.emsRefreshed = false;
EMS_Sys_Status.emsPollEnabled = false; // start up with Poll disabled
EMS_Sys_Status.emsTxEnabled = true; // start up with Tx enabled
EMS_Sys_Status.emsBusConnected = 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.emsRefreshed = false;
EMS_Sys_Status.emsPollEnabled = false; // start up with Poll disabled
EMS_Sys_Status.emsTxEnabled = true; // start up with Tx enabled
EMS_Sys_Status.emsBusConnected = false;
EMS_Sys_Status.emsRxTimestamp = 0;
EMS_Sys_Status.emsTxCapable = false;
EMS_Sys_Status.emsPollTimestamp = 0;
// thermostat
EMS_Thermostat.setpoint_roomTemp = EMS_VALUE_FLOAT_NOTSET;
@@ -215,11 +215,16 @@ void ems_init(uint8_t boiler_modelid, uint8_t thermostat_modelid) {
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
EMS_Boiler.type_id = EMS_ID_NONE;
// boiler is hardcoded
EMS_Boiler.type_id = EMS_ID_BOILER; // fixed at 0x08
EMS_Boiler.product_id = 0;
strlcpy(EMS_Boiler.version, "not set", sizeof(EMS_Boiler.version));
// for lookup later
EMS_Boiler.model_id = boiler_modelid;
EMS_Thermostat.model_id = thermostat_modelid;
// set thermostat model
EMS_Thermostat.type_id = EMS_ID_NONE; // fixed at 0x08
EMS_Thermostat.product_id = 0;
_ems_setThermostatModel(thermostat_modelid);
strlcpy(EMS_Thermostat.version, "not set", sizeof(EMS_Thermostat.version));
// counters
_ems_PollCount = 0;
@@ -258,11 +263,22 @@ void ems_setEmsRefreshed(bool b) {
}
bool ems_getBoilerEnabled() {
return (EMS_Boiler.model_id != EMS_MODEL_NONE);
return (EMS_Boiler.type_id != EMS_ID_NONE);
}
bool ems_getThermostatEnabled() {
return (EMS_Thermostat.model_id != EMS_MODEL_NONE);
return (EMS_Thermostat.type_id != EMS_ID_NONE);
}
uint8_t ems_getThermostatModel() {
return (EMS_Thermostat.model_id);
}
bool ems_getTxCapable() {
if ((millis() - EMS_Sys_Status.emsPollTimestamp) > EMS_POLL_TIMEOUT) {
EMS_Sys_Status.emsTxCapable = false;
}
return EMS_Sys_Status.emsTxCapable;
}
bool ems_getBusConnected() {
@@ -276,10 +292,6 @@ _EMS_SYS_LOGGING ems_getLogging() {
return EMS_Sys_Status.emsLogging;
}
uint8_t ems_getEmsTypesCount() {
return _EMS_Types_max;
}
void ems_setLogging(_EMS_SYS_LOGGING loglevel) {
if (loglevel <= EMS_SYS_LOGGING_VERBOSE) {
EMS_Sys_Status.emsLogging = loglevel;
@@ -297,22 +309,6 @@ void ems_setLogging(_EMS_SYS_LOGGING loglevel) {
}
}
// if the thermostat or boiler models have been provided, set them up
void ems_setModels() {
bool found = false;
if (ems_getThermostatModel() != EMS_MODEL_NONE) {
found = _ems_setModel(ems_getThermostatModel());
}
if (ems_getBoilerModel() != EMS_MODEL_NONE) {
found = found && _ems_setModel(ems_getBoilerModel());
}
if (!found) {
ems_scanDevices(); // initiate a scan
}
}
/**
* Calculate CRC checksum using lookup table for speed
* len is length of data in bytes (including the CRC byte at end)
@@ -568,17 +564,21 @@ void _ems_sendTelegram() {
*/
void ems_parseTelegram(uint8_t * telegram, uint8_t length) {
// check if we just received a single byte
// it could well be a Poll request from the boiler which has an ID 0x8B (0x0B | 0x80 to set 8th bit)
// or either a return code like 0x01 or 0x04 from the last Write command issued
// it could well be a Poll request from the boiler to us which will have a value of 0x8B (0x0B | 0x80)
// or either a return code like 0x01 or 0x04 from the last Write command
if (length == 1) {
uint8_t value = telegram[0]; // 1st byte of data package
// TODO: remove, only for debugging why some people can't do a Tx
//if ((value & 0x80) == 0x80) {
// myDebug("Poll: %02X", value);
//}
// check first for a Poll for us
if (value == (EMS_ID_ME | 0x80)) {
// we use this to see if we always have a connection to the boiler, in case of drop outs
EMS_Sys_Status.emsRxTimestamp = millis(); // timestamp of last read
EMS_Sys_Status.emsBusConnected = true;
// store when we received a last poll
EMS_Sys_Status.emsPollTimestamp = millis();
EMS_Sys_Status.emsTxCapable = true;
// do we have something to send thats waiting in the Tx queue? if so send it
if (!EMS_TxQueue.isEmpty()) {
@@ -652,7 +652,11 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) {
}
// here we know its a valid incoming telegram of at least 6 bytes
// lets process it and see what to do next
// we use this to see if we always have a connection to the boiler, in case of drop outs
EMS_Sys_Status.emsRxTimestamp = millis(); // timestamp of last read
EMS_Sys_Status.emsBusConnected = true;
// now lets process it and see what to do next
_processType(telegram, length);
}
@@ -974,9 +978,15 @@ void _process_RC30StatusMessage(uint8_t * data, uint8_t length) {
*/
void _process_RC35StatusMessage(uint8_t * data, uint8_t length) {
EMS_Thermostat.setpoint_roomTemp = ((float)data[EMS_TYPE_RC35StatusMessage_setpoint]) / (float)2;
EMS_Thermostat.curr_roomTemp = _toFloat(EMS_TYPE_RC35StatusMessage_curr, data);
EMS_Thermostat.day_mode = bitRead(data[EMS_OFFSET_RC35Get_mode_day], 1); //get day mode flag
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
// check if temp sensor is unavailable
if ((data[0] == 0x7D) && (data[1] = 0x00)) {
EMS_Thermostat.curr_roomTemp = EMS_VALUE_FLOAT_NOTSET;
} else {
EMS_Thermostat.curr_roomTemp = _toFloat(EMS_TYPE_RC35StatusMessage_curr, data);
}
EMS_Thermostat.day_mode = bitRead(data[EMS_OFFSET_RC35Get_mode_day], 1); //get day mode flag
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
}
/**
@@ -1024,6 +1034,7 @@ void _process_RCOutdoorTempMessage(uint8_t * data, uint8_t length) {
/**
* type 0x02 - get the firmware version and type of an EMS device
* look up known devices via the product id and setup if not already set
*/
void _process_Version(uint8_t * data, uint8_t length) {
// ignore short messages that we can't interpret
@@ -1031,155 +1042,142 @@ void _process_Version(uint8_t * data, uint8_t length) {
return;
}
uint8_t product_id = data[0];
uint8_t major = data[1];
uint8_t minor = data[2];
int i = 0;
int j = 0;
bool typeFound = false;
bool isThermostat = false;
char version[10] = {0};
snprintf(version, sizeof(version), "%02d.%02d", major, minor);
uint8_t product_id = data[0];
char version[10] = {0};
snprintf(version, sizeof(version), "%02d.%02d", data[1], data[2]);
// use product ID to search
while (i < _Model_Types_max) {
if (Model_Types[i].product_id == product_id) {
// see if its a known boiler
int i = 0;
bool typeFound = false;
while (i < _Boiler_Types_max) {
if (Boiler_Types[i].product_id == product_id) {
typeFound = true; // we have a matching product id. i is the index.
break;
}
i++;
}
if (!typeFound) {
myDebug("Unrecognized device found. Product ID %d, Version %s", product_id, version);
if (typeFound) {
// its a boiler
if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_BASIC) {
myDebug("Boiler found. Model %s with TypeID 0x%02X, Product ID %d, Version %s",
Boiler_Types[i].model_string,
Boiler_Types[i].type_id,
product_id,
version);
}
// if its a boiler set it (even if it was already set)
if (Boiler_Types[i].type_id == EMS_ID_BOILER) {
if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_BASIC) {
myDebug("* Setting boiler to this new type");
}
EMS_Boiler.type_id = Boiler_Types[i].type_id;
EMS_Boiler.product_id = Boiler_Types[i].product_id;
strlcpy(EMS_Boiler.version, version, sizeof(EMS_Boiler.version));
ems_getBoilerValues(); // get Boiler values that we would usually have to wait for
}
return;
}
// check to see if its a known thermostat
while (j < _Thermostat_Types_max) {
if (Thermostat_Types[j].model_id == Model_Types[i].model_id) {
isThermostat = true; // we have a matching model
// its not a boiler, maybe its a known thermostat
i = 0;
while (i < _Thermostat_Types_max) {
if (Thermostat_Types[i].product_id == product_id) {
typeFound = true; // we have a matching product id. i is the index.
break;
}
j++;
i++;
}
// set a thermostat
if (isThermostat) {
if (typeFound) {
// its a known thermostat
if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_BASIC) {
myDebug("Thermostat recognized. Model %s with TypeID 0x%02X, Product ID %d, Version %s",
Model_Types[i].model_string,
Model_Types[i].type_id,
myDebug("Thermostat found. Model %s with TypeID 0x%02X, Product ID %d, Version %s",
Thermostat_Types[i].model_string,
Thermostat_Types[i].type_id,
product_id,
version);
}
// if we don't have a thermostat set, use this one
if (!ems_getThermostatEnabled()) {
// set its capabilities
EMS_Thermostat.model_id = Model_Types[i].model_id;
EMS_Thermostat.type_id = Model_Types[i].type_id;
EMS_Thermostat.read_supported = Thermostat_Types[j].read_supported;
EMS_Thermostat.write_supported = Thermostat_Types[j].write_supported;
// if its the one we hard coded, refresh the data anyway
if ((EMS_Thermostat.model_id == EMS_MODEL_NONE) || (EMS_Thermostat.model_id == Thermostat_Types[i].model_id)) {
if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_BASIC) {
myDebug("* Setting thermostat to this new type");
}
EMS_Thermostat.model_id = Thermostat_Types[i].model_id;
EMS_Thermostat.type_id = Thermostat_Types[i].type_id;
EMS_Thermostat.read_supported = Thermostat_Types[i].read_supported;
EMS_Thermostat.write_supported = Thermostat_Types[i].write_supported;
EMS_Thermostat.product_id = product_id;
strlcpy(EMS_Thermostat.version, version, sizeof(EMS_Thermostat.version));
ems_getThermostatValues(); // get Thermostat values (if supported)
// get Thermostat values (if supported)
ems_getThermostatValues();
}
} else {
// 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,
Model_Types[i].type_id,
product_id,
version);
}
if (!ems_getBoilerEnabled()) {
EMS_Boiler.type_id = Model_Types[i].type_id;
EMS_Boiler.model_id = Model_Types[i].model_id;
strlcpy(EMS_Boiler.version, version, sizeof(EMS_Boiler.version));
ems_getBoilerValues(); // get Boiler values that we would usually have to wait for
}
myDebug("Unrecognized device found. Product ID %d, Version %s", product_id, version);
}
}
/**
* 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
/*
* Figure out the boiler and thermostat types
*/
bool _ems_setModel(uint8_t model_id) {
if (model_id == EMS_MODEL_NONE) {
return false; // invalid model_id
}
void ems_discoverModels() {
// boiler
ems_doReadCommand(EMS_TYPE_Version, EMS_ID_BOILER); // get version details of boiler
ems_getBoilerValues(); // fetch values from boiler, instead of waiting for broadcasts
// see if we have a valid model_id
uint8_t model_loc = 0;
bool found = false;
uint8_t i = 0;
const _Model_Type * model_type;
while (i < _Model_Types_max) {
model_type = &Model_Types[model_loc];
if (model_type->model_id == model_id) {
found = true; // we have a matching product id. i is the index.
// thermostat
if (EMS_Thermostat.model_id == EMS_MODEL_NONE) {
ems_scanDevices(); // auto-discover it
} else {
// set the model as hardcoded (see my_devices.h) and fetch the version and product id
_ems_setThermostatModel(EMS_Thermostat.model_id);
ems_doReadCommand(EMS_TYPE_Version, EMS_Thermostat.type_id);
ems_getThermostatValues();
}
}
/*
* Given a thermostat model ID go and fetch its characteristics
*/
void _ems_setThermostatModel(uint8_t thermostat_modelid) {
bool found = false;
uint8_t i = 0;
const _Thermostat_Type * thermostat_type;
while (i < _Thermostat_Types_max) {
thermostat_type = &Thermostat_Types[i];
if (thermostat_type->model_id == thermostat_modelid) {
found = true; // we have a matching product id
break;
}
model_loc++;
i++;
}
if (!found) {
if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_BASIC) {
myDebug("Unknown model specified");
myDebug("Unknown thermostat model specified. Trying a scan...");
}
return false; // unknown model_id
ems_scanDevices(); // auto-discover it
return;
}
// next check to see if its a known thermostat
// j will have pointer to the Thermostat details
bool isThermostat = false;
uint8_t j = 0;
while (j < _Thermostat_Types_max) {
if (Thermostat_Types[j].model_id == model_id) {
isThermostat = true; // we have a matching model
break;
}
j++;
// set the thermostat
if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_BASIC) {
myDebug("Setting Thermostat. Model %s with TypeID 0x%02X, Product ID %d",
thermostat_type->model_string,
thermostat_type->type_id,
thermostat_type->product_id);
}
// set a thermostat
if (isThermostat) {
if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_BASIC) {
myDebug("Setting Thermostat. Model %s with TypeID 0x%02X, Product ID %d",
model_type->model_string,
model_type->type_id,
model_type->product_id);
}
// set its capabilities
EMS_Thermostat.model_id = model_type->model_id;
EMS_Thermostat.type_id = model_type->type_id;
EMS_Thermostat.read_supported = Thermostat_Types[j].read_supported;
EMS_Thermostat.write_supported = Thermostat_Types[j].write_supported;
strlcpy(EMS_Thermostat.version, "unknown", sizeof(EMS_Thermostat.version));
ems_getThermostatValues(); // get Thermostat values (if supported)
} else {
// otherwise assume its a boiler
if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_BASIC) {
myDebug("Setting Boiler. Model %s with TypeID 0x%02X, Product ID %d",
model_type->model_string,
model_type->type_id,
model_type->product_id);
}
EMS_Boiler.model_id = model_type->model_id;
EMS_Boiler.type_id = model_type->type_id;
strlcpy(EMS_Boiler.version, "unknown", sizeof(EMS_Boiler.version));
ems_getBoilerValues(); // get Boiler values that we would usually have to wait for
}
return true;
// set its capabilities
EMS_Thermostat.model_id = thermostat_type->model_id;
EMS_Thermostat.type_id = thermostat_type->type_id;
EMS_Thermostat.read_supported = thermostat_type->read_supported;
EMS_Thermostat.write_supported = thermostat_type->write_supported;
}
/**
@@ -1211,17 +1209,6 @@ void _process_RCTime(uint8_t * data, uint8_t length) {
EMS_Thermostat.day = data[3];
EMS_Thermostat.month = data[1];
EMS_Thermostat.year = data[0];
// we can optional set the time based on the thermostat's time if we want.
// make sure you include Time library and TimeLib.h if enabling this
/*
setTime(EMS_Thermostat.hour,
EMS_Thermostat.minute,
EMS_Thermostat.second,
EMS_Thermostat.day,
EMS_Thermostat.month,
EMS_Thermostat.year + 2000);
*/
}
/**
@@ -1281,7 +1268,7 @@ void ems_getThermostatValues() {
}
if (!EMS_Thermostat.read_supported) {
myDebug("Read operations not yet supported for this model Thermostat");
myDebug("Read operations not yet supported for this model thermostat");
return;
}
@@ -1314,99 +1301,107 @@ void ems_getBoilerValues() {
ems_doReadCommand(EMS_TYPE_UBATotalUptimeMessage, EMS_Boiler.type_id); // get Warm Water values
}
// return pointer to Model details
int _ems_findModel(uint8_t model_id) {
uint8_t i = 0;
bool found = false;
// scan through known ID types
while (i < _Model_Types_max) {
if (Model_Types[i].model_id == model_id) {
found = true; // we have a match
break;
}
i++;
}
if (!found) {
return -1;
}
return i;
}
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};
strlcpy(buffer, Model_Types[i].model_string, size);
strlcat(buffer, " [TypeID 0x", size);
strlcat(buffer, _hextoa(Model_Types[i].type_id, tmp), size);
strlcat(buffer, "] Product ID:", size);
strlcat(buffer, itoa(Model_Types[i].product_id, tmp, 10), size);
} else {
strlcpy(buffer, "<unknown>", sizeof(buffer));
}
return buffer;
}
/**
* returns current thermostat type as a string
*/
char * ems_getThermostatType(char * buffer) {
uint8_t size = 64;
char * ems_getThermostatDescription(char * buffer) {
uint8_t size = 128;
if (!ems_getThermostatEnabled()) {
strlcpy(buffer, "<not enabled>", size);
} else {
_ems_buildModelString(buffer, size, EMS_Thermostat.model_id);
// find the boiler details
int i = 0;
bool found = false;
// scan through known ID types
while (i < _Thermostat_Types_max) {
if (Thermostat_Types[i].product_id == EMS_Thermostat.product_id) {
found = true; // we have a match
break;
}
i++;
}
if (found) {
strlcpy(buffer, Thermostat_Types[i].model_string, size);
} else {
strlcpy(buffer, "Generic Type", size);
}
char tmp[6] = {0};
strlcat(buffer, " [Type ID: 0x", size);
strlcat(buffer, _hextoa(EMS_Thermostat.type_id, tmp), size);
strlcat(buffer, "] Product ID:", size);
strlcat(buffer, itoa(EMS_Thermostat.product_id, tmp, 10), size);
strlcat(buffer, " Version:", size);
strlcat(buffer, EMS_Thermostat.version, size);
}
return buffer;
}
/**
* returns current boiler type as a string
*/
char * ems_getBoilerType(char * buffer) {
uint8_t size = 64;
char * ems_getBoilerDescription(char * buffer) {
uint8_t size = 128;
if (!ems_getBoilerEnabled()) {
strlcpy(buffer, "<not enabled>", size);
} else {
_ems_buildModelString(buffer, size, EMS_Boiler.model_id);
// find the boiler details
int i = 0;
bool found = false;
// scan through known ID types
while (i < _Boiler_Types_max) {
if (Boiler_Types[i].product_id == EMS_Boiler.product_id) {
found = true; // we have a match
break;
}
i++;
}
if (found) {
strlcpy(buffer, Boiler_Types[i].model_string, size);
} else {
strlcpy(buffer, "Generic Type", size);
}
char tmp[6] = {0};
strlcat(buffer, " [Type ID: 0x", size);
strlcat(buffer, _hextoa(EMS_Boiler.type_id, tmp), size);
strlcat(buffer, "] Product ID:", size);
strlcat(buffer, itoa(EMS_Boiler.product_id, tmp, 10), size);
strlcat(buffer, " Version:", size);
strlcat(buffer, EMS_Boiler.version, size);
}
return buffer;
}
// returns the model type for a thermostat
uint8_t ems_getThermostatModel() {
return (EMS_Thermostat.model_id);
}
// returns the model type for a boiler
uint8_t ems_getBoilerModel() {
return (EMS_Boiler.model_id);
}
/*
* Find the versions of our connected devices
*/
void ems_scanDevices() {
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;
for (_Model_Type mt : Model_Types) {
Device_Ids.push_back(mt.type_id);
// start refresh when scanning and forget anything devices we may have already set
EMS_Thermostat.type_id = EMS_ID_NONE; // forget thermostat
EMS_Thermostat.model_id = EMS_MODEL_NONE;
std::list<uint8_t> Device_Ids; // new list
// copy over boilers
for (_Boiler_Type bt : Boiler_Types) {
Device_Ids.push_back(bt.type_id);
}
// copy over thermostats
for (_Thermostat_Type tt : Thermostat_Types) {
Device_Ids.push_back(tt.type_id);
}
// remove duplicates and reserved IDs (like our own device)
Device_Ids.sort();
Device_Ids.unique();
Device_Ids.remove(EMS_MODEL_NONE);
Device_Ids.remove(EMS_MODEL_SERVICEKEY);
// send the read command with Version command
for (uint8_t type_id : Device_Ids) {
@@ -1418,36 +1413,30 @@ void ems_scanDevices() {
* Print out all handled types
*/
void ems_printAllTypes() {
myDebug("These %d telegram TypeIDs are recognized:", _EMS_Types_max);
myDebug("\nThese %d boiler type devices are supported:", _Boiler_Types_max);
uint8_t i;
for (i = 0; i < _Boiler_Types_max; i++) {
myDebug(" %s : type ID:0x%02X (%s)", Boiler_Types[i].model_string, EMS_Types[i].type, EMS_Types[i].typeString);
}
myDebug("\nThese telegram type IDs are recognized for the selected boiler:");
for (i = 0; i < _EMS_Types_max; i++) {
if (EMS_Types[i].model_id == EMS_MODEL_NONE) {
myDebug(" (all devices) : type %02X (%s)", EMS_Types[i].type, EMS_Types[i].typeString);
} else {
int index = _ems_findModel(EMS_Types[i].model_id);
if (index != -1) {
myDebug(" %s : type %02X (%s)", Model_Types[index].model_string, EMS_Types[i].type, EMS_Types[i].typeString);
}
if ((EMS_Types[i].model_id == EMS_MODEL_ALL) || (EMS_Types[i].model_id == EMS_MODEL_UBA)) {
myDebug(" type %02X (%s)", EMS_Types[i].type, EMS_Types[i].typeString);
}
}
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++) {
if (Model_Types[j].model_id == Thermostat_Types[i].model_id) {
int index = _ems_findModel(Model_Types[j].model_id);
if (index != -1) {
myDebug(" %s [ID 0x%02X] Product ID:%d Read supported:%s Write supported:%s",
Model_Types[index].model_string,
Model_Types[index].type_id,
Model_Types[index].product_id,
(Thermostat_Types[i].read_supported) ? "yes" : "no",
(Thermostat_Types[i].write_supported) ? "yes" : "no");
}
}
}
myDebug(" %s type ID:0x%02X Product ID:%d Read supported:%s Write supported:%s",
Thermostat_Types[i].model_string,
Thermostat_Types[i].type_id,
Thermostat_Types[i].product_id,
(Thermostat_Types[i].read_supported) ? "yes" : "no",
(Thermostat_Types[i].write_supported) ? "yes" : "no");
}
}

View File

@@ -1,5 +1,10 @@
/*
* Header file for ems.cpp
*
* Paul Derbyshire - https://github.com/proddy/EMS-ESP
*
* See ChangeLog.md for history
* See README.md for Acknowledgments
*
*/
@@ -8,8 +13,9 @@
#include <Arduino.h>
// 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 the "Service Key"
#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 the "Service Key"
#define EMS_ID_BOILER 0x08 // Fixed - boilers are always 0x08. I think.
#define EMS_MIN_TELEGRAM_LENGTH 6 // minimal length for a validation telegram, including CRC
@@ -25,7 +31,7 @@
#define EMS_VALUE_INT_OFF 0 // boolean false
#define EMS_VALUE_INT_NOTSET 0xFF // for 8-bit ints
#define EMS_VALUE_LONG_NOTSET 0xFFFFFF // for 3-byte longs
#define EMS_VALUE_FLOAT_NOTSET -255 // float unset
#define EMS_VALUE_FLOAT_NOTSET -255 // float
#define EMS_THERMOSTAT_READ_YES true
#define EMS_THERMOSTAT_READ_NO false
@@ -89,15 +95,17 @@ typedef enum {
typedef struct {
_EMS_RX_STATUS emsRxStatus;
_EMS_TX_STATUS emsTxStatus;
uint16_t emsRxPgks; // received
uint16_t emsTxPkgs; // sent
uint16_t emxCrcErr; // CRC errors
bool emsPollEnabled; // flag enable the response to poll messages
bool emsTxEnabled; // flag if we're allowing sending of Tx packages
_EMS_SYS_LOGGING emsLogging; // logging
bool emsRefreshed; // fresh data, needs to be pushed out to MQTT
bool emsBusConnected; // is there an active bus
unsigned long emsRxTimestamp; // timestamp of last EMS poll
uint16_t emsRxPgks; // received
uint16_t emsTxPkgs; // sent
uint16_t emxCrcErr; // CRC errors
bool emsPollEnabled; // flag enable the response to poll messages
bool emsTxEnabled; // flag if we're allowing sending of Tx packages
_EMS_SYS_LOGGING emsLogging; // logging
bool emsRefreshed; // fresh data, needs to be pushed out to MQTT
bool emsBusConnected; // is there an active bus
unsigned long emsRxTimestamp; // timestamp of last EMS message received
unsigned long emsPollTimestamp; // timestamp of last EMS poll
bool emsTxCapable; // able to send via Tx
} _EMS_Sys_Status;
// The Tx send package
@@ -139,7 +147,17 @@ typedef struct {
uint8_t product_id;
uint8_t type_id;
char model_string[50];
} _Model_Type;
} _Boiler_Type;
// Definition for thermostat type
typedef struct {
uint8_t model_id;
uint8_t product_id;
uint8_t type_id;
char model_string[50];
bool read_supported;
bool write_supported;
} _Thermostat_Type;
/*
* Telegram package defintions
@@ -191,21 +209,15 @@ typedef struct { // UBAParameterWW
// settings
char version[10];
uint8_t type_id;
uint8_t model_id;
uint8_t type_id; // this is typically always 0x08
uint8_t product_id;
} _EMS_Boiler;
// Definition for thermostat type
typedef struct {
uint8_t model_id;
bool read_supported;
bool write_supported;
} _Thermostat_Type;
// Thermostat data
typedef struct {
uint8_t type_id; // the type ID of the thermostat
uint8_t model_id; // which Thermostat type
uint8_t product_id;
bool read_supported;
bool write_supported;
char version[10];
@@ -234,7 +246,7 @@ typedef struct {
// function definitions
extern void ems_parseTelegram(uint8_t * telegram, uint8_t len);
void ems_init(uint8_t boiler_modelid, uint8_t thermostat_modelid);
void ems_init(uint8_t thermostat_modelid);
void ems_doReadCommand(uint8_t type, uint8_t dest, bool forceRefresh = false);
void ems_sendRawTelegram(char * telegram);
@@ -259,25 +271,25 @@ bool ems_getThermostatEnabled();
bool ems_getBoilerEnabled();
bool ems_getBusConnected();
_EMS_SYS_LOGGING ems_getLogging();
uint8_t ems_getEmsTypesCount();
bool ems_getEmsRefreshed();
uint8_t ems_getThermostatModel();
uint8_t ems_getBoilerModel();
void ems_discoverModels();
bool ems_getTxCapable();
void ems_scanDevices();
void ems_printAllTypes();
char * ems_getThermostatType(char * buffer);
char * ems_getThermostatDescription(char * buffer);
void ems_printTxQueue();
char * ems_getBoilerType(char * buffer);
char * ems_getBoilerDescription(char * buffer);
// private functions
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(uint8_t model_id);
char * _ems_buildModelString(char * buffer, uint8_t size, uint8_t model_id);
int _ems_findBoilerModel(uint8_t model_id);
bool _ems_setModel(uint8_t model_id);
void _ems_setThermostatModel(uint8_t thermostat_modelid);
// global so can referenced in other classes
extern _EMS_Sys_Status EMS_Sys_Status;

View File

@@ -1,5 +1,10 @@
/*
* General information about known EMS devices
*
* Paul Derbyshire - https://github.com/proddy/EMS-ESP
*
* See ChangeLog.md for history
* See README.md for Acknowledgments
*
*/
@@ -28,7 +33,7 @@
#define EMS_VALUE_UBAParameterWW_wwComfort_Eco 0xD8 // the value for eco
/*
* Thermostat...
* Thermostats...
*/
// Common for all thermostats
@@ -71,17 +76,8 @@ 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,
// generic ID for the boiler
EMS_MODEL_UBA,
EMS_MODEL_BC10,
EMS_MODEL_BC25,
EMS_MODEL_MM10,
EMS_MODEL_WM10,
EMS_MODEL_RFM20,
// thermostats
EMS_MODEL_ES73,
@@ -89,45 +85,42 @@ typedef enum {
EMS_MODEL_RC20F,
EMS_MODEL_RC30,
EMS_MODEL_RC35,
EMS_MODEL_EASY
EMS_MODEL_EASY,
EMS_MODEL_RC310,
EMS_MODEL_CW100
} _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"},
const _Boiler_Type Boiler_Types[] = {
// 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)"}
{EMS_MODEL_UBA, 72, 0x08, "MC10"},
{EMS_MODEL_UBA, 123, 0x08, "Nefit Trendline"},
{EMS_MODEL_UBA, 115, 0x08, "Nefit Topline Compact"},
{EMS_MODEL_UBA, 64, 0x08, "Sieger BK15 Boiler"},
{EMS_MODEL_UBA, 190, 0x09, "BC10 Base Controller"},
{EMS_MODEL_UBA, 125, 0x09, "BC25 Base Controller"},
{EMS_MODEL_UBA, 68, 0x09, "RFM20 Receiver"},
{EMS_MODEL_UBA, 95, 0x08, "Bosch Condens 2500"},
{EMS_MODEL_UBA, 251, 0x21, "MM10 Mixer Module"}, // warning, fake product id!
{EMS_MODEL_UBA, 250, 0x11, "WM10 Switch Module"}, // warning, fake product id!
};
/*
* Known thermostat types and their abilities
* Known thermostat types and their capabilities
*/
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}
{EMS_MODEL_ES73, 76, 0x10, "Sieger ES73", EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
{EMS_MODEL_RC20, 77, 0x17, "RC20 (e.g. Nefit Moduline 300)", EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
{EMS_MODEL_RC20F, 93, 0x18, "RC20F", EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
{EMS_MODEL_RC30, 78, 0x10, "RC30 (e.g. Nefit Moduline 400)", EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
{EMS_MODEL_RC35, 86, 0x10, "RC35", EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
{EMS_MODEL_EASY, 202, 0x18, "TC100 (e.g. Nefit Easy or CT100)", EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_NO},
{EMS_MODEL_RC310, 158, 0x10, "RC310", EMS_THERMOSTAT_READ_NO, EMS_THERMOSTAT_WRITE_NO},
{EMS_MODEL_CW100, 255, 0x18, "Bosch CW100", EMS_THERMOSTAT_READ_NO, EMS_THERMOSTAT_WRITE_NO}
};

View File

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

View File

@@ -31,23 +31,19 @@
// default values for shower logic on/off
#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 BOILER_SHOWER_ALERT 0 // enable (1) to send alert of cold water when shower time limit has exceeded
#define SHOWER_MAX_DURATION 420000 // in ms. 7 minutes, before trigger a shot of cold water
// 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)
// can be either the onboard LED on the ESP8266 or external via an external pull-up LED (e.g. D1 on bbqkees' board)
// can be enabled and disabled via the 'set led' command
#define BOILER_LED LED_BUILTIN // LED_BULLETIN for onboard LED
// set this if using an external temperature sensor like a DS18B20
#define TEMPERATURE_SENSOR_PIN D7
// D5 is the default on bbqkees' board
#define TEMPERATURE_SENSOR_PIN D5
// 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
// By default the EMS bus will be scanned for known devices based on product ids in ems_devices.h
// You can override the Thermostat model by hardcoding the model type
#define MY_THERMOSTAT_MODELID EMS_MODEL_NONE
//#define MY_BOILER_MODELID EMS_MODEL_UBA
//#define MY_THERMOSTAT_MODELID EMS_MODEL_RC20
//#define MY_THERMOSTAT_MODELID EMS_MODEL_RC35

View File

@@ -1,5 +1,10 @@
/**
*
* Paul Derbyshire - https://github.com/proddy/EMS-ESP
*/
#pragma once
#define APP_NAME "EMS-ESP Interface"
#define APP_VERSION "1.3.1"
#define APP_NAME "EMS-ESP"
#define APP_VERSION "1.3.2"
#define APP_HOSTNAME "ems-esp"