Add command filters to the triggers

This commit is contained in:
NP v/d Spek 2024-10-05 18:53:55 +02:00
parent c83b68460c
commit 7931a307b4
3 changed files with 55 additions and 18 deletions

View file

@ -1,7 +1,7 @@
from esphome import automation from esphome import automation
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_DATA, CONF_ID, CONF_TRIGGER_ID from esphome.const import CONF_COMMAND, CONF_DATA, CONF_ID, CONF_TRIGGER_ID
from esphome.core import CORE from esphome.core import CORE
CODEOWNERS = ["@nielsnl68", "@jesserockz"] CODEOWNERS = ["@nielsnl68", "@jesserockz"]
@ -66,16 +66,19 @@ CONFIG_SCHEMA = cv.Schema(
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),
cv.Optional(CONF_COMMAND): cv.Range(min=16, max=255),
} }
), ),
cv.Optional(CONF_ON_SENT): automation.validate_automation( cv.Optional(CONF_ON_SENT): automation.validate_automation(
{ {
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESPNowSentTrigger), cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESPNowSentTrigger),
cv.Optional(CONF_COMMAND): cv.Range(min=16, max=255),
} }
), ),
cv.Optional(CONF_ON_NEW_PEER): automation.validate_automation( cv.Optional(CONF_ON_NEW_PEER): automation.validate_automation(
{ {
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESPNowNewPeerTrigger), cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ESPNowNewPeerTrigger),
cv.Optional(CONF_COMMAND): cv.Range(min=16, max=255),
} }
), ),
cv.Optional(CONF_PEERS): cv.ensure_list(cv.mac_address), cv.Optional(CONF_PEERS): cv.ensure_list(cv.mac_address),
@ -101,6 +104,8 @@ async def to_code(config):
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)
if CONF_COMMAND in conf:
cg.add(trigger.set_command(conf[CONF_COMMAND]))
await automation.build_automation( await automation.build_automation(
trigger, trigger,
[(ESPNowPacketConst, "packet"), (bool, "status")], [(ESPNowPacketConst, "packet"), (bool, "status")],
@ -109,12 +114,16 @@ async def to_code(config):
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)
if CONF_COMMAND in conf:
cg.add(trigger.set_command(conf[CONF_COMMAND]))
await automation.build_automation( await automation.build_automation(
trigger, [(ESPNowPacketConst, "packet")], conf 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)
if CONF_COMMAND in conf:
cg.add(trigger.set_command(conf[CONF_COMMAND]))
await automation.build_automation( await automation.build_automation(
trigger, [(ESPNowPacketConst, "packet")], conf trigger, [(ESPNowPacketConst, "packet")], conf
) )
@ -144,6 +153,7 @@ async def register_protocol(var, config):
cv.GenerateID(): cv.use_id(ESPNowComponent), cv.GenerateID(): cv.use_id(ESPNowComponent),
cv.Optional(CONF_PEER): cv.templatable(cv.mac_address), cv.Optional(CONF_PEER): cv.templatable(cv.mac_address),
cv.Required(CONF_DATA): cv.templatable(validate_raw_data), cv.Required(CONF_DATA): cv.templatable(validate_raw_data),
cv.Optional(CONF_COMMAND): cv.templatable(cv.Range(min=16, max=255)),
}, },
key=CONF_DATA, key=CONF_DATA,
), ),
@ -155,6 +165,10 @@ async def send_action(config, action_id, template_arg, args):
template_ = await cg.templatable(config[CONF_PEER].as_hex, args, cg.uint64) template_ = await cg.templatable(config[CONF_PEER].as_hex, args, cg.uint64)
cg.add(var.set_mac(template_)) cg.add(var.set_mac(template_))
if CONF_COMMAND in config:
template_ = await cg.templatable(config[CONF_COMMAND], args, cg.uint8)
cg.add(var.set_command(template_))
data = config.get(CONF_DATA, []) data = config.get(CONF_DATA, [])
if isinstance(data, bytes): if isinstance(data, bytes):
data = list(data) data = list(data)
@ -178,13 +192,6 @@ async def send_action(config, action_id, template_arg, args):
key=CONF_PEER, key=CONF_PEER,
), ),
) )
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_PEER].as_hex, args, cg.uint64)
cg.add(var.set_mac(template_))
return var
@automation.register_action( @automation.register_action(
"espnow.peer.del", "espnow.peer.del",
DelPeerAction, DelPeerAction,

View file

@ -344,9 +344,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) { bool ESPNowProtocol::send(uint64_t peer, const uint8_t *data, uint8_t len, uint8_t command = 0) {
ESPNowPacket packet(peer, data, len, this->get_protocol_component_id()); // NOLINT ESPNowPacket packet(peer, data, len, this->get_protocol_component_id()); // NOLINT
packet.set_sequents(this->get_next_sequents()); packet.set_sequents(this->get_next_sequents(packet.peer, packet.protocol()));
packet.set_command(command);
return this->parent_->send(packet); return this->parent_->send(packet);
} }

View file

@ -23,7 +23,7 @@ static const uint64_t ESPNOW_BROADCAST_ADDR = 0xFFFFFFFFFFFF;
static const uint8_t MAX_ESPNOW_DATA_SIZE = 241; static const uint8_t MAX_ESPNOW_DATA_SIZE = 241;
static const uint8_t TRANSPORT_HEADER[] = {'N', '0', 'w'}; static const uint8_t TRANSPORT_HEADER[3] = {'N', '0', 'w'};
static const uint32_t ESPNOW_MAIN_PROTOCOL_ID = 0x447453; // = StD static const uint32_t ESPNOW_MAIN_PROTOCOL_ID = 0x447453; // = StD
static const uint8_t ESPNOW_COMMAND_ACK = 0x06; static const uint8_t ESPNOW_COMMAND_ACK = 0x06;
@ -129,7 +129,7 @@ class ESPNowProtocol : public Parented<ESPNowComponent> {
virtual void on_new_peer(const 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(uint64_t peer = 0, uint32_t protocol = 0) {
if (this->next_sequents_ == 255) { if (this->next_sequents_ == 255) {
this->next_sequents_ = 0; this->next_sequents_ = 0;
} else { } else {
@ -145,7 +145,7 @@ class ESPNowProtocol : public Parented<ESPNowComponent> {
return valid; return valid;
} }
bool send(uint64_t peer, const uint8_t *data, uint8_t len); bool send(uint64_t peer, const uint8_t *data, uint8_t len, uint8_t command = 0);
protected: protected:
uint8_t next_sequents_{255}; uint8_t next_sequents_{255};
@ -260,6 +260,8 @@ class ESPNowComponent : public Component {
template<typename... Ts> class SendAction : public Action<Ts...>, public Parented<ESPNowComponent> { template<typename... Ts> class SendAction : public Action<Ts...>, public Parented<ESPNowComponent> {
public: public:
template<typename V> void set_mac(V mac) { this->mac_ = mac; } template<typename V> void set_mac(V mac) { this->mac_ = mac; }
template<typename V> void set_command(V command) { this->command_ = command; }
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;
@ -271,6 +273,10 @@ template<typename... Ts> class SendAction : public Action<Ts...>, public Parente
void play(Ts... x) override { void play(Ts... x) override {
uint64_t mac = this->mac_.value(x...); uint64_t mac = this->mac_.value(x...);
uint8_t command = 0;
if (this->command_.has_value()) {
command = this->mac_.value(x...);
}
if (this->static_) { if (this->static_) {
this->parent_->get_default_protocol()->send(mac, this->data_static_.data(), this->data_static_.size()); this->parent_->get_default_protocol()->send(mac, this->data_static_.data(), this->data_static_.size());
@ -281,6 +287,7 @@ template<typename... Ts> class SendAction : public Action<Ts...>, public Parente
} }
protected: protected:
TemplatableValue<uint8_t, Ts...> command_{};
TemplatableValue<uint64_t, Ts...> mac_{}; TemplatableValue<uint64_t, Ts...> mac_{};
bool static_{false}; bool static_{false};
std::function<ByteBuffer(Ts...)> data_func_{}; std::function<ByteBuffer(Ts...)> data_func_{};
@ -314,24 +321,46 @@ template<typename... Ts> class DelPeerAction : public Action<Ts...>, public Pare
class ESPNowSentTrigger : public Trigger<const 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](const ESPNowPacket packet, bool status) {
[this](const ESPNowPacket packet, bool status) { this->trigger(packet, status); }); if ((this->command_ == 0) || this->command_ == packet.get_command()) {
this->trigger(packet, status);
}
});
} }
void set_command(uint8_t command) { this->command_ = command; }
protected:
uint8_t command_{0};
}; };
class ESPNowReceiveTrigger : public Trigger<const 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( parent->get_default_protocol()->add_on_receive_callback([this](const ESPNowPacket packet) {
[this](const ESPNowPacket packet) { this->trigger(packet); }); if ((this->command_ == 0) || this->command_ == packet.get_command()) {
this->trigger(packet);
}
});
} }
void set_command(uint8_t command) { this->command_ = command; }
protected:
uint8_t command_{0};
}; };
class ESPNowNewPeerTrigger : public Trigger<const 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](const ESPNowPacket packet) { this->trigger(packet); }); parent->get_default_protocol()->add_on_peer_callback([this](const ESPNowPacket packet) {
if ((this->command_ == 0) || this->command_ == packet.get_command()) {
this->trigger(packet);
}
});
} }
void set_command(uint8_t command) { this->command_ = command; }
protected:
uint8_t command_{0};
}; };
} // namespace espnow } // namespace espnow