diff --git a/src/core/emsesp.cpp b/src/core/emsesp.cpp index 977b3c2b9..8a7a6cca2 100644 --- a/src/core/emsesp.cpp +++ b/src/core/emsesp.cpp @@ -1595,6 +1595,49 @@ void EMSESP::send_write_request(const uint16_t type_id, const uint8_t dest, cons EMSESP::send_write_request(type_id, dest, offset, message_data, 1, validate_typeid); } +// answer a read or write aimed at our own bus id, so the requester is not left waiting for a timeout +// a reply to one of our own reads has the same destination and no read-bit, so only ack a write when we are not finishing a read +// see https://github.com/emsesp/EMS-ESP32/issues/3094 +void EMSESP::reply_own_request(const uint8_t * data, const uint8_t length, const uint8_t tx_state) { + if (length < 4) { + return; + } + + const uint8_t our = EMSbus::ems_bus_id(); + uint8_t mask = EMSbus::ems_mask(); + if (mask == EMSbus::EMS_MASK_UNSET) { + mask = data[0] & 0x80; // same bit RxService uses, before this telegram has been queued + } + + if (data[1] == (our | 0x80)) { + uint8_t reply[7]; + reply[0] = our | mask; + reply[1] = data[0] & 0x7F; + if (data[2] < 0xF0) { // EMS read + reply[2] = data[2]; + reply[3] = data[3]; + reply[4] = EMSbus::calculate_crc(reply, 4); + EMSuart::transmit(reply, 5); + LOG_DEBUG("Empty reply to 0x%02X read 0x%02X", reply[1], data[2]); + } else if (data[2] == 0xFF && length >= 7) { // EMS+ read + reply[2] = 0xFF; + reply[3] = data[3]; + reply[4] = data[5]; + reply[5] = data[6]; + reply[6] = EMSbus::calculate_crc(reply, 6); + EMSuart::transmit(reply, 7); + LOG_DEBUG("Empty reply to 0x%02X read 0x%02X%02X", reply[1], data[5], data[6]); + } + return; + } + + if (tx_state == Telegram::Operation::NONE && data[1] == our) { // EMS/EMS+ write + uint8_t ack = TxService::TX_WRITE_SUCCESS; + EMSuart::transmit(&ack, 1); + LOG_DEBUG("Ack write from 0x%02X", data[0] & 0x7F); + } +} + // this is main entry point when data is received on the Rx line, via emsuart library // we check if its a complete telegram or just a single byte (which could be a poll or a return status) // the CRC check is not done here, only when it's added to the Rx queue with add() @@ -1721,6 +1764,7 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) { LOG_TRACE("[UART_DEBUG] Reply after %d ms: %s", uuid::get_uptime_ms() - rx_time_, Helpers::data_to_hex(data, length).c_str()); #endif Roomctrl::check(data[1], data, length); // check if there is a message for the roomcontroller + reply_own_request(data, length, tx_state); #ifdef EMSESP_GATEWAY_TX_HOLD gateway_rx_check(data, length); diff --git a/src/core/emsesp.h b/src/core/emsesp.h index b5dcfca90..8bdb6d5b2 100644 --- a/src/core/emsesp.h +++ b/src/core/emsesp.h @@ -283,6 +283,7 @@ class EMSESP { static void process_version(const std::shared_ptr & telegram); static void publish_response(const std::shared_ptr & telegram); static void publish_all_loop(); + static void reply_own_request(const uint8_t * data, const uint8_t length, const uint8_t tx_state); // one-time compaction of per-device/command vectors once registration has been stable static void compact_entities_if_stable(); diff --git a/src/core/system.cpp b/src/core/system.cpp index d880cc9ef..632d444b8 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -749,7 +749,10 @@ void System::syslog_init() { #ifndef EMSESP_STANDALONE if (syslog_enabled_) { // start & configure syslog - syslog_.maximum_log_messages(10); + // 10 is smaller than one DEBUG/ALL bus burst (about 30 telegrams, two lines each). + // The queue is PSRAM-backed and drains at one UDP packet per 10 ms, so 100 holds + // the burst until the next quiet period. + syslog_.maximum_log_messages(100); syslog_.log_level((uuid::log::Level)syslog_level_); syslog_.mark_interval(syslog_mark_interval_); syslog_.destination(syslog_host_.c_str(), syslog_port_); @@ -1122,6 +1125,12 @@ void System::heartbeat_json(JsonObject output) { output["mqttfails"] = Mqtt::publish_fails(); output["mqttreconnects"] = Mqtt::connect_count(); } +#ifndef EMSESP_STANDALONE + if (syslog_enabled_) { + output["syslogcount"] = syslog_count(); + output["syslogfails"] = syslog_fails(); + } +#endif output["apicalls"] = WebAPIService::api_count(); // + WebAPIService::api_fails(); output["apifails"] = WebAPIService::api_fails(); diff --git a/src/web/WebActivityService.cpp b/src/web/WebActivityService.cpp index 09e12f5af..f2b3c8acd 100644 --- a/src/web/WebActivityService.cpp +++ b/src/web/WebActivityService.cpp @@ -86,9 +86,13 @@ void WebActivityService::webActivityService(AsyncWebServerRequest * request) { if (EMSESP::system_.syslog_enabled()) { statJson = statsJson.add(); statJson["id"] = 7; - statJson["s"] = EMSESP::system_.syslog_count(); - statJson["f"] = EMSESP::system_.syslog_fails(); - statJson["q"] = EMSESP::system_.syslog_count() == 0 ? 100 : 100 - (uint8_t)((100 * EMSESP::system_.syslog_fails()) / EMSESP::system_.syslog_count()); + const unsigned long syslog_count = EMSESP::system_.syslog_count(); + const unsigned long syslog_fails = EMSESP::system_.syslog_fails(); + statJson["s"] = syslog_count; + statJson["f"] = syslog_fails; + // Round to the nearest percent. Integer division alone stays on the truncated value + // (8.7% dropped still displays as 92%) until the ratio crosses the next whole percent. + statJson["q"] = syslog_count == 0 ? 100 : (uint8_t)(100 - ((100ULL * syslog_fails + syslog_count / 2) / syslog_count)); } #endif