# ESP32 NFC Music Player for Kids

This project creates a custom, kid-friendly music player that integrates seamlessly with Home Assistant. By embedding NFC tags into custom cards (e.g., printed cards with album art or characters), children can simply scan a card to instantly play their favorite music on smart speakers throughout the house. The system leverages an ESP32 Dev Kit V1 with an RC522 NFC/RFID module for scanning, a physical push button for stopping playback, and is powered wirelessly by a 3.7V LiPo battery pack.

## Project Goal

To provide an intuitive and accessible music playback system for children. Instead of navigating complex apps or voice commands, kids can choose their music independently by interacting with physical, tangible cards. Each card acts as a unique trigger in Home Assistant, allowing for flexible playback of specific songs, albums, playlists, or even stories, on designated smart speakers.

## Features

*   **NFC-triggered Music Playback:** Scan a uniquely tagged card to initiate music playback via Home Assistant automations.
*   **Kid-Friendly Interface:** Simple physical interaction ideal for young users.
*   **"Stop Music" Push Button:** A dedicated button allows immediate cessation of playback.
*   **Wireless and Portable:** Powered by a rechargeable LiPo battery for flexible placement anywhere in the home.
*   **Integrated with Home Assistant:** Leverage Home Assistant's powerful automation engine to define what each card plays, which speakers to use, and to monitor device status.
*   **Battery Status Monitoring:** Keep an eye on the device's power levels directly from Home Assistant.

---

## Table of Contents

