NFC Movie Library

Hi everyone!

Wanted to share a project I made for my kids: a movie library based on NFC tags.
I wanted to bring back the physicality of VHS tapes and DVDs.

The idea is simple: they browse through our catalog, pick a card, put it on the scanner, and watch a movie.

On the hardware side, I used an ESP32 (C3 Super Mini) and the RC522 NFC reader. The ESP32 is flashed with ESPHome for seamless integration with Home Assistant and local control.

ESPHome Configuration
---
substitutions:
  devicename: "nfc-scanner"
  friendly_name: "NFC Scanner"

packages:
  esphome: !include common/esphome.yaml
  api: !include common/api.yaml
  logger: !include common/logger.yaml
  wifi: !include common/wifi.yaml

esphome:
  # Magic variables to get the ESP32C3 Super Mini to work
  platformio_options:
    board_build.f_flash: 40000000L
    board_build.flash_mode: dio
    board_build.flash_size: 4MB
  on_boot:
    priority: 600
    then:
      - rtttl.play: 'short:d=4,o=5,b=100:16e6,16e6'

esp32:
  variant: ESP32C3
  board: esp32-c3-devkitm-1
  framework:
    type: esp-idf

status_led:
  pin:
    number: GPIO8
    inverted: true

output:
  - platform: ledc
    pin: GPIO3
    id: buzzer

rtttl:
  output: buzzer

spi:
  clk_pin: GPIO4
  mosi_pin: GPIO6
  miso_pin: GPIO5

rc522_spi:
  cs_pin: GPIO7
  on_tag:
    then:
      - rtttl.stop:
      - homeassistant.tag_scanned: !lambda 'return x;'
      - rtttl.play: 'short:d=4,o=5,b=100:16e6,16e6'




When an NFC tag is scanned, ESPHome emits a tag_scanned event to Home Assistant. This is being used to play the correct movie on our Apple TV via Plex. To do that, I maintain a “mapping” between tag IDs and Plex IDs.

The automation only works between certain hours to prevent the kids from abusing the system and watching TV all the time :wink:

Home Assistant automation
- alias: "NFC Reader - Plex"
  description: ""
  mode: single
  trigger:
  - platform: event
    event_type: tag_scanned

  # Only allow movies to be played in the morning and evening.
  # Broad time window to allow for some flexibility in schedule.
  condition:
  - condition: or
    conditions:
    - condition: time
      after: '05:00:00'
      before: '09:00:00'
    - condition: time
      after: '18:00:00'
      before: '19:50:00'  # Bed time!
  action:
  - variables:
	  # Map the ID of each tag to a Plex ID. The "name" attribute is
	  # not used but nice to have for debugging.
      NFC_MAPPING:
        53-77-08-69-71-00-01:
          name: Ratatouille
          plex_id: 37353
        53-72-08-69-71-00-01:
          name: Coco
          plex_id: 3135
		# ...
  - if:
    # Make sure the scanned tag is in the mapping
    - alias: "NFC tag is in the mapping"
      condition: template
      value_template: "{{ trigger.event.data.tag_id in NFC_MAPPING }}"
    then:
    # Turn on the Apple TV (and the TV itself) when it's in standby
    - if:
      - condition: state
        entity_id: media_player.appletv_living
        state: standby
      then:
      - service: media_player.turn_on
        data: {}
        target:
          entity_id: media_player.appletv_living
      - delay:
          seconds: 5

	# Take the Plex ID from the mapping and send a deep link to the 
	# Apple TV. This will automatically open the Plex app and start
	# or resume the given movie.
    - service: media_player.play_media
      target:
        entity_id: media_player.appletv_living
      data:
        media_content_type: url
        media_content_id: "plex://play/?metadataKey=%2Flibrary%2Fmetadata%2F{{ NFC_MAPPING[trigger.event.data.tag_id].plex_id }}&server=xxxxxxxxxxxxxx"

	# Set an appropriate (low) volume on our Sonos Beam
	# Volume controls on Apple TV only support up/down when using an eARC
	# speaker.
    - service: media_player.volume_set
	  data:
	    volume_level: 0.17
	  target:
	    entity_id: media_player.sonos_tv



Using “physical” media has many benefits in my opinion:

  • You have a limited choice of movies to watch. When I was a kid, we didn’t have an infinite catalog of movies to watch. We had a handful of VHS tapes and DVDs. We watched the same movies over and over again, each time discovering new details we would have missed otherwise.

  • It gives my kids autonomy. They can decide what they want to watch and are not dependent on us to operate the remote and navigate to the correct app. (Autonomy within certain time periods, we don’t want them watching a lot of TV)

  • With autonomy comes responsibility. When allowed, they can watch any movie they like. They can even switch between movies. But the timeframe is fixed. They can watch a good chunk of one movie, or they can watch a tiny bit of 10 different movies. It’s completely up to them.

  • They will need to learn to collaborate and compromise. We only have one TV and two half-hour slots to watch it. They must quickly agree on a movie or forfeit their viewing time. Or perhaps they use their creativity to come up with a system to decide who gets to choose the movie, eg: “You can pick in the morning, I’ll pick in the evening.”

Other benefits: it’s cheaper to buy second hand Blurays than keeping a Netflix or Disney+ subscription. My kids keep watching the same movies over and over again. Plus, the Blurays come with dubbed versions (horrible, I knnow) and many extras that are often fun to watch. I specifically love behind the scenes content.


My kids love this system, and it’s super reliable. The only issue I’m having is with TV Shows. I currently use Plex deep links to play a specific movie on my Apple TV. If I want to play TV Shows, I need to go through the Plex integration, but for some reason it complains that my Apple TV doesn’t accept playback controls.

I’m sure I’ll find a solution eventually. But for now, they’re happy with the movies :wink:


You can read the full write-up here. My 3D models are also available if you want to recreate this setup.

7 Likes

Love the idea. Keep up the good work

This is fantastic, great work!

Hello @Savjee i´m trying to recreat this NFC Tag Reader, but i´m having trouble with installing the code onto the ESP

Can you provide more information what code are you having inside esphome: !include common/esphome.yaml
api: !include common/api.yaml
logger: !include common/logger.yaml

Sure! These files are shared among pretty much all of my ESPHome devices.

esphome.yaml

---
esphome:
  name: $devicename
  comment: $friendly_name
  build_path: .builds/$devicename

api.yaml

---
# Enable Home Assistant API
api:
  encryption:
    key: !secret esphome_encryption_key

ota:
  password: !secret esphome_api_password

logger.yaml

---
# Enable logging
logger:

wifi.yaml

---
# Wi-Fi component package
# https://esphome.io/components/wifi.html

wifi:
  ssid: !secret wifi_iot_ssid
  password: !secret wifi_iot_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: ${friendly_name} AP
    password: !secret esphome_fallback_ap_password
1 Like