Joke Box
Joke Box is the original version of what evolved into the BLE Badge — an interactive, WiFi-enabled smart badge/display device built on the LilyGO T...
Joke Box
Category: Embedded Systems / IoT / Social Device / Interactive Badge
Platform: LilyGO T-Display-S3 (ESP32-S3)
Framework: Arduino via PlatformIO | C++
Status: Active — Production Ready
Project Overview
Joke Box is the original version of what evolved into the BLE Badge — an interactive, WiFi-enabled smart badge/display device built on the LilyGO T-Display-S3. It serves as a social interaction device that broadcasts a WiFi hotspot allowing nearby people to send jokes and messages directly to its screen via a captive web portal.
The device fetches live jokes from the JokeAPI, downloads mood-matched wallpaper images, and uses Bluetooth Low Energy (BLE) ambient scanning to determine the "mood" of the surrounding environment — automatically switching between calm anime-style artwork ("Zen" mode) and urban cyberpunk imagery ("Cyberpunk" mode) based on how many BLE devices are detected nearby.
Unlike the later BLE Badge evolution, Joke Box connects to a home WiFi network (via WiFiManager) before switching to simultaneous AP+STA mode, enabling both internet connectivity and local interaction concurrently.
Core Features
Live Joke Fetching
- Fetches jokes from the JokeAPI v2 (jokeapi.dev) — family-friendly filter applied (excludes NSFW, religious, political, racist, sexist, and explicit content)
- Supports both single-line jokes and two-part setup/delivery format jokes
- Dynamic font sizing: shorter jokes render in large Font4, longer jokes in smaller Font2 to fit the display
- Display label: "Haha.exe"
BLE Ambient Mood Detection
- Performs a 2-second passive BLE scan every 15 seconds using NimBLE
- If more than 15 BLE devices are detected: mood switches to "Cyberpunk" → fetches urban/dark aesthetic images from LoremFlickr
- If 15 or fewer BLE devices: mood is "Zen" → fetches anime-style artwork from nekos.best API v2
- Mood is displayed on screen as part of the wallpaper screen header
Captive Portal Web Interface
- Broadcasts WiFi AP: "Joke of the Day (Send a Joke)" (open network, no password)
- All connecting devices (iOS, Android, Windows) are automatically redirected to a styled cyberpunk web portal
- Portal features:
- Text input form to send a joke or message directly to the badge display
- WebSocket connection for real-time bidirectional communication
- Sample jokes section for inspiration
- Branded neon/terminal aesthetic with teal/cyan colour scheme
ESP-NOW Peer-to-Peer Messaging
- Simultaneously listens for ESP-NOW broadcast packets on the current WiFi channel
- Incoming ESP-NOW messages are displayed as an "Override" interrupt screen
- Device can also broadcast outgoing jokes to all nearby ESP-NOW peers via the long-press button action
Message Handling
- Received messages (from web portal or ESP-NOW) display for 60 seconds before reverting to auto mode
- Sends a "retaliation joke" broadcast to all WebSocket clients when the hardware button is held for 3+ seconds
Multi-Mode Display System
| Mode | Trigger | Description |
|---|---|---|
| AUTO | Default | Cycles: 6x wallpapers, then 2x jokes, then repeat |
| WALLPAPER (IMG) | Button cycle | Continuous wallpaper fetching every 30s |
| JOKES | Button cycle | Continuous joke fetching from JokeAPI every 30s |
| INFO (Neural Link) | Button cycle | Shows WiFi SSID and connection instructions |
Battery Monitoring
- ADC reading of LiPo voltage from GPIO 4
- Percentage displayed in bottom-right corner of every screen frame
Power Management
- Holding GPIO 14 (power button) for 2 seconds initiates graceful shutdown
- TFT sleep command sent, backlight turned off, WiFi disconnected, ESP32 enters deep sleep
- GPIO 14 LOW signal configured as wake-up trigger
Technical Architecture
| Component | Detail |
|---|---|
| MCU | ESP32-S3 @ 240 MHz |
| Display | ST7789 IPS — 170x320 pixels (portrait orientation) |
| Display Library | TFT_eSPI |
| JPEG Decoder | TJpg_Decoder (hardware-accelerated JPEG rendering) |
| BLE Stack | NimBLE-Arduino (passive scanning) |
| Web Server | ESPAsyncWebServer (non-blocking) |
| WebSocket | AsyncWebSocket at /ws |
| Captive Portal | DNSServer wildcard redirect |
| Peer-to-Peer | ESP-NOW broadcast (all 0xFF peer address) |
| WiFi Mode | Concurrent AP+STA (WIFI_AP_STA) |
| Image Buffer | 150KB PSRAM-allocated JPEG buffer |
| JSON | ArduinoJson (DynamicJsonDocument) |
| First-Run Config | WiFiManager captive portal (SmartBadge Setup AP) |
API Integrations
| Service | Endpoint | Purpose |
|---|---|---|
| JokeAPI v2 | jokeapi.dev/joke/Programming,Miscellaneous | Live joke fetching |
| nekos.best API v2 | nekos.best/api/v2/neko | Zen mode anime wallpapers |
| LoremFlickr | loremflickr.com/170/320/cyberpunk | Cyberpunk mood images |
| wsrv.nl | wsrv.nl/?url=...&output=jpg&w=170&h=320 | Image proxy, resize, convert |
Difference From BLE Badge (Later Iteration)
| Feature | Joke Box (Original) | BLE Badge (Evolution) |
|---|---|---|
| WiFi Setup | WiFiManager (home WiFi) | AP-only (no home WiFi needed) |
| Jokes Source | JokeAPI v2 (live, internet) | Local hardcoded joke bank |
| Oracle Feature | Not present | Full Oracle prediction system |
| Arcade Games | Not present | DX-Ball + Space Invaders |
| Typing Indicator | Not present | Radar animation while user types |
| Security Awareness | Not present | Full tabbed cybersecurity guides |
| Score Reporting | Not present | WebSocket game score display |
Joke Box is the earlier, simpler design; BLE Badge is the fully evolved successor with significantly more features.
Hardware Pins
| Pin | GPIO | Function |
|---|---|---|
| Power Enable | 15 | Display power rail enable |
| LCD Backlight | 38 | TFT backlight control |
| Battery ADC | 4 | LiPo voltage sensing (1:2 divider) |
| Boot Button | 0 | Mode cycling / ESP-NOW broadcast |
| Power Button | 14 | Hold 2s to enter deep sleep |
Security Notes
- No user data is stored — messages are displayed and immediately discarded from memory
- No tracking, cookies, analytics, or account systems
- Open network portal by design — social interaction device
- Input length capped at 150 characters to prevent memory exhaustion