[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
This commit is contained in:
J. Nick Koston
2026-02-19 19:04:59 -06:00
parent c1265a9490
commit b8859b990e
2 changed files with 12 additions and 20 deletions

View File

@@ -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
}

View File

@@ -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_();