mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-26 12:43:48 +00:00 
			
		
		
		
	[wake_on_lan] Make component platform independent (#6815)
This commit is contained in:
		| @@ -414,7 +414,7 @@ esphome/components/veml3235/* @kbx81 | ||||
| esphome/components/veml7700/* @latonita | ||||
| esphome/components/version/* @esphome/core | ||||
| esphome/components/voice_assistant/* @jesserockz | ||||
| esphome/components/wake_on_lan/* @willwill2will54 | ||||
| esphome/components/wake_on_lan/* @clydebarrow @willwill2will54 | ||||
| esphome/components/waveshare_epaper/* @clydebarrow | ||||
| esphome/components/web_server_base/* @OttoWinter | ||||
| esphome/components/web_server_idf/* @dentra | ||||
|   | ||||
| @@ -469,7 +469,8 @@ class LWIPRawImpl : public Socket { | ||||
|   } | ||||
|   ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) override { | ||||
|     // return ::sendto(fd_, buf, len, flags, to, tolen); | ||||
|     return 0; | ||||
|     errno = ENOSYS; | ||||
|     return -1; | ||||
|   } | ||||
|   int setblocking(bool blocking) override { | ||||
|     if (pcb_ == nullptr) { | ||||
|   | ||||
| @@ -1 +1 @@ | ||||
| CODEOWNERS = ["@willwill2will54"] | ||||
| CODEOWNERS = ["@willwill2will54", "@clydebarrow"] | ||||
|   | ||||
| @@ -2,6 +2,16 @@ import esphome.codegen as cg | ||||
| from esphome.components import button | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_ID | ||||
| from esphome.core import CORE | ||||
|  | ||||
| DEPENDENCIES = ["network"] | ||||
|  | ||||
|  | ||||
| def AUTO_LOAD(): | ||||
|     if CORE.is_esp8266 or CORE.is_rp2040: | ||||
|         return [] | ||||
|     return ["socket"] | ||||
|  | ||||
|  | ||||
| CONF_TARGET_MAC_ADDRESS = "target_mac_address" | ||||
|  | ||||
| @@ -9,25 +19,19 @@ wake_on_lan_ns = cg.esphome_ns.namespace("wake_on_lan") | ||||
|  | ||||
| WakeOnLanButton = wake_on_lan_ns.class_("WakeOnLanButton", button.Button, cg.Component) | ||||
|  | ||||
| DEPENDENCIES = ["network"] | ||||
|  | ||||
| CONFIG_SCHEMA = cv.All( | ||||
| CONFIG_SCHEMA = ( | ||||
|     button.button_schema(WakeOnLanButton) | ||||
|     .extend(cv.COMPONENT_SCHEMA) | ||||
|     .extend( | ||||
|         cv.Schema( | ||||
|             { | ||||
|                 cv.Required(CONF_TARGET_MAC_ADDRESS): cv.mac_address, | ||||
|             } | ||||
|         ), | ||||
|     ), | ||||
|     cv.only_with_arduino, | ||||
|         { | ||||
|             cv.Required(CONF_TARGET_MAC_ADDRESS): cv.mac_address, | ||||
|         } | ||||
|     ) | ||||
| ) | ||||
|  | ||||
|  | ||||
| def to_code(config): | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|  | ||||
|     yield cg.add(var.set_macaddr(*config[CONF_TARGET_MAC_ADDRESS].parts)) | ||||
|     yield cg.register_component(var, config) | ||||
|     yield button.register_button(var, config) | ||||
|     cg.add(var.set_macaddr(*config[CONF_TARGET_MAC_ADDRESS].parts)) | ||||
|     await cg.register_component(var, config) | ||||
|     await button.register_button(var, config) | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| #ifdef USE_ARDUINO | ||||
|  | ||||
| #include "wake_on_lan.h" | ||||
| #include "esphome/core/log.h" | ||||
| #include "esphome/components/network/ip_address.h" | ||||
| @@ -22,40 +20,68 @@ void WakeOnLanButton::set_macaddr(uint8_t a, uint8_t b, uint8_t c, uint8_t d, ui | ||||
|  | ||||
| void WakeOnLanButton::dump_config() { | ||||
|   LOG_BUTTON("", "Wake-on-LAN Button", this); | ||||
|   ESP_LOGCONFIG(TAG, "  Target MAC address: %02X:%02X:%02X:%02X:%02X:%02X", macaddr_[0], macaddr_[1], macaddr_[2], | ||||
|                 macaddr_[3], macaddr_[4], macaddr_[5]); | ||||
|   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..."); | ||||
|   bool begin_status = false; | ||||
|   bool end_status = false; | ||||
| #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); | ||||
| #ifdef USE_ESP8266 | ||||
|   for (auto ip : esphome::network::get_ip_addresses()) { | ||||
|     if (ip.is_ip4()) { | ||||
|       begin_status = this->udp_client_.beginPacketMulticast(broadcast, 9, ip, 128); | ||||
|       break; | ||||
|       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 | ||||
| #ifdef USE_ESP32 | ||||
|   begin_status = this->udp_client_.beginPacket(broadcast, 9); | ||||
| #endif | ||||
| } | ||||
|  | ||||
|   if (begin_status) { | ||||
|     this->udp_client_.write(PREFIX, 6); | ||||
|     for (size_t i = 0; i < 16; i++) { | ||||
|       this->udp_client_.write(macaddr_, 6); | ||||
|     } | ||||
|     end_status = this->udp_client_.endPacket(); | ||||
| 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; | ||||
|   } | ||||
|   if (!begin_status || end_status) { | ||||
|     ESP_LOGE(TAG, "Sending Wake-on-LAN Packet Failed!"); | ||||
|   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 | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -1,10 +1,12 @@ | ||||
| #pragma once | ||||
|  | ||||
| #ifdef USE_ARDUINO | ||||
|  | ||||
| #include "esphome/components/button/button.h" | ||||
| #include "esphome/core/component.h" | ||||
| #if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) | ||||
| #include "esphome/components/socket/socket.h" | ||||
| #else | ||||
| #include "WiFiUdp.h" | ||||
| #endif | ||||
|  | ||||
| namespace esphome { | ||||
| namespace wake_on_lan { | ||||
| @@ -14,14 +16,19 @@ class WakeOnLanButton : public button::Button, public Component { | ||||
|   void set_macaddr(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f); | ||||
|  | ||||
|   void dump_config() override; | ||||
|   void setup() override; | ||||
|   float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } | ||||
|  | ||||
|  protected: | ||||
| #if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) | ||||
|   std::unique_ptr<socket::Socket> broadcast_socket_{}; | ||||
| #else | ||||
|   WiFiUDP udp_client_{}; | ||||
| #endif | ||||
|   void press_action() override; | ||||
|   uint16_t port_{9}; | ||||
|   uint8_t macaddr_[6]; | ||||
| }; | ||||
|  | ||||
| }  // namespace wake_on_lan | ||||
| }  // namespace esphome | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										1
									
								
								tests/components/wake_on_lan/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/components/wake_on_lan/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| <<: !include common.yaml | ||||
							
								
								
									
										1
									
								
								tests/components/wake_on_lan/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/components/wake_on_lan/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| <<: !include common.yaml | ||||
		Reference in New Issue
	
	Block a user