From 4ed30edf3a78707f495dc250bd48a71cf4d57297 Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Sun, 24 Nov 2024 17:54:32 +0100 Subject: [PATCH] add option to modify the wifi_channel per peer --- esphome/components/espnow/__init__.py | 15 ++++++++-- esphome/components/espnow/espnow.cpp | 42 ++++++++++++++++++++++----- esphome/components/espnow/espnow.h | 16 ++++++---- esphome/components/espnow/test1.yaml | 2 ++ 4 files changed, 59 insertions(+), 16 deletions(-) diff --git a/esphome/components/espnow/__init__.py b/esphome/components/espnow/__init__.py index c6490fa1e1..b90c940181 100644 --- a/esphome/components/espnow/__init__.py +++ b/esphome/components/espnow/__init__.py @@ -88,6 +88,7 @@ DEFINE_PEER_CONFIG = cv.maybe_simple_value( { cv.Optional(CONF_PEER_ID): cv.declare_id(ESPNowPeer), cv.Required(CONF_MAC_ADDRESS): cv.mac_address, + cv.Optional(CONF_WIFI_CHANNEL): cv.int_range(0, 14), }, key=CONF_MAC_ADDRESS, ) @@ -96,7 +97,7 @@ DEFINE_PEER_CONFIG = cv.maybe_simple_value( CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(ESPNowComponent), - cv.Optional(CONF_WIFI_CHANNEL, default=0): cv.int_range(0, 14), + cv.Optional(CONF_WIFI_CHANNEL): cv.int_range(0, 14), cv.Optional(CONF_AUTO_ADD_PEER, default=False): cv.boolean, cv.Optional(CONF_USE_SENT_CHECK, default=True): cv.boolean, cv.Optional( @@ -141,8 +142,9 @@ async def to_code(config): cg.add_library("WiFi", None) cg.add_define("USE_ESPNOW") + if CONF_WIFI_CHANNEL in config: + cg.add(var.set_wifi_channel(config[CONF_WIFI_CHANNEL])) - cg.add(var.set_wifi_channel(config[CONF_WIFI_CHANNEL])) cg.add(var.set_auto_add_peer(config[CONF_AUTO_ADD_PEER])) cg.add(var.set_use_sent_check(config[CONF_USE_SENT_CHECK])) cg.add(var.set_conformation_timeout(config[CONF_CONFORMATION_TIMEOUT])) @@ -152,7 +154,11 @@ async def to_code(config): mac = espnow_hex(conf.get(CONF_MAC_ADDRESS)) if CONF_PEER_ID in conf: cg.new_variable(conf[CONF_PEER_ID], mac) - cg.add(var.add_peer(mac)) + + if CONF_WIFI_CHANNEL in conf: + cg.add(var.add_peer(mac, conf[CONF_WIFI_CHANNEL])) + else: + cg.add(var.add_peer(mac)) for conf in config.get(CONF_ON_SENT, []): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) @@ -276,6 +282,7 @@ async def send_action(config, action_id, template_arg, args): { cv.GenerateID(): cv.use_id(ESPNowComponent), cv.Required(CONF_MAC_ADDRESS): validate_peer, + cv.Optional(CONF_WIFI_CHANNEL): cv.int_range(0, 14), }, key=CONF_MAC_ADDRESS, ), @@ -308,6 +315,8 @@ async def peer_action(config, action_id, template_arg, args): if peer_id := config.get(CONF_PEER_ID): peer = await cg.get_variable(peer_id) cg.add(var.set_peer_id(peer)) + if CONF_WIFI_CHANNEL in config: + cg.add(var.set_wifi_channel(config[CONF_WIFI_CHANNEL])) await register_peer(var, config, args) diff --git a/esphome/components/espnow/espnow.cpp b/esphome/components/espnow/espnow.cpp index d988cc997b..804d43fc54 100644 --- a/esphome/components/espnow/espnow.cpp +++ b/esphome/components/espnow/espnow.cpp @@ -125,7 +125,7 @@ void ESPNowComponent::setup() { esp_wifi_get_mac(WIFI_IF_STA, (uint8_t *) &this->own_peer_address_); for (auto id : this->peers_) { - this->add_peer(id); + this->add_peer(id & 0x00FFFFFFFFFFFF, (int8_t) id >> (64 - 8)); } this->send_queue_ = xQueueCreate(SEND_BUFFER_SIZE, sizeof(ESPNowPacket)); @@ -184,7 +184,12 @@ void ESPNowComponent::espnow_task(void *param) { packet.retry(); packet.timestamp = millis(); - esp_err_t err = esp_now_send(packet.get_peer(), packet.get_content(), packet.content_size()); + esp_err_t err; + if (packet.get_peer() == 0) { + err = esp_now_send(nullptr, packet.get_content(), packet.content_size()); + } else { + err = esp_now_send(packet.get_peer(), packet.get_content(), packet.content_size()); + } if (err == ESP_OK) { ESP_LOGD(TAG, "Sended '%s' (%d.%d) from buffer. Wait for conformation.", packet.get_peer_code().c_str(), @@ -200,21 +205,32 @@ void ESPNowComponent::espnow_task(void *param) { } } -esp_err_t ESPNowComponent::add_peer(uint64_t peer) { +void ESPNowComponent::set_wifi_channel(uint8_t channel) { + if (this->is_ready() && (this->wifi_channel_ == channel)) { + ESPNowPacket packet(ESPNOW_MASS_SEND_ADDR, &channel, 1, ESPNOW_MAIN_PROTOCOL_ID, 251); + } + this->wifi_channel_ = channel; +} + +esp_err_t ESPNowComponent::add_peer(uint64_t peer, int8_t channel) { esp_err_t result = ESP_OK; + int8_t old_channel = this->wifi_channel_; + esp_now_peer_info_t peer_info = {}; + if (!this->is_ready()) { - this->peers_.push_back(peer); + this->peers_.push_back((peer & 0x00FFFFFFFFFFFF) + (channel << (64 - 8))); return result; } else { if (esp_now_is_peer_exist((uint8_t *) &peer)) { + esp_now_get_peer((const uint8_t *) &peer, &peer_info); + old_channel = peer_info.channel; result = esp_now_del_peer((uint8_t *) &peer); if (result != ESP_OK) return result; } - esp_now_peer_info_t peer_info = {}; memset(&peer_info, 0, sizeof(esp_now_peer_info_t)); - peer_info.channel = this->wifi_channel_; + peer_info.channel = (channel = -1) ? old_channel : channel; peer_info.encrypt = false; memcpy((void *) peer_info.peer_addr, (void *) &peer, 6); esp_err_t result = esp_now_add_peer(&peer_info); @@ -297,7 +313,12 @@ void ESPNowComponent::call_on_del_peer_(uint64_t peer) { bool ESPNowComponent::is_paired(uint64_t peer) { bool result = false; - if (this->pairing_protocol_ != nullptr) { + if (peer == ESPNOW_MASS_SEND_ADDR) { + return true; + } else if (peer == ESPNOW_BROADCAST_ADDR) { + this->add_peer(ESPNOW_BROADCAST_ADDR); + return true; + } else if (this->pairing_protocol_ != nullptr) { result = this->pairing_protocol_->is_paired(peer); } else { result = (esp_now_is_peer_exist((uint8_t *) &peer)); @@ -368,7 +389,12 @@ bool ESPNowComponent::send(ESPNowPacket packet) { xQueueSendToBack(this->send_queue_, (void *) &packet, 10); return true; } else { - esp_err_t err = esp_now_send(packet.get_peer(), packet.get_content(), packet.content_size()); + esp_err_t err; + if (packet.get_peer() == 0) { + err = esp_now_send(nullptr, packet.get_content(), packet.content_size()); + } else { + err = esp_now_send(packet.get_peer(), packet.get_content(), packet.content_size()); + } ESP_LOGV(TAG, "Sending to %s (%d.%d) directly%s.", packet.get_peer_code().c_str(), packet.get_sequents(), packet.attempts, (err == ESP_OK) ? "" : " FAILED"); diff --git a/esphome/components/espnow/espnow.h b/esphome/components/espnow/espnow.h index 72833cb55a..e5eb0addac 100644 --- a/esphome/components/espnow/espnow.h +++ b/esphome/components/espnow/espnow.h @@ -23,6 +23,7 @@ namespace esphome { namespace espnow { static const uint64_t ESPNOW_BROADCAST_ADDR = 0xFFFFFFFFFFFF; +static const uint64_t ESPNOW_MASS_SEND_ADDR = 0xFFFFFFFFFFFE; static const uint8_t MAX_ESPNOW_DATA_SIZE = 240; @@ -68,7 +69,7 @@ struct ESPNowPacket { uint8_t command = 0) ESPHOME_ALWAYS_INLINE { if (size > MAX_ESPNOW_DATA_SIZE) { ESP_LOGE("ESPNowPacket", "Payload size is to large. It should be less then %d instead it is %d", - MAX_ESPNOW_DATA_SIZE, size); + MAX_ESPNOW_DATA_SIZE, size); // nolint return; } if (peer == 0ull) { @@ -90,7 +91,7 @@ struct ESPNowPacket { inline ESPNowPacket(const uint8_t *peer, const uint8_t *data, uint8_t size) ESPHOME_ALWAYS_INLINE { if (size > MAX_ESPNOW_DATA_SIZE + this->prefix_size()) { ESP_LOGE("ESPNowPacket", "Received Payload size is to large. It should be less then %d instead it is %d", - MAX_ESPNOW_DATA_SIZE + this->prefix_size(), size); + MAX_ESPNOW_DATA_SIZE + this->prefix_size(), size); // nolint return; } @@ -256,7 +257,7 @@ class ESPNowComponent : public Component { float get_setup_priority() const override { return -100; } - void set_wifi_channel(uint8_t channel) { this->wifi_channel_ = channel; } + void set_wifi_channel(uint8_t channel); void set_auto_add_peer(bool value) { this->auto_add_peer_ = value; } void set_use_sent_check(bool value) { this->use_sent_check_ = value; } void set_conformation_timeout(uint32_t timeout) { this->conformation_timeout_ = timeout; } @@ -278,7 +279,7 @@ class ESPNowComponent : public Component { protocol->init_protocol(); } - esp_err_t add_peer(uint64_t peer); + esp_err_t add_peer(uint64_t peer, int8_t channel = -1); esp_err_t del_peer(uint64_t peer); bool send_queue_empty() { return uxQueueMessagesWaiting(this->send_queue_) == 0; } @@ -343,9 +344,14 @@ template class SendAction : public Action, public Parente template class NewPeerAction : public Action, public Parented { public: TEMPLATABLE_VALUE(uint64_t, mac_address); + TEMPLATABLE_VALUE(int8_t, wifi_channel); void play(Ts... x) override { uint64_t mac_address = this->mac_address_.value(x...); - parent_->add_peer(mac_address); + if (this->wifi_channel_.has_value()) { + parent_->add_peer(mac_address); + } else { + parent_->add_peer(mac_address, this->wifi_channel_.value(x...)); + } } }; diff --git a/esphome/components/espnow/test1.yaml b/esphome/components/espnow/test1.yaml index 7aa6526b74..0bd5016eff 100644 --- a/esphome/components/espnow/test1.yaml +++ b/esphome/components/espnow/test1.yaml @@ -30,6 +30,8 @@ logger: espnow: auto_add_peer: true + predefined_peers: + - mac_address: 11:22:33:44:55:66 on_receive: - logger.log: format: "Received: '%s' from '%s' command: %d RSSI: %d"