mirror of
https://github.com/esphome/esphome.git
synced 2024-11-24 16:08:10 +01:00
rework the component again.
This commit is contained in:
parent
78ce52a33c
commit
c35d7c0968
5 changed files with 233 additions and 175 deletions
|
@ -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))
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESPNowComponent::loop() {
|
||||||
|
if (!this->task_running_) {
|
||||||
xTaskCreate(application_task, "espnow_task", 8192, this, 2, &this->espnow_task_handle_);
|
xTaskCreate(application_task, "espnow_task", 8192, this, 2, &this->espnow_task_handle_);
|
||||||
|
this->task_running_ = true;
|
||||||
ESP_LOGI(TAG, "ESP-NOW setup complete");
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
this->call_on_receive_(packet);
|
||||||
} else {
|
} else {
|
||||||
this->add_peer(packet->peer);
|
this->call_on_new_peer_(packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->defer([this, packet]() { this->on_receive_(packet); });
|
if (xQueueReceive(this->send_queue_, (void *) &packet, (TickType_t) 1) == pdTRUE) {
|
||||||
}
|
ESP_LOGD(TAG, "Handling send packet for 0x%12llx (%d.%d).", packet.peer, packet.sequents(), packet.attempts);
|
||||||
// if (packet == nullptr) {
|
|
||||||
packet = new ESPNowPacket(); // NOLINT
|
if (packet.attempts > MAX_NUMBER_OF_RETRYS) {
|
||||||
// }
|
ESP_LOGE(TAG, "Dropped 0x%12llx (0x%04x.%d). To many send retries", packet.peer, packet.sequents(),
|
||||||
if (xQueueReceive(this->send_queue_, (void *) packet, (TickType_t) 1) == pdTRUE) {
|
packet.attempts);
|
||||||
if (packet->attempts > MAX_NUMBER_OF_RETRYS) {
|
|
||||||
ESP_LOGW(TAG, "To many send retries. Packet dropped. 0x%04x", packet->sequents());
|
|
||||||
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
|
||||||
|
|
|
@ -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.");
|
||||||
|
// this->parent_->get_default_protocol()->send(mac, this->data_static_.data(), this->data_static_.size());
|
||||||
} else {
|
} else {
|
||||||
auto val = this->data_func_(x...);
|
ESP_LOGI("ESPNOW:SendAction", "Action Send ByteBuffer lambda value now");
|
||||||
this->parent_->get_default_protocol()->write(mac, val);
|
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); });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
54
esphome/components/espnow/test.yaml
Normal file
54
esphome/components/espnow/test.yaml
Normal 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"
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue