rework the component again.

This commit is contained in:
NP v/d Spek 2024-09-29 19:03:21 +02:00
parent 78ce52a33c
commit c35d7c0968
5 changed files with 233 additions and 175 deletions

View file

@ -11,7 +11,7 @@ ESPNowComponent = espnow_ns.class_("ESPNowComponent", cg.Component)
ESPNowListener = espnow_ns.class_("ESPNowListener") ESPNowListener = espnow_ns.class_("ESPNowListener")
ESPNowPacket = espnow_ns.class_("ESPNowPacket") ESPNowPacket = espnow_ns.class_("ESPNowPacket")
ESPNowPacketPtr = ESPNowPacket.operator("ptr") ESPNowPacketConst = ESPNowPacket.operator("const")
ESPNowInterface = espnow_ns.class_( ESPNowInterface = espnow_ns.class_(
@ -94,17 +94,21 @@ async def to_code(config):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation( await automation.build_automation(
trigger, trigger,
[(ESPNowPacketPtr, "packet"), (bool, "status")], [(ESPNowPacketConst, "packet"), (bool, "status")],
conf, conf,
) )
for conf in config.get(CONF_ON_RECEIVE, []): for conf in config.get(CONF_ON_RECEIVE, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [(ESPNowPacketPtr, "packet")], conf) await automation.build_automation(
trigger, [(ESPNowPacketConst, "packet")], conf
)
for conf in config.get(CONF_ON_NEW_PEER, []): for conf in config.get(CONF_ON_NEW_PEER, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [(ESPNowPacketPtr, "packet")], conf) await automation.build_automation(
trigger, [(ESPNowPacketConst, "packet")], conf
)
for conf in config.get(CONF_PEERS, []): for conf in config.get(CONF_PEERS, []):
cg.add(var.add_peer(conf.as_hex)) cg.add(var.add_peer(conf.as_hex))

View file

@ -36,37 +36,6 @@ static void application_task(void *param) {
ESPNowComponent *ESPNowComponent::static_{nullptr}; // NOLINT ESPNowComponent *ESPNowComponent::static_{nullptr}; // NOLINT
/* ESPNowPacket ********************************************************************** */
ESPNowPacket::ESPNowPacket(uint64_t peer, const uint8_t *data, uint8_t size, uint32_t protocol) {
assert(size <= MAX_ESPNOW_DATA_SIZE);
this->set_peer(peer);
this->is_broadcast =
(std::memcmp((const void *) this->peer_as_bytes(), (const void *) &ESPNOW_BROADCAST_ADDR, 6) == 0);
this->protocol(protocol);
this->size = size;
std::memcpy(this->payload_as_bytes(), data, size);
this->calc_crc();
}
ESPNowPacket::ESPNowPacket(uint64_t peer, const uint8_t *data, uint8_t size) {
this->set_peer(peer);
std::memcpy(this->content_as_bytes(), data, size);
this->size = size - this->prefix_size();
}
bool ESPNowPacket::is_valid() {
uint16_t crc = this->crc();
this->calc_crc();
bool valid = (memcmp((const void *) &this->content, (const void *) &TRANSPORT_HEADER, 3) == 0);
valid &= (this->protocol() != 0);
valid &= (this->crc() == crc);
this->crc(crc);
return valid;
}
/* ESPNowComponent ********************************************************************** */ /* ESPNowComponent ********************************************************************** */
ESPNowComponent::ESPNowComponent() { ESPNowComponent::static_ = this; } // NOLINT ESPNowComponent::ESPNowComponent() { ESPNowComponent::static_ = this; } // NOLINT
@ -76,16 +45,16 @@ void ESPNowComponent::dump_config() {
ESP_LOGCONFIG(TAG, " MAC Address: 0x%12llx.", this->own_peer_address_); ESP_LOGCONFIG(TAG, " MAC Address: 0x%12llx.", this->own_peer_address_);
} }
void ESPNowComponent::show_packet(const std::string &title, ESPNowPacket *packet) { void ESPNowComponent::show_packet(std::string title, const ESPNowPacket &packet) {
/* /*
char buf[20]; char buf[20];
sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
ESP_LOGVV(TAG, "%s packet: M:%s H:%cx%cx%c P:%c%c%c 0x%02x S:%02x C:ox%02x~0x%02x S:%02d V:%s", "test", ESP_LOGVV(TAG, "%s packet: M:%s H:%cx%cx%c P:%c%c%c 0x%02x S:%02x C:ox%02x~0x%02x S:%02d V:%s", "test",
buf, packet->content_at(0), packet->content_at(1), buf, packet.content_at(0), packet.content_at(1),
packet->content_at(2), packet->content_at(3), packet->content_at(4), packet->content_at(5), packet.content_at(2), packet.content_at(3), packet.content_at(4), packet.content_at(5),
packet->content_at(6), packet->content_at(7), packet->crc(), packet->calc_crc(), packet->content_size() packet.content_at(6), packet.content_at(7), packet.crc(), packet.calc_crc(), packet.content_size()
packet->is_valid() ? "Yes" : "No"); packet.is_valid() ? "Yes" : "No");
*/ */
} }
@ -167,10 +136,13 @@ void ESPNowComponent::setup() {
this->mark_failed(); this->mark_failed();
return; return;
} }
}
xTaskCreate(application_task, "espnow_task", 8192, this, 2, &this->espnow_task_handle_); void ESPNowComponent::loop() {
if (!this->task_running_) {
ESP_LOGI(TAG, "ESP-NOW setup complete"); xTaskCreate(application_task, "espnow_task", 8192, this, 2, &this->espnow_task_handle_);
this->task_running_ = true;
}
} }
esp_err_t ESPNowComponent::add_peer(uint64_t addr) { esp_err_t ESPNowComponent::add_peer(uint64_t addr) {
@ -214,24 +186,24 @@ ESPNowProtocol *ESPNowComponent::get_protocol_component_(uint32_t protocol) {
return this->protocols_[protocol]; return this->protocols_[protocol];
} }
void ESPNowComponent::on_receive_(ESPNowPacket *packet) { void ESPNowComponent::call_on_receive_(const ESPNowPacket packet) {
ESPNowProtocol *protocol = this->get_protocol_component_(packet->protocol()); ESPNowProtocol *protocol = this->get_protocol_component_(packet.protocol());
if (protocol != nullptr) { if (protocol != nullptr) {
protocol->on_receive(packet); this->defer([protocol, packet]() { protocol->on_receive(packet); });
} }
} }
void ESPNowComponent::on_sent_(ESPNowPacket *packet, bool status) { void ESPNowComponent::call_on_sent_(const ESPNowPacket packet, bool status) {
ESPNowProtocol *protocol = this->get_protocol_component_(packet->protocol()); ESPNowProtocol *protocol = this->get_protocol_component_(packet.protocol());
if (protocol != nullptr) { if (protocol != nullptr) {
protocol->on_sent(packet, packet); this->defer([protocol, packet, status]() { protocol->on_sent(packet, status); });
} }
} }
void ESPNowComponent::on_new_peer_(ESPNowPacket *packet) { void ESPNowComponent::call_on_new_peer_(const ESPNowPacket packet) {
ESPNowProtocol *protocol = this->get_protocol_component_(packet->protocol()); ESPNowProtocol *protocol = this->get_protocol_component_(packet.protocol());
if (protocol != nullptr) { if (protocol != nullptr) {
protocol->on_new_peer(packet); this->defer([protocol, packet]() { protocol->on_new_peer(packet); });
} }
} }
@ -258,46 +230,46 @@ void ESPNowComponent::on_data_received(const uint8_t *addr, const uint8_t *data,
(wifi_promiscuous_pkt_t *) (data - sizeof(wifi_pkt_rx_ctrl_t) - 39); // = sizeof (espnow_frame_format_t) (wifi_promiscuous_pkt_t *) (data - sizeof(wifi_pkt_rx_ctrl_t) - 39); // = sizeof (espnow_frame_format_t)
rx_ctrl = &promiscuous_pkt->rx_ctrl; rx_ctrl = &promiscuous_pkt->rx_ctrl;
#endif #endif
ESPNowPacket *packet = new ESPNowPacket((uint64_t) *addr, data, (uint8_t) size); // NOLINT ESPNowPacket packet((uint64_t) *addr, data, (uint8_t) size); // NOLINT
packet->is_broadcast = broadcast; packet.is_broadcast = broadcast;
if (rx_ctrl != nullptr) { if (rx_ctrl != nullptr) {
packet->rssi = rx_ctrl->rssi; packet.rssi = rx_ctrl->rssi;
packet->timestamp = rx_ctrl->timestamp; packet.timestamp = rx_ctrl->timestamp;
} else { } else {
packet->timestamp = millis(); packet.timestamp = millis();
} }
/// this->show_packet("Receive", *packet); /// this->show_packet("Receive", *packet);
if (packet->is_valid()) { if (packet.is_valid()) {
xQueueSendToBack(ESPNowComponent::static_->receive_queue_, (void *) packet, 10); xQueueSendToBack(ESPNowComponent::static_->receive_queue_, (void *) &packet, 10);
} else { } else {
ESP_LOGE(TAG, "Invalid ESP-NOW packet received (CRC)"); ESP_LOGE(TAG, "Invalid ESP-NOW packet received (CRC)");
} }
} }
bool ESPNowComponent::write(ESPNowPacket *packet) { bool ESPNowComponent::send(ESPNowPacket packet) {
uint8_t *mac = packet->peer_as_bytes(); uint8_t *mac = packet.peer_as_bytes();
// this->show_packet("Write", *packet);
// this->show_packet("Write", packet);
if (this->is_failed()) { if (this->is_failed()) {
ESP_LOGE(TAG, "Cannot send espnow packet, espnow failed to setup"); ESP_LOGE(TAG, "Cannot send espnow packet, espnow failed to setup");
} else if (this->send_queue_full()) { } else if (this->send_queue_full()) {
ESP_LOGE(TAG, "Send Buffer Out of Memory."); ESP_LOGE(TAG, "Send Buffer Out of Memory.");
} else if (!esp_now_is_peer_exist(mac)) { } else if (!esp_now_is_peer_exist(mac)) {
ESP_LOGW(TAG, "Peer not registered: 0x%12llx.", packet->peer); ESP_LOGW(TAG, "Peer not registered: 0x%12llx.", packet.peer);
} else if (!packet->is_valid()) { } else if (!packet.is_valid()) {
ESP_LOGW(TAG, "Packet is invalid. maybe you need to ::calc_crc(). the packat before writing."); ESP_LOGW(TAG, "Packet is invalid. maybe you need to ::calc_crc(). the packat before writing.");
} else if (this->use_sent_check_) { } else if (this->use_sent_check_) {
xQueueSendToBack(this->send_queue_, (void *) packet, 10); ESP_LOGD(TAG, "Place 0x%12llx (%d.%d) into send buffer. Used: %d of %d", packet.peer, packet.sequents(),
ESP_LOGVV(TAG, "Send to 0x%12llx (%d.%d): Buffer Used: %d", packet->peer, packet->sequents(), packet->attempts, packet.attempts, this->send_queue_used(), SEND_BUFFER_SIZE);
this->send_queue_used()); xQueueSendToBack(this->send_queue_, (void *) &packet, 10);
return true; return true;
} else { } else {
esp_err_t err = esp_now_send((uint8_t *) &mac, packet->content_as_bytes(), packet->content_size()); esp_err_t err = esp_now_send((uint8_t *) &mac, packet.content_as_bytes(), packet.content_size());
ESP_LOGVV(TAG, "S: 0x%04x.%d B: %d%s.", packet->sequents(), packet->attempts, this->send_queue_used(), ESP_LOGD(TAG, "Sended 0x%12llx (%d.%d) directly%s.", packet.peer, packet.sequents(), packet.attempts,
(err == ESP_OK) ? "" : " FAILED"); (err == ESP_OK) ? "" : " FAILED");
this->defer([this, packet, err]() { this->on_sent_(packet, err == ESP_OK); }); this->call_on_sent_(packet, err == ESP_OK);
return true; return true;
} }
@ -305,50 +277,49 @@ bool ESPNowComponent::write(ESPNowPacket *packet) {
} }
void ESPNowComponent::runner() { void ESPNowComponent::runner() {
ESPNowPacket *packet{nullptr}; // NOLINT ESPNowPacket packet; // NOLINT
for (;;) { for (;;) {
// if (packet == nullptr) {
packet = new ESPNowPacket(); // NOLINT
// }
if (xQueueReceive(this->receive_queue_, (void *) &packet, (TickType_t) 1) == pdTRUE) { if (xQueueReceive(this->receive_queue_, (void *) &packet, (TickType_t) 1) == pdTRUE) {
uint8_t *mac = packet->peer_as_bytes(); uint8_t *mac = packet.peer_as_bytes();
ESP_LOGD(TAG, "Handling received packet from 0x%12llx (%d.%d).", packet.peer, packet.sequents(), packet.attempts);
if (!esp_now_is_peer_exist(mac)) { if (esp_now_is_peer_exist(mac)) {
if (!this->auto_add_peer_) { this->call_on_receive_(packet);
this->defer([this, packet]() { this->on_new_peer_(packet); }); } else if (this->auto_add_peer_) {
continue; this->add_peer(packet.peer);
} else { this->call_on_receive_(packet);
this->add_peer(packet->peer); } else {
} this->call_on_new_peer_(packet);
} }
this->defer([this, packet]() { this->on_receive_(packet); });
} }
// if (packet == nullptr) { if (xQueueReceive(this->send_queue_, (void *) &packet, (TickType_t) 1) == pdTRUE) {
packet = new ESPNowPacket(); // NOLINT ESP_LOGD(TAG, "Handling send packet for 0x%12llx (%d.%d).", packet.peer, packet.sequents(), packet.attempts);
// }
if (xQueueReceive(this->send_queue_, (void *) packet, (TickType_t) 1) == pdTRUE) { if (packet.attempts > MAX_NUMBER_OF_RETRYS) {
if (packet->attempts > MAX_NUMBER_OF_RETRYS) { ESP_LOGE(TAG, "Dropped 0x%12llx (0x%04x.%d). To many send retries", packet.peer, packet.sequents(),
ESP_LOGW(TAG, "To many send retries. Packet dropped. 0x%04x", packet->sequents()); packet.attempts);
this->unlock(); this->unlock();
continue; continue;
} else if (this->is_locked()) { } else if (this->is_locked()) {
if (millis() - packet->timestamp > 1000) { if (millis() - packet.timestamp > 1000) {
ESP_LOGE(TAG, "TimeOut (0x%04x.%d).", packet->sequents(), packet->attempts); ESP_LOGW(TAG, "TimeOut 0x%12llx (0x%04x.%d).", packet.peer, packet.sequents(), packet.attempts);
packet->retry(); packet.retry();
this->unlock(); this->unlock();
} }
} else { } else {
this->lock(); this->lock();
packet->retry(); packet.retry();
packet->timestamp = millis(); packet.timestamp = millis();
uint8_t *mac = packet->peer_as_bytes(); uint8_t *mac = packet.peer_as_bytes();
esp_err_t err = esp_now_send(mac, packet->content_as_bytes(), packet->content_size()); esp_err_t err = esp_now_send(mac, packet.content_as_bytes(), packet.content_size());
if (err == ESP_OK) { if (err == ESP_OK) {
ESP_LOGV(TAG, "S: 0x%04x.%d. Wait for conformation.", packet->sequents(), packet->attempts); ESP_LOGV(TAG, "Sended 0x%12llx (%d.%d). Wait for conformation.", packet.peer, packet.sequents(),
packet.attempts);
} else { } else {
ESP_LOGE(TAG, "S: 0x%04x.%d B: %d.", packet->sequents(), packet->attempts, this->send_queue_used()); ESP_LOGE(TAG, "Sending 0x%12llx (%d.%d) FAILED. B: %d.", packet.peer, packet.sequents(), packet.attempts,
this->send_queue_used());
this->unlock(); this->unlock();
} }
} }
@ -361,37 +332,34 @@ void ESPNowComponent::on_data_sent(const uint8_t *mac_addr, esp_now_send_status_
if ((ESPNowComponent::static_ == nullptr) || !ESPNowComponent::static_->use_sent_check_) { if ((ESPNowComponent::static_ == nullptr) || !ESPNowComponent::static_->use_sent_check_) {
return; return;
} }
ESPNowPacket *packet = new ESPNowPacket(); // NOLINT ESPNowPacket packet; // NOLINT
uint64_t mac64 = (uint64_t) *mac_addr; uint64_t mac64 = (uint64_t) *mac_addr;
if (xQueuePeek(ESPNowComponent::static_->send_queue_, (void *) packet, 10 / portTICK_PERIOD_MS) == pdTRUE) { if (xQueuePeek(ESPNowComponent::static_->send_queue_, (void *) &packet, 10 / portTICK_PERIOD_MS) == pdTRUE) {
if (status != ESP_OK) { if (status != ESP_OK) {
ESP_LOGE(TAG, "sent packet failed (0x%04x.%d)", packet->sequents(), packet->attempts); ESP_LOGE(TAG, "sent packet failed (0x%04x.%d)", packet.sequents(), packet.attempts);
} else if (packet->peer != mac64) { } else if (packet.peer != mac64) {
ESP_LOGE(TAG, " Invalid mac address. (0x%04x.%d) expected: 0x%12llx got: 0x%12llx", packet->sequents(), ESP_LOGE(TAG, " Invalid mac address. (0x%04x.%d) expected: 0x%12llx got: 0x%12llx", packet.sequents(),
packet->attempts, packet->peer, mac64); packet.attempts, packet.peer, mac64);
} else { } else {
ESP_LOGV(TAG, "Confirm sent (0x%04x.%d)", packet->sequents(), packet->attempts); ESP_LOGV(TAG, "Confirm sent (0x%04x.%d)", packet.sequents(), packet.attempts);
ESPNowComponent::static_->defer([packet]() { ESPNowComponent::static_->call_on_sent_(packet, true);
ESPNowComponent::static_->on_sent_(packet, true); xQueueReceive(ESPNowComponent::static_->send_queue_, (void *) &packet, 10 / portTICK_PERIOD_MS);
ESPNowPacket tmp;
xQueueReceive(ESPNowComponent::static_->send_queue_, (void *) &tmp, 10 / portTICK_PERIOD_MS);
ESPNowComponent::static_->unlock();
});
return; return;
} }
ESPNowComponent::static_->defer([packet]() { ESPNowComponent::static_->call_on_sent_(packet, false);
ESPNowComponent::static_->on_sent_(packet, false); ESPNowComponent::static_->unlock();
ESPNowComponent::static_->unlock();
});
} }
} }
/* ESPNowProtocol ********************************************************************** */ /* ESPNowProtocol ********************************************************************** */
bool ESPNowProtocol::write(uint64_t peer, const uint8_t *data, uint8_t len) { bool ESPNowProtocol::send(uint64_t peer, const uint8_t *data, uint8_t len) {
ESPNowPacket *packet = new ESPNowPacket(peer, data, len, this->get_protocol_component_id()); // NOLINT ESPNowPacket packet(peer, data, len, this->get_protocol_component_id()); // NOLINT
packet->sequents(this->get_next_sequents()); packet.sequents(this->get_next_sequents());
return this->parent_->write(packet); ESP_LOGD(TAG, "Created packet to Send for 0x%12llx (%d.%d) directly.", packet.peer, packet.sequents(),
packet.attempts);
return this->parent_->send(packet);
} }
} // namespace espnow } // namespace espnow

View file

@ -7,6 +7,8 @@
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include "esphome/core/bytebuffer.h" #include "esphome/core/bytebuffer.h"
#include "esphome/core/log.h"
#include <esp_now.h> #include <esp_now.h>
#include <esp_crc.h> #include <esp_crc.h>
@ -51,15 +53,29 @@ struct ESPNowPacket {
uint8_t payload[MAX_ESPNOW_DATA_SIZE + 1]{0}; uint8_t payload[MAX_ESPNOW_DATA_SIZE + 1]{0};
} __attribute__((packed)) content; } __attribute__((packed)) content;
ESPNowPacket() {} inline ESPNowPacket() ESPHOME_ALWAYS_INLINE {}
// Create packet to be send. // Create packet to be send.
ESPNowPacket(uint64_t peer, const uint8_t *data, uint8_t size, uint32_t protocol); inline ESPNowPacket(uint64_t peer, const uint8_t *data, uint8_t size, uint32_t protocol) ESPHOME_ALWAYS_INLINE {
assert(size <= MAX_ESPNOW_DATA_SIZE);
this->set_peer(peer);
this->is_broadcast =
(std::memcmp((const void *) this->peer_as_bytes(), (const void *) &ESPNOW_BROADCAST_ADDR, 6) == 0);
this->protocol(protocol);
this->size = size;
std::memcpy(this->payload_as_bytes(), data, size);
this->calc_crc();
}
// Load received packet's. // Load received packet's.
ESPNowPacket(uint64_t peer, const uint8_t *data, uint8_t size); ESPNowPacket(uint64_t peer, const uint8_t *data, uint8_t size) ESPHOME_ALWAYS_INLINE {
this->set_peer(peer);
std::memcpy(this->content_as_bytes(), data, size);
this->size = size - this->prefix_size();
}
uint8_t *peer_as_bytes() { return (uint8_t *) &(this->peer); } inline uint8_t *peer_as_bytes() const { return (uint8_t *) &(this->peer); }
void set_peer(uint64_t peer) { inline void set_peer(uint64_t peer) ESPHOME_ALWAYS_INLINE {
if (peer == 0) { if (peer == 0) {
this->peer = ESPNOW_BROADCAST_ADDR; this->peer = ESPNOW_BROADCAST_ADDR;
} else { } else {
@ -67,39 +83,48 @@ struct ESPNowPacket {
} }
}; };
inline uint8_t prefix_size() { return sizeof(this->content.prefix); } uint8_t prefix_size() const { return sizeof((*this).content.prefix); }
inline uint8_t content_size() { return this->prefix_size() + this->size; } uint8_t content_size() const { return ((*this).prefix_size() + (*this).size); }
inline uint32_t protocol() { return this->content.prefix.protocol; } inline uint32_t protocol() const { return this->content.prefix.protocol; }
void protocol(uint32_t protocol) { inline void protocol(uint32_t protocol) ESPHOME_ALWAYS_INLINE {
this->content.prefix.protocol = protocol; this->content.prefix.protocol = protocol;
this->calc_crc(); this->calc_crc();
} }
inline uint8_t sequents() { return this->content.prefix.sequents; } uint8_t sequents() const { return (*this).content.prefix.sequents; }
void sequents(uint8_t sequents) { inline void sequents(uint8_t sequents) ESPHOME_ALWAYS_INLINE {
this->content.prefix.sequents = sequents; this->content.prefix.sequents = sequents;
this->calc_crc(); this->calc_crc();
} }
uint8_t *content_as_bytes() { return (uint8_t *) &(this->content); } inline uint8_t *content_as_bytes() const { return (uint8_t *) &(this->content); }
uint8_t *payload_as_bytes() { return (uint8_t *) &(this->content.payload); } inline uint8_t *payload_as_bytes() const { return (uint8_t *) &(this->content.payload); }
uint8_t content_at(uint8_t pos) { inline uint8_t content_at(uint8_t pos) const {
assert(pos < this->size); assert(pos < this->size);
return *(((uint8_t *) &this->content) + pos); return *(((uint8_t *) &this->content) + pos);
} }
uint8_t crc() { return this->content.prefix.crc; } inline uint8_t crc() const { return this->content.prefix.crc; }
void crc(uint8_t crc) { this->content.prefix.crc = crc; } inline void crc(uint8_t crc) { this->content.prefix.crc = crc; }
void calc_crc() { void calc_crc() {
this->content.prefix.crc = 0; this->content.prefix.crc = 0;
uint8_t crc = esp_crc8_le(0, this->peer_as_bytes(), 6); uint8_t crc = esp_crc8_le(0, this->peer_as_bytes(), 6);
this->content.prefix.crc = esp_crc8_le(crc, (const uint8_t *) &this->content, this->size); this->content.prefix.crc = esp_crc8_le(crc, (const uint8_t *) this->content_as_bytes(), this->content_size());
} }
void retry() { this->attempts++; } inline void retry() ESPHOME_ALWAYS_INLINE { attempts++; }
bool is_valid(); inline bool is_valid() {
uint16_t tmp_crc = crc();
this->calc_crc();
bool valid = (memcmp((const void *) this->content_as_bytes(), (const void *) &TRANSPORT_HEADER, 3) == 0);
valid &= (this->protocol() != 0);
valid &= (this->crc() == tmp_crc);
this->crc(tmp_crc);
return valid;
}
}; };
class ESPNowComponent; class ESPNowComponent;
@ -108,9 +133,9 @@ class ESPNowProtocol : public Parented<ESPNowComponent> {
public: public:
ESPNowProtocol(){}; ESPNowProtocol(){};
virtual void on_receive(ESPNowPacket *packet){}; virtual void on_receive(const ESPNowPacket &packet){};
virtual void on_sent(ESPNowPacket *packet, bool status){}; virtual void on_sent(const ESPNowPacket &packet, bool status){};
virtual void on_new_peer(ESPNowPacket *packet){}; virtual void on_new_peer(const ESPNowPacket &packet){};
virtual uint32_t get_protocol_component_id() = 0; virtual uint32_t get_protocol_component_id() = 0;
uint8_t get_next_sequents() { uint8_t get_next_sequents() {
@ -129,10 +154,7 @@ class ESPNowProtocol : public Parented<ESPNowComponent> {
return valid; return valid;
} }
bool write(uint64_t peer, const uint8_t *data, uint8_t len); bool send(uint64_t peer, const uint8_t *data, uint8_t len);
bool write(uint64_t peer, ByteBuffer &data) {
return this->write(peer, data.get_data().data(), (uint8_t) data.get_used_space());
}
protected: protected:
uint8_t next_sequents_{255}; uint8_t next_sequents_{255};
@ -142,25 +164,25 @@ class ESPNowDefaultProtocol : public ESPNowProtocol {
public: public:
uint32_t get_protocol_component_id() override { return ESPNOW_MAIN_PROTOCOL_ID; }; uint32_t get_protocol_component_id() override { return ESPNOW_MAIN_PROTOCOL_ID; };
void add_on_receive_callback(std::function<void(ESPNowPacket *)> &&callback) { void add_on_receive_callback(std::function<void(const ESPNowPacket)> &&callback) {
this->on_receive_.add(std::move(callback)); this->on_receive_.add(std::move(callback));
} }
void on_receive(ESPNowPacket *packet) override { this->on_receive_.call(packet); }; void on_receive(const ESPNowPacket &packet) override { this->on_receive_.call(packet); };
void add_on_sent_callback(std::function<void(ESPNowPacket *, bool status)> &&callback) { void add_on_sent_callback(std::function<void(const ESPNowPacket, bool status)> &&callback) {
this->on_sent_.add(std::move(callback)); this->on_sent_.add(std::move(callback));
} }
void on_sent(ESPNowPacket *packet, bool status) override { this->on_sent_.call(packet, status); }; void on_sent(const ESPNowPacket &packet, bool status) override { this->on_sent_.call(packet, status); };
void add_on_peer_callback(std::function<void(ESPNowPacket *)> &&callback) { void add_on_peer_callback(std::function<void(const ESPNowPacket)> &&callback) {
this->on_new_peer_.add(std::move(callback)); this->on_new_peer_.add(std::move(callback));
} }
void on_new_peer(ESPNowPacket *packet) override { this->on_new_peer_.call(packet); }; void on_new_peer(const ESPNowPacket &packet) override { this->on_new_peer_.call(packet); };
protected: protected:
CallbackManager<void(ESPNowPacket *, bool)> on_sent_; CallbackManager<void(const ESPNowPacket, bool)> on_sent_;
CallbackManager<void(ESPNowPacket *)> on_receive_; CallbackManager<void(const ESPNowPacket)> on_receive_;
CallbackManager<void(ESPNowPacket *)> on_new_peer_; CallbackManager<void(const ESPNowPacket)> on_new_peer_;
}; };
class ESPNowComponent : public Component { class ESPNowComponent : public Component {
@ -184,10 +206,11 @@ class ESPNowComponent : public Component {
void set_use_sent_check(bool value) { this->use_sent_check_ = value; } void set_use_sent_check(bool value) { this->use_sent_check_ = value; }
void setup() override; void setup() override;
void loop() override;
void runner(); void runner();
bool write(ESPNowPacket *packet); bool send(ESPNowPacket packet);
void register_protocol(ESPNowProtocol *protocol) { void register_protocol(ESPNowProtocol *protocol) {
protocol->set_parent(this); protocol->set_parent(this);
@ -208,7 +231,7 @@ class ESPNowComponent : public Component {
ESPNowDefaultProtocol *get_default_protocol(); ESPNowDefaultProtocol *get_default_protocol();
void show_packet(const std::string &title, ESPNowPacket *packet); void show_packet(std::string title, const ESPNowPacket &packet);
protected: protected:
bool validate_channel_(uint8_t channel); bool validate_channel_(uint8_t channel);
@ -220,9 +243,9 @@ class ESPNowComponent : public Component {
bool use_sent_check_{true}; bool use_sent_check_{true};
bool lock_{false}; bool lock_{false};
void on_receive_(ESPNowPacket *packet); void call_on_receive_(const ESPNowPacket packet);
void on_sent_(ESPNowPacket *packet, bool status); void call_on_sent_(const ESPNowPacket packet, bool status);
void on_new_peer_(ESPNowPacket *packet); void call_on_new_peer_(const ESPNowPacket packet);
QueueHandle_t receive_queue_{}; QueueHandle_t receive_queue_{};
QueueHandle_t send_queue_{}; QueueHandle_t send_queue_{};
@ -233,6 +256,7 @@ class ESPNowComponent : public Component {
ESPNowDefaultProtocol *default_protocol_{nullptr}; ESPNowDefaultProtocol *default_protocol_{nullptr};
TaskHandle_t espnow_task_handle_{nullptr}; TaskHandle_t espnow_task_handle_{nullptr};
bool task_running_{false};
static ESPNowComponent *static_; // NOLINT static ESPNowComponent *static_; // NOLINT
}; };
@ -243,21 +267,28 @@ template<typename... Ts> class SendAction : public Action<Ts...>, public Parente
void set_data_template(std::function<ByteBuffer(Ts...)> func) { void set_data_template(std::function<ByteBuffer(Ts...)> func) {
this->data_func_ = func; this->data_func_ = func;
this->static_ = false; this->static_ = false;
ESP_LOGCONFIG("ESPNOW:SendAction", "Add ByteBuffer lambda value to send");
} }
void set_data_static(const std::vector<uint8_t> &data) { void set_data_static(const std::vector<uint8_t> &data) {
this->data_static_ = data; this->data_static_ = data;
this->static_ = true; this->static_ = true;
ESP_LOGCONFIG("ESPNOW:SendAction", "Add static std:vector value to send");
} }
void play(Ts... x) override { void play(Ts... x) override {
auto mac = this->mac_.value(x...); ESP_LOGI("ESPNOW:SendAction", "Execute Play.");
/*
uint64_t mac = this->mac_.value(x...);
if (this->static_) { if (this->static_) {
this->parent_->get_default_protocol()->write(mac, this->data_static_.data(), this->data_static_.size()); ESP_LOGI("ESPNOW:SendAction", "Action Send static std:vector value now.");
} else { // this->parent_->get_default_protocol()->send(mac, this->data_static_.data(), this->data_static_.size());
auto val = this->data_func_(x...); } else {
this->parent_->get_default_protocol()->write(mac, val); ESP_LOGI("ESPNOW:SendAction", "Action Send ByteBuffer lambda value now");
} ByteBuffer data = this->data_func_(x...);
// this->parent_->get_default_protocol()->send(mac, data.get_data().data(), (uint8_t) data.get_used_space());
}
*/
} }
protected: protected:
@ -291,25 +322,26 @@ template<typename... Ts> class DelPeerAction : public Action<Ts...>, public Pare
TemplatableValue<uint64_t, Ts...> mac_{}; TemplatableValue<uint64_t, Ts...> mac_{};
}; };
class ESPNowSentTrigger : public Trigger<ESPNowPacket *, bool> { class ESPNowSentTrigger : public Trigger<const ESPNowPacket, bool> {
public: public:
explicit ESPNowSentTrigger(ESPNowComponent *parent) { explicit ESPNowSentTrigger(ESPNowComponent *parent) {
parent->get_default_protocol()->add_on_sent_callback( parent->get_default_protocol()->add_on_sent_callback(
[this](ESPNowPacket *packet, bool status) { this->trigger(packet, status); }); [this](const ESPNowPacket packet, bool status) { this->trigger(packet, status); });
} }
}; };
class ESPNowReceiveTrigger : public Trigger<ESPNowPacket *> { class ESPNowReceiveTrigger : public Trigger<const ESPNowPacket> {
public: public:
explicit ESPNowReceiveTrigger(ESPNowComponent *parent) { explicit ESPNowReceiveTrigger(ESPNowComponent *parent) {
parent->get_default_protocol()->add_on_receive_callback([this](ESPNowPacket *packet) { this->trigger(packet); }); parent->get_default_protocol()->add_on_receive_callback(
[this](const ESPNowPacket packet) { this->trigger(packet); });
} }
}; };
class ESPNowNewPeerTrigger : public Trigger<ESPNowPacket *> { class ESPNowNewPeerTrigger : public Trigger<const ESPNowPacket> {
public: public:
explicit ESPNowNewPeerTrigger(ESPNowComponent *parent) { explicit ESPNowNewPeerTrigger(ESPNowComponent *parent) {
parent->get_default_protocol()->add_on_peer_callback([this](ESPNowPacket *packet) { this->trigger(packet); }); parent->get_default_protocol()->add_on_peer_callback([this](const ESPNowPacket packet) { this->trigger(packet); });
} }
}; };

View file

@ -0,0 +1,54 @@
# These substitutions allow the end user to override certain values
substitutions:
name: "lum-iot-test"
friendly_name: "Project Template"
#xternal_components:
# - source: github://pr#7141
# components: [ espnow ]
# refresh: 1 sec
esp32:
board: esp32dev
framework:
type: esp-idf
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: esphome.project-template
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
on_receive:
- logger.log:
format: "Received: %s RSSI: %d"
args: [packet.payload_as_bytes(), packet.rssi]
binary_sensor:
- platform: gpio
pin:
number: GPIO00
inverted: true
mode:
input: true
pullup: true
name: Button
on_click:
- espnow.send: "hallo everyone"

View file

@ -5,7 +5,7 @@ espnow:
on_receive: on_receive:
- logger.log: - logger.log:
format: "Received: %s RSSI: %d" format: "Received: %s RSSI: %d"
args: [packet->content_as_bytes(), packet->rssi] args: [packet.content_as_bytes(), packet.rssi]
binary_sensor: binary_sensor:
- platform: gpio - platform: gpio