From 535c8dd70fe05bf49d0fafeb0de433f7e606f1fb Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Wed, 20 Nov 2024 10:36:48 +0100 Subject: [PATCH] -add option to set a global keeper to be used withe the espnow.send action. peer= keeper - the keeper is templatable. - introduce protocol modes Keeper, drudge and universal - revert back event call's - add get)iwb_peer_address() - prepare for pairing protocol --- esphome/components/espnow/__init__.py | 51 ++++--- esphome/components/espnow/espnow.cpp | 115 +++++++++++----- esphome/components/espnow/espnow.h | 183 +++++++++++++++----------- esphome/components/espnow/test1.yaml | 57 ++++++++ esphome/components/espnow/test2.yaml | 76 +++++++++++ 5 files changed, 356 insertions(+), 126 deletions(-) create mode 100644 esphome/components/espnow/test1.yaml create mode 100644 esphome/components/espnow/test2.yaml diff --git a/esphome/components/espnow/__init__.py b/esphome/components/espnow/__init__.py index ba4cbe5455..d9ca89510a 100644 --- a/esphome/components/espnow/__init__.py +++ b/esphome/components/espnow/__init__.py @@ -8,6 +8,8 @@ CODEOWNERS = ["@nielsnl68", "@jesserockz"] espnow_ns = cg.esphome_ns.namespace("espnow") ESPNowComponent = espnow_ns.class_("ESPNowComponent", cg.Component) +ESPNowProtocol = espnow_ns.class_("ESPNowProtocol") + ESPNowListener = espnow_ns.class_("ESPNowListener") ESPNowPacket = espnow_ns.class_("ESPNowPacket") @@ -46,10 +48,20 @@ CONF_PEER = "peer" CONF_PEERS = "peers" CONF_USE_SENT_CHECK = "use_sent_check" CONF_WIFI_CHANNEL = "wifi_channel" - +CONF_PROTOCOL_MODE = "protocol_mode" +CONF_KEEPER = "keeper" CONF_MAC_CHARS = "0123456789-AbCdEfGhIjKlMnOpQrStUvWxYz+aBcDeFgHiJkLmNoPqRsTuVwXyZ" +validate_command = cv.Range(min=1, max=250) + +ESPNowProtocol_mode = espnow_ns.enum("ESPNowProtocol_mode") +ENUM_MODE = { + "universal": ESPNowProtocol_mode.universal, + "keeper": ESPNowProtocol_mode.keeper, + "drudge": ESPNowProtocol_mode.drudge, +} + def validate_raw_data(value): if isinstance(value, str): @@ -83,15 +95,18 @@ def validate_peer(value): if isinstance(value, (int)): return value + value = cv.string_strict(value) + + if value.lower() == CONF_KEEPER: + return 0x0 + if value.find(":") != -1: return convert_mac_address(value) if len(value) == 8: - value = cv.string_strict(value) - mac = 0 - for x in value: - n = CONF_MAC_CHARS.find(x) + for x in range(8, 0, -1): + n = CONF_MAC_CHARS.find(value[x - 1]) if n == -1: raise cv.Invalid(f"peer code is invalid. ({value}|{x})") mac = (mac << 6) + n @@ -112,28 +127,29 @@ CONFIG_SCHEMA = cv.Schema( CONF_CONFORMATION_TIMEOUT, default="5000ms" ): cv.positive_time_period_milliseconds, cv.Optional(CONF_RETRIES, default=5): cv.int_range(min=1, max=10), + cv.Optional(CONF_KEEPER): cv.templatable(validate_peer), cv.Optional(CONF_ON_RECEIVE): automation.validate_automation( { cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESPNowReceiveTrigger), - cv.Optional(CONF_COMMAND): cv.Range(min=16, max=255), + cv.Optional(CONF_COMMAND): validate_command, } ), cv.Optional(CONF_ON_BROADCAST): automation.validate_automation( { cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESPNowBroadcaseTrigger), - cv.Optional(CONF_COMMAND): cv.Range(min=0, max=255), + cv.Optional(CONF_COMMAND): validate_command, } ), cv.Optional(CONF_ON_SENT): automation.validate_automation( { cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESPNowSentTrigger), - cv.Optional(CONF_COMMAND): cv.Range(min=0, max=255), + cv.Optional(CONF_COMMAND): validate_command, } ), cv.Optional(CONF_ON_NEW_PEER): automation.validate_automation( { cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESPNowNewPeerTrigger), - cv.Optional(CONF_COMMAND): cv.Range(min=16, max=255), + cv.Optional(CONF_COMMAND): validate_command, } ), cv.Optional(CONF_PEERS): cv.ensure_list(validate_peer), @@ -157,6 +173,10 @@ async def to_code(config): cg.add(var.set_conformation_timeout(config[CONF_CONFORMATION_TIMEOUT])) cg.add(var.set_retries(config[CONF_RETRIES])) + if CONF_KEEPER in config: + template_ = await cg.templatable(config[CONF_KEEPER], [], cg.uint64) + cg.add(var.set_keeper(template_)) + for conf in config.get(CONF_PEERS, []): cg.add(var.add_peer(conf)) @@ -198,24 +218,27 @@ async def to_code(config): PROTOCOL_SCHEMA = cv.Schema( { cv.GenerateID(CONF_ESPNOW): cv.use_id(ESPNowComponent), + cv.Optional(CONF_PROTOCOL_MODE): cv.enum(ENUM_MODE, string=True), }, cv.only_on_esp32, -).extend(cv.COMPONENT_SCHEMA) +) async def register_protocol(var, config): now = await cg.get_variable(config[CONF_ESPNOW]) cg.add(now.register_protocol(var)) + if config[CONF_PROTOCOL_MODE]: + cg.add(var.set_protocol_mode(config[CONF_PROTOCOL_MODE])) @automation.register_action( - "espnow.broatcast", + "espnow.broadcast", SendAction, cv.maybe_simple_value( { cv.GenerateID(): cv.use_id(ESPNowComponent), cv.Required(CONF_PAYLOAD): cv.templatable(validate_raw_data), - cv.Optional(CONF_COMMAND): cv.templatable(cv.Range(min=16, max=255)), + cv.Optional(CONF_COMMAND): cv.templatable(validate_command), }, key=CONF_PAYLOAD, ), @@ -228,9 +251,7 @@ async def register_protocol(var, config): cv.GenerateID(): cv.use_id(ESPNowComponent), cv.Required(CONF_PEER): cv.templatable(validate_peer), cv.Required(CONF_PAYLOAD): cv.templatable(validate_raw_data), - cv.Optional(CONF_COMMAND, default=0): cv.templatable( - cv.Range(min=0, max=255) - ), + cv.Optional(CONF_COMMAND): cv.templatable(validate_command), } ), ) diff --git a/esphome/components/espnow/espnow.cpp b/esphome/components/espnow/espnow.cpp index 0b5510be22..cb897811d6 100644 --- a/esphome/components/espnow/espnow.cpp +++ b/esphome/components/espnow/espnow.cpp @@ -30,11 +30,13 @@ static const size_t SEND_BUFFER_SIZE = 200; ESPNowComponent *ESPNowComponent::static_{nullptr}; // NOLINT std::string espnow_encode_peer(uint64_t peer) { - std::string str1 = ""; if (peer == FAILED) { return "[Not Set]"; } else if (peer == ESPNOW_BROADCAST_ADDR) return "[BroadCast]"; + + std::string str1 = ""; + str1.reserve(8); do { str1.push_back(chars[peer & 63]); // Add on the left peer = peer >> 6; @@ -63,10 +65,10 @@ ESPNowComponent::ESPNowComponent() { ESPNowComponent::static_ = this; } // NOLI void ESPNowComponent::dump_config() { ESP_LOGCONFIG(TAG, "esp_now:"); - ESP_LOGCONFIG(TAG, " Own Peer Address: %s.", espnow_encode_peer(this->own_peer_address_).c_str()); + ESP_LOGCONFIG(TAG, " Own Peer code: %s.", espnow_encode_peer(this->own_peer_address_).c_str()); + ESP_LOGCONFIG(TAG, " Keeper Peer code: %s.", espnow_encode_peer(this->get_keeper()).c_str()); ESP_LOGCONFIG(TAG, " Wifi channel: %d.", this->wifi_channel_); ESP_LOGCONFIG(TAG, " Auto add new peers: %s.", this->auto_add_peer_ ? "Yes" : "No"); - ESP_LOGCONFIG(TAG, " Use sent status: %s.", this->use_sent_check_ ? "Yes" : "No"); ESP_LOGCONFIG(TAG, " Convermation timeout: %" PRIx32 "ms.", this->conformation_timeout_); ESP_LOGCONFIG(TAG, " Send retries: %d.", this->retries_); @@ -142,7 +144,10 @@ void ESPNowComponent::setup() { esp_wifi_get_mac(WIFI_IF_STA, (uint8_t *) &this->own_peer_address_); for (auto id : this->peers_) { - add_peer(id); + this->add_peer(id); + } + if (this->get_keeper() != 0) { + this->add_peer(this->get_keeper()); } this->send_queue_ = xQueueCreate(SEND_BUFFER_SIZE, sizeof(ESPNowPacket)); @@ -172,16 +177,16 @@ void ESPNowComponent::espnow_task(void *param) { ESPNowPacket packet; // NOLINT for (;;) { if (xQueueReceive(this_espnow->receive_queue_, (void *) &packet, (TickType_t) 1) == pdTRUE) { - uint8_t *mac = packet.get_peer(); - if (!packet.is_broadcast || !this_espnow->call_on_broadcast_(packet)) { - if (!esp_now_is_peer_exist(mac) && !this_espnow->call_on_new_peer_(packet)) { - if (this_espnow->auto_add_peer_) { - this_espnow->add_peer(packet.peer); - } - } - if (esp_now_is_peer_exist(mac)) { - this_espnow->call_on_receive_(packet); - } + if (packet.is_broadcast) { + this_espnow->call_on_broadcast_(packet); + continue; + } else if (!this_espnow->is_paired(packet.peer)) { + this_espnow->call_on_new_peer_(packet); + } + if (this_espnow->is_paired(packet.peer)) { + this_espnow->call_on_receive_(packet); + } else { + ESP_LOGI(TAG, "message skipt, not paired."); } } if (xQueueReceive(this_espnow->send_queue_, (void *) &packet, (TickType_t) 1) == pdTRUE) { @@ -218,26 +223,39 @@ void ESPNowComponent::espnow_task(void *param) { } esp_err_t ESPNowComponent::add_peer(uint64_t peer) { + esp_err_t result = ESP_OK; if (!this->is_ready()) { this->peers_.push_back(peer); - return ESP_OK; + return result; } else { - this->del_peer(peer); + if (esp_now_is_peer_exist((uint8_t *) &peer)) { + 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.encrypt = false; memcpy((void *) peer_info.peer_addr, (void *) &peer, 6); - - return esp_now_add_peer(&peer_info); + esp_err_t result = esp_now_add_peer(&peer_info); + if (result == ESP_OK) { + this->call_on_add_peer_(peer); + } + return result; } } esp_err_t ESPNowComponent::del_peer(uint64_t peer) { - if (esp_now_is_peer_exist((uint8_t *) &peer)) - return esp_now_del_peer((uint8_t *) &peer); - return ESP_OK; + esp_err_t result = ESP_OK; + if (esp_now_is_peer_exist((uint8_t *) &peer)) { + esp_err_t result = esp_now_del_peer((uint8_t *) &peer); + if (result == ESP_OK) { + this->call_on_del_peer_(peer); + } + } + return result; } ESPNowDefaultProtocol *ESPNowComponent::get_default_protocol() { @@ -255,36 +273,61 @@ ESPNowProtocol *ESPNowComponent::get_protocol_(uint32_t protocol) { return this->protocols_[protocol]; } -bool ESPNowComponent::call_on_receive_(ESPNowPacket &packet) { +void ESPNowComponent::call_on_receive_(ESPNowPacket &packet) { ESPNowProtocol *protocol = this->get_protocol_(packet.get_protocol()); if (protocol != nullptr) { - return protocol->on_receive(packet); + this->defer([protocol, packet]() { protocol->on_receive(packet); }); } - return false; } -bool ESPNowComponent::call_on_broadcast_(ESPNowPacket &packet) { +void ESPNowComponent::call_on_broadcast_(ESPNowPacket &packet) { ESPNowProtocol *protocol = this->get_protocol_(packet.get_protocol()); if (protocol != nullptr) { - return protocol->on_broadcast(packet); + this->defer([protocol, packet]() { protocol->on_broadcast(packet); }); } - return false; } -bool ESPNowComponent::call_on_sent_(ESPNowPacket &packet, bool status) { +void ESPNowComponent::call_on_sent_(ESPNowPacket &packet, bool status) { ESPNowProtocol *protocol = this->get_protocol_(packet.get_protocol()); if (protocol != nullptr) { - return protocol->on_sent(packet, status); + this->defer([protocol, packet, status]() { protocol->on_sent(packet, status); }); } - return false; } -bool ESPNowComponent::call_on_new_peer_(ESPNowPacket &packet) { +void ESPNowComponent::call_on_new_peer_(ESPNowPacket &packet) { ESPNowProtocol *protocol = this->get_protocol_(packet.get_protocol()); if (protocol != nullptr) { - return protocol->on_new_peer(packet); + this->defer([protocol, packet]() { protocol->on_new_peer(packet); }); } - return false; +} + +void ESPNowComponent::call_on_add_peer_(uint64_t peer) { + this->defer([this, peer]() { + for (const auto &kv : this->protocols_) { + kv.second->on_add_peer(peer); + } + }); +} + +void ESPNowComponent::call_on_del_peer_(uint64_t peer) { + this->defer([this, peer]() { + for (const auto &kv : this->protocols_) { + kv.second->on_del_peer(peer); + } + }); +} + +bool ESPNowComponent::is_paired(uint64_t peer) { + bool result = false; + if (this->pairing_protocol_ != nullptr) { + result = this->pairing_protocol_->is_paired(peer); + } else { + result = (esp_now_is_peer_exist((uint8_t *) &peer)); + } + if (!result && this->auto_add_peer_) { + result = (this->add_peer(peer) == ESP_OK); + } + return result; } /**< callback function of receiving ESPNOW data */ @@ -335,7 +378,7 @@ bool ESPNowComponent::send(ESPNowPacket packet) { ESP_LOGE(TAG, "Cannot send espnow packet, espnow failed to setup"); } else if (this->send_queue_full()) { ESP_LOGE(TAG, "Send Buffer Out of Memory."); - } else if (!esp_now_is_peer_exist(packet.get_peer())) { + } else if (!this->is_paired(packet.peer)) { ESP_LOGE(TAG, "Peer not registered: %s.", packet.get_peer_code().c_str()); } else if (!packet.is_valid()) { ESP_LOGE(TAG, "This Packet is invalid: %s (%d.%d)", packet.get_peer_code().c_str(), packet.get_sequents(), @@ -382,6 +425,10 @@ void ESPNowComponent::on_data_sent(const uint8_t *mac_addr, esp_now_send_status_ /* ESPNowProtocol ********************************************************************** */ bool ESPNowProtocol::send(uint64_t peer, const uint8_t *data, uint8_t len, uint8_t command) { + if (peer == 0x0) { + peer = this->get_keeper(); + } + ESPNowPacket packet(peer, data, len, this->get_protocol_id(), command); // NOLINT packet.set_sequents(this->get_next_sequents(packet.peer)); return this->parent_->send(packet); diff --git a/esphome/components/espnow/espnow.h b/esphome/components/espnow/espnow.h index 7f5e0fa5ed..f74d4d85b7 100644 --- a/esphome/components/espnow/espnow.h +++ b/esphome/components/espnow/espnow.h @@ -15,13 +15,15 @@ #include #include #include +#include +#include namespace esphome { namespace espnow { static const uint64_t ESPNOW_BROADCAST_ADDR = 0xFFFFFFFFFFFF; -static const uint8_t MAX_ESPNOW_DATA_SIZE = 241; +static const uint8_t MAX_ESPNOW_DATA_SIZE = 240; static const uint8_t TRANSPORT_HEADER[3] = {'N', '0', 'w'}; static const uint32_t ESPNOW_MAIN_PROTOCOL_ID = 0x447453; // = StD @@ -33,6 +35,10 @@ static const uint8_t ESPNOW_COMMAND_RESEND = 0x05; static const char chars[] = "0123456789-AbCdEfGhIjKlMnOpQrStUvWxYz+aBcDeFgHiJkLmNoPqRsTuVwXyZ"; static const uint64_t FAILED = 0; +template std::string espnow_i2h(T i) { return sprintf("%04x", i); } + +std::string espnow_rdm(std::string::size_type length); + std::string espnow_encode_peer(uint64_t peer); uint64_t espnow_decode_peer(std::string peer); @@ -96,9 +102,6 @@ struct ESPNowPacket { uint8_t content_size() const { return (this->prefix_size() + this->size); } inline void set_peer(const uint8_t *peer) ESPHOME_ALWAYS_INLINE { - if (*peer == 0) { - peer = (uint8_t *) &ESPNOW_BROADCAST_ADDR; - } memcpy((void *) this->get_peer(), (const void *) peer, 6); }; inline bool is_peer(const uint8_t *peer) const { return memcmp(peer, this->get_peer(), 6) == 0; } @@ -137,33 +140,45 @@ struct ESPNowPacket { class ESPNowComponent; +enum ESPNowProtocol_mode { universal, keeper, drudge }; + class ESPNowProtocol : public Parented { public: - ESPNowProtocol(){}; + void set_protocol_mode(ESPNowProtocol_mode mode) { this->protocol_mode_ = mode; } + ESPNowProtocol_mode get_protocol_mode() { return this->protocol_mode_; } - virtual bool on_receive(const ESPNowPacket &packet) { return false; }; - virtual bool on_broadcast(const ESPNowPacket &packet) { return false; }; - - virtual bool on_sent(const ESPNowPacket &packet, bool status) { return false; }; - virtual bool on_new_peer(const ESPNowPacket &packet) { return false; }; + protected: + ESPNowProtocol_mode protocol_mode_{universal}; + public: virtual uint32_t get_protocol_id() = 0; virtual std::string get_protocol_name() = 0; + virtual void init_protocol() {} - uint8_t get_next_sequents() { return this->get_next_sequents(0); } - virtual uint8_t get_next_sequents(uint64_t peer) { - if (this->next_sequents_ == 255) { - this->next_sequents_ = 0; + virtual void on_receive(const ESPNowPacket &packet){}; + virtual void on_broadcast(const ESPNowPacket &packet) { this->on_receive(packet); }; + + virtual void on_sent(const ESPNowPacket &packet, bool status){}; + virtual void on_new_peer(const ESPNowPacket &packet){}; + + virtual void on_add_peer(uint64_t peer){}; + virtual void on_del_peer(uint64_t peer){}; + + virtual bool is_paired(uint64_t to_peer) { return true; } + + uint8_t get_next_sequents(uint64_t peer) { + if (this->next_sequents_[peer] == 255) { + this->next_sequents_[peer] = 0; } else { - this->next_sequents_++; + this->next_sequents_[peer]++; } - return this->next_sequents_; + return this->next_sequents_[peer]; } - bool is_valid_squence(uint8_t received_sequence) { - bool valid = this->next_sequents_ + 1 == received_sequence; + bool is_valid_squence(uint64_t peer, uint8_t received_sequence) { + bool valid = this->next_sequents_[peer] + 1 == received_sequence; if (valid) { - this->next_sequents_ = received_sequence; + this->next_sequents_[peer] = received_sequence; } return valid; } @@ -171,7 +186,17 @@ class ESPNowProtocol : public Parented { bool send(uint64_t peer, const uint8_t *data, uint8_t len, uint8_t command = 0); protected: - uint8_t next_sequents_{255}; + std::map next_sequents_{}; + std::string get_mode_name_() { + switch (this->protocol_mode_) { + case universal: + return "Universal"; + case keeper: + return "Keeper"; + case drudge: + return "Drudge"; + } + } }; class ESPNowDefaultProtocol : public ESPNowProtocol { @@ -182,35 +207,28 @@ class ESPNowDefaultProtocol : public ESPNowProtocol { void add_on_receive_callback(std::function &&callback) { this->on_receive_.add(std::move(callback)); } - bool on_receive(const ESPNowPacket &packet) override { - this->on_receive_.call(packet); - return this->on_receive_.size() > 0; - }; + void on_receive(const ESPNowPacket &packet) override { this->on_receive_.call(packet); }; void add_on_broadcast_callback(std::function &&callback) { this->on_broadcast_.add(std::move(callback)); } - - bool on_broadcast(const ESPNowPacket &packet) override { - this->on_broadcast_.call(packet); - return this->on_broadcast_.size() > 0; + void on_broadcast(const ESPNowPacket &packet) override { + if (this->on_broadcast_.size() > 0) { + this->on_broadcast_.call(packet); + } else { + this->on_receive(packet); + } }; void add_on_sent_callback(std::function &&callback) { this->on_sent_.add(std::move(callback)); } - bool on_sent(const ESPNowPacket &packet, bool status) override { - this->on_sent_.call(packet, status); - return this->on_sent_.size() > 0; - }; + void on_sent(const ESPNowPacket &packet, bool status) override { this->on_sent_.call(packet, status); }; - void add_on_peer_callback(std::function &&callback) { + void add_on_new_peer_callback(std::function &&callback) { this->on_new_peer_.add(std::move(callback)); } - bool on_new_peer(const ESPNowPacket &packet) override { - this->on_new_peer_.call(packet); - return this->on_new_peer_.size() > 0; - }; + void on_new_peer(const ESPNowPacket &packet) override { this->on_new_peer_.call(packet); }; protected: CallbackManager on_sent_; @@ -240,62 +258,73 @@ class ESPNowComponent : public Component { void set_use_sent_check(bool value) { this->use_sent_check_ = value; } void set_conformation_timeout(uint32_t timeout) { this->conformation_timeout_ = timeout; } void set_retries(uint8_t value) { this->retries_ = value; } + void set_pairing_protocol(ESPNowProtocol *pairing_protocol) { this->pairing_protocol_ = pairing_protocol; } + void set_keeper(uint64_t keeper) { this->keeper_ = keeper; } +} uint64_t get_keeper() { + return this->keeper_; +} +uint64_t get_own_peer_address() { return this->own_peer_address_; } - void setup() override; - void loop() override; +void setup() override; +void loop() override; - bool send(ESPNowPacket packet); +bool is_paired(uint64_t to_peer); - void register_protocol(ESPNowProtocol *protocol) { - protocol->set_parent(this); - this->protocols_[protocol->get_protocol_id()] = protocol; - } +bool send(ESPNowPacket packet); - esp_err_t add_peer(uint64_t peer); - esp_err_t del_peer(uint64_t peer); +void register_protocol(ESPNowProtocol *protocol) { + protocol->set_parent(this); + this->protocols_[protocol->get_protocol_id()] = protocol; + protocol->init_protocol(); +} - bool send_queue_empty() { return uxQueueMessagesWaiting(this->send_queue_) == 0; } - bool send_queue_full() { return uxQueueSpacesAvailable(this->send_queue_) == 0; } - size_t send_queue_used() { return uxQueueMessagesWaiting(this->send_queue_); } - size_t send_queue_free() { return uxQueueSpacesAvailable(this->send_queue_); } +esp_err_t add_peer(uint64_t peer); +esp_err_t del_peer(uint64_t peer); - void lock() { this->lock_ = true; } - bool is_locked() { return this->lock_; } - void unlock() { this->lock_ = false; } +bool send_queue_empty() { return uxQueueMessagesWaiting(this->send_queue_) == 0; } +bool send_queue_full() { return uxQueueSpacesAvailable(this->send_queue_) == 0; } +size_t send_queue_used() { return uxQueueMessagesWaiting(this->send_queue_); } +size_t send_queue_free() { return uxQueueSpacesAvailable(this->send_queue_); } - ESPNowDefaultProtocol *get_default_protocol(); +void lock() { this->lock_ = true; } +bool is_locked() { return this->lock_; } +void unlock() { this->lock_ = false; } - void show_packet(const std::string &title, const ESPNowPacket &packet); +ESPNowDefaultProtocol *get_default_protocol(); - static void espnow_task(void *params); +void show_packet(const std::string &title, const ESPNowPacket &packet); - protected: - bool validate_channel_(uint8_t channel); - ESPNowProtocol *get_protocol_(uint32_t protocol); +static void espnow_task(void *params); - uint64_t own_peer_address_{0}; - uint8_t wifi_channel_{0}; +protected: +bool validate_channel_(uint8_t channel); +ESPNowProtocol *get_protocol_(uint32_t protocol); +ESPNowProtocol *pairing_protocol_{nullptr}; +uint64_t own_peer_address_{0}; +uint8_t wifi_channel_{0}; +uint32_t conformation_timeout_{5000}; +uint8_t retries_{5}; - uint32_t conformation_timeout_{5000}; - uint8_t retries_{5}; +bool auto_add_peer_{false}; +bool use_sent_check_{true}; - bool auto_add_peer_{false}; - bool use_sent_check_{true}; +bool lock_{false}; - bool lock_{false}; +void call_on_receive_(ESPNowPacket &packet); +void call_on_broadcast_(ESPNowPacket &packet); +void call_on_sent_(ESPNowPacket &packet, bool status); +void call_on_new_peer_(ESPNowPacket &packet); - bool call_on_receive_(ESPNowPacket &packet); - bool call_on_broadcast_(ESPNowPacket &packet); - bool call_on_sent_(ESPNowPacket &packet, bool status); - bool call_on_new_peer_(ESPNowPacket &packet); +void call_on_add_peer_(uint64_t peer); +void call_on_del_peer_(uint64_t peer); - QueueHandle_t receive_queue_{}; - QueueHandle_t send_queue_{}; +QueueHandle_t receive_queue_{}; +QueueHandle_t send_queue_{}; - std::map protocols_{}; - std::vector peers_{}; - bool task_running_{false}; - static ESPNowComponent *static_; // NOLINT +std::map protocols_{}; +std::vector peers_{}; +bool task_running_{false}; +static ESPNowComponent *static_; // NOLINT }; template class SendAction : public Action, public Parented { @@ -380,7 +409,7 @@ class ESPNowBroadcaseTrigger : public Trigger { class ESPNowNewPeerTrigger : public Trigger { public: explicit ESPNowNewPeerTrigger(ESPNowComponent *parent) { - parent->get_default_protocol()->add_on_peer_callback([this](const ESPNowPacket packet) { + parent->get_default_protocol()->add_on_new_peer_callback([this](const ESPNowPacket packet) { if ((this->command_ == 0) || this->command_ == packet.get_command()) { this->trigger(packet); } diff --git a/esphome/components/espnow/test1.yaml b/esphome/components/espnow/test1.yaml new file mode 100644 index 0000000000..1b7301b69a --- /dev/null +++ b/esphome/components/espnow/test1.yaml @@ -0,0 +1,57 @@ +# These substitutions allow the end user to override certain values +substitutions: + name: "lum-iot-test1" + friendly_name: "Project Template" + +esp32: + board: esp32dev + framework: + type: esp-idf + # version: 5.1.5 + +esphome: + name: "${name}" + # Friendly names are used where appropriate in Home Assistant + friendly_name: "${friendly_name}" + # Automatically add the mac address to the name + # so you can use a single firmware for all devices + name_add_mac_suffix: false + + # This will allow for (future) project identification, + # configuration and updates. + project: + name: LumenSoft.espnow-test + version: "1.0" + +# To be able to get logs from the device via serial and api. +logger: + level: verbose + +espnow: + auto_add_peer: false + peers: + - FF:FF:FF:FF:FF:FF + - flW1QA3k + + on_receive: + - logger.log: + format: "Received: '%s' from '%s' command: %d RSSI: %d" + args: + [ + packet.get_payload(), + packet.get_peer_code().c_str(), + packet.get_command(), + packet.rssi, + ] + + on_broadcast: + - command: 123 + then: + - logger.log: + format: "Broadcast Received from: '%s' RSSI: %d: %s" + args: + [ + packet.get_peer_code().c_str(), + packet.rssi, + packet.get_payload(), + ] diff --git a/esphome/components/espnow/test2.yaml b/esphome/components/espnow/test2.yaml new file mode 100644 index 0000000000..78018b1946 --- /dev/null +++ b/esphome/components/espnow/test2.yaml @@ -0,0 +1,76 @@ +# These substitutions allow the end user to override certain values +substitutions: + name: "lum-iot-test2" + friendly_name: "Project Template" + +esp32: + board: esp32dev + framework: + type: esp-idf + # version: 5.1.5 + +esphome: + name: "${name}" + # Friendly names are used where appropriate in Home Assistant + friendly_name: "${friendly_name}" + # Automatically add the mac address to the name + # so you can use a single firmware for all devices + name_add_mac_suffix: false + + # This will allow for (future) project identification, + # configuration and updates. + project: + name: LumenSoft.espnow-test + version: "1.0" + +# To be able to get logs from the device via serial and api. +logger: + level: verbose + +espnow: + auto_add_peer: true + peers: + - FF:FF:FF:FF:FF:FF + keeper: rmT7YF9o + on_receive: + - logger.log: + format: "Received: '%s' from '%s' command: %d RSSI: %d" + args: + [ + packet.get_payload(), + packet.get_peer_code().c_str(), + packet.get_command(), + packet.rssi, + ] + + on_broadcast: + - command: 123 + then: + - logger.log: + format: "Broadcast Received from: '%s' RSSI: %d: %s" + args: + [ + packet.get_peer_code().c_str(), + packet.rssi, + packet.get_payload(), + ] + +interval: + - interval: 30sec + startup_delay: 20sec + then: + - espnow.broadcast: + payload: "Broadcast message" + command: 123 + - interval: 5sec + then: + - espnow.send: + peer: keeper + payload: "tesing the test" + +binary_sensor: + - platform: gpio + pin: GPIO39 + name: Button + on_click: + - espnow.peer.del: rmT7YF9o