New implementation; the espnow compoment.

This commit is contained in:
NP v/d Spek 2024-07-26 16:06:16 +02:00
parent 39c0019534
commit 4750c97606
3 changed files with 811 additions and 0 deletions

View file

@ -0,0 +1,198 @@
from esphome import automation
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import (
CONF_DATA,
CONF_ID,
CONF_MAC_ADDRESS,
CONF_TRIGGER_ID,
CONF_WIFI,
)
from esphome.core import CORE
CODEOWNERS = ["@LumenSoftNL", "@jesserockz"]
espnow_ns = cg.esphome_ns.namespace("esp_now")
ESPNowComponent = espnow_ns.class_("ESPNowComponent", cg.Component)
ESPNowListener = espnow_ns.class_("ESPNowListener")
ESPNowPackage = espnow_ns.class_("ESPNowPackage")
ESPNowPackagePtrConst = ESPNowPackage.operator("ptr") # .operator("const")
ESPNowInterface = espnow_ns.class_(
"ESPNowInterface", cg.Component, cg.Parented.template(ESPNowComponent)
)
ESPNowSendTrigger = espnow_ns.class_("ESPNowSendTrigger", automation.Trigger.template())
ESPNowReceiveTrigger = espnow_ns.class_(
"ESPNowReceiveTrigger", automation.Trigger.template()
)
ESPNowNewPeerTrigger = espnow_ns.class_(
"ESPNowNewPeerTrigger", automation.Trigger.template()
)
SendAction = espnow_ns.class_("SendAction", automation.Action)
NewPeerAction = espnow_ns.class_("NewPeerAction", automation.Action)
DelPeerAction = espnow_ns.class_("DelPeerAction", automation.Action)
CONF_ESPNOW = "espnow"
CONF_ON_PACKAGE_RECEIVED = "on_package_received"
CONF_ON_PACKAGE_SEND = "on_package_send"
CONF_ON_NEW_PEER = "on_new_peer"
CONF_CHANNEL = "wifi_channel"
CONF_PEERS = "peers"
CONF_AUTO_ADD_PEER = "auto_add_peer"
def validate_raw_data(value):
if isinstance(value, str):
return value.encode("utf-8")
if isinstance(value, list):
return cv.Schema([cv.hex_uint8_t])(value)
raise cv.Invalid(
"data must either be a string wrapped in quotes or a list of bytes"
)
def disallowed_component(comp):
"""Validate that this option can only be specified when the component `comp` is not loaded."""
def validator(value):
if comp in CORE.loaded_integrations:
raise cv.Invalid(f"This component requires component {comp}")
return value
return validator
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(ESPNowComponent),
cv.Optional(CONF_CHANNEL, default=0): cv.int_range(0, 14),
cv.Optional(CONF_AUTO_ADD_PEER, default=False): cv.boolean,
cv.Optional(CONF_ON_PACKAGE_RECEIVED): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESPNowReceiveTrigger),
}
),
cv.Optional(CONF_ON_PACKAGE_SEND): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESPNowSendTrigger),
}
),
cv.Optional(CONF_ON_NEW_PEER): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESPNowNewPeerTrigger),
}
),
cv.Optional(CONF_PEERS): cv.ensure_list(cv.mac_address),
},
disallowed_component(CONF_WIFI),
).extend(cv.COMPONENT_SCHEMA)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
if CORE.is_esp8266:
cg.add_library("ESP8266WiFi", None)
elif CORE.is_esp32 and CORE.using_arduino:
cg.add_library("WiFi", None)
elif CORE.is_rp2040:
cg.add_library("WiFi", None)
cg.add_define("USE_ESPNOW")
cg.add(var.set_wifi_channel(config[CONF_CHANNEL]))
cg.add(var.set_auto_add_peer(config[CONF_AUTO_ADD_PEER]))
for conf in config.get(CONF_ON_PACKAGE_SEND, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(
trigger, [(ESPNowPackagePtrConst, "it")], conf
)
for conf in config.get(CONF_ON_PACKAGE_RECEIVED, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(
trigger, [(ESPNowPackagePtrConst, "it")], conf
)
for conf in config.get(CONF_ON_NEW_PEER, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(
trigger, [(ESPNowPackagePtrConst, "it")], conf
)
for conf in config.get(CONF_PEERS, []):
cg.add(var.add_peer(conf.as_hex))
@automation.register_action(
"espnow.send",
SendAction,
cv.maybe_simple_value(
{
cv.GenerateID(): cv.use_id(ESPNowComponent),
cv.Optional(CONF_MAC_ADDRESS): cv.templatable(cv.mac_address),
cv.Required(CONF_DATA): cv.templatable(validate_raw_data),
},
key=CONF_DATA,
),
)
async def send_action(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
if CONF_MAC_ADDRESS in config:
template_ = await cg.templatable(
config[CONF_MAC_ADDRESS].as_hex, args, cg.uint64
)
cg.add(var.set_mac(template_))
data = config.get(CONF_DATA, [])
if isinstance(data, bytes):
data = list(data)
if cg.is_template(data):
templ = await cg.templatable(data, args, cg.std_vector.template(cg.uint8))
cg.add(var.set_data_template(templ))
else:
cg.add(var.set_data_static(data))
return var
@automation.register_action(
"espnow.new.peer",
NewPeerAction,
cv.maybe_simple_value(
{
cv.GenerateID(): cv.use_id(ESPNowComponent),
cv.Required(CONF_MAC_ADDRESS): cv.templatable(cv.mac_address),
},
key=CONF_MAC_ADDRESS,
),
)
async def new_peer_action(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
template_ = await cg.templatable(config[CONF_MAC_ADDRESS].as_hex, args, cg.uint64)
cg.add(var.set_mac(template_))
return var
@automation.register_action(
"espnow.del.peer",
DelPeerAction,
cv.maybe_simple_value(
{
cv.GenerateID(): cv.use_id(ESPNowComponent),
cv.Required(CONF_MAC_ADDRESS): cv.templatable(cv.mac_address),
},
key=CONF_MAC_ADDRESS,
),
)
async def del_peer_action(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
template_ = await cg.templatable(config[CONF_MAC_ADDRESS].as_hex, args, cg.uint64)
cg.add(var.set_mac(template_))
return var

View file

@ -0,0 +1,328 @@
#include "espnow.h"
#include <string.h>
#include "esp_mac.h"
#include "esp_random.h"
#include "esp_wifi.h"
#include "esp_crc.h"
#include "esp_now.h"
#include "esp_event.h"
#ifdef USE_WIFI
#include "esphome/components/wifi/wifi_component.h"
#endif
#include "esphome/core/version.h"
#include "esphome/core/log.h"
namespace esphome {
namespace esp_now {
static const char *const TAG = "esp_now";
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 1)
typedef struct {
uint16_t frame_head;
uint16_t duration;
uint8_t destination_address[6];
uint8_t source_address[6];
uint8_t broadcast_address[6];
uint16_t sequence_control;
uint8_t category_code;
uint8_t organization_identifier[3]; // 0x18fe34
uint8_t random_values[4];
struct {
uint8_t element_id; // 0xdd
uint8_t lenght; //
uint8_t organization_identifier[3]; // 0x18fe34
uint8_t type; // 4
uint8_t version;
uint8_t body[0];
} vendor_specific_content;
} __attribute__((packed)) espnow_frame_format_t;
#endif
void ESPNowInterface::setup() { parent_->register_protocol(this); }
ESPNowPackage::ESPNowPackage(const uint64_t mac_address, const std::vector<uint8_t> data) {
this->mac_address_ = mac_address;
this->data_ = data;
}
ESPNowPackage::ESPNowPackage(const uint64_t mac_address, const uint8_t *data, size_t len) {
this->data_.resize(len);
std::copy_n(data, len, this->data_.begin());
}
ESPNowComponent::ESPNowComponent() { global_esp_now = this; }
void ESPNowComponent::log_error_(std::string msg, esp_err_t err) { ESP_LOGE(TAG, msg.c_str(), esp_err_to_name(err)); }
void ESPNowComponent::dump_config() {
ESP_LOGCONFIG(TAG, "esp_now:");
ESP_LOGCONFIG(TAG, " MAC Address: " MACSTR, MAC2STR(ESPNOW_ADDR_SELF));
// ESP_LOGCONFIG(TAG, " WiFi Channel: %n", WiFi.channel());
}
bool ESPNowComponent::validate_channel_(uint8_t channel) {
wifi_country_t g_self_country;
esp_wifi_get_country(&g_self_country);
if (channel >= g_self_country.schan + g_self_country.nchan) {
ESP_LOGE(TAG, "Can't set channel %d, not allowed in country %c%c%c.", channel, g_self_country.cc[0],
g_self_country.cc[1], g_self_country.cc[2]);
return false;
}
return true;
}
void ESPNowComponent::setup() {
ESP_LOGI(TAG, "Setting up ESP-NOW...");
#ifdef USE_WIFI
global_wifi_component.disable();
#else // Set device as a Wi-Fi Station
esp_event_loop_create_default();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_wifi_disconnect());
#endif
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
#ifdef CONFIG_ESPNOW_ENABLE_LONG_RANGE
esp_wifi_get_protocol(ESP_IF_WIFI_STA, WIFI_PROTOCOL_LR);
#endif
esp_wifi_set_promiscuous(true);
esp_wifi_set_channel(this->wifi_channel_, WIFI_SECOND_CHAN_NONE);
esp_wifi_set_promiscuous(false);
this->send_lock_ = xSemaphoreCreateMutex();
if (!this->send_lock_) {
ESP_LOGE(TAG, "Create send semaphore mutex fail");
this->mark_failed();
return;
}
esp_err_t err = esp_now_init();
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_now_init failed: %s", esp_err_to_name(err));
this->mark_failed();
return;
}
err = esp_now_register_recv_cb(ESPNowComponent::on_data_received);
if (err != ESP_OK) {
this->log_error_("esp_now_register_recv_cb failed: %s", err);
this->mark_failed();
return;
}
err = esp_now_register_send_cb(ESPNowComponent::on_data_send);
if (err != ESP_OK) {
this->log_error_("esp_now_register_send_cb failed: %s", err);
this->mark_failed();
return;
}
esp_wifi_get_mac(WIFI_IF_STA, ESPNOW_ADDR_SELF);
ESP_LOGI(TAG, "ESP-NOW add peers.");
for (auto &address : this->peers_) {
ESP_LOGI(TAG, "Add peer 0x%s .", format_hex(address).c_str());
add_peer(address);
}
ESP_LOGI(TAG, "ESP-NOW setup complete");
}
ESPNowPackage *ESPNowComponent::send_package(ESPNowPackage *package) {
uint8_t mac[6];
package->mac_bytes((uint8_t *) &mac);
if (esp_now_is_peer_exist((uint8_t *) &mac)) {
this->send_queue_.push(std::move(package));
} else {
ESP_LOGW(TAG, "Peer does not exist cant send this package: %02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2],
mac[3], mac[4], mac[5]);
}
return package;
}
esp_err_t ESPNowComponent::add_peer(uint64_t addr) {
if (!this->is_ready()) {
this->peers_.push_back(addr);
return ESP_OK;
} else {
uint8_t mac[6];
this->del_peer(addr);
uint64_to_addr(addr, (uint8_t *) &mac);
esp_now_peer_info_t peerInfo = {};
memset(&peerInfo, 0, sizeof(esp_now_peer_info_t));
peerInfo.channel = this->wifi_channel_;
peerInfo.encrypt = false;
memcpy(peerInfo.peer_addr, mac, 6);
return esp_now_add_peer(&peerInfo);
}
}
esp_err_t ESPNowComponent::del_peer(uint64_t addr) {
uint8_t mac[6];
uint64_to_addr(addr, (uint8_t *) &mac);
if (esp_now_is_peer_exist((uint8_t *) &mac))
return esp_now_del_peer((uint8_t *) &mac);
return ESP_OK;
}
void ESPNowComponent::on_package_received(ESPNowPackage *package) {
for (auto *protocol : this->protocols_) {
if (protocol->on_package_received(package)) {
return;
}
}
this->on_package_receved_.call(package);
}
void ESPNowComponent::on_package_send(ESPNowPackage *package) {
for (auto *protocol : this->protocols_) {
if (protocol->on_package_send(package)) {
return;
}
}
this->on_package_send_.call(package);
}
void ESPNowComponent::on_new_peer(ESPNowPackage *package) {
for (auto *protocol : this->protocols_) {
if (protocol->on_new_peer(package)) {
return;
}
}
this->on_new_peer_.call(package);
}
void ESPNowComponent::unHold_send_(uint64_t mac) {
for (ESPNowPackage *package : this->send_queue_) {
if (package->is_holded() && package->mac_address() == mac) {
package->reset_counter();
}
}
}
void ESPNowComponent::loop() {
if (!send_queue_.empty() && this->can_send_ && !this->status_has_warning()) {
ESPNowPackage *package = this->send_queue_.front();
ESPNowPackage *front = package;
while (package->is_holded()) {
this->send_queue_.pop();
this->send_queue_.push(package);
package = this->send_queue_.front();
if (front == package)
break;
}
if (!package->is_holded()) {
if (package->get_counter() == 5) {
this->status_set_warning("to many send retries. Stopping sending until new package received.");
} else {
uint8_t mac_address[6];
package->mac_bytes((uint8_t *) &mac_address);
esp_err_t err = esp_now_send(mac_address, package->data().data(), package->data().size());
package->inc_counter();
if (err != ESP_OK) {
this->log_error_("esp_now_init failed: %s", err);
this->send_queue_.pop();
this->send_queue_.push(package);
} else {
this->can_send_ = false;
}
}
}
}
while (!receive_queue_.empty()) {
ESPNowPackage *package = std::move(this->receive_queue_.front());
this->receive_queue_.pop();
uint8_t mac[6];
package->mac_bytes((uint8_t *) &mac);
if (!esp_now_is_peer_exist((uint8_t *) &mac)) {
if (this->auto_add_peer_) {
this->add_peer(addr_to_uint64((uint8_t *) &mac));
} else {
this->on_new_peer(package);
}
}
if (esp_now_is_peer_exist((uint8_t *) &mac)) {
this->unHold_send_(package->mac_address());
this->on_package_received(package);
} else {
ESP_LOGW(TAG, "Peer does not exist can't handle this package: %02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1],
mac[2], mac[3], mac[4], mac[5]);
}
}
}
/**< callback function of receiving ESPNOW data */
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 1)
void ESPNowComponent::on_data_received((const esp_now_recv_info_t *recv_info, const uint8_t *data, int size)
#else
void ESPNowComponent::on_data_received(const uint8_t *addr, const uint8_t *data, int size)
#endif
{
wifi_pkt_rx_ctrl_t *rx_ctrl = NULL;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 1)
uint8_t *addr = recv_info->src_addr;
rx_ctrl = recv_info->rx_ctrl;
#else
wifi_promiscuous_pkt_t *promiscuous_pkt =
(wifi_promiscuous_pkt_t *) (data - sizeof(wifi_pkt_rx_ctrl_t) - sizeof(espnow_frame_format_t));
rx_ctrl = &promiscuous_pkt->rx_ctrl;
#endif
ESPNowPackage *package = new ESPNowPackage(addr_to_uint64(addr), data, size);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 1)
package->is_broadcast(memcmp(recv_info->des_addr, ESP_NOW.BROADCAST_ADDR, ESP_NOW_ETH_ALEN) == 0);
#endif
package->rssi(rx_ctrl->rssi);
package->timestamp(rx_ctrl->timestamp);
global_esp_now->push_receive_package_(package);
}
void ESPNowComponent::on_data_send(const uint8_t *mac_addr, esp_now_send_status_t status) {
ESPNowPackage *package = global_esp_now->send_queue_.front();
espnow_addr_t mac;
uint64_to_addr(package->mac_address(), mac);
if (status != ESP_OK) {
ESP_LOGE(TAG, "on_data_send failed");
} else if (std::memcmp(mac, mac_addr, 6) != 0) {
ESP_LOGE(TAG, "on_data_send Invalid mac address.");
ESP_LOGW(TAG, "expected: %02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
ESP_LOGW(TAG, "returned: %02X:%02X:%02X:%02X:%02X:%02X", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
mac_addr[4], mac_addr[5]);
} else {
global_esp_now->on_package_send(package);
global_esp_now->send_queue_.pop();
}
global_esp_now->can_send_ = true;
}
ESPNowComponent *global_esp_now = nullptr;
} // namespace esp_now
} // namespace esphome

View file

@ -0,0 +1,285 @@
#pragma once
// #if defined(USE_ESP32)
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
#include "esphome/core/helpers.h"
#include <esp_now.h>
#include <array>
#include <memory>
#include <queue>
#include <vector>
namespace esphome {
namespace esp_now {
typedef uint8_t espnow_addr_t[6];
static const uint64_t ESPNOW_BROADCAST_ADDR = 0xFFFFFFFFFFFF;
static espnow_addr_t ESPNOW_ADDR_SELF = {0};
static void uint64_to_addr(uint64_t address, uint8_t *bd_addr) {
*(bd_addr + 0) = (address >> 40) & 0xff;
*(bd_addr + 1) = (address >> 32) & 0xff;
*(bd_addr + 2) = (address >> 24) & 0xff;
*(bd_addr + 3) = (address >> 16) & 0xff;
*(bd_addr + 4) = (address >> 8) & 0xff;
*(bd_addr + 5) = (address >> 0) & 0xff;
}
static uint64_t addr_to_uint64(const uint8_t *address) {
uint64_t u = 0;
u |= uint64_t(*(address + 0) & 0xFF) << 40;
u |= uint64_t(*(address + 1) & 0xFF) << 32;
u |= uint64_t(*(address + 2) & 0xFF) << 24;
u |= uint64_t(*(address + 3) & 0xFF) << 16;
u |= uint64_t(*(address + 4) & 0xFF) << 8;
u |= uint64_t(*(address + 5) & 0xFF) << 0;
return u;
}
class ESPNowComponent;
template<typename T, typename Container = std::deque<T> > class iterable_queue : public std::queue<T, Container> {
public:
typedef typename Container::iterator iterator;
typedef typename Container::const_iterator const_iterator;
iterator begin() { return this->c.begin(); }
iterator end() { return this->c.end(); }
const_iterator begin() const { return this->c.begin(); }
const_iterator end() const { return this->c.end(); }
};
class ESPNowPackage {
public:
ESPNowPackage(const uint64_t mac_address, const std::vector<uint8_t> data);
ESPNowPackage(const uint64_t mac_address, const uint8_t *data, size_t len);
uint64_t mac_address() { return this->mac_address_ == 0 ? ESPNOW_BROADCAST_ADDR : this->mac_address_; }
void mac_bytes(uint8_t *mac_addres) {
uint64_t mac = this->mac_address_ == 0 ? ESPNOW_BROADCAST_ADDR : this->mac_address_;
uint64_to_addr(mac, mac_addres);
}
std::vector<uint8_t> data() { return data_; }
uint8_t get_counter() { return send_count_; }
void inc_counter() {
send_count_ = send_count_ + 1;
if (send_count_ > 5 && !is_holded_) {
set_holding();
}
}
void reset_counter() {
send_count_ = 0;
del_holding();
}
void is_broadcast(bool value) { this->is_broadcast_ = value; }
bool is_broadcast() const { return this->is_broadcast_; }
void timestamp(uint32_t value) { this->timestamp_ = value; }
uint32_t timestamp() { return this->timestamp_; }
void rssi(int8_t rssi) { this->rssi_ = rssi; }
int8_t rssi() { return this->rssi_; }
bool is_holded() { return this->is_holded_; }
void set_holding() { this->is_holded_ = true; }
void del_holding() { this->is_holded_ = false; }
protected:
uint64_t mac_address_{0};
std::vector<uint8_t> data_;
uint8_t send_count_{0};
bool is_broadcast_{false};
uint32_t timestamp_{0};
uint8_t rssi_{0};
bool is_holded_{false};
};
class ESPNowInterface : public Component, public Parented<ESPNowComponent> {
public:
ESPNowInterface(){};
void setup() override;
virtual bool on_package_received(ESPNowPackage *package) { return false; };
virtual bool on_package_send(ESPNowPackage *package) { return false; };
virtual bool on_new_peer(ESPNowPackage *package) { return false; };
};
class ESPNowComponent : public Component {
public:
ESPNowComponent();
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 1)
static void on_data_received((const esp_now_recv_info_t *recv_info, const uint8_t *data, int size);
#else
static void on_data_received(const uint8_t *addr, const uint8_t *data, int size);
#endif
static void on_data_send(const uint8_t *mac_addr, esp_now_send_status_t status);
void dump_config() override;
float get_setup_priority() const override {
return -100; }
void setup() override;
void loop() override;
void set_wifi_channel(uint8_t channel) {
this->wifi_channel_ = channel; }
ESPNowPackage *send_package(const uint64_t mac_address, const uint8_t *data, int len) {
auto package = new ESPNowPackage(mac_address, data, len);
return this->send_package(package);
}
ESPNowPackage *send_package(const uint64_t mac_address, const std::vector<uint8_t> data) {
auto package = new ESPNowPackage(mac_address, data);
return this->send_package(package);
}
ESPNowPackage *send_package(ESPNowPackage *package);
void add_on_package_send_callback(std::function<void(ESPNowPackage *)> &&callback) {
this->on_package_send_.add(std::move(callback));
}
void add_on_package_receive_callback(std::function<void(ESPNowPackage *)> &&callback) {
this->on_package_receved_.add(std::move(callback));
}
void add_on_peer_callback(std::function<void(ESPNowPackage *)> &&callback) {
this->on_new_peer_.add(std::move(callback));
}
void register_protocol(ESPNowInterface *protocol) {
protocol->set_parent(this);
this->protocols_.push_back(protocol);
}
esp_err_t add_peer(uint64_t addr);
esp_err_t del_peer(uint64_t addr);
void set_auto_add_peer(bool value) {
this->auto_add_peer_ = value; }
void on_package_received(ESPNowPackage *package);
void on_package_send(ESPNowPackage *package);
void on_new_peer(ESPNowPackage *package);
void log_error_(std::string msg, esp_err_t err);
protected:
void unHold_send_(uint64_t mac);
void push_receive_package_(ESPNowPackage *package) {
this->receive_queue_.push(std::move(package)); }
bool validate_channel_(uint8_t channel);
uint8_t wifi_channel_{0};
bool auto_add_peer_{false};
CallbackManager<void(ESPNowPackage *)> on_package_send_;
CallbackManager<void(ESPNowPackage *)> on_package_receved_;
CallbackManager<void(ESPNowPackage *)> on_new_peer_;
iterable_queue<ESPNowPackage *> receive_queue_{};
iterable_queue<ESPNowPackage *> send_queue_{};
std::vector<ESPNowInterface *> protocols_{};
std::vector<uint64_t> peers_{};
SemaphoreHandle_t send_lock_ = NULL;
bool can_send_{true};
};
template<typename... Ts> class SendAction : public Action<Ts...>, public Parented<ESPNowComponent> {
public:
template<typename V> void set_mac(V mac) { this->mac_ = mac; }
void set_data_template(std::function<std::vector<uint8_t>(Ts...)> func) {
this->data_func_ = func;
this->static_ = false;
}
void set_data_static(const std::vector<uint8_t> &data) {
this->data_static_ = data;
this->static_ = true;
}
void play(Ts... x) override {
auto mac = this->mac_.value(x...);
if (this->static_) {
this->parent_->send_package(mac, this->data_static_);
} else {
auto val = this->data_func_(x...);
this->parent_->send_package(mac, val);
}
}
protected:
TemplatableValue<uint64_t, Ts...> mac_{};
bool static_{false};
std::function<std::vector<uint8_t>(Ts...)> data_func_{};
std::vector<uint8_t> data_static_{};
};
template<typename... Ts> class NewPeerAction : public Action<Ts...>, public Parented<ESPNowComponent> {
public:
template<typename V> void set_mac(V mac) { this->mac_ = mac; }
void play(Ts... x) override {
auto mac = this->mac_.value(x...);
parent_->add_peer(mac);
}
protected:
TemplatableValue<uint64_t, Ts...> mac_{};
};
template<typename... Ts> class DelPeerAction : public Action<Ts...>, public Parented<ESPNowComponent> {
public:
template<typename V> void set_mac(V mac) { this->mac_ = mac; }
void play(Ts... x) override {
auto mac = this->mac_.value(x...);
parent_->del_peer(mac);
}
protected:
TemplatableValue<uint64_t, Ts...> mac_{};
};
class ESPNowSendTrigger : public Trigger<ESPNowPackage *> {
public:
explicit ESPNowSendTrigger(ESPNowComponent *parent) {
parent->add_on_package_send_callback([this](ESPNowPackage *value) { this->trigger(value); });
}
};
class ESPNowReceiveTrigger : public Trigger<ESPNowPackage *> {
public:
explicit ESPNowReceiveTrigger(ESPNowComponent *parent) {
parent->add_on_package_receive_callback([this](ESPNowPackage *value) { this->trigger(value); });
}
};
class ESPNowNewPeerTrigger : public Trigger<ESPNowPackage *> {
public:
explicit ESPNowNewPeerTrigger(ESPNowComponent *parent) {
parent->add_on_peer_callback([this](ESPNowPackage *value) { this->trigger(value); });
}
};
extern ESPNowComponent *global_esp_now;
} // namespace esp_now
} // namespace esphome
// #endif