1.  [Components Required](#1-components-required)
2.  [Wiring Guide](#2-wiring-guide)
    *   [Power Supply (Battery, Charger, Boost Converter)](#power-supply-battery-charger-boost-converter)
    *   [ESP32 & RC522 (SPI)](#esp32--rc522-spi)
    *   [Push Button](#push-button)
3.  [ESPHome Configuration (`esphome.yaml`)](#3-esphome-configuration-esphomeyaml)
    *   [SPI Bus Configuration](#spi-bus-configuration)
    *   [RC522 RFID Scanner](#rc522-rfid-scanner)
    *   [Physical Push Button](#physical-push-button)
    *   [Battery Voltage Sensor](#battery-voltage-sensor)
4.  [Home Assistant Integration](#4-home-assistant-integration)
    *   [RFID Tag Scans](#rfid-tag-scans)
    *   [Physical Button](#physical-button)
    *   [Battery Status](#battery-status)
5.  [Power Consumption & Battery Life Considerations](#5-power-consumption--battery-life-considerations)

---

## 1. Components Required

*   **ESP32 Dev Kit V1** (or compatible ESP32 board)
*   **RC522 RFID/NFC Module** (SPI interface)
*   **3.7V LiPo Battery** (e.g., 1800mAh 18650 cell, or similar)
*   **LiPo Charging & Protection Module** (e.g., TP4056 or similar, with B+/B-/OUT+/OUT- terminals and USB-C port)
*   **DC-DC Step-Up (Boost) Converter Module** (e.g., MT3608 based, adjustable output to 5V)
*   **Momentary Push Button** (2-pin)
*   **Header Pins / Jumper Wires**
*   **Soldering Iron & Solder** (for power connections and possibly battery leads)
*   **Multimeter** (essential for setting boost converter output and checking voltages)
*   **(Optional) Resistor: 100k Ohm** (for accurate battery voltage sensing)

## 2. Wiring Guide

**Safety Note:** Always double-check polarity for battery connections. Test the boost converter output with a multimeter *before* connecting it to the ESP32!

### Power Supply (Battery, Charger, Boost Converter)

This setup converts the LiPo's voltage (3.7-4.2V) to a stable 5V for the ESP32's VIN pin.

1.  **LiPo Battery to Charging Module:**
    *   Solder the **positive (+) lead** of your 3.7V LiPo battery to the `B+` pad on the LiPo charging module.
    *   Solder the **negative (-) lead** of your 3.7V LiPo battery to the `B-` pad on the LiPo charging module.
    *   *You can use the USB-C port on the charging module to charge the battery.*

2.  **Charging Module to Boost Converter:**
    *   Connect the `OUT+` pad from the LiPo charging module to the `IN+` (or `VIN+`) pad of your DC-DC Step-Up (Boost) Converter.
    *   Connect the `OUT-` pad from the LiPo charging module to the `IN-` (or `VIN-`) pad of your DC-DC Step-Up (Boost) Converter.

3.  **Adjust Boost Converter Output (CRITICAL STEP):**
    *   Attach the LiPo battery to the charging module (which is now connected to the boost converter).
    *   Using a multimeter, measure the voltage between the `OUT+` and `OUT-` pads of the **boost converter**.
    *   Carefully adjust the small potentiometer (a tiny screw) on the boost converter module until the multimeter reads exactly **5.0V**.
    *   *Do NOT skip this step. Connecting incorrect voltage can damage your ESP32.*

4.  **Boost Converter to ESP32:**
    *   Connect the `OUT+` pad of the **boost converter** to the **VIN** pin on your ESP32 Dev Kit.
    *   Connect the `OUT-` pad of the **boost converter** to a **GND** pin on your ESP32 Dev Kit.

### ESP32 & RC522 (SPI)

The RC522 uses the SPI communication protocol. Refer to the ESP32 Dev Kit V1 pinout.

*   **RC522 VCC** $\rightarrow$ **ESP32 3.3V** (The ESP32's on-board regulator will supply 3.3V)
*   **RC522 GND** $\rightarrow$ **ESP32 GND**
*   **RC522 MOSI** $\rightarrow$ **ESP32 GPIO23** (V_SPI_D)
*   **RC522 MISO** $\rightarrow$ **ESP32 GPIO19** (V_SPI_Q)
*   **RC522 SCK** $\rightarrow$ **ESP32 GPIO18** (V_SPI_CLK)
*   **RC522 SS (SDA/NSS/CS)** $\rightarrow$ **ESP32 GPIO5** (V_SPI_CSO - Chip Select)
*   **RC522 RST** $\rightarrow$ **ESP32 GPIO17** (TXD 2 - Reset pin)

### Push Button

The push button uses an internal pull-up resistor on the ESP32.

*   One lead of the push button $\rightarrow$ **ESP32 GPIO4**
*   The other lead of the push button $\rightarrow$ **ESP32 GND**

### Battery Voltage Sensor (Optional, but Recommended for Monitoring)

To monitor the LiPo battery voltage, you need an Analog-to-Digital Converter (ADC) input on the ESP32. The raw battery voltage (3.7-4.2V) is too high for the ESP32's ADC directly (max 3.3V, actual range for ADC is often less, e.g., 0-1V for some ADCs), so a voltage divider is required.

**Voltage Divider Calculation:**
To measure 0-4.2V using an ADC that reads 0-3.3V (or 0-1V if using attenuation), a simple voltage divider with two resistors is used. A common setup to map ~4.2V down to ~3.3V is a 100k Ohm resistor and a 220k Ohm resistor.

*   **R1 (100k Ohm):** Connect one end to the `OUT+` of your **charging module** (this is the battery voltage, before any boost conversion).
*   **R2 (220k Ohm):** Connect one end to the other end of R1, and the other end to **ESP32 GND**.
*   **ADC Input:** Connect a jumper wire from the junction of R1 and R2 to **ESP32 GPIO34** (ADC1_6 - recommended ADC pin for voltage sensing).

This divider will scale 4.2V down to approximately 2.9V, which is safe for the ESP32's ADC.

## 3. ESPHome Configuration (`esphome.yaml`)

This configuration assumes your device is named `rfid_scanner_battery`.

```yaml
# ...

# SPI Bus Configuration (for RC522)
spi:
  clk_pin: GPIO18
  miso_pin: GPIO19
  mosi_pin: GPIO23

# RC522 RFID Scanner Configuration
rc522_spi:
  cs_pin: GPIO5
  reset_pin: GPIO17 # Connected to RC522 RST
  update_interval: 1s # How often the RC522 scans for tags
  # on_tag: This trigger fires when a new tag is detected
  on_tag:
    then:
      # Send the scanned tag's UID to Home Assistant's tag reader integration
      - homeassistant.tag_scanned: !lambda 'return x;'
      # Optional: Log the tag UID to the ESPHome console
      - logger.log: "RFID Tag Scanned: %s"

# Binary Sensor for the Physical Push Button
binary_sensor:
  - platform: gpio
    pin:
      number: GPIO4 # Wired to ESP32 GPIO4
      mode: INPUT_PULLUP # Activates internal pull-up, button connects to GND
      inverted: True # Interprets LOW as 'pressed' (ON state in HA)
    name: "Stop Button" # Name exposed in Home Assistant
    id: stop_button # Unique ID for internal ESPHome use
    # Optional: Actions to perform directly on the ESP32 when pressed/released
    # on_press:
    #   - logger.log: "Stop Button Pressed!"
    # on_release:
    #   - logger.log: "Stop Button Released!"

# Sensor for Battery Voltage Monitoring
sensor:
  - platform: adc
    pin: GPIO34 # Input from the voltage divider
    name: "Battery Voltage"
    unit_of_measurement: "V"
    icon: "mdi:battery-voltage"
    # The actual voltage divider ratio is (R1+R2)/R2.
    # For R1=100k and R2=220k, ratio is (100+220)/220 = 320/220 = 1.4545
    # The attenuation selects the input voltage range of the ADC.
    # ADC_ATTEN_DB_11 (full 3.3V range) is often necessary for voltage dividers.
    # Check ESP32 datasheet for specific ADC pin voltage ranges and attenuation.
    # Some older ESP32 ADCs might only be linear up to 1V. GPIO34 is usually ADC1_CH6.
    attenuation: 11db # Use 11dB attenuation to measure up to 3.3V
    # The calibrate_linear value should be `(R1 + R2) / R2` * `(Max Input Voltage / ADC Theoretical Max)` if not attenuation 11db (e.g. 1.1V default)
    # With 11db attenuation, 3.3V == 3.3V, so scale = voltage divider ratio.
    # If the default ADC reads 0-1.1V and 11db extends to 3.3V, the scaling factor is 3.
    # So, 1.4545 * 3 = 4.3635 
    # Let's adjust this for more robust operation.
    # To calibrate, measure battery voltage directly with multimeter (at OUT+ of charger module).
    # Then read the value from Home Assistant or ESPHome logs.
    # Adjust `calibrate_linear` until the ESPHome reading matches the multimeter.
    # Starting estimate: Divide battery voltage by ESP32's ADC reading.
    # A safer approach for calibrate_linear for 100k/220k on 11db attenuation is usually around 4.36.
    calibrate_linear:
      - 0 -> 0 # Start point
      # The value 4.3635 comes from: (R1+R2)/R2 * (Measured max voltage for 11dB/Internal Reference voltage for 11dB or 3.3V)
      # For (100k+220k)/220k = 1.4545, assuming a 3.3V internal ref for 11dB attenuation
      # This is often adjusted empirically. If your ESP32 ADC reads ~2.9V for a 3.3V supply (via divider),
      # and the actual battery is 4.2V, then the factor is 4.2/2.9 = ~1.45.
      # The 1.45 should be applied to the value before the resistor divider.
      # The 'calibrate_linear' factor is (Actual Vout) / (ADC V in).
      # If your ADC reads 2.9V and it should mean 4.2V, then 4.2/2.9 = 1.448
      - 2.9 -> 4.2 # Example: If ADC reads 2.9V, actual battery is 4.2V. You'll need to measure and tune this.
    update_interval: 60s # Check battery voltage every minute
```

**Customization Notes for Battery Voltage Sensor:**
*   The `calibrate_linear` values `(2.9 -> 4.2)` are example values. You will need to **empirically calibrate** this.
    1.  Measure the actual physical battery voltage (at the charger module's `OUT+`) using your multimeter.
    2.  Check the `sensor.battery_voltage` entity in Home Assistant (or ESPHome logs).
    3.  Adjust the second number (`4.2` in `2.9 -> 4.2`) in the `calibrate_linear` until the ESPHome sensor reading matches your multimeter's reading for the corresponding ADC input (`2.9` for the divided voltage). You may also adjust the first number based on what the ADC *actually* reads when the battery is at that specific voltage via the divider.
*   The `GPIO34` is a good choice as it's typically ADC1, which is not affected by Wi-Fi usage, unlike ADC2 pins.

## 4. Home Assistant Integration

Once you upload the ESPHome configuration and add the device to Home Assistant, the following entities will automatically appear:

### RFID Tag Scans

*   **Behavior:** When an RFID tag is scanned by the RC522, an event will be fired in Home Assistant via the `homeassistant.tag_scanned` service.
*   **Usage:** You can create **Home Assistant automations** that trigger off of this `tag_scanned` event. The automation will receive the UID of the scanned tag, allowing you to perform actions based on specific tags (e.g., unlock a door, arm/disarm alarm, toggle lights).

### Physical Button

*   **Entity ID:** `binary_sensor.rfid_scanner_battery_stop_button` (adjust based on your device and button names)
*   **Behavior:** This entity will be `on` when the button is pressed and `off` when released.
*   **Usage:** You can use this `binary_sensor` as a **trigger in Home Assistant automations** (e.g., "when `binary_sensor.rfid_scanner_battery_stop_button` changes to `on`...").

### Battery Status

*   **Entity ID:** `sensor.rfid_scanner_battery_battery_voltage` (adjust based on your device name)
*   **Behavior:** This sensor will report the current voltage of your LiPo battery in Volts (V).
*   **Usage:** You can display this sensor in your Home Assistant dashboards, plot its history, and create **automations** to notify you when the battery voltage drops below a certain threshold (e.g., `< 3.5V`) to indicate it needs recharging.

## 5. Power Consumption & Battery Life Considerations

**IMPORTANT:** With the RC522 continuously ready to scan and the ESP32's Wi-Fi always connected (necessary for immediate Home Assistant communication), this setup will **consume significant power**.

*   **Estimated Continuous Current Draw:** Approximately **130-150 mA** from the 3.7V battery (including ESP32, RC522, and boost converter losses).
*   **Estimated Battery Life (1800mAh LiPo):** Approximately **10-14 hours** of continuous operation.

**Recommendations for Extended Battery Life (if "always ready" is not strictly absolute):**

*   **Implement Deep Sleep:** If you can tolerate a delay (1-2 seconds) for the device to wake up, connect Wi-Fi, and become ready, using ESPHome's `deep_sleep` component in between scans is paramount for battery longevity (potentially weeks/months). This would require a trigger (like a physical button press, or a PIR sensor) to wake the device.
*   **Lower Wi-Fi Power Save Mode:** `power_save_mode: light` is a good start. `power_save_mode: high` (modem sleep) saves more power but can sometimes increase latency or connection issues.
*   **Periodically Disable RC522:** If you can accept brief periods where the RC522 isn't scanning, you could turn it off for periods via `reset_pin` or cutting its power with a MOSFET.

For truly long-term, "always ready" battery operation, this particular configuration (ESP32 Wi-Fi + RC522 active) is challenging. Consider powering it directly via a 5V USB power adapter if continuous uptime is crucial.