tagreader icon indicating copy to clipboard operation
tagreader copied to clipboard

actually read contents of NFC tag

Open snizzleorg opened this issue 3 years ago • 20 comments

Hi,

thanks for this great little device.

Can this be used to actually transmit the contents of the NFC tag to home-assistant?

I would like to store Spotify URIs on the tags which then would be used to play the item. Currently this works via automation but it means that I would have to create an automation linking every tag id to a Spotify URI....

Thanks

snizzleorg avatar Dec 04 '20 11:12 snizzleorg

just to try an answer this... simple answer is NO .. Long answer is no its not been implemented (yet) make sure your using the PN532 as a reader, using other readers (which i initially thought you may off), may only be able to read UID, and therefore, ony able to use that...

check this thread for that info... https://github.com/adonno/tagreader/issues/41

gadget78 avatar Jan 05 '21 15:01 gadget78

it's implemented now: https://esphome.io/components/binary_sensor/pn532.html

snizzleorg avatar Feb 03 '21 19:02 snizzleorg

So..... Is it possible to return BOTH the card uid AND the written uuid? (And possibly more data)? How do I do that in the .yaml file?

This makes using the scanner as an access device to open and close doors, less susceptible to copying by third parties (if you check the card id and uuid combination). This is not 100% tamper proof I know... but it helps. Card_id's cannot be changed most of the time.

