[nfc] Pass tags to triggers by reference and keep the listener list in static storage (#19902)

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Keith Burzinski
2026-09-29 15:00:23 -05:00
committed by GitHub
co-authored by Claude Fable 5.1
parent 6b465443bc
commit 662c7db222
15 changed files with 54 additions and 28 deletions
+2 -1
View File
@@ -7,7 +7,8 @@ nfc_ns = cg.esphome_ns.namespace("nfc")
Nfcc = nfc_ns.class_("Nfcc")
NfcTag = nfc_ns.class_("NfcTag")
NfcTagConstRef = NfcTag.operator("ref").operator("const")
NfcTagListener = nfc_ns.class_("NfcTagListener")
NfcOnTagTrigger = nfc_ns.class_(
"NfcOnTagTrigger", automation.Trigger.template(cg.std_string, NfcTag)
"NfcOnTagTrigger", automation.Trigger.template(cg.std_string, NfcTagConstRef)
)
+2 -1
View File
@@ -7,7 +7,8 @@
namespace esphome::nfc {
class NfcOnTagTrigger final : public Trigger<std::string, NfcTag> {
/// Fires with the formatted UID and the tag itself; the tag is passed by reference so no copy is made per trigger
class NfcOnTagTrigger final : public Trigger<std::string, const NfcTag &> {
public:
void process(const std::unique_ptr<NfcTag> &tag);
};
@@ -20,7 +20,6 @@ NfcTagBinarySensor = nfc_ns.class_(
binary_sensor.BinarySensor,
cg.Component,
NfcTagListener,
cg.Parented.template(Nfcc),
)
@@ -59,12 +58,15 @@ CONFIG_SCHEMA = cv.All(
)
_request_listener_slot = cg.slot_counter("NFC_TAG_LISTENER_COUNT")
async def to_code(config: ConfigType) -> None:
var = await binary_sensor.new_binary_sensor(config)
await cg.register_component(var, config)
await cg.register_parented(var, config[CONF_NFCC_ID])
hub = await cg.get_variable(config[CONF_NFCC_ID])
_request_listener_slot(str(hub))
cg.add(hub.register_listener(var))
if CONF_NDEF_CONTAINS in config:
cg.add(var.set_ndef_match_string(config[CONF_NDEF_CONTAINS]))
@@ -7,10 +7,7 @@ namespace esphome::nfc {
static const char *const TAG = "nfc.binary_sensor";
void NfcTagBinarySensor::setup() {
this->parent_->register_listener(this);
this->publish_initial_state(false);
}
void NfcTagBinarySensor::setup() { this->publish_initial_state(false); }
void NfcTagBinarySensor::dump_config() {
std::string match_str = "name";
@@ -8,10 +8,7 @@
namespace esphome::nfc {
class NfcTagBinarySensor final : public binary_sensor::BinarySensor,
public Component,
public NfcTagListener,
public Parented<Nfcc> {
class NfcTagBinarySensor final : public binary_sensor::BinarySensor, public Component, public NfcTagListener {
public:
void setup() override;
void dump_config() override;
+3 -1
View File
@@ -83,10 +83,12 @@ class NfcTagListener {
class Nfcc {
public:
#ifdef NFC_TAG_LISTENER_COUNT
void register_listener(NfcTagListener *listener) { this->tag_listeners_.push_back(listener); }
protected:
std::vector<NfcTagListener *> tag_listeners_;
StaticVector<NfcTagListener *, NFC_TAG_LISTENER_COUNT> tag_listeners_;
#endif
};
} // namespace esphome::nfc
+4 -4
View File
@@ -4,14 +4,14 @@ namespace esphome::nfc {
static const char *const TAG = "nfc.helpers";
bool has_ha_tag_ndef(NfcTag &tag) { return !get_ha_tag_ndef(tag).empty(); }
bool has_ha_tag_ndef(const NfcTag &tag) { return !get_ha_tag_ndef(tag).empty(); }
std::string get_ha_tag_ndef(NfcTag &tag) {
std::string get_ha_tag_ndef(const NfcTag &tag) {
if (!tag.has_ndef_message()) {
return std::string();
}
auto message = tag.get_ndef_message();
auto records = message->get_records();
const auto &message = tag.get_ndef_message();
const auto &records = message->get_records();
for (const auto &record : records) {
std::string payload = record->get_payload();
size_t pos = payload.find(HA_TAG_ID_PREFIX);
+2 -2
View File
@@ -8,8 +8,8 @@ static const char HA_TAG_ID_EXT_RECORD_TYPE[] = "android.com:pkg";
static const char HA_TAG_ID_EXT_RECORD_PAYLOAD[] = "io.homeassistant.companion.android";
static const char HA_TAG_ID_PREFIX[] = "https://www.home-assistant.io/tag/";
std::string get_ha_tag_ndef(NfcTag &tag);
std::string get_ha_tag_ndef(const NfcTag &tag);
std::string get_random_ha_tag_ndef();
bool has_ha_tag_ndef(NfcTag &tag);
bool has_ha_tag_ndef(const NfcTag &tag);
} // namespace esphome::nfc
+4 -3
View File
@@ -42,9 +42,10 @@ class NfcTag {
}
NfcTagUid &get_uid() { return this->uid_; };
const std::string &get_tag_type() { return this->tag_type_; };
bool has_ndef_message() { return this->ndef_message_ != nullptr; };
const std::shared_ptr<NdefMessage> &get_ndef_message() { return this->ndef_message_; };
const NfcTagUid &get_uid() const { return this->uid_; };
const std::string &get_tag_type() const { return this->tag_type_; };
bool has_ndef_message() const { return this->ndef_message_ != nullptr; };
const std::shared_ptr<NdefMessage> &get_ndef_message() const { return this->ndef_message_; };
void set_ndef_message(std::unique_ptr<NdefMessage> ndef_message) { this->ndef_message_ = std::move(ndef_message); };
protected:
+2 -2
View File
@@ -66,7 +66,7 @@ async def setup_pn532(var: MockObj, config: ConfigType) -> None:
_request_ontag_trigger_slot(str(var))
cg.add(var.register_ontag_trigger(trigger))
await automation.build_automation(
trigger, [(cg.std_string, "x"), (nfc.NfcTag, "tag")], conf
trigger, [(cg.std_string, "x"), (nfc.NfcTagConstRef, "tag")], conf
)
for conf in config.get(CONF_ON_TAG_REMOVED, []):
@@ -74,7 +74,7 @@ async def setup_pn532(var: MockObj, config: ConfigType) -> None:
_request_ontagremoved_trigger_slot(str(var))
cg.add(var.register_ontagremoved_trigger(trigger))
await automation.build_automation(
trigger, [(cg.std_string, "x"), (nfc.NfcTag, "tag")], conf
trigger, [(cg.std_string, "x"), (nfc.NfcTagConstRef, "tag")], conf
)
await automation.build_callback_automations(var, config, _CALLBACK_AUTOMATIONS)
+2 -2
View File
@@ -144,7 +144,7 @@ async def setup_pn71xx(var: MockObj, config: ConfigType) -> None:
_request_ontag_trigger_slot(str(var))
cg.add(var.register_ontag_trigger(trigger))
await automation.build_automation(
trigger, [(cg.std_string, "x"), (nfc.NfcTag, "tag")], conf
trigger, [(cg.std_string, "x"), (nfc.NfcTagConstRef, "tag")], conf
)
for conf in config.get(CONF_ON_TAG_REMOVED, []):
@@ -152,7 +152,7 @@ async def setup_pn71xx(var: MockObj, config: ConfigType) -> None:
_request_ontagremoved_trigger_slot(str(var))
cg.add(var.register_ontagremoved_trigger(trigger))
await automation.build_automation(
trigger, [(cg.std_string, "x"), (nfc.NfcTag, "tag")], conf
trigger, [(cg.std_string, "x"), (nfc.NfcTagConstRef, "tag")], conf
)
await automation.build_callback_automations(var, config, _CALLBACK_AUTOMATIONS)
+4
View File
@@ -569,9 +569,11 @@ void PN71xx::erase_tag_(const uint8_t tag_index) {
trigger->process(this->discovered_endpoint_[tag_index].tag);
}
#endif
#ifdef NFC_TAG_LISTENER_COUNT
for (auto *listener : this->tag_listeners_) {
listener->tag_off(*this->discovered_endpoint_[tag_index].tag);
}
#endif
char uid_buf[nfc::FORMAT_UID_BUFFER_SIZE];
ESP_LOGI(TAG, "Tag %s removed", nfc::format_uid_to(uid_buf, this->discovered_endpoint_[tag_index].tag->get_uid()));
// keep the remaining entries in order; selecting_endpoint_ indexes into this list
@@ -908,9 +910,11 @@ void PN71xx::process_rf_intf_activated_oid_(nfc::NciMessage &rx) { // an endpoi
trigger->process(working_endpoint.tag);
}
#endif
#ifdef NFC_TAG_LISTENER_COUNT
for (auto *listener : this->tag_listeners_) {
listener->tag_on(*working_endpoint.tag);
}
#endif
working_endpoint.trig_called = true;
break;
}
+1
View File
@@ -141,6 +141,7 @@
#define MICRONOVA_LISTENER_COUNT 1
#define USE_MICRONOVA_WRITER
#define MK2PVROUTER_LISTENER_COUNT 1
#define NFC_TAG_LISTENER_COUNT 1
#define PN532_BINARY_SENSOR_COUNT 1
#define PN532_ON_TAG_REMOVED_TRIGGER_COUNT 1
#define PN532_ON_TAG_TRIGGER_COUNT 1
+9
View File
@@ -1,6 +1,15 @@
pn532_spi:
id: pn532_nfcc_spi
cs_pin: ${cs_pin}
on_tag:
then:
- delay: 10ms
- lambda: |-
ESP_LOGD("test", "%s %zu %d %d", tag.get_tag_type().c_str(), tag.get_uid().size(), tag.has_ndef_message(),
nfc::has_ha_tag_ndef(tag));
on_tag_removed:
then:
- lambda: ESP_LOGD("test", "%s", tag.get_tag_type().c_str());
binary_sensor:
- platform: pn532
+13 -2
View File
@@ -24,8 +24,19 @@ pn7160_spi:
emulation_message: https://www.home-assistant.io/tag/pulse_ce
tag_ttl: 1000ms
on_tag:
- logger.log: "Tag"
then:
- delay: 10ms
- lambda: |-
ESP_LOGD("test", "%s %zu %d %s", tag.get_tag_type().c_str(), tag.get_uid().size(), tag.has_ndef_message(),
nfc::get_ha_tag_ndef(tag).c_str());
on_tag_removed:
- logger.log: "Tag removed"
then:
- lambda: ESP_LOGD("test", "%s", tag.get_tag_type().c_str());
on_emulated_tag_scan:
- logger.log: "Tag emulated"
binary_sensor:
- platform: nfc
nfcc_id: nfcc_pn7160_spi
name: Pulse tag
ndef_contains: pulse