From b8859b990e128439527f1435e614cd139f89b5cd Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 19 Feb 2026 19:04:59 -0600 Subject: [PATCH] [e131] Drain all queued packets per loop iteration Previously the BSD socket path read only one UDP packet per loop() call. With multi-universe setups (e.g. 380 RGBW LEDs across 3 universes), this caused the light to re-render the entire strip for each universe packet separately, resulting in visible tearing and ~3x unnecessary RMT writes. Now both socket backends drain all available packets before returning, so multi-universe frames are applied atomically and the light only writes once per frame. The duplicated packet processing logic is consolidated into a shared loop with a platform-specific read_() helper. Tested on ESP32-IDF with 380 SK6812 RGBW LEDs (3 universes): - Light total CPU dropped from 5820ms to 1108ms per 60s (~5x) - Combined e131+light dropped from 6944ms to 4811ms per 60s - Visible tearing eliminated --- esphome/components/e131/e131.cpp | 31 +++++++++++-------------------- esphome/components/e131/e131.h | 1 + 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/esphome/components/e131/e131.cpp b/esphome/components/e131/e131.cpp index 941927122c..04a4fc0d03 100644 --- a/esphome/components/e131/e131.cpp +++ b/esphome/components/e131/e131.cpp @@ -70,27 +70,9 @@ void E131Component::loop() { E131Packet packet; int universe = 0; uint8_t buf[1460]; + ssize_t len; -#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) - ssize_t len = this->socket_->read(buf, sizeof(buf)); - if (len == -1) { - return; - } - - if (!this->packet_(buf, (size_t) len, universe, packet)) { - ESP_LOGV(TAG, "Invalid packet received of size %d.", (int) len); - return; - } - - if (!this->process_(universe, packet)) { - ESP_LOGV(TAG, "Ignored packet for %d universe of size %d.", universe, packet.count); - } -#elif defined(USE_SOCKET_IMPL_LWIP_TCP) - while (auto packet_size = this->udp_.parsePacket()) { - auto len = this->udp_.read(buf, sizeof(buf)); - if (len <= 0) - continue; - + while ((len = this->read_(buf, sizeof(buf))) > 0) { if (!this->packet_(buf, (size_t) len, universe, packet)) { ESP_LOGV(TAG, "Invalid packet received of size %d.", (int) len); continue; @@ -100,6 +82,15 @@ void E131Component::loop() { ESP_LOGV(TAG, "Ignored packet for %d universe of size %d.", universe, packet.count); } } +} + +ssize_t E131Component::read_(uint8_t *buf, size_t len) { +#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) + return this->socket_->read(buf, len); +#elif defined(USE_SOCKET_IMPL_LWIP_TCP) + if (!this->udp_.parsePacket()) + return -1; + return this->udp_.read(buf, len); #endif } diff --git a/esphome/components/e131/e131.h b/esphome/components/e131/e131.h index fee447b678..16976a66ef 100644 --- a/esphome/components/e131/e131.h +++ b/esphome/components/e131/e131.h @@ -46,6 +46,7 @@ class E131Component : public esphome::Component { void set_method(E131ListenMethod listen_method) { this->listen_method_ = listen_method; } protected: + ssize_t read_(uint8_t *buf, size_t len); bool packet_(const uint8_t *data, size_t len, int &universe, E131Packet &packet); bool process_(int universe, const E131Packet &packet); bool join_igmp_groups_();