Something like this.... (All uuids and card id's replaced by random ones)

Event 1 fired sometime:
{
    "event_type": "tag_scanned",
    "data": {
        "tag_id": "5fb05d54-8f55-4de1-a7e3-8b7c662a3939",
        "card_id": "EA-67-F5-12",
        "device_id": "somedeviceid"
    },
    "origin": "LOCAL",
    "time_fired": "2021-05-09T07:35:52.983457+00:00",
    "context": {
        "id": "6b58b2b0524fe8a13145714e0572cd03",
        "parent_id": null,
        "user_id": null
    }
}

Retroman445 avatar May 09 '21 07:05 Retroman445

It would be good to be able to read the additional data. I've got data stored on mine, such as the playlist id, rather than having to write these out in the HA automation.

So if could read the data could just rely on what the tag has stored.

seanmccabe avatar May 27 '21 21:05 seanmccabe

as I see there now is NDEF support:

pn532_i2c:
  id: pn532_board
  on_tag:
    then:
    - homeassistant.tag_scanned: !lambda |
        if (!tag.has_ndef_message()) {
          ESP_LOGD("tagreader", "No NDEF");
          return x;
        }
        auto message = tag.get_ndef_message();
        auto records = message->get_records();
        for (auto &record : records) {
          std::string payload = record->get_payload();
          size_t pos = payload.find("https://www.home-assistant.io/tag/");
          if (pos != std::string::npos) {
            return payload.substr(pos + 34);
          }
        }
        ESP_LOGD("tagreader", "Bad NDEF, fallback to uid");
        return x;

But ideally I would like to store just va Spotify URI. I guess that also could be achieved by slightly modifying the above. Any idea what the best way forward would be - meaning without breaking compatibility? keeping the home-assistant URL intact and then just amending the URI?

something like

https://www.home-assistant.io/tag/spotify/album/6vl01TUphnCUkObyzNTLSg as a URL stored on the card?

snizzleorg avatar Aug 02 '21 16:08 snizzleorg

Hey,

big thanks also from here - this is an amazing basis to build a jukebox. I was attempting the same as @snizzleorg.

I was planning to write Spotify URIs to NFC tags, read them via the PN532 and insert the URI to the mediaplayer.play_media service in Homeassistant. This way I only need to update the URI on the NFC, when I want to update the album my kids are listening to and not update the scripting on Homeassistant.

When adapting the original tagreader.yaml like below, at least I get the URI as the ID of the NFC tag. I did not manage to get much further, but thought this was worth sharing:

pn532_i2c:
  id: pn532_board
  on_tag:
    then:
    - homeassistant.tag_scanned: !lambda |
        if (!tag.has_ndef_message()) {
          ESP_LOGD("tagreader", "No NDEF");
          return x;
        }
        auto message = tag.get_ndef_message();
        auto records = message->get_records();
        for (auto &record : records) {
          std::string payload = record->get_payload();
          {
            return payload;
          }
        }
        ESP_LOGD("tagreader", "Bad NDEF, fallback to uid");
        return x;

re-lin avatar Jan 16 '22 23:01 re-lin

here's the solution https://github.com/adonno/tagreader/pull/156 Please test your hardware carefully with this mod since I was not able to test it on wemos D1 and my nodemcuv2 seems to be running out of resources. But after stripping original code, everything works as expected.

To run this end-to-end you will need also this blueprint https://community.home-assistant.io/t/play-music-tag-event-from-ndef-url/400965

luka6000 avatar Mar 10 '22 22:03 luka6000

@luka6000 I tested your mod but unfortunately it crashes upon reading a URL. normal tags do work

[22:10:05][I][app:102]: ESPHome version 2022.2.6 compiled on Mar 11 2022, 21:52:38
[22:10:05][I][app:104]: Project adonno.tag_reader version 1.4
[22:10:05][C][wifi:491]: WiFi:
[22:10:05][C][wifi:353]:   Local MAC: 5C:CF:7F:99:B7:B9
[22:10:05][C][wifi:354]:   SSID: [redacted]
[22:10:05][C][wifi:355]:   IP Address: 192.168.178.148
[22:10:05][C][wifi:356]:   BSSID: [redacted]
[22:10:05][C][wifi:358]:   Hostname: 'tagreader-99b7b9'
[22:10:05][C][wifi:360]:   Signal strength: -82 dB ▂▄▆█
[22:10:05][C][wifi:364]:   Channel: 11
[22:10:05][C][wifi:365]:   Subnet: 255.255.255.0
[22:10:05][C][wifi:366]:   Gateway: 192.168.178.1
[22:10:05][C][wifi:367]:   DNS1: 192.168.178.1
[22:10:05][C][wifi:368]:   DNS2: 0.0.0.0
[22:10:05][C][logger:233]: Logger:
[22:10:05][C][logger:234]:   Level: DEBUG
[22:10:05][C][logger:235]:   Log Baud Rate: 115200
[22:10:05][C][logger:236]:   Hardware UART: UART0
[22:10:05][C][i2c.arduino:038]: I2C Bus:
[22:10:05][C][i2c.arduino:039]:   SDA Pin: GPIO4
[22:10:05][C][i2c.arduino:040]:   SCL Pin: GPIO5
[22:10:05][C][i2c.arduino:041]:   Frequency: 400000 Hz
[22:10:05][C][i2c.arduino:044]:   Recovery: bus successfully recovered
[22:10:05][C][template.switch:058]: Template Switch 'TagReader Buzzer Enabled'
[22:10:05][C][template.switch:058]:   Icon: 'mdi:volume-high'
[22:10:05][C][template.switch:059]:   Restore State: YES
[22:10:05][C][template.switch:060]:   Optimistic: YES
[22:10:05][C][template.switch:058]: Template Switch 'TagReader LED enabled'
[22:10:05][C][template.switch:058]:   Icon: 'mdi:alarm-light-outline'
[22:10:05][C][template.switch:059]:   Restore State: YES
[22:10:05][C][template.switch:060]:   Optimistic: YES
[22:10:05][C][esp8266_pwm:022]: ESP8266 PWM:
[22:10:05][C][esp8266_pwm:023]:   Pin: GPIO13
[22:10:05][C][esp8266_pwm:024]:   Frequency: 988.0 Hz
[22:10:05][C][light:098]: Light 'TagReader LED'
[22:10:05][C][light:100]:   Default Transition Length: 1.0s
[22:10:05][C][light:101]:   Gamma Correct: 2.80
[22:10:05][C][restart.button:017]: Restart Button 'TagReader Restart'
[22:10:05][C][pn532:347]: PN532:
[22:10:05][C][pn532:359]:   Update Interval: 1.0s
[22:10:05][C][pn532_i2c:128]:   Address: 0x24
[22:10:05][C][status:034]: Status Binary Sensor 'TagReader Status'
[22:10:05][C][status:034]:   Device Class: 'connectivity'
[22:10:05][C][version.text_sensor:021]: Version Text Sensor 'TagReader ESPHome Version'
[22:10:05][C][version.text_sensor:021]:   Icon: 'mdi:new-box'
[22:10:05][C][rtttl:018]: Rtttl
[22:10:05][C][captive_portal:144]: Captive Portal:
[22:10:05][C][mdns:084]: mDNS:
[22:10:05][C][mdns:085]:   Hostname: tagreader-99b7b9
[22:10:05][C][ota:085]: Over-The-Air Updates:
[22:10:05][C][ota:086]:   Address: tagreader-99b7b9.local:8266
[22:10:05][C][api:138]: API Server:
[22:10:05][C][api:139]:   Address: tagreader-99b7b9.local:6053
[22:10:05][C][api:143]:   Using noise encryption: NO
[22:10:05][C][improv_serial:032]: Improv Serial:
[22:10:05][C][wifi_info:009]: WifiInfo IPAddress 'TagReader IP Address'
[22:10:05][C][wifi_info:009]:   Icon: 'mdi:wifi'
[22:10:05][C][wifi_info:011]: WifiInfo SSID 'TagReader Connected SSID'
[22:10:05][C][wifi_info:011]:   Icon: 'mdi:wifi-strength-2'
[22:10:23][D][pn532:283]: Mifare ultralight
[22:10:24][E][pn532.mifare_ultralight:031]: Error reading page 19
[22:10:24][D][tagreader:260]: No NDEF
[22:10:24][D][rtttl:038]: Playing song success
[22:10:24][D][light:035]: 'TagReader LED' Setting:
[22:10:24][D][light:046]:   State: ON
[22:10:24][D][light:050]:   Brightness: 100%
[22:10:24][D][light:057]:   Red: 0%, Green: 100%, Blue: 0%
[22:10:24][D][light:077]:   Flash length: 0.5s
[22:10:24][D][pn532:162]: Found new tag '04-AF-10-92-F3-67-80'
[22:10:24][D][pn532:295]: Waiting to read next tag
[22:10:24][D][rtttl:094]: Playback finished
INFO tagreader-99b7b9.local: Ping timed out!
INFO Disconnected from ESPHome API for tagreader-99b7b9.local
WARNING Disconnected from API
WARNING Can't connect to ESPHome API for tagreader-99b7b9.local: Error resolving IP address: [Errno -2] Name or service not known
INFO Trying to reconnect to tagreader-99b7b9.local in the background

snizzleorg avatar Mar 11 '22 21:03 snizzleorg

When I use serial logging I get a little more info:

INFO Reading configuration /config/esphome/tagreader-99b7b9.yaml...
INFO Starting log output from /dev/ttyUSB0 with baud rate 115200
[22:11:46][D][pn532:283]: Mifare ultralight
[22:11:46][D][tagreader:260]: No NDEF
[22:11:46][D][rtttl:038]: Playing song success
[22:11:46][D][light:035]: 'TagReader LED' Setting:
[22:11:46][D][light:046]:   State: ON
[22:11:46][D][light:050]:   Brightness: 100%
[22:11:46][D][light:057]:   Red: 0%, Green: 100%, Blue: 0%
[22:11:46][D][light:077]:   Flash length: 0.5s
[22:11:46][D][pn532:162]: Found new tag '04-9E-BF-D2-2F-66-80'
[22:11:46][D][pn532:295]: Waiting to read next tag
[22:11:46][D][rtttl:094]: Playback finished
[22:11:52][D][pn532:283]: Mifare ultralight
[22:11:52][D][tagreader:260]: No NDEF
[22:11:52][D][rtttl:038]: Playing song success
[22:11:52][D][light:035]: 'TagReader LED' Setting:
[22:11:52][D][light:046]:   State: ON
[22:11:52][D][light:050]:   Brightness: 100%
[22:11:52][D][light:057]:   Red: 0%, Green: 100%, Blue: 0%
[22:11:52][D][light:077]:   Flash length: 0.5s
[22:11:52][D][pn532:162]: Found new tag '04-9E-BF-D2-2F-66-80'
[22:11:52][D][pn532:295]: Waiting to read next tag
[22:11:52][D][rtttl:094]: Playback finished
[22:11:59][D][pn532:283]: Mifare ultralight
[22:12:00][D][tagreader:232]: Found music tag NDEF
[22:12:00][D][tagreader:252]: Sending event music_tag
[22:12:00][D][tagreader:272]: Not HA NDEF, fallback to uid
[22:12:00][D][rtttl:038]: Playing song success
[22:12:00][D][light:035]: 'TagReader LED' Setting:
[22:12:00][D][light:046]:   State: ON
[22:12:00][D][light:050]:   Brightness: 100%
[22:12:00][D][light:057]:   Red: 0%, Green: 100%, Blue: 0%
[22:12:00][D][light:077]:   Flash length: 0.5s
[22:12:00][D][pn532:162]: Found new tag '04-AF-10-92-F3-67-80'
[22:12:00][D][pn532:166]:   NDEF formatted records:
[22:12:00][D][pn532:168]:     U - https://open.spotify.com/playlist/37i9dQZEVXcOeVn3WS7FuB?si=P7v3NM-YQzaoK6KreGls9g
[22:12:00][D][pn532:295]: Waiting to read next tag
[22:12:08]
[22:12:08] ets Jan  8 2013,rst cause:4, boot mode:(3,6)
[22:12:08]
[22:12:08]wdt reset
[22:12:08]load 0x4010f000, len 3460, room 16 
[22:12:08]tail 4
[22:12:08]chksum 0xcc
[22:12:08]load 0x3fff20b8, len 40, room 4 
[22:12:08]tail 4
[22:12:08]chksum 0xc9
[22:12:08]csum 0xc9
[22:12:08]v0007b4a0
[22:12:08]~ld
[22:12:08][I][logger:214]: Log initialized
[22:12:08][C][ota:461]: There have been 2 suspected unsuccessful boot attempts.
[22:12:08][I][app:029]: Running through setup()...
[22:12:08][I][i2c.arduino:161]: Performing I2C bus recovery

snizzleorg avatar Mar 11 '22 21:03 snizzleorg

ok, so it's not only my nodemcu running out of resources. There is a lot of stuff to get rid of. I'll try to cut out all I can from original tagreader to make it work. This is how I run it now. It also includes special "sonos://" url which allows me to play My Sonos stations.

substitutions:
  name: nfcreader
  friendly_name: NFCreader
  myplatfrm: ESP8266
  myboard: nodemcuv2
  buzpin: D7
  ledpin: D8

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

#   # Enable fallback hotspot (captive portal) in case wifi connection fails
#   ap:
#     ssid: "nfcreader Fallback Hotspot"
#     password: "espHOME4you"

# captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api:
  services:
  - service: write_music_tag
    variables:
      music_url: string
    then:
    - light.turn_on:
        id: activity_led
        brightness: 100%
        red: 100%
        green: 0%
        blue: 0%    
    - lambda: |-
        auto message = new nfc::NdefMessage();
        std::string uri = "";
        uri += music_url;
        message->add_uri_record(uri);
        id(pn532_board).write_mode(message);
    - rtttl.play: "write:d=24,o=5,b=100:b"
    - wait_until:
        not:
          pn532.is_writing:
    - light.turn_off:
        id: activity_led
    - rtttl.play: "write:d=24,o=5,b=100:b,c"

ota:

esphome:
  name: $name
  platform: $myplatfrm
  board: $myboard
  name_add_mac_suffix: false
  on_boot:
    priority: -10
    then:
    - wait_until:
        api.connected:
    - logger.log: API is connected!
    - rtttl.play: "success:d=24,o=5,b=100:b,c"
    - switch.turn_on: buzzer_enabled

  
# Define switches to control LED and buzzer from HA
switch:
- platform: template
  name: "${friendly_name} Buzzer Enabled"
  id: buzzer_enabled
  icon: mdi:volume-high
  optimistic: true
  restore_state: true
  entity_category: config

i2c:
  scan: False
  frequency: 400kHz

globals:
  id: source
  type: std::string

pn532_i2c:
  id: pn532_board
  on_tag:
    then:

    - if:
        condition:
          lambda: |
            if (tag.has_ndef_message()) {
              auto message = tag.get_ndef_message();
              auto records = message->get_records();
              for (auto &record : records) {
                std::string payload = record->get_payload();
                std::string type = record->get_type();
                size_t applemusic = payload.find("https://open.spotify.com");
                size_t spotify = payload.find("https://music.apple.com");
                size_t sonos = payload.find("sonos://");
                if (type == "U" and (
                  applemusic != std::string::npos or
                  spotify != std::string::npos
                )) {
                  ESP_LOGD("tagreader", "Found music tag NDEF");
                  id(source)="music";
                  return true;
                }
                else if (type == "U" and (
                  sonos != std::string::npos
                )) {
                  ESP_LOGD("tagreader", "Found Sonos music tag NDEF");
                  id(source)="sonos";
                  return true;
                }
              }
            }
            return false;
        then:
        - homeassistant.event:
            event: esphome.music_tag
            data_template:
              reader: !lambda |
                return App.get_name().c_str();
              source: !lambda |
                return id(source);
              url: !lambda |
                auto message = tag.get_ndef_message();
                auto records = message->get_records();
                for (auto &record : records) {
                  std::string payload = record->get_payload();
                  std::string type = record->get_type();
                  size_t music = payload.find("https://");
                  if (type == "U" and music != std::string::npos ) {
                    ESP_LOGD("tagreader", "Sending event music_tag");
                    return payload;
                  }
                  else if (type == "U" and id(source) == "sonos") {
                    ESP_LOGD("tagreader", "Sending event Sonos music_tag");
                    return payload.substr(8);
                  }
                }
                return x;

    - homeassistant.tag_scanned: !lambda |
        if (!tag.has_ndef_message()) {
          ESP_LOGD("tagreader", "No NDEF");
          return x;
        }
        auto message = tag.get_ndef_message();
        auto records = message->get_records();
        for (auto &record : records) {
          std::string payload = record->get_payload();
          size_t pos = payload.find("https://www.home-assistant.io/tag/");
          if (pos != std::string::npos) {
            return payload.substr(pos + 34);
          }
        }
        ESP_LOGD("tagreader", "Bad NDEF, fallback to uid");
        return x;
    - if:
        condition:
          switch.is_on: buzzer_enabled
        then:
        - rtttl.play: "scan:d=24,o=5,b=100:c,b"



button:
  - platform: restart
    name: "Restart"

# Define the buzzer output
output:
- platform: esp8266_pwm
  pin: $buzpin
  id: buzzer

binary_sensor:
  - platform: status
    name: "${friendly_name} Status"
    entity_category: diagnostic

# Define buzzer as output for RTTTL
rtttl:
  output: buzzer

light:
- platform: neopixelbus
  variant: WS2812
  pin: $ledpin
  num_leds: 1
  flash_transition_length: 500ms
  type: GRB
  id: activity_led
  name: "${friendly_name} LED"
  restore_mode: ALWAYS_OFF

luka6000 avatar Mar 12 '22 00:03 luka6000

That's working! and it is really cool! Thanks!

snizzleorg avatar Mar 12 '22 07:03 snizzleorg

And how do you get the sonos:// url for a specific station? I don't see any share functionality in the sonos app.

snizzleorg avatar Mar 12 '22 07:03 snizzleorg

Add any radio station to My Sonos and then use URL sonos://station name And that's it. Got another idea about it so stay tuned 😉

luka6000 avatar Mar 12 '22 09:03 luka6000

ok, I've isolated the problem and it's with NeoPixelBus. Connection with D8 pin is not a recommended scenario for ESP8266. For now, no ideas on how to get it working. With led off it's ok.

luka6000 avatar Mar 12 '22 12:03 luka6000

@snizzleorg ok solved. Works with original tagreader code. @adonno are you interested in this functionality or do you prefer me to fork tagreader and keep it separately?

luka6000 avatar Mar 12 '22 16:03 luka6000

I'll add it at some point haven't gotten around yet but tomorrow i will have some time and review it i think it's quite useful

adonno avatar Mar 12 '22 16:03 adonno

@luka6000 any idea how to get podcasts working? It seems that https://open.spotify.com/show/ is the link but I guess then the way of passing that onto the Sonos would be different...

ok.. seems to be an issue with the home-assistant Sonos media player. It does not play shows...

snizzleorg avatar Apr 02 '22 08:04 snizzleorg

Sorry, I don't use Spotify. Can you add Spotify podcast to My Sonos? If so, you can play it by name using media_player source service. Just write_music_tag with url=sonos-2:// and info "name of the stream", without quotes and exactly as seen in Sonos app in My Sonos section. Check this automation blueprint https://gist.github.com/luka6000/ec6406e44de3dff082dd7e22cedcff93

luka6000 avatar Apr 02 '22 22:04 luka6000

@luka6000 podcasts show up as sonos albums. So it seems not to be possible. I am using your blueprint and it really works great.

snizzleorg avatar Apr 10 '22 18:04 snizzleorg

@adonno @Retroman445 @luka6000

from this thread, it seems to me that now -june 2022- : 1- esphome pn532 si supporting NDEF Writing/reading
2- addonno kit & the MASTER brach is NOW supporting also this function in Mifare Classic 1K .

kindly ask:

  • Is it correct ?
  • Can we use this feature, as requested bu retroman445, to write some other data into the card for access contro for a B&B ?
  • does exist a blueprint for this gate control feature ?

Giuliano69 avatar Jun 02 '22 20:06 Giuliano69