mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-08 16:59:50 +03:00
silent_mode and startup
This commit is contained in:
@@ -67,7 +67,7 @@ typedef struct {
|
|||||||
bool shower_timer; // true if we want to report back on shower times
|
bool shower_timer; // true if we want to report back on shower times
|
||||||
bool shower_alert; // true if we want the alert of cold water
|
bool shower_alert; // true if we want the alert of cold water
|
||||||
bool led_enabled; // LED on/off
|
bool led_enabled; // LED on/off
|
||||||
bool test_mode; // test mode to stop automatic Tx on/off
|
bool silent_mode; // stop automatic Tx on/off
|
||||||
uint16_t publish_time; // frequency of MQTT publish in seconds
|
uint16_t publish_time; // frequency of MQTT publish in seconds
|
||||||
uint8_t led_gpio;
|
uint8_t led_gpio;
|
||||||
uint8_t dallas_gpio;
|
uint8_t dallas_gpio;
|
||||||
@@ -90,7 +90,7 @@ command_t PROGMEM project_cmds[] = {
|
|||||||
{true, "dallas_parasite <on | off>", "set to on if powering Dallas via parasite"},
|
{true, "dallas_parasite <on | off>", "set to on if powering Dallas via parasite"},
|
||||||
{true, "thermostat_type <type ID>", "set the thermostat type id (e.g. 10 for 0x10)"},
|
{true, "thermostat_type <type ID>", "set the thermostat type id (e.g. 10 for 0x10)"},
|
||||||
{true, "boiler_type <type ID>", "set the boiler type id (e.g. 8 for 0x08)"},
|
{true, "boiler_type <type ID>", "set the boiler type id (e.g. 8 for 0x08)"},
|
||||||
{true, "test_mode <on | off>", "test_mode turns on/off all automatic reads"},
|
{true, "silent_mode <on | off>", "when on all automatic Tx is disabled"},
|
||||||
{true, "shower_timer <on | off>", "notify via MQTT all shower durations"},
|
{true, "shower_timer <on | off>", "notify via MQTT all shower durations"},
|
||||||
{true, "shower_alert <on | off>", "send a warning of cold water after shower time is exceeded"},
|
{true, "shower_alert <on | off>", "send a warning of cold water after shower time is exceeded"},
|
||||||
{false, "info", "show data captured on the EMS bus"},
|
{false, "info", "show data captured on the EMS bus"},
|
||||||
@@ -109,7 +109,8 @@ command_t PROGMEM project_cmds[] = {
|
|||||||
{false, "boiler read <type ID>", "send read request to boiler"},
|
{false, "boiler read <type ID>", "send read request to boiler"},
|
||||||
{false, "boiler wwtemp <degrees>", "set boiler warm water temperature"},
|
{false, "boiler wwtemp <degrees>", "set boiler warm water temperature"},
|
||||||
{false, "boiler tapwater <on | off>", "set boiler warm tap water on/off"},
|
{false, "boiler tapwater <on | off>", "set boiler warm tap water on/off"},
|
||||||
{false, "boiler comfort <hot | eco | intelligent>", "set boiler warm water comfort setting"}
|
{false, "boiler comfort <hot | eco | intelligent>", "set boiler warm water comfort setting"},
|
||||||
|
{false, "startup", "send startup sequence to bus master - still experimental"}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -275,7 +276,7 @@ void showInfo() {
|
|||||||
myDebug(" System logging set to None");
|
myDebug(" System logging set to None");
|
||||||
}
|
}
|
||||||
|
|
||||||
myDebug(" LED is %s, Test Mode is %s", EMSESP_Status.led_enabled ? "on" : "off", EMSESP_Status.test_mode ? "on" : "off");
|
myDebug(" LED is %s, Silent mode is %s", EMSESP_Status.led_enabled ? "on" : "off", EMSESP_Status.silent_mode ? "on" : "off");
|
||||||
myDebug(" # connected Dallas temperature sensors=%d", EMSESP_Status.dallas_sensors);
|
myDebug(" # connected Dallas temperature sensors=%d", EMSESP_Status.dallas_sensors);
|
||||||
|
|
||||||
myDebug(" Thermostat is %s, Boiler is %s, Shower Timer is %s, Shower Alert is %s",
|
myDebug(" Thermostat is %s, Boiler is %s, Shower Timer is %s, Shower Alert is %s",
|
||||||
@@ -285,8 +286,9 @@ void showInfo() {
|
|||||||
((EMSESP_Status.shower_alert) ? "enabled" : "disabled"));
|
((EMSESP_Status.shower_alert) ? "enabled" : "disabled"));
|
||||||
|
|
||||||
myDebug("\n%sEMS Bus stats:%s", COLOR_BOLD_ON, COLOR_BOLD_OFF);
|
myDebug("\n%sEMS Bus stats:%s", COLOR_BOLD_ON, COLOR_BOLD_OFF);
|
||||||
myDebug(" Bus Connected=%s, # Rx telegrams=%d, # Tx telegrams=%d, # Crc Errors=%d",
|
myDebug(" Bus Connected=%s, Tx is %s, # Rx telegrams=%d, # Tx telegrams=%d, # Crc Errors=%d",
|
||||||
(ems_getBusConnected() ? "yes" : "no"),
|
(ems_getBusConnected() ? "yes" : "no"),
|
||||||
|
(ems_getTxCapable() ? "active" : "not active"),
|
||||||
EMS_Sys_Status.emsRxPgks,
|
EMS_Sys_Status.emsRxPgks,
|
||||||
EMS_Sys_Status.emsTxPkgs,
|
EMS_Sys_Status.emsTxPkgs,
|
||||||
EMS_Sys_Status.emxCrcErr);
|
EMS_Sys_Status.emxCrcErr);
|
||||||
@@ -365,7 +367,7 @@ void showInfo() {
|
|||||||
}
|
}
|
||||||
_renderFloatValue("Boiler temperature", "C", EMS_Boiler.boilTemp);
|
_renderFloatValue("Boiler temperature", "C", EMS_Boiler.boilTemp);
|
||||||
_renderIntValue("Pump modulation", "%", EMS_Boiler.pumpMod);
|
_renderIntValue("Pump modulation", "%", EMS_Boiler.pumpMod);
|
||||||
_renderLongValue("Burner # restarts", "times", EMS_Boiler.burnStarts);
|
_renderLongValue("Burner # starts", "times", EMS_Boiler.burnStarts);
|
||||||
if (EMS_Boiler.burnWorkMin != EMS_VALUE_LONG_NOTSET) {
|
if (EMS_Boiler.burnWorkMin != EMS_VALUE_LONG_NOTSET) {
|
||||||
myDebug(" Total burner operating time: %d days %d hours %d minutes",
|
myDebug(" Total burner operating time: %d days %d hours %d minutes",
|
||||||
EMS_Boiler.burnWorkMin / 1440,
|
EMS_Boiler.burnWorkMin / 1440,
|
||||||
@@ -685,9 +687,12 @@ bool FSCallback(MYESP_FSACTION action, const JsonObject json) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// test mode
|
// test mode
|
||||||
if (!(EMSESP_Status.test_mode = json["test_mode"])) {
|
if (!(EMSESP_Status.silent_mode = json["silent_mode"])) {
|
||||||
EMSESP_Status.test_mode = false; // default value
|
EMSESP_Status.silent_mode = false; // default value
|
||||||
recreate_config = true;
|
ems_setTxDisabled(false);
|
||||||
|
recreate_config = true;
|
||||||
|
} else {
|
||||||
|
ems_setTxDisabled(true); // silent_mpde is on
|
||||||
}
|
}
|
||||||
|
|
||||||
// shower_timer
|
// shower_timer
|
||||||
@@ -718,7 +723,7 @@ bool FSCallback(MYESP_FSACTION action, const JsonObject json) {
|
|||||||
json["dallas_parasite"] = EMSESP_Status.dallas_parasite;
|
json["dallas_parasite"] = EMSESP_Status.dallas_parasite;
|
||||||
json["thermostat_type"] = EMS_Thermostat.type_id;
|
json["thermostat_type"] = EMS_Thermostat.type_id;
|
||||||
json["boiler_type"] = EMS_Boiler.type_id;
|
json["boiler_type"] = EMS_Boiler.type_id;
|
||||||
json["test_mode"] = EMSESP_Status.test_mode;
|
json["silent_mode"] = EMSESP_Status.silent_mode;
|
||||||
json["shower_timer"] = EMSESP_Status.shower_timer;
|
json["shower_timer"] = EMSESP_Status.shower_timer;
|
||||||
json["shower_alert"] = EMSESP_Status.shower_alert;
|
json["shower_alert"] = EMSESP_Status.shower_alert;
|
||||||
json["publish_time"] = EMSESP_Status.publish_time;
|
json["publish_time"] = EMSESP_Status.publish_time;
|
||||||
@@ -753,16 +758,19 @@ bool SettingsCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
// test mode
|
// test mode
|
||||||
if ((strcmp(setting, "test_mode") == 0) && (wc == 2)) {
|
if ((strcmp(setting, "silent_mode") == 0) && (wc == 2)) {
|
||||||
if (strcmp(value, "on") == 0) {
|
if (strcmp(value, "on") == 0) {
|
||||||
EMSESP_Status.test_mode = true;
|
EMSESP_Status.silent_mode = true;
|
||||||
ok = true;
|
ok = true;
|
||||||
myDebug("* Reboot to go into test mode.");
|
myDebug("* in Silent mode. All Tx is disabled.");
|
||||||
|
ems_setTxDisabled(true);
|
||||||
} else if (strcmp(value, "off") == 0) {
|
} else if (strcmp(value, "off") == 0) {
|
||||||
EMSESP_Status.test_mode = false;
|
EMSESP_Status.silent_mode = false;
|
||||||
ok = true;
|
ok = true;
|
||||||
|
ems_setTxDisabled(false);
|
||||||
|
myDebug("* out of Silent mode. Tx is enabled.");
|
||||||
} else {
|
} else {
|
||||||
myDebug("Error. Usage: set test_mode <on | off>");
|
myDebug("Error. Usage: set silent_mode <on | off>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -859,7 +867,7 @@ bool SettingsCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, c
|
|||||||
myDebug(" boiler_type=%02X", EMS_Boiler.type_id);
|
myDebug(" boiler_type=%02X", EMS_Boiler.type_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
myDebug(" test_mode=%s", EMSESP_Status.test_mode ? "on" : "off");
|
myDebug(" silent_mode=%s", EMSESP_Status.silent_mode ? "on" : "off");
|
||||||
myDebug(" shower_timer=%s", EMSESP_Status.shower_timer ? "on" : "off");
|
myDebug(" shower_timer=%s", EMSESP_Status.shower_timer ? "on" : "off");
|
||||||
myDebug(" shower_alert=%s", EMSESP_Status.shower_alert ? "on" : "off");
|
myDebug(" shower_alert=%s", EMSESP_Status.shower_alert ? "on" : "off");
|
||||||
myDebug(" publish_time=%d", EMSESP_Status.publish_time);
|
myDebug(" publish_time=%d", EMSESP_Status.publish_time);
|
||||||
@@ -910,6 +918,11 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) {
|
|||||||
ok = true;
|
ok = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strcmp(first_cmd, "startup") == 0) {
|
||||||
|
ems_startupTelegrams();
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
|
|
||||||
// shower settings
|
// shower settings
|
||||||
if ((strcmp(first_cmd, "shower") == 0) && (wc == 2)) {
|
if ((strcmp(first_cmd, "shower") == 0) && (wc == 2)) {
|
||||||
char * second_cmd = _readWord();
|
char * second_cmd = _readWord();
|
||||||
@@ -1140,8 +1153,10 @@ void WIFICallback() {
|
|||||||
} else {
|
} else {
|
||||||
emsuart_init();
|
emsuart_init();
|
||||||
myDebug("[UART] Opened Rx/Tx connection");
|
myDebug("[UART] Opened Rx/Tx connection");
|
||||||
// go and find the boiler and thermostat types
|
if (!EMSESP_Status.silent_mode) {
|
||||||
ems_discoverModels();
|
// go and find the boiler and thermostat types, if not in silent mode
|
||||||
|
ems_discoverModels();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1152,7 +1167,7 @@ void initEMSESP() {
|
|||||||
EMSESP_Status.shower_timer = false;
|
EMSESP_Status.shower_timer = false;
|
||||||
EMSESP_Status.shower_alert = false;
|
EMSESP_Status.shower_alert = false;
|
||||||
EMSESP_Status.led_enabled = true; // LED is on by default
|
EMSESP_Status.led_enabled = true; // LED is on by default
|
||||||
EMSESP_Status.test_mode = false;
|
EMSESP_Status.silent_mode = false;
|
||||||
EMSESP_Status.publish_time = DEFAULT_PUBLISHVALUES_TIME;
|
EMSESP_Status.publish_time = DEFAULT_PUBLISHVALUES_TIME;
|
||||||
|
|
||||||
EMSESP_Status.timestamp = millis();
|
EMSESP_Status.timestamp = millis();
|
||||||
@@ -1354,7 +1369,7 @@ void setup() {
|
|||||||
// at this point we have the settings from our internall SPIFFS config file
|
// at this point we have the settings from our internall SPIFFS config file
|
||||||
|
|
||||||
// enable regular checks if not in test mode
|
// enable regular checks if not in test mode
|
||||||
if (!EMSESP_Status.test_mode) {
|
if (!EMSESP_Status.silent_mode) {
|
||||||
publishValuesTimer.attach(EMSESP_Status.publish_time, do_publishValues); // post MQTT EMS values
|
publishValuesTimer.attach(EMSESP_Status.publish_time, do_publishValues); // post MQTT EMS values
|
||||||
publishSensorValuesTimer.attach(EMSESP_Status.publish_time, do_publishSensorValues); // post MQTT sensor values
|
publishSensorValuesTimer.attach(EMSESP_Status.publish_time, do_publishSensorValues); // post MQTT sensor values
|
||||||
regularUpdatesTimer.attach(REGULARUPDATES_TIME, do_regularUpdates); // regular reads from the EMS
|
regularUpdatesTimer.attach(REGULARUPDATES_TIME, do_regularUpdates); // regular reads from the EMS
|
||||||
@@ -1387,7 +1402,7 @@ void loop() {
|
|||||||
|
|
||||||
// publish the values to MQTT, only if the values have changed
|
// publish the values to MQTT, only if the values have changed
|
||||||
// although we don't want to publish when doing a deep scan of the thermostat
|
// although we don't want to publish when doing a deep scan of the thermostat
|
||||||
if (ems_getEmsRefreshed() && (scanThermostat_count == 0) && (!EMSESP_Status.test_mode)) {
|
if (ems_getEmsRefreshed() && (scanThermostat_count == 0) && (!EMSESP_Status.silent_mode)) {
|
||||||
publishValues(false);
|
publishValues(false);
|
||||||
ems_setEmsRefreshed(false); // reset
|
ems_setEmsRefreshed(false); // reset
|
||||||
}
|
}
|
||||||
|
|||||||
135
src/ems.cpp
135
src/ems.cpp
@@ -118,7 +118,7 @@ const _EMS_Type EMS_Types[] = {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// calculate sizes of arrays
|
// calculate sizes of arrays at compile
|
||||||
uint8_t _EMS_Types_max = ArraySize(EMS_Types); // number of defined types
|
uint8_t _EMS_Types_max = ArraySize(EMS_Types); // number of defined types
|
||||||
uint8_t _Boiler_Types_max = ArraySize(Boiler_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
|
uint8_t _Thermostat_Types_max = ArraySize(Thermostat_Types); // number of defined thermostat types
|
||||||
@@ -162,6 +162,7 @@ void ems_init() {
|
|||||||
EMS_Sys_Status.emsBusConnected = false;
|
EMS_Sys_Status.emsBusConnected = false;
|
||||||
EMS_Sys_Status.emsRxTimestamp = 0;
|
EMS_Sys_Status.emsRxTimestamp = 0;
|
||||||
EMS_Sys_Status.emsTxCapable = false;
|
EMS_Sys_Status.emsTxCapable = false;
|
||||||
|
EMS_Sys_Status.emsTxDisabled = false;
|
||||||
EMS_Sys_Status.emsPollTimestamp = 0;
|
EMS_Sys_Status.emsPollTimestamp = 0;
|
||||||
EMS_Sys_Status.txRetryCount = 0;
|
EMS_Sys_Status.txRetryCount = 0;
|
||||||
|
|
||||||
@@ -234,12 +235,12 @@ void ems_init() {
|
|||||||
|
|
||||||
// set boiler type
|
// set boiler type
|
||||||
EMS_Boiler.product_id = 0;
|
EMS_Boiler.product_id = 0;
|
||||||
strlcpy(EMS_Boiler.version, "not set", sizeof(EMS_Boiler.version));
|
strlcpy(EMS_Boiler.version, "?", sizeof(EMS_Boiler.version));
|
||||||
|
|
||||||
// set thermostat model
|
// set thermostat model
|
||||||
EMS_Thermostat.model_id = EMS_MODEL_NONE;
|
EMS_Thermostat.model_id = EMS_MODEL_NONE;
|
||||||
EMS_Thermostat.product_id = 0;
|
EMS_Thermostat.product_id = 0;
|
||||||
strlcpy(EMS_Thermostat.version, "not set", sizeof(EMS_Thermostat.version));
|
strlcpy(EMS_Thermostat.version, "?", sizeof(EMS_Thermostat.version));
|
||||||
|
|
||||||
// default logging is none
|
// default logging is none
|
||||||
ems_setLogging(EMS_SYS_LOGGING_DEFAULT);
|
ems_setLogging(EMS_SYS_LOGGING_DEFAULT);
|
||||||
@@ -275,6 +276,10 @@ uint8_t ems_getThermostatModel() {
|
|||||||
return (EMS_Thermostat.model_id);
|
return (EMS_Thermostat.model_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ems_setTxDisabled(bool b) {
|
||||||
|
EMS_Sys_Status.emsTxDisabled = b;
|
||||||
|
}
|
||||||
|
|
||||||
bool ems_getTxCapable() {
|
bool ems_getTxCapable() {
|
||||||
if ((millis() - EMS_Sys_Status.emsPollTimestamp) > EMS_POLL_TIMEOUT) {
|
if ((millis() - EMS_Sys_Status.emsPollTimestamp) > EMS_POLL_TIMEOUT) {
|
||||||
EMS_Sys_Status.emsTxCapable = false;
|
EMS_Sys_Status.emsTxCapable = false;
|
||||||
@@ -392,7 +397,7 @@ char * _smallitoa(uint8_t value, char * buffer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* for decimals 0 to 999, printed as a string
|
/* for decimals 0 to 999, printed as a string
|
||||||
* From Simon Arlott @nomis
|
* From @nomis
|
||||||
*/
|
*/
|
||||||
char * _smallitoa3(uint16_t value, char * buffer) {
|
char * _smallitoa3(uint16_t value, char * buffer) {
|
||||||
buffer[0] = ((value / 100) == 0) ? '0' : (value / 100) + '0';
|
buffer[0] = ((value / 100) == 0) ? '0' : (value / 100) + '0';
|
||||||
@@ -406,24 +411,24 @@ char * _smallitoa3(uint16_t value, char * buffer) {
|
|||||||
* debug print a telegram to telnet/serial including the CRC
|
* debug print a telegram to telnet/serial including the CRC
|
||||||
* len is length in bytes including the CRC
|
* len is length in bytes including the CRC
|
||||||
*/
|
*/
|
||||||
void _debugPrintTelegram(const char * prefix, uint8_t * data, uint8_t len, const char * color) {
|
void _debugPrintTelegram(const char * prefix, _EMS_RxTelegram EMS_RxTelegram, const char * color) {
|
||||||
if (EMS_Sys_Status.emsLogging <= EMS_SYS_LOGGING_BASIC)
|
if (EMS_Sys_Status.emsLogging <= EMS_SYS_LOGGING_BASIC)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
char output_str[200] = {0};
|
char output_str[200] = {0};
|
||||||
char buffer[16] = {0};
|
char buffer[16] = {0};
|
||||||
|
uint8_t len = EMS_RxTelegram.length;
|
||||||
unsigned long upt = millis();
|
uint8_t * data = EMS_RxTelegram.telegram;
|
||||||
|
|
||||||
strlcpy(output_str, "(", sizeof(output_str));
|
strlcpy(output_str, "(", sizeof(output_str));
|
||||||
strlcat(output_str, COLOR_CYAN, sizeof(output_str));
|
strlcat(output_str, COLOR_CYAN, sizeof(output_str));
|
||||||
strlcat(output_str, _smallitoa((uint8_t)((upt / 3600000) % 24), buffer), sizeof(output_str));
|
strlcat(output_str, _smallitoa((uint8_t)((EMS_RxTelegram.timestamp / 3600000) % 24), buffer), sizeof(output_str));
|
||||||
strlcat(output_str, ":", sizeof(output_str));
|
strlcat(output_str, ":", sizeof(output_str));
|
||||||
strlcat(output_str, _smallitoa((uint8_t)((upt / 60000) % 60), buffer), sizeof(output_str));
|
strlcat(output_str, _smallitoa((uint8_t)((EMS_RxTelegram.timestamp / 60000) % 60), buffer), sizeof(output_str));
|
||||||
strlcat(output_str, ":", sizeof(output_str));
|
strlcat(output_str, ":", sizeof(output_str));
|
||||||
strlcat(output_str, _smallitoa((uint8_t)((upt / 1000) % 60), buffer), sizeof(output_str));
|
strlcat(output_str, _smallitoa((uint8_t)((EMS_RxTelegram.timestamp / 1000) % 60), buffer), sizeof(output_str));
|
||||||
strlcat(output_str, ".", sizeof(output_str));
|
strlcat(output_str, ".", sizeof(output_str));
|
||||||
strlcat(output_str, _smallitoa3(upt % 1000, buffer), sizeof(output_str));
|
strlcat(output_str, _smallitoa3(EMS_RxTelegram.timestamp % 1000, buffer), sizeof(output_str));
|
||||||
strlcat(output_str, COLOR_RESET, sizeof(output_str));
|
strlcat(output_str, COLOR_RESET, sizeof(output_str));
|
||||||
strlcat(output_str, ") ", sizeof(output_str));
|
strlcat(output_str, ") ", sizeof(output_str));
|
||||||
|
|
||||||
@@ -468,9 +473,13 @@ void _ems_sendTelegram() {
|
|||||||
// if we're in raw mode just fire and forget
|
// if we're in raw mode just fire and forget
|
||||||
if (EMS_TxTelegram.action == EMS_TX_TELEGRAM_RAW) {
|
if (EMS_TxTelegram.action == EMS_TX_TELEGRAM_RAW) {
|
||||||
EMS_TxTelegram.data[EMS_TxTelegram.length - 1] = _crcCalculator(EMS_TxTelegram.data, EMS_TxTelegram.length); // add the CRC
|
EMS_TxTelegram.data[EMS_TxTelegram.length - 1] = _crcCalculator(EMS_TxTelegram.data, EMS_TxTelegram.length); // add the CRC
|
||||||
_debugPrintTelegram("Sending raw", EMS_TxTelegram.data, EMS_TxTelegram.length, COLOR_CYAN); // always show
|
_EMS_RxTelegram EMS_RxTelegram;
|
||||||
emsuart_tx_buffer(EMS_TxTelegram.data, EMS_TxTelegram.length); // send the telegram to the UART Tx
|
EMS_RxTelegram.length = EMS_TxTelegram.length;
|
||||||
EMS_TxQueue.shift(); // remove from queue
|
EMS_RxTelegram.telegram = EMS_TxTelegram.data;
|
||||||
|
EMS_RxTelegram.timestamp = millis(); // now
|
||||||
|
_debugPrintTelegram("Sending raw", EMS_RxTelegram, COLOR_CYAN); // always show
|
||||||
|
emsuart_tx_buffer(EMS_TxTelegram.data, EMS_TxTelegram.length); // send the telegram to the UART Tx
|
||||||
|
EMS_TxQueue.shift(); // remove from queue
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -514,7 +523,11 @@ void _ems_sendTelegram() {
|
|||||||
snprintf(s, sizeof(s), "Sending validate of type 0x%02X to 0x%02X:", EMS_TxTelegram.type, EMS_TxTelegram.dest & 0x7F);
|
snprintf(s, sizeof(s), "Sending validate of type 0x%02X to 0x%02X:", EMS_TxTelegram.type, EMS_TxTelegram.dest & 0x7F);
|
||||||
}
|
}
|
||||||
|
|
||||||
_debugPrintTelegram(s, EMS_TxTelegram.data, EMS_TxTelegram.length, COLOR_CYAN);
|
_EMS_RxTelegram EMS_RxTelegram;
|
||||||
|
EMS_RxTelegram.length = EMS_TxTelegram.length;
|
||||||
|
EMS_RxTelegram.telegram = EMS_TxTelegram.data;
|
||||||
|
EMS_RxTelegram.timestamp = millis(); // now
|
||||||
|
_debugPrintTelegram(s, EMS_RxTelegram, COLOR_CYAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
// send the telegram to the UART Tx
|
// send the telegram to the UART Tx
|
||||||
@@ -577,12 +590,19 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) {
|
|||||||
// check if we just received a single byte
|
// check if we just received a single byte
|
||||||
// it could well be a Poll request from the boiler for us, which will have a value of 0x8B (0x0B | 0x80)
|
// it could well be a Poll request from the boiler for us, which will have a value of 0x8B (0x0B | 0x80)
|
||||||
// or either a return code like 0x01 or 0x04 from the last Write command
|
// or either a return code like 0x01 or 0x04 from the last Write command
|
||||||
|
|
||||||
|
// create the Rx package
|
||||||
|
_EMS_RxTelegram EMS_RxTelegram;
|
||||||
|
EMS_RxTelegram.length = length;
|
||||||
|
EMS_RxTelegram.telegram = telegram;
|
||||||
|
EMS_RxTelegram.timestamp = millis();
|
||||||
|
|
||||||
if (length == 1) {
|
if (length == 1) {
|
||||||
uint8_t value = telegram[0]; // 1st byte of data package
|
uint8_t value = telegram[0]; // 1st byte of data package
|
||||||
|
|
||||||
// check first for a Poll for us
|
// check first for a Poll for us
|
||||||
if (value == (EMS_ID_ME | 0x80)) {
|
if (value == (EMS_ID_ME | 0x80)) {
|
||||||
EMS_Sys_Status.emsPollTimestamp = millis(); // store when we received a last poll
|
EMS_Sys_Status.emsPollTimestamp = EMS_RxTelegram.timestamp; // store when we received a last poll
|
||||||
EMS_Sys_Status.emsTxCapable = true;
|
EMS_Sys_Status.emsTxCapable = true;
|
||||||
|
|
||||||
// do we have something to send thats waiting in the Tx queue?
|
// do we have something to send thats waiting in the Tx queue?
|
||||||
@@ -628,7 +648,7 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) {
|
|||||||
if (telegram[length - 1] != crc) {
|
if (telegram[length - 1] != crc) {
|
||||||
EMS_Sys_Status.emxCrcErr++;
|
EMS_Sys_Status.emxCrcErr++;
|
||||||
if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_VERBOSE) {
|
if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_VERBOSE) {
|
||||||
_debugPrintTelegram("Corrupt telegram:", telegram, length, COLOR_RED);
|
_debugPrintTelegram("Corrupt telegram:", EMS_RxTelegram, COLOR_RED);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -647,24 +667,25 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) {
|
|||||||
|
|
||||||
// here we know its a valid incoming telegram of at least 6 bytes
|
// here we know its a valid incoming telegram of at least 6 bytes
|
||||||
// we use this to see if we always have a connection to the boiler, in case of drop outs
|
// 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.emsRxTimestamp = EMS_RxTelegram.timestamp; // timestamp of last read
|
||||||
EMS_Sys_Status.emsBusConnected = true;
|
EMS_Sys_Status.emsBusConnected = true;
|
||||||
|
|
||||||
// now lets process it and see what to do next
|
// now lets process it and see what to do next
|
||||||
_processType(telegram, length);
|
_processType(EMS_RxTelegram);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* print detailed telegram
|
* print detailed telegram
|
||||||
* and then call its callback if there is one defined
|
* and then call its callback if there is one defined
|
||||||
*/
|
*/
|
||||||
void _ems_processTelegram(uint8_t * telegram, uint8_t length) {
|
void _ems_processTelegram(_EMS_RxTelegram EMS_RxTelegram) {
|
||||||
// header
|
// header
|
||||||
uint8_t src = telegram[0] & 0x7F;
|
uint8_t * telegram = EMS_RxTelegram.telegram;
|
||||||
uint8_t dest = telegram[1] & 0x7F; // remove 8th bit to handle both reads and writes
|
uint8_t src = telegram[0] & 0x7F;
|
||||||
uint8_t type = telegram[2];
|
uint8_t dest = telegram[1] & 0x7F; // remove 8th bit to handle both reads and writes
|
||||||
uint8_t offset = telegram[3];
|
uint8_t type = telegram[2];
|
||||||
uint8_t * data = telegram + 4; // data block starts at position 5
|
uint8_t offset = telegram[3];
|
||||||
|
uint8_t * data = telegram + 4; // data block starts at position 5
|
||||||
|
|
||||||
// print detailed telegram data
|
// print detailed telegram data
|
||||||
if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_THERMOSTAT) {
|
if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_THERMOSTAT) {
|
||||||
@@ -710,11 +731,11 @@ void _ems_processTelegram(uint8_t * telegram, uint8_t length) {
|
|||||||
if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_THERMOSTAT) {
|
if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_THERMOSTAT) {
|
||||||
// only print ones to/from thermostat if logging is set to thermostat only
|
// only print ones to/from thermostat if logging is set to thermostat only
|
||||||
if ((src == EMS_Thermostat.type_id) || (dest == EMS_Thermostat.type_id)) {
|
if ((src == EMS_Thermostat.type_id) || (dest == EMS_Thermostat.type_id)) {
|
||||||
_debugPrintTelegram(output_str, telegram, length, color_s);
|
_debugPrintTelegram(output_str, EMS_RxTelegram, color_s);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// always print
|
// always print
|
||||||
_debugPrintTelegram(output_str, telegram, length, color_s);
|
_debugPrintTelegram(output_str, EMS_RxTelegram, color_s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -746,7 +767,7 @@ void _ems_processTelegram(uint8_t * telegram, uint8_t length) {
|
|||||||
// call callback function to process it
|
// call callback function to process it
|
||||||
// as we only handle complete telegrams (not partial) check that the offset is 0
|
// as we only handle complete telegrams (not partial) check that the offset is 0
|
||||||
if (offset == EMS_ID_NONE) {
|
if (offset == EMS_ID_NONE) {
|
||||||
(void)EMS_Types[i].processType_cb(type, data, length - 5);
|
(void)EMS_Types[i].processType_cb(type, data, EMS_RxTelegram.length - 5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -767,19 +788,22 @@ void _removeTxQueue() {
|
|||||||
* length is only data bytes, excluding the BRK
|
* length is only data bytes, excluding the BRK
|
||||||
* We only remove from the Tx queue if the read or write was successful
|
* We only remove from the Tx queue if the read or write was successful
|
||||||
*/
|
*/
|
||||||
void _processType(uint8_t * telegram, uint8_t length) {
|
void _processType(_EMS_RxTelegram EMS_RxTelegram) {
|
||||||
|
uint8_t * telegram = EMS_RxTelegram.telegram;
|
||||||
|
uint8_t length = EMS_RxTelegram.length;
|
||||||
|
|
||||||
// header
|
// header
|
||||||
uint8_t src = telegram[0] & 0x7F; // removing 8th bit as we deal with both reads and writes here
|
uint8_t src = telegram[0] & 0x7F; // removing 8th bit as we deal with both reads and writes here
|
||||||
|
|
||||||
// if its an echo of ourselves from the master UBA, ignore
|
// if its an echo of ourselves from the master UBA, ignore
|
||||||
if (src == EMS_ID_ME) {
|
if (src == EMS_ID_ME) {
|
||||||
//_debugPrintTelegram("Telegram echo:", telegram, length, COLOR_BLUE);
|
_debugPrintTelegram("echo:", EMS_RxTelegram, COLOR_WHITE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if its a broadcast and we didn't just send anything, process it and exit
|
// if its a broadcast and we didn't just send anything, process it and exit
|
||||||
if (EMS_Sys_Status.emsTxStatus == EMS_TX_STATUS_IDLE) {
|
if (EMS_Sys_Status.emsTxStatus == EMS_TX_STATUS_IDLE) {
|
||||||
_ems_processTelegram(telegram, length);
|
_ems_processTelegram(EMS_RxTelegram);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -791,13 +815,13 @@ void _processType(uint8_t * telegram, uint8_t length) {
|
|||||||
// and if not we probably didn't get any response so remove the last Tx from the queue and process the telegram anyway
|
// and if not we probably didn't get any response so remove the last Tx from the queue and process the telegram anyway
|
||||||
if ((telegram[1] & 0x7F) != EMS_ID_ME) {
|
if ((telegram[1] & 0x7F) != EMS_ID_ME) {
|
||||||
_removeTxQueue();
|
_removeTxQueue();
|
||||||
_ems_processTelegram(telegram, length);
|
_ems_processTelegram(EMS_RxTelegram);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// first double check we actually have something in the queue
|
// first double check we actually have something in the queue
|
||||||
if (EMS_TxQueue.isEmpty()) {
|
if (EMS_TxQueue.isEmpty()) {
|
||||||
_ems_processTelegram(telegram, length);
|
_ems_processTelegram(EMS_RxTelegram);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -832,7 +856,7 @@ void _processType(uint8_t * telegram, uint8_t length) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ems_processTelegram(telegram, length); // process it always
|
_ems_processTelegram(EMS_RxTelegram); // process it always
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EMS_TxTelegram.action == EMS_TX_TELEGRAM_WRITE) {
|
if (EMS_TxTelegram.action == EMS_TX_TELEGRAM_WRITE) {
|
||||||
@@ -1128,7 +1152,7 @@ void _process_Version(uint8_t type, uint8_t * data, uint8_t length) {
|
|||||||
|
|
||||||
if (typeFound) {
|
if (typeFound) {
|
||||||
// its a boiler
|
// its a boiler
|
||||||
myDebug("Boiler type device found. Model %s with TypeID 0x%02X, Product ID %d, Version %s",
|
myDebug("Boiler found. Model %s with TypeID 0x%02X, Product ID %d, Version %s",
|
||||||
Boiler_Types[i].model_string,
|
Boiler_Types[i].model_string,
|
||||||
Boiler_Types[i].type_id,
|
Boiler_Types[i].type_id,
|
||||||
product_id,
|
product_id,
|
||||||
@@ -1198,7 +1222,6 @@ void _process_Version(uint8_t type, uint8_t * data, uint8_t length) {
|
|||||||
} else {
|
} else {
|
||||||
myDebug("Unrecognized device found. TypeID 0x%02X, Product ID %d, Version %s", type, product_id, version);
|
myDebug("Unrecognized device found. TypeID 0x%02X, Product ID %d, Version %s", type, product_id, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1531,6 +1554,11 @@ void ems_doReadCommand(uint8_t type, uint8_t dest, bool forceRefresh) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we're preventing all outbound traffic, quit
|
||||||
|
if (EMS_Sys_Status.emsTxDisabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_EMS_TxTelegram EMS_TxTelegram = EMS_TX_TELEGRAM_NEW; // create new Tx
|
_EMS_TxTelegram EMS_TxTelegram = EMS_TX_TELEGRAM_NEW; // create new Tx
|
||||||
EMS_TxTelegram.timestamp = millis(); // set timestamp
|
EMS_TxTelegram.timestamp = millis(); // set timestamp
|
||||||
EMS_Sys_Status.txRetryCount = 0; // reset retry counter
|
EMS_Sys_Status.txRetryCount = 0; // reset retry counter
|
||||||
@@ -1569,6 +1597,10 @@ void ems_sendRawTelegram(char * telegram) {
|
|||||||
char * p;
|
char * p;
|
||||||
char value[10] = {0};
|
char value[10] = {0};
|
||||||
|
|
||||||
|
if (EMS_Sys_Status.emsTxDisabled) {
|
||||||
|
return; // user has disabled all Tx
|
||||||
|
}
|
||||||
|
|
||||||
_EMS_TxTelegram EMS_TxTelegram = EMS_TX_TELEGRAM_NEW; // create new Tx
|
_EMS_TxTelegram EMS_TxTelegram = EMS_TX_TELEGRAM_NEW; // create new Tx
|
||||||
EMS_TxTelegram.timestamp = millis(); // set timestamp
|
EMS_TxTelegram.timestamp = millis(); // set timestamp
|
||||||
EMS_Sys_Status.txRetryCount = 0; // reset retry counter
|
EMS_Sys_Status.txRetryCount = 0; // reset retry counter
|
||||||
@@ -1594,6 +1626,10 @@ void ems_sendRawTelegram(char * telegram) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (count == 0) {
|
||||||
|
return; // nothing to send
|
||||||
|
}
|
||||||
|
|
||||||
// calculate length including header and CRC
|
// calculate length including header and CRC
|
||||||
EMS_TxTelegram.length = count + 2;
|
EMS_TxTelegram.length = count + 2;
|
||||||
EMS_TxTelegram.type_validate = EMS_ID_NONE;
|
EMS_TxTelegram.type_validate = EMS_ID_NONE;
|
||||||
@@ -1845,3 +1881,26 @@ void ems_setWarmTapWaterActivated(bool activated) {
|
|||||||
|
|
||||||
EMS_TxQueue.push(EMS_TxTelegram); // add to queue
|
EMS_TxQueue.push(EMS_TxTelegram); // add to queue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start up sequence for UBA Master
|
||||||
|
* Still experimental
|
||||||
|
*/
|
||||||
|
void ems_startupTelegrams() {
|
||||||
|
if ((EMS_Sys_Status.emsTxDisabled) || (!EMS_Sys_Status.emsBusConnected)) {
|
||||||
|
myDebug("Unable to send startup sequence when in silent mode or bus is disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
myDebug("Sending startup sequence...");
|
||||||
|
char s[20] = {0};
|
||||||
|
|
||||||
|
// (00:07:27.512) Telegram echo: telegram: 0B 08 1D 00 00 (CRC=84), #data=1
|
||||||
|
// Write type 0x1D to get out of function test mode
|
||||||
|
snprintf(s, sizeof(s), "%02X %02X 1D 00 00", EMS_ID_ME, EMS_Boiler.type_id);
|
||||||
|
ems_sendRawTelegram(s);
|
||||||
|
|
||||||
|
// (00:07:35.555) Telegram echo: telegram: 0B 88 01 00 1B (CRC=8B), #data=1
|
||||||
|
// Read type 0x01
|
||||||
|
snprintf(s, sizeof(s), "%02X %02X 01 00 1B", EMS_ID_ME, EMS_Boiler.type_id | 0x80);
|
||||||
|
ems_sendRawTelegram(s);
|
||||||
|
}
|
||||||
|
|||||||
17
src/ems.h
17
src/ems.h
@@ -92,6 +92,7 @@ typedef struct {
|
|||||||
unsigned long emsRxTimestamp; // timestamp of last EMS message received
|
unsigned long emsRxTimestamp; // timestamp of last EMS message received
|
||||||
unsigned long emsPollTimestamp; // timestamp of last EMS poll sent to us
|
unsigned long emsPollTimestamp; // timestamp of last EMS poll sent to us
|
||||||
bool emsTxCapable; // able to send via Tx
|
bool emsTxCapable; // able to send via Tx
|
||||||
|
bool emsTxDisabled; // true to prevent all Tx
|
||||||
uint8_t txRetryCount; // # times the last Tx was re-sent
|
uint8_t txRetryCount; // # times the last Tx was re-sent
|
||||||
} _EMS_Sys_Status;
|
} _EMS_Sys_Status;
|
||||||
|
|
||||||
@@ -112,6 +113,12 @@ typedef struct {
|
|||||||
uint8_t data[EMS_MAX_TELEGRAM_LENGTH];
|
uint8_t data[EMS_MAX_TELEGRAM_LENGTH];
|
||||||
} _EMS_TxTelegram;
|
} _EMS_TxTelegram;
|
||||||
|
|
||||||
|
// The Rx receive package
|
||||||
|
typedef struct {
|
||||||
|
uint32_t timestamp; // timestamp from millis()
|
||||||
|
uint8_t * telegram; // the full data package
|
||||||
|
uint8_t length; // length in bytes
|
||||||
|
} _EMS_RxTelegram;
|
||||||
|
|
||||||
|
|
||||||
// default empty Tx
|
// default empty Tx
|
||||||
@@ -179,7 +186,7 @@ typedef struct { // UBAParameterWW
|
|||||||
float extTemp; // Outside temperature
|
float extTemp; // Outside temperature
|
||||||
float boilTemp; // Boiler temperature
|
float boilTemp; // Boiler temperature
|
||||||
uint8_t pumpMod; // Pump modulation
|
uint8_t pumpMod; // Pump modulation
|
||||||
uint32_t burnStarts; // # burner restarts
|
uint32_t burnStarts; // # burner starts
|
||||||
uint32_t burnWorkMin; // Total burner operating time
|
uint32_t burnWorkMin; // Total burner operating time
|
||||||
uint32_t heatWorkMin; // Total heat operating time
|
uint32_t heatWorkMin; // Total heat operating time
|
||||||
|
|
||||||
@@ -251,12 +258,12 @@ void ems_setWarmWaterTemp(uint8_t temperature);
|
|||||||
void ems_setWarmWaterActivated(bool activated);
|
void ems_setWarmWaterActivated(bool activated);
|
||||||
void ems_setWarmTapWaterActivated(bool activated);
|
void ems_setWarmTapWaterActivated(bool activated);
|
||||||
void ems_setPoll(bool b);
|
void ems_setPoll(bool b);
|
||||||
void ems_setTxEnabled(bool b);
|
|
||||||
void ems_setLogging(_EMS_SYS_LOGGING loglevel);
|
void ems_setLogging(_EMS_SYS_LOGGING loglevel);
|
||||||
void ems_setEmsRefreshed(bool b);
|
void ems_setEmsRefreshed(bool b);
|
||||||
void ems_setWarmWaterModeComfort(uint8_t comfort);
|
void ems_setWarmWaterModeComfort(uint8_t comfort);
|
||||||
bool ems_checkEMSBUSAlive();
|
bool ems_checkEMSBUSAlive();
|
||||||
void ems_setModels();
|
void ems_setModels();
|
||||||
|
void ems_setTxDisabled(bool b);
|
||||||
|
|
||||||
void ems_getThermostatValues();
|
void ems_getThermostatValues();
|
||||||
void ems_getBoilerValues();
|
void ems_getBoilerValues();
|
||||||
@@ -277,10 +284,12 @@ char * ems_getThermostatDescription(char * buffer);
|
|||||||
void ems_printTxQueue();
|
void ems_printTxQueue();
|
||||||
char * ems_getBoilerDescription(char * buffer);
|
char * ems_getBoilerDescription(char * buffer);
|
||||||
|
|
||||||
|
void ems_startupTelegrams();
|
||||||
|
|
||||||
// private functions
|
// private functions
|
||||||
uint8_t _crcCalculator(uint8_t * data, uint8_t len);
|
uint8_t _crcCalculator(uint8_t * data, uint8_t len);
|
||||||
void _processType(uint8_t * telegram, uint8_t length);
|
void _processType(_EMS_RxTelegram EMS_RxTelegram);
|
||||||
void _debugPrintPackage(const char * prefix, uint8_t * data, uint8_t len, const char * color);
|
void _debugPrintPackage(const char * prefix, _EMS_RxTelegram EMS_RxTelegram, const char * color);
|
||||||
void _ems_clearTxData();
|
void _ems_clearTxData();
|
||||||
int _ems_findBoilerModel(uint8_t model_id);
|
int _ems_findBoilerModel(uint8_t model_id);
|
||||||
bool _ems_setModel(uint8_t model_id);
|
bool _ems_setModel(uint8_t model_id);
|
||||||
|
|||||||
Reference in New Issue
Block a user