ESPHome  2024.11.0
wake_on_lan.cpp
Go to the documentation of this file.
1 #include "wake_on_lan.h"
2 #ifdef USE_NETWORK
3 #include "esphome/core/log.h"
6 
7 namespace esphome {
8 namespace wake_on_lan {
9 
10 static const char *const TAG = "wake_on_lan.button";
11 static const uint8_t PREFIX[6] = {255, 255, 255, 255, 255, 255};
12 
13 void WakeOnLanButton::set_macaddr(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f) {
14  macaddr_[0] = a;
15  macaddr_[1] = b;
16  macaddr_[2] = c;
17  macaddr_[3] = d;
18  macaddr_[4] = e;
19  macaddr_[5] = f;
20 }
21 
23  LOG_BUTTON("", "Wake-on-LAN Button", this);
24  ESP_LOGCONFIG(TAG, " Target MAC address: %02X:%02X:%02X:%02X:%02X:%02X", this->macaddr_[0], this->macaddr_[1],
25  this->macaddr_[2], this->macaddr_[3], this->macaddr_[4], this->macaddr_[5]);
26 }
27 
29  if (!network::is_connected()) {
30  ESP_LOGW(TAG, "Network not connected");
31  return;
32  }
33  ESP_LOGI(TAG, "Sending Wake-on-LAN Packet...");
34 #if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
35  struct sockaddr_storage saddr {};
36  auto addr_len =
37  socket::set_sockaddr(reinterpret_cast<sockaddr *>(&saddr), sizeof(saddr), "255.255.255.255", this->port_);
38  uint8_t buffer[6 + sizeof this->macaddr_ * 16];
39  memcpy(buffer, PREFIX, sizeof(PREFIX));
40  for (size_t i = 0; i != 16; i++) {
41  memcpy(buffer + i * sizeof(this->macaddr_) + sizeof(PREFIX), this->macaddr_, sizeof(this->macaddr_));
42  }
43  if (this->broadcast_socket_->sendto(buffer, sizeof(buffer), 0, reinterpret_cast<const sockaddr *>(&saddr),
44  addr_len) <= 0)
45  ESP_LOGW(TAG, "sendto() error %d", errno);
46 #else
47  IPAddress broadcast = IPAddress(255, 255, 255, 255);
48  for (auto ip : esphome::network::get_ip_addresses()) {
49  if (ip.is_ip4()) {
50  if (this->udp_client_.beginPacketMulticast(broadcast, 9, ip, 128) != 0) {
51  this->udp_client_.write(PREFIX, 6);
52  for (size_t i = 0; i < 16; i++) {
53  this->udp_client_.write(macaddr_, 6);
54  }
55  if (this->udp_client_.endPacket() != 0)
56  return;
57  ESP_LOGW(TAG, "WOL broadcast failed");
58  return;
59  }
60  }
61  }
62  ESP_LOGW(TAG, "No ip4 addresses to broadcast to");
63 #endif
64 }
65 
67 #if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
68  this->broadcast_socket_ = socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
69  if (this->broadcast_socket_ == nullptr) {
70  this->mark_failed();
71  this->status_set_error("Could not create socket");
72  return;
73  }
74  int enable = 1;
75  auto err = this->broadcast_socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
76  if (err != 0) {
77  this->status_set_warning("Socket unable to set reuseaddr");
78  // we can still continue
79  }
80  err = this->broadcast_socket_->setsockopt(SOL_SOCKET, SO_BROADCAST, &enable, sizeof(int));
81  if (err != 0) {
82  this->status_set_warning("Socket unable to set broadcast");
83  }
84 #endif
85 }
86 
87 } // namespace wake_on_lan
88 } // namespace esphome
89 #endif
void set_macaddr(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f)
Definition: wake_on_lan.cpp:13
void status_set_warning(const char *message="unspecified")
Definition: component.cpp:151
bool is_connected()
Return whether the node is connected to the network (through wifi, eth, ...)
Definition: util.cpp:15
network::IPAddresses get_ip_addresses()
Definition: util.cpp:40
void status_set_error(const char *message="unspecified")
Definition: component.cpp:159
std::unique_ptr< socket::Socket > broadcast_socket_
Definition: wake_on_lan.h:25
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:118
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
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().
Definition: socket.cpp:21
std::unique_ptr< Socket > socket(int domain, int type, int protocol)
Create a socket of the given domain, type and protocol.