Embedded Systems / IoT / Social Computing / Wearable Technology

BLE Badge

BLE Badge is an advanced, interactive smart wearable badge built on the LilyGO T-Display-S3 (ESP32-S3). It is designed to operate as a fully self-c...

BLE Badge

Category: Embedded Systems / IoT / Social Computing / Wearable Technology
Platform: LilyGO T-Display-S3 (ESP32-S3)
Framework: Arduino via PlatformIO | C++
Status: Active — Production Ready


Project Overview

BLE Badge is an advanced, interactive smart wearable badge built on the LilyGO T-Display-S3 (ESP32-S3). It is designed to operate as a fully self-contained social and entertainment device — worn at conferences, hackathons, events, or simply as a conversation-starting piece of hardware art.

At its core, BLE Badge broadcasts a WiFi Access Point that nearby devices can connect to, enabling them to interact with the badge in real time through a captive web portal. The badge simultaneously scans for Bluetooth Low Energy (BLE) devices in the environment, uses that ambient signal density as a "mood sensor," and dynamically adapts its display content accordingly. It supports two-way communication via ESP-NOW (peer-to-peer WiFi messaging), a built-in WebSocket server for live updates, and a full arcade game system accessible from connected phones.


Core Features

Multi-Mode Display System

The badge operates across four selectable system modes:

Mode Description
AUTO Automatically cycles: wallpaper images → jokes → wallpaper
WALLPAPER (IMG) Continuously fetches and displays JPEG images from external APIs
JOKES Cycles through fetched or locally stored jokes
INFO (Neural Link) Displays connection instructions and WiFi details

BLE Ambient Mood Detection

  • Continuously scans the 2.4 GHz spectrum for nearby Bluetooth Low Energy devices
  • If more than 15 BLE devices are detected in a 2-second scan window, the badge switches its wallpaper mood to "Cyberpunk" (fetches urban/dark aesthetic images from LoremFlickr)
  • Below this threshold, the badge is in "Zen" mode (fetches soft anime-style images from nekos.best API)
  • This creates an automatic, environment-reactive personality for the badge

Captive Portal Web Interface

  • Badge broadcasts an open WiFi AP called "Joke of the Day (Send a Joke)"
  • Any connecting device (iOS or Android) is automatically redirected to a cyberpunk-themed captive portal
  • The portal includes:
    • A text input to transmit custom jokes or messages directly to the badge screen
    • An "Oracle" feature — consult the badge for a random philosophical prediction
    • A built-in Arcade OS with two playable browser games (DX-Ball, Space Invaders)
    • A Network Data Flow animated canvas visualisation showing data flowing through the system
    • Tabbed cybersecurity awareness guides for both everyday users and advanced practitioners

ESP-NOW Peer-to-Peer Messaging

  • Operates as both an ESP-NOW transmitter and receiver simultaneously
  • Can receive joke payloads broadcast from other ESP32 devices on the same channel
  • Incoming ESP-NOW messages are displayed as an "Override" screen on the badge
  • Long-pressing the hardware button broadcasts a "retaliation joke" back to all connected WebSocket clients

WebSocket Real-Time Communication

  • Full WebSocket server at /ws on port 80
  • Supports live typing notifications (badge shows a radar animation while someone is composing a message)
  • Game score reporting — browser-based arcade games send scores back to the badge via WebSocket
  • Oracle prediction requests and replies over WebSocket

Dynamic JPEG Wallpaper System

  • Downloads and renders full-resolution JPEG images directly to the TFT display
  • PSRAM-backed 150KB image buffer for efficient memory management
  • Images are fetched from external REST APIs and displayed using the TJpg_Decoder hardware-accelerated JPEG renderer
  • Automatic fallback to locally stored Oracle predictions if offline

Oracle Prediction Engine

  • Internal database of philosophical predictions and witty quotes
  • Displayed locally on the badge screen in rotation
  • Externally accessible via the WebSocket Oracle interface from connected browsers

Battery Monitoring

  • Real-time battery voltage ADC reading
  • Percentage display in the badge UI corner at all times

Power Management

  • Deep sleep mode triggered by holding the GPIO 14 power button for 2 seconds
  • Wakes on GPIO 14 low signal
  • Clean shutdown sequence: TFT sleep command, backlight off, WiFi disconnect, deep sleep entry

Technical Architecture

Component Detail
MCU ESP32-S3 @ 240 MHz
Display ST7789 IPS — 170x320 pixels, 16-bit colour
Display Library TFT_eSPI with TJpg_Decoder for JPEG rendering
BLE Stack NimBLE-Arduino (passive scanning, low overhead)
Web Server ESPAsyncWebServer (non-blocking, event-driven)
WebSocket AsyncWebSocket on /ws endpoint
Captive Portal DNSServer (wildcard DNS redirect) + CaptiveRequestHandler
Peer-to-Peer ESP-NOW broadcast (MAC FF:FF:FF:FF:FF:FF)
Image Buffer 150KB PSRAM-allocated ring buffer
JSON ArduinoJson 6.x with streaming deserialization
Connectivity WiFi AP + STA concurrent mode (WIFI_AP_STA)

Hardware Specifications

Pin GPIO Function
Power Enable 15 Must be HIGH for display power rail
LCD Backlight 38 PWM backlight control
Battery ADC 4 1:2 voltage divider for LiPo sensing
Boot Button 0 Mode cycling / long press = retaliation broadcast
Power Button 14 Hold 2s for deep sleep / wake trigger

API Integrations

Service Purpose
nekos.best API v2 Zen mood wallpaper images (anime aesthetic)
LoremFlickr Cyberpunk mood images (urban/dark aesthetic)
wsrv.nl Image proxy and resize service (JPEG output, fit-contain)

Arcade Games (Browser-Based)

Both games run entirely in the browser canvas and report high scores to the badge via WebSocket:

Game Controls
DX-Ball Touch/drag paddle (landscape orientation required)
Space Invaders Touch left/right to move, tap centre to fire

Security & Privacy Design

  • No user data stored at any time — messages are displayed and immediately discarded
  • No analytics, cookies, or tracking of any kind
  • Complete anonymity — no names, accounts, or identifiers
  • Network intentionally air-gapped (AP-only when in message mode — no internet routing from connected clients)
  • Input sanitisation: message payloads are truncated at 150 characters to prevent memory exhaustion attacks
Return to Projects