An interactive kiosk for the Human Machine exhibit. A child scans a body-part artifact on the NFC reader, picks a language, and watches a short educational video — then the screen resets for the next visitor.
Supported languages: English, Spanish (Español), Telugu
Child scans artifact ➜ Language selection screen ➜ Video plays ➜ Back to start
(NFC) (buttons or touchscreen) (auto-play)
- Splash screen — displays "Scan Here" with a picture of how to scan.
- NFC scan — the child holds an organ artifact (with an embedded NFC tag) near the reader. The screen switches to language selection.
- Language selection — three physical buttons (or on-screen buttons) let the child choose English, Spanish, or Telugu. If no button is pressed within 15 seconds, English is chosen automatically.
- Video playback — the matching video plays full-screen.
- Reset — when the video ends, the screen returns to step 1.
| Item | Notes |
|---|---|
| Raspberry Pi 5 | With power supply and microSD card (32 GB+) |
| PN532 NFC HAT | Waveshare — plugs directly onto the Pi GPIO header |
| 3 push buttons | For language selection (English / Spanish / Telugu) |
| Display | Any monitor or TV with HDMI input |
| Jumper wires | To connect buttons to the GPIO header |
Everything is installed automatically by the setup script. For reference:
- Raspberry Pi OS (Bookworm, 64-bit) — the standard Pi operating system
- Python 3.11+ — comes with Pi OS
- Node.js — installed during setup, used to build the on-screen display
- Django — Python web server (backend)
- React + Vite — on-screen interface (frontend)
- Use the Raspberry Pi Imager to flash Raspberry Pi OS (64-bit) onto a microSD card.
- Boot the Pi, connect to Wi-Fi, and finish the first-time setup wizard.
- Open a terminal (the black icon in the taskbar).
The NFC hat communicates over SPI, which is off by default.
sudo raspi-configNavigate with the arrow keys:
Interface Options ➜ SPI ➜ Yes ➜ Finish
Reboot when prompted:
sudo rebootAfter rebooting, open a terminal and run:
cd ~/Desktop
git clone https://github.com/UTDallasEPICS/Sci-Tech-Discovery-Center-Interactive-Signage.git
cd Sci-Tech-Discovery-Center-Interactive-SignageThis single command installs all dependencies and builds the display:
./setup.shThe script will:
- Install system packages (Node.js, Python venv tools)
- Create isolated Python environments for the backend and hardware layer
- Install all Python and JavaScript dependencies
- Build the frontend
- Generate a secret key
- Verify that SPI is enabled
This takes 5–10 minutes on a Pi 5. You will see progress as it runs. If you see any red error text, read the message — it will tell you what to fix.
The NFC hat plugs directly onto the Pi's 40-pin GPIO header — no soldering needed. The three language buttons connect to the hat's pass-through pins:
Button GPIO Pin Physical Pin Wire to
────────────── ────────── ────────────── ────────────────
English GPIO 17 Pin 11 3.3V (Pin 1 or 17)
Spanish GPIO 27 Pin 13 3.3V (Pin 1 or 17)
Telugu GPIO 22 Pin 15 3.3V (Pin 1 or 17)
For each button:
- Connect one leg to the GPIO pin listed above.
- Connect the other leg to 3.3V (any of Pin 1 or Pin 17 on the header).
- The software uses internal pull-down resistors, so no external resistors are needed.
For detailed wiring photos, see the document "Raspberry Pi Wiring Instructions" uploaded on EduSourced.
cd ~/Desktop/Sci-Tech-Discovery-Center-Interactive-Signage
./start.shThis starts the web server, NFC reader, and button listener, then opens Chromium in kiosk mode (full-screen, no browser controls).
Press Ctrl+C in the terminal where start.sh is running.
Or, from any terminal:
cd ~/Desktop/Sci-Tech-Discovery-Center-Interactive-Signage
./stop.shTo make the kiosk start automatically every time the Pi is powered on, run the included helper script:
./autostart-enable.shThis automatically detects your Pi's desktop environment (labwc on Bookworm, or LXDE on older systems) and configures the right autostart method.
Reboot to test:
sudo rebootThe system should start on its own after the desktop loads. It waits a few seconds for everything to be ready, then launches the server and browser.
To disable auto-start:
./autostart-disable.shIf auto-start isn't working, check the log file for errors:
cat signage.logThis file is created automatically whenever start.sh runs in the background
(i.e., launched by autostart rather than from a terminal).
Videos are stored in frontend/public/artifacts/. Each organ has a folder
with one video per language:
frontend/public/artifacts/
├── heart/
│ ├── en.mp4 (English)
│ ├── es.mp4 (Spanish)
│ └── te.mp4 (Telugu)
├── brain/
│ ├── en.mp4
│ ├── es.mp4
│ └── te.mp4
├── lungs/
│ ...
To replace a video: drop the new .mp4 file into the correct folder with
the correct name (en.mp4, es.mp4, or te.mp4), replacing the old one.
After changing any videos, rebuild the frontend:
cd ~/Desktop/Sci-Tech-Discovery-Center-Interactive-Signage/frontend
npx vite buildThen restart the system (./stop.sh then ./start.sh).
-
Create a new folder under
frontend/public/artifacts/(e.g.,stomach/) and put the three videos inside (en.mp4,es.mp4,te.mp4). -
Find the NFC tag's ID by scanning it and checking the terminal output of
UIDRead_Updated.py— it prints the decimal ID. -
Edit
interactive-signage-backend/polls/testdata.jsonand add a new entry:
{
"id": "YOUR_NFC_TAG_DECIMAL_ID",
"name": "stomach",
"path": {
"en": "artifacts/stomach/en.mp4",
"es": "artifacts/stomach/es.mp4",
"te": "artifacts/stomach/te.mp4"
}
}- Rebuild the frontend and restart:
cd ~/Desktop/Sci-Tech-Discovery-Center-Interactive-Signage/frontend
npx vite build
cd ..
./stop.sh
./start.sh- Make sure you rebuilt the frontend after adding or changing videos:
cd frontend && npx vite build
- Check that the video file exists at the expected path (e.g.,
frontend/dist/artifacts/heart/en.mp4).
- Verify SPI is enabled:
ls /dev/spidev*should show/dev/spidev0.0. If not, runsudo raspi-configand enable SPI under Interface Options. - Make sure the PN532 HAT is seated firmly on the GPIO header.
- Check the terminal output of
start.shfor error messages from the NFC reader.
- Verify wiring: each button should connect a GPIO pin (17, 27, or 22) to 3.3V when pressed.
- Check the terminal output — button presses are logged when detected.
- The on-screen buttons also work as a fallback if the physical buttons have an issue.
This was a bug in earlier versions. If you are seeing this, make sure you are running the latest code. Pull the latest changes:
cd ~/Desktop/Sci-Tech-Discovery-Center-Interactive-Signage
git pull
./setup.shMake sure you are in the correct directory:
cd ~/Desktop/Sci-Tech-Discovery-Center-Interactive-SignageThis is normal on newer Pi OS versions. The setup script avoids this by using
virtual environments. Do not run pip install directly — always use
./setup.sh.
If Chromium does not launch, open it manually and go to
http://localhost:8000. To go full-screen, press F11.
Press F11 to toggle full-screen in Chromium, or close it and re-run
./start.sh which opens Chromium in kiosk mode automatically.
Sci-Tech-Discovery-Center-Interactive-Signage/
│
├── setup.sh ← Run once to install everything
├── start.sh ← Start the kiosk
├── stop.sh ← Stop the kiosk
├── autostart-enable.sh ← Enable auto-start on boot
├── autostart-disable.sh ← Disable auto-start on boot
│
├── frontend/ ← On-screen interface (React)
│ ├── src/ ← Source code
│ ├── public/artifacts/ ← Video files (edit these)
│ └── dist/ ← Built output (auto-generated)
│
├── interactive-signage-backend/ ← Web server (Django)
│ ├── polls/
│ │ ├── views.py ← API endpoints
│ │ ├── getpath.py ← Video path lookup
│ │ └── testdata.json ← NFC ID → video mapping
│ └── mysite/
│ └── settings.py ← Server configuration
│
└── Hardware_Layer/ ← Raspberry Pi hardware scripts
├── UIDRead_Updated.py ← NFC tag reader
├── ButtonPress_Updated.py ← Physical button listener
└── pn532/ ← NFC hat driver library
| Layer | Technology |
|---|---|
| Display | React 19 + Vite + Tailwind CSS |
| Server | Django 5 (Python) with Server-Sent Events |
| Hardware | PN532 NFC HAT (SPI) + GPIO push buttons |
| Communication | REST API + SSE for real-time updates |
| Storage | JSON config file + local .mp4 video files |
┌────────────────┐ HTTP ┌──────────────────┐ SSE ┌──────────────┐
│ NFC Reader │ ──────────────► │ │ ◄──────────► │ │
│ (Python) │ /api/receive- │ Django Server │ /api/events │ React App │
│ │ id/ │ (port 8000) │ │ (browser) │
├────────────────┤ │ │ │ │
│ Button Script │ ──────────────► │ │ ───────────► │ │
│ (Python) │ /api/receive- │ │ /api/ │ │
│ │ button/ │ │ showinfo │ │
└────────────────┘ └──────────────────┘ └──────────────┘
| Endpoint | Method | Purpose |
|---|---|---|
/api/receive-id/?id=<id> |
GET | Register an NFC scan |
/api/receive-button/?button=a|b|c |
GET | Register a language button press (a=EN, b=ES, c=TE) |
/api/showinfo/ |
GET | Get the video path for the current scan + language |
/api/resetinfo/ |
GET | Reset state for the next visitor |
/api/events/ |
GET | SSE stream — pushes scanned_id, button_press, button_press_timeout events |
You can run just the backend and frontend on any machine for UI development. The hardware scripts are skipped automatically when SPI is not available, and the on-screen language buttons work without physical buttons.
# Terminal 1 — backend
cd interactive-signage-backend
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python manage.py runserver
# Terminal 2 — frontend (with hot reload)
cd frontend
npm install
npm run devThen open http://localhost:5173 (Vite dev server) or http://localhost:8000
(Django serving the built frontend).
You can simulate an NFC scan with curl:
curl "http://localhost:8000/api/receive-id/?id=1212866967841409"And simulate a button press:
curl "http://localhost:8000/api/receive-button/?button=a"