mirror of
https://github.com/esphome/esphome.git
synced 2025-02-13 00:18:21 +00:00
88 lines
3.0 KiB
C++
88 lines
3.0 KiB
C++
#include "wake_on_lan.h"
|
|
#include "esphome/core/log.h"
|
|
#include "esphome/components/network/ip_address.h"
|
|
#include "esphome/components/network/util.h"
|
|
|
|
namespace esphome {
|
|
namespace wake_on_lan {
|
|
|
|
static const char *const TAG = "wake_on_lan.button";
|
|
static const uint8_t PREFIX[6] = {255, 255, 255, 255, 255, 255};
|
|
|
|
void WakeOnLanButton::set_macaddr(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f) {
|
|
macaddr_[0] = a;
|
|
macaddr_[1] = b;
|
|
macaddr_[2] = c;
|
|
macaddr_[3] = d;
|
|
macaddr_[4] = e;
|
|
macaddr_[5] = f;
|
|
}
|
|
|
|
void WakeOnLanButton::dump_config() {
|
|
LOG_BUTTON("", "Wake-on-LAN Button", this);
|
|
ESP_LOGCONFIG(TAG, " Target MAC address: %02X:%02X:%02X:%02X:%02X:%02X", this->macaddr_[0], this->macaddr_[1],
|
|
this->macaddr_[2], this->macaddr_[3], this->macaddr_[4], this->macaddr_[5]);
|
|
}
|
|
|
|
void WakeOnLanButton::press_action() {
|
|
if (!network::is_connected()) {
|
|
ESP_LOGW(TAG, "Network not connected");
|
|
return;
|
|
}
|
|
ESP_LOGI(TAG, "Sending Wake-on-LAN Packet...");
|
|
#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
|
|
struct sockaddr_storage saddr {};
|
|
auto addr_len =
|
|
socket::set_sockaddr(reinterpret_cast<sockaddr *>(&saddr), sizeof(saddr), "255.255.255.255", this->port_);
|
|
uint8_t buffer[6 + sizeof this->macaddr_ * 16];
|
|
memcpy(buffer, PREFIX, sizeof(PREFIX));
|
|
for (size_t i = 0; i != 16; i++) {
|
|
memcpy(buffer + i * sizeof(this->macaddr_) + sizeof(PREFIX), this->macaddr_, sizeof(this->macaddr_));
|
|
}
|
|
if (this->broadcast_socket_->sendto(buffer, sizeof(buffer), 0, reinterpret_cast<const sockaddr *>(&saddr),
|
|
addr_len) <= 0)
|
|
ESP_LOGW(TAG, "sendto() error %d", errno);
|
|
#else
|
|
IPAddress broadcast = IPAddress(255, 255, 255, 255);
|
|
for (auto ip : esphome::network::get_ip_addresses()) {
|
|
if (ip.is_ip4()) {
|
|
if (this->udp_client_.beginPacketMulticast(broadcast, 9, ip, 128) != 0) {
|
|
this->udp_client_.write(PREFIX, 6);
|
|
for (size_t i = 0; i < 16; i++) {
|
|
this->udp_client_.write(macaddr_, 6);
|
|
}
|
|
if (this->udp_client_.endPacket() != 0)
|
|
return;
|
|
ESP_LOGW(TAG, "WOL broadcast failed");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
ESP_LOGW(TAG, "No ip4 addresses to broadcast to");
|
|
#endif
|
|
}
|
|
|
|
void WakeOnLanButton::setup() {
|
|
#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
|
|
this->broadcast_socket_ = socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
|
|
if (this->broadcast_socket_ == nullptr) {
|
|
this->mark_failed();
|
|
this->status_set_error("Could not create socket");
|
|
return;
|
|
}
|
|
int enable = 1;
|
|
auto err = this->broadcast_socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
|
|
if (err != 0) {
|
|
this->status_set_warning("Socket unable to set reuseaddr");
|
|
// we can still continue
|
|
}
|
|
err = this->broadcast_socket_->setsockopt(SOL_SOCKET, SO_BROADCAST, &enable, sizeof(int));
|
|
if (err != 0) {
|
|
this->status_set_warning("Socket unable to set broadcast");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
} // namespace wake_on_lan
|
|
} // namespace esphome
|