ESPHome 2026.5.0
Loading...
Searching...
No Matches
e131.cpp
Go to the documentation of this file.
1#include "e131.h"
2#ifdef USE_NETWORK
4#include "esphome/core/log.h"
5
6#include <algorithm>
7
8namespace esphome::e131 {
9
10static const char *const TAG = "e131";
11static const int PORT = 5568;
12
14
16#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
17 if (this->socket_) {
18 this->socket_->close();
19 }
20#elif defined(USE_SOCKET_IMPL_LWIP_TCP)
21 this->udp_.stop();
22#endif
23}
24
26#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
27 this->socket_ = socket::socket_ip(SOCK_DGRAM, IPPROTO_IP);
28
29 int enable = 1;
30 int err = this->socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
31 if (err != 0) {
32 ESP_LOGW(TAG, "Socket unable to set reuseaddr: errno %d", err);
33 // we can still continue
34 }
35 err = this->socket_->setblocking(false);
36 if (err != 0) {
37 ESP_LOGW(TAG, "Socket unable to set nonblocking mode: errno %d", err);
38 this->mark_failed();
39 return;
40 }
41
42 struct sockaddr_storage server;
43
44 socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), PORT);
45 if (sl == 0) {
46 ESP_LOGW(TAG, "Socket unable to set sockaddr: errno %d", errno);
47 this->mark_failed();
48 return;
49 }
50
51 err = this->socket_->bind((struct sockaddr *) &server, sizeof(server));
52 if (err != 0) {
53 ESP_LOGW(TAG, "Socket unable to bind: errno %d", errno);
54 this->mark_failed();
55 return;
56 }
57#elif defined(USE_SOCKET_IMPL_LWIP_TCP)
58 if (!this->udp_.begin(PORT)) {
59 ESP_LOGW(TAG, "Cannot bind E1.31 to port %d.", PORT);
60 this->mark_failed();
61 return;
62 }
63#endif
64
66}
67
69 E131Packet packet;
70 int universe = 0;
71 uint8_t buf[1460];
73
74 // Drain all queued packets so multi-universe frames are applied
75 // atomically before the light writes. Without this, each universe
76 // packet would trigger a separate full-strip write causing tearing.
77 while ((len = this->read_(buf, sizeof(buf))) > 0) {
78 if (!this->packet_(buf, (size_t) len, universe, packet)) {
79 ESP_LOGV(TAG, "Invalid packet received of size %d.", (int) len);
80 continue;
81 }
82
83 if (!this->process_(universe, packet)) {
84 ESP_LOGV(TAG, "Ignored packet for %d universe of size %d.", universe, packet.count);
85 }
86 }
87}
88
90 if (std::find(light_effects_.begin(), light_effects_.end(), light_effect) != light_effects_.end()) {
91 return;
92 }
93
94 auto effect_name = light_effect->get_name();
95 ESP_LOGD(TAG, "Registering '%.*s' for universes %d-%d.", (int) effect_name.size(), effect_name.c_str(),
96 light_effect->get_first_universe(), light_effect->get_last_universe());
97
98 light_effects_.push_back(light_effect);
99
100 for (auto universe = light_effect->get_first_universe(); universe <= light_effect->get_last_universe(); ++universe) {
102 }
103}
104
106 auto it = std::find(light_effects_.begin(), light_effects_.end(), light_effect);
107 if (it == light_effects_.end()) {
108 return;
109 }
110
111 auto effect_name = light_effect->get_name();
112 ESP_LOGD(TAG, "Unregistering '%.*s' for universes %d-%d.", (int) effect_name.size(), effect_name.c_str(),
113 light_effect->get_first_universe(), light_effect->get_last_universe());
114
115 // Swap with last element and pop for O(1) removal (order doesn't matter)
116 *it = light_effects_.back();
117 light_effects_.pop_back();
118
119 for (auto universe = light_effect->get_first_universe(); universe <= light_effect->get_last_universe(); ++universe) {
121 }
122}
123
125 bool handled = false;
126
127 ESP_LOGV(TAG, "Received E1.31 packet for %d universe, with %d bytes", universe, packet.count);
128
129 for (auto *light_effect : light_effects_) {
130 handled = light_effect->process_(universe, packet) || handled;
131 }
132
133 return handled;
134}
135
136} // namespace esphome::e131
137
138#endif
void mark_failed()
Mark this component as failed.
std::vector< E131AddressableLightEffect * > light_effects_
Definition e131.h:70
void loop() override
Definition e131.cpp:68
void add_effect(E131AddressableLightEffect *light_effect)
Definition e131.cpp:89
void remove_effect(E131AddressableLightEffect *light_effect)
Definition e131.cpp:105
bool packet_(const uint8_t *data, size_t len, int &universe, E131Packet &packet)
bool process_(int universe, const E131Packet &packet)
Definition e131.cpp:124
std::unique_ptr< socket::Socket > socket_
Definition e131.h:66
void setup() override
Definition e131.cpp:25
ssize_t read_(uint8_t *buf, size_t len)
Definition e131.h:48
StringRef get_name() const
Returns the name of this effect.
uint16_t universe
uint32_t socklen_t
Definition headers.h:99
__int64 ssize_t
Definition httplib.h:178
std::unique_ptr< Socket > socket_ip(int type, int protocol)
Create a socket in the newest available IP domain (IPv6 or IPv4) of the given type and protocol.
Definition socket.cpp:87
socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port)
Set a sockaddr to the any address and specified port for the IP version used by socket_ip().
Definition socket.cpp:146
std::string size_t len