1
0
mirror of https://github.com/esphome/esphome.git synced 2025-02-01 10:40:56 +00:00

rework peer mac_address opdate.

adding static peer option.
This commit is contained in:
NP v/d Spek 2024-11-23 15:54:52 +01:00
parent 36ca1e7213
commit d23346165e
5 changed files with 171 additions and 172 deletions

View File

@ -1,8 +1,13 @@
from esphome import automation from esphome import automation, core
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_COMMAND, CONF_ID, CONF_PAYLOAD, CONF_TRIGGER_ID from esphome.const import (
from esphome.core import CORE CONF_COMMAND,
CONF_ID,
CONF_MAC_ADDRESS,
CONF_PAYLOAD,
CONF_TRIGGER_ID,
)
CODEOWNERS = ["@nielsnl68", "@jesserockz"] CODEOWNERS = ["@nielsnl68", "@jesserockz"]
@ -13,7 +18,7 @@ ESPNowProtocol = espnow_ns.class_("ESPNowProtocol")
ESPNowListener = espnow_ns.class_("ESPNowListener") ESPNowListener = espnow_ns.class_("ESPNowListener")
ESPNowPacket = espnow_ns.class_("ESPNowPacket") ESPNowPacket = espnow_ns.class_("ESPNowPacket")
ESPNowPeer = espnow_ns.class_("Peer") ESPNowPeer = cg.uint64
ESPNowPacketConst = ESPNowPacket.operator("const") ESPNowPacketConst = ESPNowPacket.operator("const")
@ -36,7 +41,7 @@ SendAction = espnow_ns.class_("SendAction", automation.Action)
NewPeerAction = espnow_ns.class_("NewPeerAction", automation.Action) NewPeerAction = espnow_ns.class_("NewPeerAction", automation.Action)
DelPeerAction = espnow_ns.class_("DelPeerAction", automation.Action) DelPeerAction = espnow_ns.class_("DelPeerAction", automation.Action)
SetKeeperAction = espnow_ns.class_("SetKeeperAction", automation.Action) SetKeeperAction = espnow_ns.class_("SetKeeperAction", automation.Action)
SetStaticPeerAction = espnow_ns.class_("SetStaticPeerAction", automation.Action)
CONF_AUTO_ADD_PEER = "auto_add_peer" CONF_AUTO_ADD_PEER = "auto_add_peer"
CONF_CONFORMATION_TIMEOUT = "conformation_timeout" CONF_CONFORMATION_TIMEOUT = "conformation_timeout"
@ -47,21 +52,19 @@ CONF_ON_BROADCAST = "on_broadcast"
CONF_ON_SENT = "on_sent" CONF_ON_SENT = "on_sent"
CONF_ON_NEW_PEER = "on_new_peer" CONF_ON_NEW_PEER = "on_new_peer"
CONF_PEER = "peer" CONF_PEER = "peer"
CONF_PEERS = "peers" CONF_PEER_ID = "peer_id"
CONF_PREDEFINED_PEERS = "predefined_peers"
CONF_USE_SENT_CHECK = "use_sent_check" CONF_USE_SENT_CHECK = "use_sent_check"
CONF_WIFI_CHANNEL = "wifi_channel" CONF_WIFI_CHANNEL = "wifi_channel"
CONF_PROTOCOL_MODE = "protocol_mode" CONF_PROTOCOL_MODE = "protocol_mode"
CONF_KEEPER = "keeper"
CONF_MAC_CHARS = "0123456789-AbCdEfGhIjKlMnOpQrStUvWxYz+aBcDeFgHiJkLmNoPqRsTuVwXyZ"
validate_command = cv.Range(min=1, max=250) validate_command = cv.Range(min=1, max=250)
ESPNowProtocol_mode = espnow_ns.enum("ESPNowProtocol_mode") ESPNowProtocol_mode = espnow_ns.enum("ESPNowProtocol_mode")
ENUM_MODE = { ENUM_MODE = {
"universal": ESPNowProtocol_mode.universal, "universal": ESPNowProtocol_mode.pm_universal,
"keeper": ESPNowProtocol_mode.keeper, "keeper": ESPNowProtocol_mode.pm_keeper,
"drudge": ESPNowProtocol_mode.drudge, "drudge": ESPNowProtocol_mode.pm_drudge,
} }
@ -75,48 +78,19 @@ def validate_raw_data(value):
) )
def convert_mac_address(value): def espnow_hex(mac_address):
parts = value.split(":") it = reversed(mac_address.parts)
if len(parts) != 6: num = "".join(f"{part:02X}" for part in it)
raise cv.Invalid("MAC Address must consist of 6 : (colon) separated parts") return cg.RawExpression(f"0x{num}ULL")
parts_int = 0
if any(len(part) != 2 for part in parts):
raise cv.Invalid("MAC Address must be format XX:XX:XX:XX:XX:XX")
for part in parts:
try:
parts_int = (parts_int << 8) + int(part, 16)
except ValueError:
# pylint: disable=raise-missing-from
raise cv.Invalid(
"MAC Address parts must be hexadecimal values from 00 to FF"
)
return parts_int
def validate_peer(value): DEFINE_PEER_CONFIG = cv.maybe_simple_value(
if isinstance(value, (int)): {
return value cv.Optional(CONF_PEER_ID): cv.declare_id(ESPNowPeer),
cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
value = cv.string_strict(value) },
key=CONF_MAC_ADDRESS,
if value.lower() == CONF_KEEPER: )
return 0x0
if value.find(":") != -1:
return convert_mac_address(value)
if len(value) == 8:
mac = 0
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
return mac
raise cv.Invalid(
f"peer code '{value}' needs to be 8 characters width, or a valid Mac address or a hexidacimal value of 12 chars width starting with '0x'"
)
CONFIG_SCHEMA = cv.Schema( CONFIG_SCHEMA = cv.Schema(
@ -126,10 +100,10 @@ CONFIG_SCHEMA = cv.Schema(
cv.Optional(CONF_AUTO_ADD_PEER, default=False): cv.boolean, cv.Optional(CONF_AUTO_ADD_PEER, default=False): cv.boolean,
cv.Optional(CONF_USE_SENT_CHECK, default=True): cv.boolean, cv.Optional(CONF_USE_SENT_CHECK, default=True): cv.boolean,
cv.Optional( cv.Optional(
CONF_CONFORMATION_TIMEOUT, default="5000ms" CONF_CONFORMATION_TIMEOUT, default="5s"
): cv.positive_time_period_milliseconds, ): cv.positive_time_period_milliseconds,
cv.Optional(CONF_RETRIES, default=5): cv.int_range(min=1, max=10), cv.Optional(CONF_RETRIES, default=5): cv.int_range(min=1, max=10),
cv.Optional(CONF_KEEPER): cv.templatable(validate_peer), cv.Optional(CONF_PREDEFINED_PEERS): cv.ensure_list(DEFINE_PEER_CONFIG),
cv.Optional(CONF_ON_RECEIVE): automation.validate_automation( cv.Optional(CONF_ON_RECEIVE): automation.validate_automation(
{ {
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESPNowReceiveTrigger), cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESPNowReceiveTrigger),
@ -154,7 +128,6 @@ CONFIG_SCHEMA = cv.Schema(
cv.Optional(CONF_COMMAND): validate_command, cv.Optional(CONF_COMMAND): validate_command,
} }
), ),
cv.Optional(CONF_PEERS): cv.ensure_list(validate_peer),
}, },
cv.only_on_esp32, cv.only_on_esp32,
).extend(cv.COMPONENT_SCHEMA) ).extend(cv.COMPONENT_SCHEMA)
@ -164,7 +137,7 @@ async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config) await cg.register_component(var, config)
if CORE.using_arduino: if core.CORE.using_arduino:
cg.add_library("WiFi", None) cg.add_library("WiFi", None)
cg.add_define("USE_ESPNOW") cg.add_define("USE_ESPNOW")
@ -175,12 +148,11 @@ async def to_code(config):
cg.add(var.set_conformation_timeout(config[CONF_CONFORMATION_TIMEOUT])) cg.add(var.set_conformation_timeout(config[CONF_CONFORMATION_TIMEOUT]))
cg.add(var.set_retries(config[CONF_RETRIES])) cg.add(var.set_retries(config[CONF_RETRIES]))
if CONF_KEEPER in config: for conf in config.get(CONF_PREDEFINED_PEERS, []):
template_ = await cg.templatable(config[CONF_KEEPER], [], cg.uint64) mac = espnow_hex(conf.get(CONF_MAC_ADDRESS))
cg.add(var.set_keeper(template_)) if CONF_PEER_ID in conf:
cg.new_variable(conf[CONF_PEER_ID], mac)
for conf in config.get(CONF_PEERS, []): cg.add(var.add_peer(mac))
cg.add(var.add_peer(conf))
for conf in config.get(CONF_ON_SENT, []): for conf in config.get(CONF_ON_SENT, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
@ -233,6 +205,25 @@ async def register_protocol(var, config):
cg.add(var.set_protocol_mode(config[CONF_PROTOCOL_MODE])) cg.add(var.set_protocol_mode(config[CONF_PROTOCOL_MODE]))
def validate_peer(value):
if isinstance(value, cv.Lambda):
return cv.returning_lambda(value)
if value.find(":") != -1:
return cv.mac_address(value)
return cv.use_id(ESPNowPeer)(value)
async def register_peer(var, config, args):
peer = config.get(CONF_MAC_ADDRESS, 0xFFFFFFFFFFFF)
if isinstance(peer, core.MACAddress):
peer = espnow_hex(peer)
if isinstance(peer, core.ID):
peer = await cg.get_variable(peer)
template_ = await cg.templatable(peer, args, cg.uint64)
cg.add(var.set_mac_address(template_))
@automation.register_action( @automation.register_action(
"espnow.broadcast", "espnow.broadcast",
SendAction, SendAction,
@ -240,7 +231,7 @@ async def register_protocol(var, config):
{ {
cv.GenerateID(): cv.use_id(ESPNowComponent), cv.GenerateID(): cv.use_id(ESPNowComponent),
cv.Required(CONF_PAYLOAD): cv.templatable(validate_raw_data), cv.Required(CONF_PAYLOAD): cv.templatable(validate_raw_data),
cv.Optional(CONF_COMMAND, default=0): cv.templatable(validate_command), cv.Optional(CONF_COMMAND): cv.templatable(validate_command),
}, },
key=CONF_PAYLOAD, key=CONF_PAYLOAD,
), ),
@ -251,9 +242,9 @@ async def register_protocol(var, config):
cv.Schema( cv.Schema(
{ {
cv.GenerateID(): cv.use_id(ESPNowComponent), cv.GenerateID(): cv.use_id(ESPNowComponent),
cv.Required(CONF_PEER): cv.templatable(validate_peer), cv.Required(CONF_MAC_ADDRESS): validate_peer,
cv.Required(CONF_PAYLOAD): cv.templatable(validate_raw_data), cv.Required(CONF_PAYLOAD): cv.templatable(validate_raw_data),
cv.Optional(CONF_COMMAND, default=0): cv.templatable(validate_command), cv.Optional(CONF_COMMAND): cv.templatable(validate_command),
} }
), ),
) )
@ -261,11 +252,9 @@ async def send_action(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg) var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID]) await cg.register_parented(var, config[CONF_ID])
peer = config.get(CONF_PEER, 0xFFFFFFFFFFFF) await register_peer(var, config, args)
template_ = await cg.templatable(peer, args, cg.uint64)
cg.add(var.set_peer(template_))
command = config.get(CONF_COMMAND, 0) if command := config.get(CONF_COMMAND):
template_ = await cg.templatable(command, args, cg.uint8) template_ = await cg.templatable(command, args, cg.uint8)
cg.add(var.set_command(template_)) cg.add(var.set_command(template_))
@ -281,14 +270,14 @@ async def send_action(config, action_id, template_arg, args):
@automation.register_action( @automation.register_action(
"espnow.peer.new", "espnow.peer.add",
NewPeerAction, NewPeerAction,
cv.maybe_simple_value( cv.maybe_simple_value(
{ {
cv.GenerateID(): cv.use_id(ESPNowComponent), cv.GenerateID(): cv.use_id(ESPNowComponent),
cv.Required(CONF_PEER): cv.templatable(validate_peer), cv.Required(CONF_MAC_ADDRESS): validate_peer,
}, },
key=CONF_PEER, key=CONF_MAC_ADDRESS,
), ),
) )
@automation.register_action( @automation.register_action(
@ -297,25 +286,29 @@ async def send_action(config, action_id, template_arg, args):
cv.maybe_simple_value( cv.maybe_simple_value(
{ {
cv.GenerateID(): cv.use_id(ESPNowComponent), cv.GenerateID(): cv.use_id(ESPNowComponent),
cv.Required(CONF_PEER): cv.templatable(validate_peer), cv.Required(CONF_MAC_ADDRESS): validate_peer,
}, },
key=CONF_PEER, key=CONF_MAC_ADDRESS,
), ),
) )
@automation.register_action( @automation.register_action(
"espnow.keeper.set", "espnow.static.peer",
SetKeeperAction, SetStaticPeerAction,
cv.maybe_simple_value( cv.Schema(
{ {
cv.GenerateID(): cv.use_id(ESPNowComponent), cv.GenerateID(): cv.use_id(ESPNowComponent),
cv.Required(CONF_PEER): cv.templatable(validate_peer), cv.Required(CONF_PEER_ID): cv.use_id(ESPNowPeer),
}, cv.Required(CONF_MAC_ADDRESS): validate_peer,
key=CONF_PEER, }
), ),
) )
async def peer_action(config, action_id, template_arg, args): async def peer_action(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg) var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID]) await cg.register_parented(var, config[CONF_ID])
template_ = await cg.templatable(config[CONF_PEER], args, cg.uint64) if peer_id := config.get(CONF_PEER_ID):
cg.add(var.set_peer(template_)) peer = await cg.get_variable(peer_id)
cg.add(var.set_peer_id(peer))
await register_peer(var, config, args)
return var return var

