50 static const char *
const TAG =
"udp";
52 static size_t round4(
size_t value) {
return (value + 3) & ~3; }
59 static const size_t MAX_PACKET_SIZE = 508;
60 static const uint16_t MAGIC_NUMBER = 0x4553;
61 static const uint16_t MAGIC_PING = 0x5048;
62 static const uint32_t PREF_HASH = 0x45535043;
72 static const size_t MAX_PING_KEYS = 4;
74 static inline void add(std::vector<uint8_t> &vec, uint32_t data) {
75 vec.push_back(data & 0xFF);
76 vec.push_back((data >> 8) & 0xFF);
77 vec.push_back((data >> 16) & 0xFF);
78 vec.push_back((data >> 24) & 0xFF);
81 static inline uint32_t get_uint32(uint8_t *&buf) {
82 uint32_t data = *buf++;
89 static inline uint16_t get_uint16(uint8_t *&buf) {
90 uint16_t data = *buf++;
95 static inline void add(std::vector<uint8_t> &vec, uint8_t data) { vec.push_back(data); }
96 static inline void add(std::vector<uint8_t> &vec, uint16_t data) {
97 vec.push_back((uint8_t) data);
98 vec.push_back((uint8_t) (data >> 8));
100 static inline void add(std::vector<uint8_t> &vec,
DataKey data) { vec.push_back(data); }
101 static void add(std::vector<uint8_t> &vec,
const char *str) {
102 auto len = strlen(str);
104 for (
size_t i = 0; i !=
len; i++) {
105 vec.push_back(*str++);
111 if (strlen(this->name_) > 255) {
113 this->status_set_error(
"Device name exceeds 255 chars");
116 this->resend_ping_key_ = this->ping_pong_enable_;
119 this->pref_.
load(&this->rolling_code_[1]);
120 this->rolling_code_[1]++;
121 this->pref_.save(&this->rolling_code_[1]);
123 ESP_LOGV(TAG,
"Rolling code incremented, upper part now %u", (
unsigned) this->rolling_code_[1]);
125 for (
auto &
sensor : this->sensors_) {
127 this->updated_ =
true;
132 #ifdef USE_BINARY_SENSOR 133 for (
auto &
sensor : this->binary_sensors_) {
135 this->updated_ =
true;
140 this->should_send_ = this->ping_pong_enable_;
142 this->should_send_ |= !this->sensors_.empty();
144 #ifdef USE_BINARY_SENSOR 145 this->should_send_ |= !this->binary_sensors_.empty();
147 this->should_listen_ = !this->providers_.empty() || this->is_encrypted_();
149 add(this->header_, MAGIC_NUMBER);
150 add(this->header_, this->name_);
152 while (this->header_.size() & 0x3)
153 this->header_.push_back(0);
154 #if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) 155 for (
const auto &
address : this->addresses_) {
158 this->sockaddrs_.push_back(saddr);
161 if (this->should_send_) {
162 this->broadcast_socket_ =
socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
163 if (this->broadcast_socket_ ==
nullptr) {
165 this->status_set_error(
"Could not create socket");
169 auto err = this->broadcast_socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable,
sizeof(
int));
171 this->status_set_warning(
"Socket unable to set reuseaddr");
174 err = this->broadcast_socket_->setsockopt(SOL_SOCKET, SO_BROADCAST, &enable,
sizeof(
int));
176 this->status_set_warning(
"Socket unable to set broadcast");
181 if (this->should_listen_) {
182 this->listen_socket_ =
socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
183 if (this->listen_socket_ ==
nullptr) {
185 this->status_set_error(
"Could not create socket");
188 auto err = this->listen_socket_->setblocking(
false);
190 ESP_LOGE(TAG,
"Unable to set nonblocking: errno %d", errno);
192 this->status_set_error(
"Unable to set nonblocking");
196 err = this->listen_socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable,
sizeof(enable));
198 this->status_set_warning(
"Socket unable to set reuseaddr");
204 server.
sin_addr.s_addr = ESPHOME_INADDR_ANY;
205 server.
sin_port = htons(this->port_);
207 if (this->listen_address_.has_value()) {
208 struct ip_mreq imreq = {};
209 imreq.imr_interface.s_addr = ESPHOME_INADDR_ANY;
210 inet_aton(this->listen_address_.value().str().c_str(), &imreq.imr_multiaddr);
211 server.
sin_addr.s_addr = imreq.imr_multiaddr.s_addr;
212 ESP_LOGV(TAG,
"Join multicast %s", this->listen_address_.value().str().c_str());
213 err = this->listen_socket_->setsockopt(IPPROTO_IP, IP_ADD_MEMBERSHIP, &imreq,
sizeof(imreq));
215 ESP_LOGE(TAG,
"Failed to set IP_ADD_MEMBERSHIP. Error %d", errno);
217 this->status_set_error(
"Failed to set IP_ADD_MEMBERSHIP");
222 err = this->listen_socket_->bind((
struct sockaddr *) &server,
sizeof(server));
224 ESP_LOGE(TAG,
"Socket unable to bind: errno %d", errno);
226 this->status_set_error(
"Unable to bind socket");
231 #ifdef USE_SOCKET_IMPL_LWIP_TCP 233 for (
const auto &
address : this->addresses_) {
234 auto ipaddr = IPAddress();
235 ipaddr.fromString(
address.c_str());
236 this->ipaddrs_.push_back(ipaddr);
238 if (this->should_listen_)
239 this->udp_client_.begin(this->port_);
245 if (this->rolling_code_enable_) {
247 add(this->data_, this->rolling_code_[0]);
248 add(this->data_, this->rolling_code_[1]);
249 this->increment_code_();
253 for (
auto pkey : this->ping_keys_) {
255 add(this->data_, pkey.second);
262 uint32_t buffer[MAX_PACKET_SIZE / 4];
263 memset(buffer, 0,
sizeof buffer);
265 auto header_len = round4(this->header_.size()) / 4;
266 auto len = round4(data_.size()) / 4;
267 memcpy(buffer, this->header_.data(), this->header_.size());
268 memcpy(buffer + header_len, this->data_.data(), this->data_.size());
269 if (this->is_encrypted_()) {
270 xxtea::encrypt(buffer + header_len, len, (uint32_t *) this->encryption_key_.data());
272 auto total_len = (header_len +
len) * 4;
273 this->send_packet_(buffer, total_len);
277 auto len = 1 + 1 + 1 + strlen(
id);
278 if (
len + this->header_.size() + this->data_.size() > MAX_PACKET_SIZE) {
281 add(this->data_, key);
282 add(this->data_, (uint8_t) data);
283 add(this->data_,
id);
286 FuData udata{.f32 = data};
287 this->add_data_(key,
id, udata.u32);
291 auto len = 4 + 1 + 1 + strlen(
id);
292 if (
len + this->header_.size() + this->data_.size() > MAX_PACKET_SIZE) {
295 add(this->data_, key);
296 add(this->data_, data);
297 add(this->data_,
id);
304 for (
auto &
sensor : this->sensors_) {
305 if (all ||
sensor.updated) {
311 #ifdef USE_BINARY_SENSOR 312 for (
auto &
sensor : this->binary_sensors_) {
313 if (all ||
sensor.updated) {
320 this->updated_ =
false;
321 this->resend_data_ =
false;
325 this->updated_ =
true;
326 this->resend_data_ = this->should_send_;
327 auto now =
millis() / 1000;
328 if (this->last_key_time_ + this->ping_pong_recyle_time_ < now) {
329 this->resend_ping_key_ = this->ping_pong_enable_;
330 this->last_key_time_ = now;
335 uint8_t buf[MAX_PACKET_SIZE];
336 if (this->should_listen_) {
338 #if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) 339 auto len = this->listen_socket_->read(buf,
sizeof(buf));
341 #ifdef USE_SOCKET_IMPL_LWIP_TCP 342 auto len = this->udp_client_.parsePacket();
344 len = this->udp_client_.read(buf,
sizeof(buf));
347 this->process_(buf,
len);
353 if (this->resend_ping_key_)
354 this->send_ping_pong_request_();
355 if (this->updated_) {
356 this->send_data_(this->resend_data_);
361 if (!this->is_encrypted_())
363 if (this->ping_keys_.count(name) == 0 && this->ping_keys_.size() == MAX_PING_KEYS) {
364 ESP_LOGW(TAG,
"Ping key from %s discarded", name);
367 this->ping_keys_[
name] = key;
368 this->resend_data_ =
true;
369 ESP_LOGV(TAG,
"Ping key from %s now %X", name, (
unsigned) key);
374 ESP_LOGW(TAG,
"Bad ping request");
377 auto key = get_uint32(ptr);
378 this->add_key_(name, key);
379 ESP_LOGV(TAG,
"Updated ping key for %s to %08X", name, (
unsigned) key);
382 static bool process_rolling_code(
Provider &provider, uint8_t *&buf,
const uint8_t *
end) {
385 auto code0 = get_uint32(buf);
386 auto code1 = get_uint32(buf);
388 ESP_LOGW(TAG,
"Rolling code for %s %08lX:%08lX is old", provider.
name, (
unsigned long) code1,
389 (
unsigned long) code0);
401 auto ping_key_seen = !this->ping_pong_enable_;
403 ESP_LOGV(TAG,
"Bad length %zu", len);
408 uint8_t *start_ptr = buf;
409 const uint8_t *end = buf +
len;
411 auto magic = get_uint16(buf);
412 if (magic != MAGIC_NUMBER && magic != MAGIC_PING) {
413 ESP_LOGV(TAG,
"Bad magic %X", magic);
418 if (hlen > len - 3) {
419 ESP_LOGV(TAG,
"Bad hostname length %u > %zu", hlen, len - 3);
422 memcpy(namebuf, buf, hlen);
423 if (strcmp(this->name_, namebuf) == 0) {
424 ESP_LOGV(TAG,
"Ignoring our own data");
428 if (magic == MAGIC_PING) {
429 this->process_ping_request_(namebuf, buf, end - buf);
432 if (round4(len) != len) {
433 ESP_LOGW(TAG,
"Bad length %zu", len);
436 hlen = round4(hlen + 3);
437 buf = start_ptr + hlen;
439 ESP_LOGV(TAG,
"No data after header");
443 if (this->providers_.count(namebuf) == 0) {
444 ESP_LOGVV(TAG,
"Unknown hostname %s", namebuf);
447 auto &provider = this->providers_[namebuf];
450 ping_key_seen =
true;
452 ESP_LOGV(TAG,
"Found hostname %s", namebuf);
454 auto &sensors = this->remote_sensors_[namebuf];
456 #ifdef USE_BINARY_SENSOR 457 auto &binary_sensors = this->remote_binary_sensors_[namebuf];
465 if (!process_rolling_code(provider, buf, end))
468 ESP_LOGV(TAG,
"Expected rolling_key or data_key, got %X", byte);
477 ESP_LOGV(TAG,
"PING_KEY requires 4 more bytes");
480 auto key = get_uint32(buf);
481 if (key == this->ping_key_) {
482 ping_key_seen =
true;
483 ESP_LOGV(TAG,
"Found good ping key %X", (
unsigned) key);
485 ESP_LOGV(TAG,
"Unknown ping key %X", (
unsigned) key);
489 if (!ping_key_seen) {
490 ESP_LOGW(TAG,
"Ping key not seen");
491 this->resend_ping_key_ =
true;
496 ESP_LOGV(TAG,
"Binary sensor key requires at least 3 more bytes");
502 ESP_LOGV(TAG,
"Sensor key requires at least 6 more bytes");
505 rdata.u32 = get_uint32(buf);
507 ESP_LOGW(TAG,
"Unknown key byte %X", byte);
512 if (end - buf < hlen) {
513 ESP_LOGV(TAG,
"Name length of %u not available", hlen);
516 memset(namebuf, 0,
sizeof namebuf);
517 memcpy(namebuf, buf, hlen);
518 ESP_LOGV(TAG,
"Found sensor key %d, id %s, data %lX", byte, namebuf, (
unsigned long) rdata.u32);
521 if (byte ==
SENSOR_KEY && sensors.count(namebuf) != 0)
522 sensors[namebuf]->publish_state(rdata.f32);
524 #ifdef USE_BINARY_SENSOR 526 binary_sensors[namebuf]->publish_state(rdata.u32 != 0);
532 ESP_LOGCONFIG(TAG,
"UDP:");
533 ESP_LOGCONFIG(TAG,
" Port: %u", this->port_);
534 ESP_LOGCONFIG(TAG,
" Encrypted: %s", YESNO(this->is_encrypted_()));
535 ESP_LOGCONFIG(TAG,
" Ping-pong: %s", YESNO(this->ping_pong_enable_));
536 for (
const auto &
address : this->addresses_)
537 ESP_LOGCONFIG(TAG,
" Address: %s",
address.c_str());
538 if (this->listen_address_.has_value()) {
539 ESP_LOGCONFIG(TAG,
" Listen address: %s", this->listen_address_.value().str().c_str());
542 for (
auto sensor : this->sensors_)
543 ESP_LOGCONFIG(TAG,
" Sensor: %s",
sensor.id);
545 #ifdef USE_BINARY_SENSOR 546 for (
auto sensor : this->binary_sensors_)
547 ESP_LOGCONFIG(TAG,
" Binary Sensor: %s",
sensor.id);
549 for (
const auto &host : this->providers_) {
550 ESP_LOGCONFIG(TAG,
" Remote host: %s", host.first.c_str());
551 ESP_LOGCONFIG(TAG,
" Encrypted: %s", YESNO(!host.second.encryption_key.empty()));
553 for (
const auto &
sensor : this->remote_sensors_[host.first.c_str()])
554 ESP_LOGCONFIG(TAG,
" Sensor: %s",
sensor.first.c_str());
556 #ifdef USE_BINARY_SENSOR 557 for (
const auto &
sensor : this->remote_binary_sensors_[host.first.c_str()])
558 ESP_LOGCONFIG(TAG,
" Binary Sensor: %s",
sensor.first.c_str());
563 if (this->rolling_code_enable_) {
564 if (++this->rolling_code_[0] == 0) {
565 this->rolling_code_[1]++;
566 this->pref_.save(&this->rolling_code_[1]);
571 #if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) 572 for (
const auto &saddr : this->sockaddrs_) {
573 auto result = this->broadcast_socket_->sendto(data, len, 0, &saddr,
sizeof(saddr));
575 ESP_LOGW(TAG,
"sendto() error %d", errno);
578 #ifdef USE_SOCKET_IMPL_LWIP_TCP 579 auto iface = IPAddress(0, 0, 0, 0);
580 for (
const auto &saddr : this->ipaddrs_) {
581 if (this->udp_client_.beginPacketMulticast(saddr, this->port_, iface, 128) != 0) {
582 this->udp_client_.write((
const uint8_t *) data, len);
583 auto result = this->udp_client_.endPacket();
585 ESP_LOGW(TAG,
"udp.write() error");
595 this->ping_header_.clear();
596 add(this->ping_header_, MAGIC_PING);
597 add(this->ping_header_, this->name_);
598 add(this->ping_header_, this->ping_key_);
599 this->send_packet_(this->ping_header_.data(), this->ping_header_.size());
600 this->resend_ping_key_ =
false;
601 ESP_LOGV(TAG,
"Sent new ping request %08X", (
unsigned) this->ping_key_);
void add_on_state_callback(std::function< void(float)> &&callback)
Add a callback that will be called every time a filtered value arrives.
void encrypt(uint32_t *v, size_t n, const uint32_t *k)
Encrypt a block of data in-place using XXTEA algorithm with 256-bit key.
std::vector< uint8_t > encryption_key
void decrypt(uint32_t *v, size_t n, const uint32_t *k)
Decrypt a block of data in-place using XXTEA algorithm with 256-bit key.
uint32_t random_uint32()
Return a random 32-bit unsigned integer.
void add_binary_data_(uint8_t key, const char *id, bool data)
bool is_connected()
Return whether the node is connected to the network (through wifi, eth, ...)
uint32_t IRAM_ATTR HOT millis()
void send_data_(bool all)
float state
This member variable stores the last state that has passed through all filters.
void process_(uint8_t *buf, size_t len)
Process a received packet.
ESPPreferences * global_preferences
void dump_config() override
void add_key_(const char *name, uint32_t key)
Application App
Global storage of Application pointer - only one Application can exist.
const std::string & get_name() const
Get the name of this Application set by pre_setup().
void send_packet_(void *data, size_t len)
float get_state() const
Getter-syntax for .state.
virtual ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash)=0
Implementation of SPI Controller mode.
void add_data_(uint8_t key, const char *id, float data)
void send_ping_pong_request_()
void process_ping_request_(const char *name, uint8_t *ptr, size_t len)
socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const std::string &ip_address, uint16_t port)
Set a sockaddr to the specified address and port for the IP version used by socket_ip().
esphome::sensor::Sensor * sensor
std::unique_ptr< Socket > socket(int domain, int type, int protocol)
Create a socket of the given domain, type and protocol.