Help with first ESP32 NFC reader please

Hi all,

I’m trying to set up my first ESP32 NFC tag reader in ESPHome but not getting too far, can I get some help please :slight_smile:

I have the ESP32 connected to the PN532 over I2C, the dip switches are set as seen on the web; 1 on, 2off, connected SDA to GPIO21 and SCL to GPIO22 on the ESP32

I then created a new device in ESPHome on Home Assistant, added the PN532 NFC component and flashed the device.

The new device was detected by ESP Home integration so I added it.

Thats as far as I have got, I can’t see any entities so I must have missed something. On the ESP environment monitors I made I had to add some code from the ESP device library and it worked, however I can’t see any code block on the PN532 only snippets which does not make sense to me I’m afraid.

Is there soemthing I need to add to make this work??

Thanks In advannce

Documentation describes how to set up tags and how to make binary sensors.

Thanks,

I’ve been looking at that page for a while; it seems to show little blocks of code but no “whole” code example?

I managed to get HA tag section to recognise a tag by trial and error updating bits of code but still no entity I can see.

I’m currently looking at ChatGPT which is providing some code and I’ll try that while searching.

I would expect a “Tag Read” notification plus a “Tag data” entity maybe?? I woul dneed to recognise each tag in Node Red.

You just add the code snippets in the linked page to your yaml.

If you post your complete yaml correctly formatted someone will let you know whats wrong.

It can be tricky getting started with esphome, and following old tutorials can also cause issues, we have all been there.

I think NFC reader is probably not best way to get used to esphome. You could configure for example uptime sensor and gpio switch for onboard LED to start with. When you are comfortable with esphome, logs and code uploading, add your reader.

Thanks and noted,

Its not the first, the DHT22 monitors were easy - one cut-n-paste block that made sense. The NFC does seem far more complex.

I’ll post code shortly..

I guess you have added the i2c bus?

Yes, thanks.

I’m getting data now but its unreliable, will post code asap

This is the code currently running, its still not right as i have given the tag a name as well as the same name being used as the ID but in settings-tags it shows either the name or a long UID code.

I think I have burnt chatgpt out on this one, I thought it would be easier really.

Any thoughts here?

esphome:
  name: esp-nfc
  friendly_name: ESP_NFC

esp32:
  variant: esp32
  framework:
    type: esp-idf

logger:

api:
  encryption:
    key: "xxxxxxx"

ota:
  - platform: esphome

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  ap:
    ssid: "ESP_NFC Fallback Hotspot"
    password: "xxxxxxxxx"

captive_portal:


# --------------------------------------------------
# ONBOARD LED
# --------------------------------------------------

output:
  - platform: gpio
    pin: GPIO2
    id: onboard_led


# --------------------------------------------------
# SPI BUS
# --------------------------------------------------

spi:
  clk_pin: 18
  miso_pin: 19
  mosi_pin: 23
  id: spi_1


# --------------------------------------------------
# PN532 - SPI
# --------------------------------------------------

pn532_spi:
  id: nfc_reader
  cs_pin: 5
  spi_id: spi_1
  update_interval: 1s

  on_tag:
    then:

      # ------------------------------------------------
      # HOME ASSISTANT TAG
      #
      # Only the NDEF Home Assistant tag ID is used.
      # The physical PN532 UID is NOT used.
      # ------------------------------------------------

      - homeassistant.tag_scanned: !lambda |-
          if (!tag.has_ndef_message()) {
            return "";
          }

          auto message = tag.get_ndef_message();
          auto records = message->get_records();

          const std::string prefix =
              "https://www.home-assistant.io/tag/";

          for (auto &record : records) {
            std::string payload = record->get_payload();

            size_t pos = payload.find(prefix);

            if (pos != std::string::npos) {
              return payload.substr(pos + prefix.length());
            }
          }

          return "";

      # ------------------------------------------------
      # DISPLAY TAG ID
      # ------------------------------------------------

      - lambda: |-
          if (!tag.has_ndef_message()) {
            ESP_LOGW("nfc", "Tag has no NDEF message - ignored");
            return;
          }

          auto message = tag.get_ndef_message();
          auto records = message->get_records();

          const std::string prefix =
              "https://www.home-assistant.io/tag/";

          for (auto &record : records) {
            std::string payload = record->get_payload();

            size_t pos = payload.find(prefix);

            if (pos != std::string::npos) {
              std::string tag_id =
                  payload.substr(pos + prefix.length());

              ESP_LOGI("nfc", "HA TAG: %s", tag_id.c_str());

              id(nfc_tag_id).publish_state(tag_id);

              return;
            }
          }

          ESP_LOGW(
              "nfc",
              "No Home Assistant tag URL found - ignored"
          );

      # ------------------------------------------------
      # TAG SCANNED INDICATOR
      # ------------------------------------------------

      - binary_sensor.template.publish:
          id: nfc_tag_scanned
          state: ON

      # ------------------------------------------------
      # FLASH ONBOARD LED
      # ------------------------------------------------

      - output.turn_on: onboard_led

      - delay: 200ms

      - output.turn_off: onboard_led

      # ------------------------------------------------
      # RESET SCANNED INDICATOR
      # ------------------------------------------------

      - delay: 300ms

      - binary_sensor.template.publish:
          id: nfc_tag_scanned
          state: OFF