View File

@ -29,34 +29,23 @@ static const size_t SEND_BUFFER_SIZE = 200;
ESPNowComponent *ESPNowComponent::static_{nullptr}; // NOLINT ESPNowComponent *ESPNowComponent::static_{nullptr}; // NOLINT
std::string espnow_encode_peer(uint64_t peer) { void show_packet(const std::string &title, const ESPNowPacket &packet) {
if (peer == FAILED) { ESP_LOGV(TAG, "%s packet. Peer: '%s', Protocol:%c%c%c-%02x, Sequents: %d.%d, Size: %d, Valid: %s", title.c_str(),
packet.get_peer_code().c_str(), packet.at(3), packet.at(4), packet.at(5), packet.at(6), packet.at(7),
packet.attempts, packet.content_size(), packet.is_valid() ? "Yes" : "No");
}
std::string peer_str(const uint64_t peer) {
char mac[24];
if (peer == 0)
return "[Not Set]"; return "[Not Set]";
} else if (peer == ESPNOW_BROADCAST_ADDR) if (peer == ESPNOW_BROADCAST_ADDR)
return "[BroadCast]"; return "[Broadcast]";
uint8_t *peer_ = (uint8_t *) &peer;
std::string str1 = ""; snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X", peer_[0], peer_[1], peer_[2], peer_[3], peer_[4],
str1.reserve(8); peer_[5]);
do {
str1.push_back(chars[peer & 63]); // Add on the left
peer = peer >> 6;
} while (peer != 0);
return str1;
};
uint64_t espnow_decode_peer(std::string peer) {
uint64_t mac = 0;
if (peer.size() != 8)
return FAILED;
for (int pos = peer.size(); pos > 0; pos--) {
char *p = strchr(chars, peer[pos - 1]);
if (p == nullptr)
return FAILED;
mac = (mac << 6) + (p - chars);
}
return mac; return mac;
}; }
/* ESPNowComponent ********************************************************************** */ /* ESPNowComponent ********************************************************************** */
@ -65,8 +54,7 @@ ESPNowComponent::ESPNowComponent() { ESPNowComponent::static_ = this; } // NOLI
void ESPNowComponent::dump_config() { void ESPNowComponent::dump_config() {
ESP_LOGCONFIG(TAG, "esp_now:"); ESP_LOGCONFIG(TAG, "esp_now:");
ESP_LOGCONFIG(TAG, " Own Peer code: %s.", espnow_encode_peer(this->own_peer_address_).c_str()); ESP_LOGCONFIG(TAG, " Own Peer code: %s.", peer_str(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, " Wifi channel: %d.", this->wifi_channel_);
ESP_LOGCONFIG(TAG, " Auto add new peers: %s.", this->auto_add_peer_ ? "Yes" : "No"); 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, " Use sent status: %s.", this->use_sent_check_ ? "Yes" : "No");
@ -74,13 +62,6 @@ void ESPNowComponent::dump_config() {
ESP_LOGCONFIG(TAG, " Send retries: %d.", this->retries_); ESP_LOGCONFIG(TAG, " Send retries: %d.", this->retries_);
} }
void ESPNowComponent::show_packet(const std::string &title, const ESPNowPacket &packet) {
ESP_LOGV(TAG, "%s packet. Peer: '%s', Header: %c%c%c, Protocol:%c%c%c-%02x, Sequents: %d.%d, Size: %d, Valid: %s",
title.c_str(), packet.get_peer_code().c_str(), packet.at(0), packet.at(1), packet.at(2), packet.at(3),
packet.at(4), packet.at(5), packet.at(6), packet.at(7), packet.attempts, packet.content_size(),
packet.is_valid() ? "Yes" : "No");
}
bool ESPNowComponent::validate_channel_(uint8_t channel) { bool ESPNowComponent::validate_channel_(uint8_t channel) {
wifi_country_t g_self_country; wifi_country_t g_self_country;
esp_wifi_get_country(&g_self_country); esp_wifi_get_country(&g_self_country);
@ -146,9 +127,6 @@ void ESPNowComponent::setup() {
for (auto id : this->peers_) { for (auto id : this->peers_) {
this->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)); this->send_queue_ = xQueueCreate(SEND_BUFFER_SIZE, sizeof(ESPNowPacket));
if (this->send_queue_ == nullptr) { if (this->send_queue_ == nullptr) {
@ -362,7 +340,8 @@ void ESPNowComponent::on_data_received(const uint8_t *addr, const uint8_t *data,
} else { } else {
packet.timestamp = millis(); packet.timestamp = millis();
} }
ESPNowComponent::static_->show_packet("Receive", packet);
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);
@ -407,7 +386,7 @@ void ESPNowComponent::on_data_sent(const uint8_t *mac_addr, esp_now_send_status_
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 (packet.peer != peer) { if (packet.peer != peer) {
ESP_LOGE(TAG, " Invalid mac address. Expected: %s (%d.%d); got: %s", packet.get_peer_code().c_str(), ESP_LOGE(TAG, " Invalid mac address. Expected: %s (%d.%d); got: %s", packet.get_peer_code().c_str(),
packet.get_sequents(), packet.attempts, espnow_encode_peer(peer).c_str()); packet.get_sequents(), packet.attempts, peer_str(peer).c_str());
return; return;
} else if (status != ESP_OK) { } else if (status != ESP_OK) {
ESP_LOGE(TAG, "Sent packet failed for %s (%d.%d)", packet.get_peer_code().c_str(), packet.get_sequents(), ESP_LOGE(TAG, "Sent packet failed for %s (%d.%d)", packet.get_peer_code().c_str(), packet.get_sequents(),
@ -425,12 +404,10 @@ void ESPNowComponent::on_data_sent(const uint8_t *mac_addr, esp_now_send_status_
/* ESPNowProtocol ********************************************************************** */ /* ESPNowProtocol ********************************************************************** */
bool ESPNowProtocol::send(uint64_t peer, const uint8_t *data, uint8_t len, uint8_t command) { bool ESPNowProtocol::send(uint64_t peer, const uint8_t *data, uint8_t len, uint8_t command) {
if (peer == 0x0 && this->parent_ != nullptr) { if (peer == 0ULL)
peer = this->parent_->get_keeper(); return false;
}
ESPNowPacket packet(peer, data, len, this->get_protocol_id(), command); // NOLINT ESPNowPacket packet(peer, data, len, this->get_protocol_id(), command); // NOLINT
packet.set_sequents(this->get_next_sequents(packet.peer)); packet.set_sequents(this->get_next_sequents(peer));
return this->parent_->send(packet); return this->parent_->send(packet);
} }

View File

@ -7,6 +7,7 @@
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esp_mac.h"
#include <esp_now.h> #include <esp_now.h>
#include <array> #include <array>
@ -32,15 +33,17 @@ static const uint8_t ESPNOW_COMMAND_ACK = 0x06;
static const uint8_t ESPNOW_COMMAND_NAK = 0x15; static const uint8_t ESPNOW_COMMAND_NAK = 0x15;
static const uint8_t ESPNOW_COMMAND_RESEND = 0x05; static const uint8_t ESPNOW_COMMAND_RESEND = 0x05;
static const char chars[] = "0123456789-AbCdEfGhIjKlMnOpQrStUvWxYz+aBcDeFgHiJkLmNoPqRsTuVwXyZ";
static const uint64_t FAILED = 0; static const uint64_t FAILED = 0;
struct ESPNowPacket;
template<typename T> std::string espnow_i2h(T i) { return sprintf("%04x", i); } template<typename T> std::string espnow_i2h(T i) { return sprintf("%04x", i); }
std::string espnow_rdm(std::string::size_type length); std::string espnow_rdm(std::string::size_type length);
std::string espnow_encode_peer(uint64_t peer); std::string peer_str(const uint64_t peer);
uint64_t espnow_decode_peer(std::string peer);
void show_packet(const std::string &title, const ESPNowPacket &packet);
struct ESPNowPacket { struct ESPNowPacket {
uint64_t peer{0}; uint64_t peer{0};
@ -107,7 +110,7 @@ struct ESPNowPacket {
inline bool is_peer(const uint8_t *peer) const { return memcmp(peer, this->get_peer(), 6) == 0; } inline bool is_peer(const uint8_t *peer) const { return memcmp(peer, this->get_peer(), 6) == 0; }
inline uint8_t *get_peer() const { return (uint8_t *) &(this->peer); } inline uint8_t *get_peer() const { return (uint8_t *) &(this->peer); }
inline std::string get_peer_code() const { return espnow_encode_peer(this->peer); } inline std::string get_peer_code() const { return peer_str(this->peer); }
inline uint32_t get_protocol() const { return this->content.prefix.protocol & 0x00FFFFFF; } inline uint32_t get_protocol() const { return this->content.prefix.protocol & 0x00FFFFFF; }
inline void set_protocol(uint32_t protocol) { inline void set_protocol(uint32_t protocol) {
@ -140,7 +143,7 @@ struct ESPNowPacket {
class ESPNowComponent; class ESPNowComponent;
enum ESPNowProtocol_mode { universal, keeper, drudge }; enum ESPNowProtocol_mode { pm_universal, pm_keeper, pm_drudge };
class ESPNowProtocol : public Parented<ESPNowComponent> { class ESPNowProtocol : public Parented<ESPNowComponent> {
public: public:
@ -148,7 +151,7 @@ class ESPNowProtocol : public Parented<ESPNowComponent> {
ESPNowProtocol_mode get_protocol_mode() { return this->protocol_mode_; } ESPNowProtocol_mode get_protocol_mode() { return this->protocol_mode_; }
protected: protected:
ESPNowProtocol_mode protocol_mode_{universal}; ESPNowProtocol_mode protocol_mode_{pm_universal};
public: public:
virtual uint32_t get_protocol_id() = 0; virtual uint32_t get_protocol_id() = 0;
@ -189,11 +192,11 @@ class ESPNowProtocol : public Parented<ESPNowComponent> {
std::map<uint64_t, uint8_t> next_sequents_{}; std::map<uint64_t, uint8_t> next_sequents_{};
std::string get_mode_name_() { std::string get_mode_name_() {
switch (this->protocol_mode_) { switch (this->protocol_mode_) {
case universal: case pm_universal:
return "Universal"; return "Universal";
case keeper: case pm_keeper:
return "Keeper"; return "Keeper";
case drudge: case pm_drudge:
return "Drudge"; return "Drudge";
} }
} }
@ -259,8 +262,7 @@ class ESPNowComponent : public Component {
void set_conformation_timeout(uint32_t timeout) { this->conformation_timeout_ = timeout; } void set_conformation_timeout(uint32_t timeout) { this->conformation_timeout_ = timeout; }
void set_retries(uint8_t value) { this->retries_ = value; } void set_retries(uint8_t value) { this->retries_ = value; }
void set_pairing_protocol(ESPNowProtocol *pairing_protocol) { this->pairing_protocol_ = pairing_protocol; } 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_; } uint64_t get_own_peer_address() { return this->own_peer_address_; }
void setup() override; void setup() override;
@ -290,8 +292,6 @@ class ESPNowComponent : public Component {
ESPNowDefaultProtocol *get_default_protocol(); ESPNowDefaultProtocol *get_default_protocol();
void show_packet(const std::string &title, const ESPNowPacket &packet);
static void espnow_task(void *params); static void espnow_task(void *params);
protected: protected:
@ -302,7 +302,6 @@ class ESPNowComponent : public Component {
uint8_t wifi_channel_{0}; uint8_t wifi_channel_{0};
uint32_t conformation_timeout_{5000}; uint32_t conformation_timeout_{5000};
uint8_t retries_{5}; uint8_t retries_{5};
uint64_t keeper_{0};
bool auto_add_peer_{false}; bool auto_add_peer_{false};
bool use_sent_check_{true}; bool use_sent_check_{true};
@ -326,49 +325,55 @@ class ESPNowComponent : public Component {
static ESPNowComponent *static_; // NOLINT static ESPNowComponent *static_; // NOLINT
}; };
/********************************* Actions **************************************/
template<typename... Ts> class SendAction : public Action<Ts...>, public Parented<ESPNowComponent> { template<typename... Ts> class SendAction : public Action<Ts...>, public Parented<ESPNowComponent> {
public: TEMPLATABLE_VALUE(uint64_t, mac_address);
TEMPLATABLE_VALUE(uint64_t, peer);
TEMPLATABLE_VALUE(uint8_t, command); TEMPLATABLE_VALUE(uint8_t, command);
TEMPLATABLE_VALUE(std::vector<uint8_t>, payload); TEMPLATABLE_VALUE(std::vector<uint8_t>, payload);
public:
void play(Ts... x) override { void play(Ts... x) override {
uint64_t peer = this->peer_.value(x...); uint64_t peer = this->mac_address_.value(x...);
uint8_t command = this->command_.value(x...); uint8_t command = this->command_.value(x...);
std::vector<uint8_t> payload = this->payload_.value(x...); std::vector<uint8_t> payload = this->payload_.value(x...);
ESP_LOGVV("SendAction", "send to 0x%12llx, command %d, payload size: %d", peer, command, payload.size());
this->parent_->get_default_protocol()->send(peer, payload.data(), payload.size(), command); this->parent_->get_default_protocol()->send(peer, payload.data(), payload.size(), command);
} }
}; };
template<typename... Ts> class NewPeerAction : public Action<Ts...>, public Parented<ESPNowComponent> { template<typename... Ts> class NewPeerAction : public Action<Ts...>, public Parented<ESPNowComponent> {
public: public:
TEMPLATABLE_VALUE(uint64_t, peer); TEMPLATABLE_VALUE(uint64_t, mac_address);
void play(Ts... x) override { void play(Ts... x) override {
auto peer = this->peer_.value(x...); uint64_t mac_address = this->mac_address_.value(x...);
parent_->add_peer(peer); parent_->add_peer(mac_address);
} }
}; };
template<typename... Ts> class DelPeerAction : public Action<Ts...>, public Parented<ESPNowComponent> { template<typename... Ts> class DelPeerAction : public Action<Ts...>, public Parented<ESPNowComponent> {
public: public:
TEMPLATABLE_VALUE(uint64_t, peer); TEMPLATABLE_VALUE(uint64_t, mac_address);
void play(Ts... x) override { void play(Ts... x) override {
auto peer = this->peer_.value(x...); uint64_t mac_address = this->mac_address_.value(x...);
parent_->del_peer(peer); parent_->del_peer(mac_address);
} }
}; };
template<typename... Ts> class SetKeeperAction : public Action<Ts...>, public Parented<ESPNowComponent> { template<typename... Ts> class SetStaticPeerAction : public Action<Ts...>, public Parented<ESPNowComponent> {
public: public:
TEMPLATABLE_VALUE(uint64_t, peer); TEMPLATABLE_VALUE(uint64_t, mac_address);
void set_peer_id(uint64_t &peer_id) { this->peer_id_ = &peer_id; }
void play(Ts... x) override { void play(Ts... x) override {
auto peer = this->peer_.value(x...); uint64_t mac_address = this->mac_address_.value(x...);
parent_->set_keeper(peer); *(this->peer_id_) = mac_address;
if (mac_address != 0)
parent_->add_peer(mac_address);
} }
protected:
uint64_t *peer_id_;
}; };
/********************************* triggers **************************************/
class ESPNowSentTrigger : public Trigger<const ESPNowPacket, bool> { class ESPNowSentTrigger : public Trigger<const ESPNowPacket, bool> {
public: public:
explicit ESPNowSentTrigger(ESPNowComponent *parent) { explicit ESPNowSentTrigger(ESPNowComponent *parent) {

View File

@ -7,7 +7,8 @@ esp32:
board: esp32dev board: esp32dev
framework: framework:
type: esp-idf type: esp-idf
# version: 5.1.5 # version: 5.2.1
# platform_version: 6.6.0
esphome: esphome:
name: "${name}" name: "${name}"
@ -28,11 +29,7 @@ logger:
level: verbose level: verbose
espnow: espnow:
auto_add_peer: false auto_add_peer: true
peers:
- FF:FF:FF:FF:FF:FF
- flW1QA3k
on_receive: on_receive:
- logger.log: - logger.log:
format: "Received: '%s' from '%s' command: %d RSSI: %d" format: "Received: '%s' from '%s' command: %d RSSI: %d"
@ -44,11 +41,12 @@ espnow:
packet.rssi, packet.rssi,
] ]
# this works only when esp_idf v5.1.5+ is being used.
on_broadcast: on_broadcast:
- command: 123 - command: 123
then: then:
- logger.log: - logger.log:
format: "Broadcast Received from: '%s' RSSI: %d: %s" format: "Broadcast from: '%s' RSSI: %d: %s"
args: args:
[ [
packet.get_peer_code().c_str(), packet.get_peer_code().c_str(),

View File

@ -7,7 +7,8 @@ esp32:
board: esp32dev board: esp32dev
framework: framework:
type: esp-idf type: esp-idf
# version: 5.1.5 # version: 5.2.1
# platform_version: 6.6.0
esphome: esphome:
name: "${name}" name: "${name}"
@ -27,11 +28,18 @@ esphome:
logger: logger:
level: verbose level: verbose
globals:
- id: hub_address
type: uint64_t
initial_value: "0xE86BEA23CD98"
restore_value: yes
espnow: espnow:
auto_add_peer: true auto_add_peer: true
peers: predefined_peers:
- FF:FF:FF:FF:FF:FF - peer_id: keeper
keeper: rmT7YF9o mac_address: E8:6B:EA:23:CD:98
on_receive: on_receive:
- logger.log: - logger.log:
format: "Received: '%s' from '%s' command: %d RSSI: %d" format: "Received: '%s' from '%s' command: %d RSSI: %d"
@ -65,12 +73,30 @@ interval:
- interval: 5sec - interval: 5sec
then: then:
- espnow.send: - espnow.send:
peer: keeper mac_address: keeper
payload: "tesing the test" payload: "Used static keeper value"
command: 222
- espnow.send:
mac_address: E8:6B:EA:23:CD:98
payload: "used fixed mac address"
command: 123
- espnow.send:
# dynamic peer address
mac_address: !lambda return keeper;
payload: "use keeper dynamicly "
command: 62
- espnow.send:
mac_address: !lambda return id(hub_address);
payload: "Using a global numberic value dynamicly"
command: 132
binary_sensor: binary_sensor:
- platform: gpio - platform: gpio
pin: GPIO39 pin: GPIO39
name: Button name: Button
on_click: on_click:
- espnow.peer.del: rmT7YF9o - espnow.static.peer:
peer_id: keeper
mac_address: 80:6B:EA:23:CD:87
- espnow.peer.add: 80:6B:EA:23:AA:BB
- espnow.peer.del: 80:6B:EA:23:AA:BB