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/esp_ldo/* @clydebarrow | ||||
| esphome/components/espnow/* @jesserockz | ||||
| esphome/components/espnow/packet_transport/* @EasilyBoredEngineer | ||||
| esphome/components/ethernet_info/* @gtjadsonsantos | ||||
| esphome/components/event/* @nohat | ||||
| 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: | ||||
|   id: espnow_component | ||||
|   auto_add_peer: false | ||||
|   channel: 1 | ||||
|   peers: | ||||
| @@ -50,3 +51,26 @@ espnow: | ||||
|           - format_mac_address_pretty(info.src_addr).c_str() | ||||
|           - format_hex_pretty(data, size).c_str() | ||||
|           - 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