# --------------------------------------------------
# TAG ID SENSOR
# --------------------------------------------------

text_sensor:
  - platform: template
    name: "NFC Tag ID"
    id: nfc_tag_id
    icon: "mdi:nfc"


# --------------------------------------------------
# TAG SCANNED
# --------------------------------------------------

binary_sensor:
  - platform: template
    name: "NFC Tag Scanned"
    id: nfc_tag_scanned
    icon: "mdi:nfc"

Simplified it, got rid of looking for NDEF etc, seems to work better and i can code the tag response in Node Red

Has anyone noticed if you scan an Android phone it gives a new ID each time - I’m sure theres a way round that?

esphome:
  name: esp-nfc
  friendly_name: ESP_NFC

esp32:
  variant: esp32
  framework:
    type: esp-idf

logger:

api:
  encryption:
    key: "xxxxxxx"

ota:
  - platform: esphome

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  ap:
    ssid: "ESP_NFC Fallback Hotspot"
    password: "xxxxxxxx"

captive_portal:


# --------------------------------------------------
# ONBOARD LED
# --------------------------------------------------

output:
  - platform: gpio
    pin: GPIO2
    id: onboard_led

  - platform: gpio
    pin: GPIO4
    id: nfc_buzzer

# --------------------------------------------------
# SPI BUS
# --------------------------------------------------

spi:
  clk_pin: 18
  miso_pin: 19
  mosi_pin: 23
  id: spi_1

# --------------------------------------------------
# PN532 - SPI
# --------------------------------------------------

pn532_spi:
  id: nfc_reader
  cs_pin: 5
  spi_id: spi_1
  update_interval: 1s

  on_tag:
    then:
      # Blink onboard LED
      - output.turn_on: onboard_led
      - delay: 300ms
      - output.turn_off: onboard_led

      # Buzzer beep
      - output.turn_on: nfc_buzzer
      - delay: 200ms
      - output.turn_off: nfc_buzzer

      # Send UID to Home Assistant
      - homeassistant.tag_scanned: !lambda |
          auto uid = tag.get_uid();
          std::string result;

          for (size_t i = 0; i < uid.size(); i++) {
            if (i > 0) {
              result += "-";
            }

            char buf[3];
            snprintf(buf, sizeof(buf), "%02X", uid[i]);
            result += buf;
          }

          return result;

sensor:
  - platform: wifi_signal
    name: "NFC Reader WiFi Signal"
    update_interval: 60s

Maybe rooted phone.
Or sticker on the phone case…

Purely for education (mine) if the ID of a phone and it seems my fitbit device as well changes on every scan, how is it used in the outside world for any useful purpose?

Would be pretty cool to unlock and lock using the fitbit but i cant see a way it can be used with a rolling ID code???

Neither do I.
Detecting rolling code is difficult, try to detect something static.
If not possible, NFC adhesive sticker is pretty easy way to go..

LOL, for fun I threw the problem at CGPT and we had some fun down the rabbit hole.

We got as far as CGPT compiling a custom low-level firmware set for me to install that would examine the PN532 responses in far more depth than usual looking for a common denominator that would allow me to use the phone and fitbit as an idenitifer which could be converted into a usable Tag ID

I stopped at that point as I didn’t fancy installing stuff that I knew nothing about from a source such as CGPT, but it was interesting.

I can also suggest not turning on very_verbose logging for the ESP as well, it’s an active little thing :slight_smile:

example of using nfc

Try this one