mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	[espnow] Add transport platform for packet_transport (#11025)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							03def13917
						
					
				
				
					commit
					ca2fe994a1
				
			| @@ -161,6 +161,7 @@ esphome/components/esp32_rmt_led_strip/* @jesserockz | |||||||
| esphome/components/esp8266/* @esphome/core | esphome/components/esp8266/* @esphome/core | ||||||
| esphome/components/esp_ldo/* @clydebarrow | esphome/components/esp_ldo/* @clydebarrow | ||||||
| esphome/components/espnow/* @jesserockz | esphome/components/espnow/* @jesserockz | ||||||
|  | esphome/components/espnow/packet_transport/* @EasilyBoredEngineer | ||||||
| esphome/components/ethernet_info/* @gtjadsonsantos | esphome/components/ethernet_info/* @gtjadsonsantos | ||||||
| esphome/components/event/* @nohat | esphome/components/event/* @nohat | ||||||
| esphome/components/exposure_notifications/* @OttoWinter | esphome/components/exposure_notifications/* @OttoWinter | ||||||
|   | |||||||
							
								
								
									
										39
									
								
								esphome/components/espnow/packet_transport/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								esphome/components/espnow/packet_transport/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  | """ESP-NOW transport platform for packet_transport component.""" | ||||||
|  |  | ||||||
|  | import esphome.codegen as cg | ||||||
|  | from esphome.components.packet_transport import ( | ||||||
|  |     PacketTransport, | ||||||
|  |     new_packet_transport, | ||||||
|  |     transport_schema, | ||||||
|  | ) | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.core import HexInt | ||||||
|  | from esphome.cpp_types import PollingComponent | ||||||
|  |  | ||||||
|  | from .. import ESPNowComponent, espnow_ns | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@EasilyBoredEngineer"] | ||||||
|  | DEPENDENCIES = ["espnow"] | ||||||
|  |  | ||||||
|  | ESPNowTransport = espnow_ns.class_("ESPNowTransport", PacketTransport, PollingComponent) | ||||||
|  |  | ||||||
|  | CONF_ESPNOW_ID = "espnow_id" | ||||||
|  | CONF_PEER_ADDRESS = "peer_address" | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = transport_schema(ESPNowTransport).extend( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(CONF_ESPNOW_ID): cv.use_id(ESPNowComponent), | ||||||
|  |         cv.Optional(CONF_PEER_ADDRESS, default="FF:FF:FF:FF:FF:FF"): cv.mac_address, | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     """Set up the ESP-NOW transport component.""" | ||||||
|  |     var, _ = await new_packet_transport(config) | ||||||
|  |  | ||||||
|  |     await cg.register_parented(var, config[CONF_ESPNOW_ID]) | ||||||
|  |  | ||||||
|  |     # Set peer address - convert MAC to parts array like ESP-NOW does | ||||||
|  |     mac = config[CONF_PEER_ADDRESS] | ||||||
|  |     cg.add(var.set_peer_address([HexInt(x) for x in mac.parts])) | ||||||
| @@ -0,0 +1,97 @@ | |||||||
|  | #include "espnow_transport.h" | ||||||
|  |  | ||||||
|  | #ifdef USE_ESP32 | ||||||
|  |  | ||||||
|  | #include "esphome/core/application.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace espnow { | ||||||
|  |  | ||||||
|  | static const char *const TAG = "espnow.transport"; | ||||||
|  |  | ||||||
|  | bool ESPNowTransport::should_send() { return this->parent_ != nullptr && !this->parent_->is_failed(); } | ||||||
|  |  | ||||||
|  | void ESPNowTransport::setup() { | ||||||
|  |   packet_transport::PacketTransport::setup(); | ||||||
|  |  | ||||||
|  |   if (this->parent_ == nullptr) { | ||||||
|  |     ESP_LOGE(TAG, "ESPNow component not set"); | ||||||
|  |     this->mark_failed(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ESP_LOGI(TAG, "Registering ESP-NOW handlers"); | ||||||
|  |   ESP_LOGI(TAG, "Peer address: %02X:%02X:%02X:%02X:%02X:%02X", this->peer_address_[0], this->peer_address_[1], | ||||||
|  |            this->peer_address_[2], this->peer_address_[3], this->peer_address_[4], this->peer_address_[5]); | ||||||
|  |  | ||||||
|  |   // Register received handler | ||||||
|  |   this->parent_->register_received_handler(static_cast<ESPNowReceivedPacketHandler *>(this)); | ||||||
|  |  | ||||||
|  |   // Register broadcasted handler | ||||||
|  |   this->parent_->register_broadcasted_handler(static_cast<ESPNowBroadcastedHandler *>(this)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ESPNowTransport::update() { | ||||||
|  |   packet_transport::PacketTransport::update(); | ||||||
|  |   this->updated_ = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ESPNowTransport::send_packet(const std::vector<uint8_t> &buf) const { | ||||||
|  |   if (this->parent_ == nullptr) { | ||||||
|  |     ESP_LOGE(TAG, "ESPNow component not set"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (buf.empty()) { | ||||||
|  |     ESP_LOGW(TAG, "Attempted to send empty packet"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (buf.size() > ESP_NOW_MAX_DATA_LEN) { | ||||||
|  |     ESP_LOGE(TAG, "Packet too large: %zu bytes (max %d)", buf.size(), ESP_NOW_MAX_DATA_LEN); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Send to configured peer address | ||||||
|  |   this->parent_->send(this->peer_address_.data(), buf.data(), buf.size(), [](esp_err_t err) { | ||||||
|  |     if (err != ESP_OK) { | ||||||
|  |       ESP_LOGW(TAG, "Send failed: %d", err); | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool ESPNowTransport::on_received(const ESPNowRecvInfo &info, const uint8_t *data, uint8_t size) { | ||||||
|  |   ESP_LOGV(TAG, "Received packet of size %u from %02X:%02X:%02X:%02X:%02X:%02X", size, info.src_addr[0], | ||||||
|  |            info.src_addr[1], info.src_addr[2], info.src_addr[3], info.src_addr[4], info.src_addr[5]); | ||||||
|  |  | ||||||
|  |   if (data == nullptr || size == 0) { | ||||||
|  |     ESP_LOGW(TAG, "Received empty or null packet"); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->packet_buffer_.resize(size); | ||||||
|  |   memcpy(this->packet_buffer_.data(), data, size); | ||||||
|  |   this->process_(this->packet_buffer_); | ||||||
|  |   return false;  // Allow other handlers to run | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool ESPNowTransport::on_broadcasted(const ESPNowRecvInfo &info, const uint8_t *data, uint8_t size) { | ||||||
|  |   ESP_LOGV(TAG, "Received broadcast packet of size %u from %02X:%02X:%02X:%02X:%02X:%02X", size, info.src_addr[0], | ||||||
|  |            info.src_addr[1], info.src_addr[2], info.src_addr[3], info.src_addr[4], info.src_addr[5]); | ||||||
|  |  | ||||||
|  |   if (data == nullptr || size == 0) { | ||||||
|  |     ESP_LOGW(TAG, "Received empty or null broadcast packet"); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->packet_buffer_.resize(size); | ||||||
|  |   memcpy(this->packet_buffer_.data(), data, size); | ||||||
|  |   this->process_(this->packet_buffer_); | ||||||
|  |   return false;  // Allow other handlers to run | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace espnow | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif  // USE_ESP32 | ||||||
| @@ -0,0 +1,44 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "../espnow_component.h" | ||||||
|  |  | ||||||
|  | #ifdef USE_ESP32 | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/components/packet_transport/packet_transport.h" | ||||||
|  |  | ||||||
|  | #include <vector> | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace espnow { | ||||||
|  |  | ||||||
|  | class ESPNowTransport : public packet_transport::PacketTransport, | ||||||
|  |                         public Parented<ESPNowComponent>, | ||||||
|  |                         public ESPNowReceivedPacketHandler, | ||||||
|  |                         public ESPNowBroadcastedHandler { | ||||||
|  |  public: | ||||||
|  |   void setup() override; | ||||||
|  |   void update() override; | ||||||
|  |   float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } | ||||||
|  |  | ||||||
|  |   void set_peer_address(peer_address_t address) { | ||||||
|  |     memcpy(this->peer_address_.data(), address.data(), ESP_NOW_ETH_ALEN); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // ESPNow handler interface | ||||||
|  |   bool on_received(const ESPNowRecvInfo &info, const uint8_t *data, uint8_t size) override; | ||||||
|  |   bool on_broadcasted(const ESPNowRecvInfo &info, const uint8_t *data, uint8_t size) override; | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   void send_packet(const std::vector<uint8_t> &buf) const override; | ||||||
|  |   size_t get_max_packet_size() override { return ESP_NOW_MAX_DATA_LEN; } | ||||||
|  |   bool should_send() override; | ||||||
|  |  | ||||||
|  |   peer_address_t peer_address_{{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}; | ||||||
|  |   std::vector<uint8_t> packet_buffer_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace espnow | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif  // USE_ESP32 | ||||||
| @@ -1,4 +1,5 @@ | |||||||
| espnow: | espnow: | ||||||
|  |   id: espnow_component | ||||||
|   auto_add_peer: false |   auto_add_peer: false | ||||||
|   channel: 1 |   channel: 1 | ||||||
|   peers: |   peers: | ||||||
| @@ -50,3 +51,26 @@ espnow: | |||||||
|           - format_mac_address_pretty(info.src_addr).c_str() |           - format_mac_address_pretty(info.src_addr).c_str() | ||||||
|           - format_hex_pretty(data, size).c_str() |           - format_hex_pretty(data, size).c_str() | ||||||
|           - info.rx_ctrl->rssi |           - info.rx_ctrl->rssi | ||||||
|  |  | ||||||
|  | packet_transport: | ||||||
|  |   - platform: espnow | ||||||
|  |     id: transport1 | ||||||
|  |     espnow_id: espnow_component | ||||||
|  |     peer_address: "FF:FF:FF:FF:FF:FF" | ||||||
|  |     encryption: | ||||||
|  |       key: "0123456789abcdef0123456789abcdef" | ||||||
|  |     sensors: | ||||||
|  |       - temp_sensor | ||||||
|  |     providers: | ||||||
|  |       - name: test_provider | ||||||
|  |         encryption: | ||||||
|  |           key: "0123456789abcdef0123456789abcdef" | ||||||
|  |  | ||||||
|  | sensor: | ||||||
|  |   - platform: internal_temperature | ||||||
|  |     id: temp_sensor | ||||||
|  |  | ||||||
|  |   - platform: packet_transport | ||||||
|  |     provider: test_provider | ||||||
|  |     remote_id: temp_sensor | ||||||
|  |     id: remote_temp | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user