ESPHome 2026.2.4
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 {
9namespace e131 {
10
11static const char *const TAG = "e131";
12static const int PORT = 5568;
13
15
17#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
18 if (this->socket_) {
19 this->socket_->close();
20 }
21#elif defined(USE_SOCKET_IMPL_LWIP_TCP)
22 this->udp_.stop();
23#endif
24}
25
27#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
28 this->socket_ = socket::socket_ip(SOCK_DGRAM, IPPROTO_IP);
29
30 int enable = 1;
31 int err = this->socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
32 if (err != 0) {
33 ESP_LOGW(TAG, "Socket unable to set reuseaddr: errno %d", err);
34 // we can still continue
35 }
36 err = this->socket_->setblocking(false);
37 if (err != 0) {
38 ESP_LOGW(TAG, "Socket unable to set nonblocking mode: errno %d", err);
39 this->mark_failed();
40 return;
41 }
42
43 struct sockaddr_storage server;
44
45 socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), PORT);
46 if (sl == 0) {
47 ESP_LOGW(TAG, "Socket unable to set sockaddr: errno %d", errno);
48 this->mark_failed();
49 return;
50 }
51
52 err = this->socket_->bind((struct sockaddr *) &server, sizeof(server));
53 if (err != 0) {
54 ESP_LOGW(TAG, "Socket unable to bind: errno %d", errno);
55 this->mark_failed();
56 return;
57 }
58#elif defined(USE_SOCKET_IMPL_LWIP_TCP)
59 if (!this->udp_.begin(PORT)) {
60 ESP_LOGW(TAG, "Cannot bind E1.31 to port %d.", PORT);
61 this->mark_failed();
62 return;
63 }
64#endif
65
67}
68
70 E131Packet packet;
71 int universe = 0;
72 uint8_t buf[1460];
73
74#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
75 ssize_t len = this->socket_->read(buf, sizeof(buf));
76 if (len == -1) {
77 return;
78 }
79
80 if (!this->packet_(buf, (size_t) len, universe, packet)) {
81 ESP_LOGV(TAG, "Invalid packet received of size %d.", (int) len);
82 return;
83 }
84
85 if (!this->process_(universe, packet)) {
86 ESP_LOGV(TAG, "Ignored packet for %d universe of size %d.", universe, packet.count);
87 }
88#elif defined(USE_SOCKET_IMPL_LWIP_TCP)
89 while (auto packet_size = this->udp_.parsePacket()) {
90 auto len = this->udp_.read(buf, sizeof(buf));
91 if (len <= 0)
92 continue;
93
94 if (!this->packet_(buf, (size_t) len, universe, packet)) {
95 ESP_LOGV(TAG, "Invalid packet received of size %d.", (int) len);
96 continue;
97 }
98
99 if (!this->process_(universe, packet)) {
100 ESP_LOGV(TAG, "Ignored packet for %d universe of size %d.", universe, packet.count);
101 }
102 }
103#endif
104}
105
107 if (std::find(light_effects_.begin(), light_effects_.end(), light_effect) != light_effects_.end()) {
108 return;
109 }
110
111 auto effect_name = light_effect->get_name();
112 ESP_LOGD(TAG, "Registering '%.*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 light_effects_.push_back(light_effect);
116
117 for (auto universe = light_effect->get_first_universe(); universe <= light_effect->get_last_universe(); ++universe) {
119 }
120}
121
123 auto it = std::find(light_effects_.begin(), light_effects_.end(), light_effect);
124 if (it == light_effects_.end()) {
125 return;
126 }
127
128 auto effect_name = light_effect->get_name();
129 ESP_LOGD(TAG, "Unregistering '%.*s' for universes %d-%d.", (int) effect_name.size(), effect_name.c_str(),
130 light_effect->get_first_universe(), light_effect->get_last_universe());
131
132 // Swap with last element and pop for O(1) removal (order doesn't matter)
133 *it = light_effects_.back();
134 light_effects_.pop_back();
135
136 for (auto universe = light_effect->get_first_universe(); universe <= light_effect->get_last_universe(); ++universe) {
138 }
139}
140
142 bool handled = false;
143
144 ESP_LOGV(TAG, "Received E1.31 packet for %d universe, with %d bytes", universe, packet.count);
145
146 for (auto *light_effect : light_effects_) {
147 handled = light_effect->process_(universe, packet) || handled;
148 }
149
150 return handled;
151}
152
153} // namespace e131
154} // namespace esphome
155#endif
virtual void mark_failed()
Mark this component as failed.
std::vector< E131AddressableLightEffect * > light_effects_
Definition e131.h:57
void loop() override
Definition e131.cpp:69
void add_effect(E131AddressableLightEffect *light_effect)
Definition e131.cpp:106
void remove_effect(E131AddressableLightEffect *light_effect)
Definition e131.cpp:122
bool packet_(const uint8_t *data, size_t len, int &universe, E131Packet &packet)
bool process_(int universe, const E131Packet &packet)
Definition e131.cpp:141
std::unique_ptr< socket::Socket > socket_
Definition e131.h:53
void setup() override
Definition e131.cpp:26
StringRef get_name() const
Returns the name of this effect.
uint16_t universe
uint32_t socklen_t
Definition headers.h:97
__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:104
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:159
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string size_t len
Definition helpers.h:692