Tonies NFC Story Box

Building my own NFC Story box





9/7/2025 – Semtex

Soooo,… I’ve been taught about these Tonies boxes. They seem great and all but ultimately looks like a nice business model around buying tons of plastic toys that you pay the golden price for what is essentially just an NFC tag with a pre-recorded audio file. I’ve spent some time on the drawing board to see what could fit our use cases and came up with a few ideas. I’ve designed 2 versions relying on the same hardware. One that will mostly rely on Home Assistant and a standalone one with everything embedded.

The Tonies Box

The Tonies box is a small speaker with an NFC reader. You put a toy on top of it and it plays the associated audio file. You can also record your own audio files and create your own toys. The box is designed to be kid-friendly, with a simple interface and a durable design.

V1

The first version is the simplest one.

flowchart TD
    A[" NFC Tag"] -->|"Read UID"| B["󰒓 ESP32"]
    B -->|"Trigger HA Action"| C["󰋜 HA"]
    C -->|"Start Pyscript"| D["󰣳 NAS"]
    D -->|"Start Audio on Media player"| E["󰋜 HA"]

Basically, you just use the NFC UUID to trigger an action in Home assistant, this just pass the UUID to a python script that returns a random audio file path from a folder in my NAS. Home assistant then plays the audio file on a media player (My SONOS kit in this case).

Pretty straightforward, easy to implement, easy to scale. The downside is that it relies on Home Assistant and a network connection to work. It’s not a standalone solution.

Hardware

  • ESP32
  • NFC Reader (PN532)
  • A working HA instance
  • A media player (SONOS, Google Home, Alexa, etc.)
  • Power supply (USB or battery)
  • 3D printed case

Software

I flashed the ESP32 with ESPHome and used the PN532 NFC/RFID controller library to read the NFC tags. I then created an automation in Home Assistant to trigger the pyscript when a new tag is detected.

esp32-nfc.yaml

esphome:
  name: esp32-nfc

esp32:
  board: esp32dev
  framework:
    type: arduino

wifi:
  ssid: "YOUR_SSID"
  password: "xoxoxo"

logger:
api:
ota:
  platform: esphome

i2c:
  sda: GPIO21
  scl: GPIO22
  scan: true

pn532_i2c:
  id: nfc_reader
  update_interval: 1s
  on_tag:
    then:
      - logger.log:
          format: "Tag read : %s"
          args: ["x.c_str()"]
      - homeassistant.tag_scanned: !lambda 'return x;'

# ADD LAST NFC READ AS SENSOR

You then flash this file with esphome run esp32-nfc.yaml, You’ll then have to have ESPHome integration in Home Assistant and it should discover your ESP32.

ESP32 HA Integration
ESP32 HA Integration

You’ll also have to setup Pyscript in Home Assistant in order to add Actions that triggers a Python script.

@service
def play_random_tonie(tag=None, player="media_player.salon"):
    """Pick a random audio file from a folder and play it on a media player."""

    import os, random

    base = f"/media/NAS/Media/Toniestx/{tag}"
    if not os.path.exists(base):
        log.error(f"Dossier introuvable : {base}")
        return

    files = [f for f in os.listdir(base) if f.lower().endswith(".mp3")]
    if not files:
        log.error(f"Aucun fichier trouvé pour le tag {tag}")
        return

    choice = random.choice(files)
    media_id = f"media-source://media_source/local/NAS/Media/Toniestx/{tag}/{choice}"

    log.info(f"Lecture aléatoire : {media_id}")

    media_player.play_media(
        entity_id=player,
        media_content_id=media_id,
        media_content_type="music",
    )

You can then create an Home Assistant script to call the pyscript with the tag and the media player as parameters.

alias: Lire un tonie aléatoire (random tone)
mode: single
fields:
  tag:
    name: Tag
    description: UID du tag NFC (nom du dossier)
    required: true
    selector:
      text: {}
  player:
    name: Lecteur
    description: media_player cible
    required: true
    selector:
      entity:
        domain: media_player
sequence:
  - data:
      tag: "{{ tag }}"
      player: "{{ player }}"
    action: pyscript.play_random_tonie
description: Récupère et lit automatiquement un tonie aléatoire à partir d'un tag NFC
icon: mdi:toy-brick

And call this script from an automation when a new tag is detected. You could totally call the pyscript directly from the automation but having HA script in between allows you to test it, expand, reuse it easily. It also helps passing variables

alias: Toniebox - Tag NFC détecté

Now, you place an NFC tag on the reader, this should add it to the list of detected tags in Home Assistant. Create a folder which name is the tag ID in the media folder containing mp3 files and it should work.

The case

I’ve opted for this nice looking retro case that I found on MakerWorld

3d printed case
Case

It is quite empty once printed as the esp32 and the NFC reader are both quite small and there shouldn’t be much more into it.

V2

The second version is a standalone one. It doesn’t rely on Home Assistant or any network connection.

The core will remain the same, an ESP32 with an NFC reader, but this time, the ESP32 will handle everything. It will read the NFC tag, pick a random audio file from a folder in an SD card and play it on a small speaker. It will also provide a simple GUI through a small OLED display, 3 buttons and a rotary knob will allow to navigate, play, pause, skip, volume up/down, etc.

A web interface shall allow to add songs, manage the audio library,… It is a Design in Progress.