Skip to content

Latest commit

 

History

History
157 lines (106 loc) · 7.03 KB

File metadata and controls

157 lines (106 loc) · 7.03 KB

System Architecture

← Back to README


Overview

The Physical Button Project is three independent systems that talk to each other over a local network:

┌──────────────────────────────────────────────────────────────────┐
│                        Local Network (WiFi)                      │
│                                                                  │
│  ┌──────────────┐   UDP events    ┌─────────────────────────┐    │
│  │ Button Device│ ─────────────►  │  button-authenticator   │    │
│  │  (ESP32-S3)  │                 │   (Node.js / Express)   │    │
│  │              │ ◄─────────────  │     SQLite database     │    │
│  └──────────────┘  HTTP (config/  └───────────┬─────────────┘    │
│                       modes)                  │                  │
│  ┌──────────────┐                             │ REST API         │
│  │ Button Device│                             │                  │
│  └──────────────┘                   ┌─────────▼───────────┐      │
│                                     │  button-dashboard   │      │
│  ┌──────────────┐                   │   (React / Vite)    │      │
│  │ Button Device│                   └─────────────────────┘      │
│  └──────────────┘                         browser                │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

Devices and server all live on the same LAN. There is no cloud dependency for the core click loop.


Firmware (ESP32-S3)

Startup State Machine

Power on
    │
    ▼
Saved WiFi credentials?
    │
    ├─ YES → Connect to home WiFi → discover server → run event loop
    │
    └─ NO  → Scan for "Button_Setup" AP
                 │
                 ├─ AP found  → join as setup FOLLOWER (UDP listener)
                 │
                 └─ AP absent → become setup LEADER (create AP + web server)

Setup Leader Flow

The first unconfigured device creates the Button_Setup access point and serves a web page on http://192.168.4.1. Other unconfigured devices that boot within the next second or two detect the AP and join as followers, announcing themselves over UDP port 4211.

The user connects their phone or laptop to Button_Setup (password: buttonsetup) and opens the setup page. The page shows all discovered devices, lets the user select the home WiFi SSID, enter the password, and assign a module type to each device. On submit, the leader broadcasts credentials to all followers over UDP, then all devices reboot and connect to the home network.


Server Discovery

After connecting to the home WiFi, each device sends a DISCOVER_SERVER UDP broadcast on port 4210. The button-authenticator server responds with its address. Discovery retries until a response arrives or a configurable timeout expires.

Design Decisions

UDP was chosen for discovery and lightweight event transmission because the devices are local-network appliances and the events are small. HTTP is still used where reliability, configuration, and dashboard integration matter more than low overhead.

Event Loop

Once a server address is known:

  • Button presses are sent as UDP datagrams (device ID + button position).
  • Mode updates can be pulled from the server via HTTP and written to the device's OLED display.
  • The onboard BOOT button, held for 3 seconds, performs a factory reset (clears saved WiFi credentials).

End-to-End Event Demo

The button matrix demo shows the event path from physical input to backend server log.

Watch button matrix demo

Hardware Modules

The firmware supports swappable module types declared at setup time:

Module Hardware
button 4×3 button matrix (up to 12 buttons), optional OLED, optional rotary encoder

Additional module types can be added without restructuring the firmware.


Backend (button-authenticator)

A Node.js/Express 5 server with a SQLite database.

Responsibilities

  • Receive UDP broadcasts for server discovery and respond with the server address.
  • Accept button click events from devices.
  • Store and query device metadata, button metadata, and click history.
  • Serve a REST API consumed by button-dashboard.

Key API Endpoints

Method Path Description
GET /devices List all device IDs
GET /devices/detailed Full device info including buttons and modes
GET /device/:deviceId Single device record
POST /device/:deviceId Upsert device metadata (name, image, purpose, modes)
GET /buttons/:deviceId List button IDs for a device
GET /buttons/:deviceId/detailed Full button info
GET /button/:deviceId/:buttonId Single button record
POST /button/:deviceId/:buttonId Upsert button metadata
POST /buttonClick Record a button press (with optional mode)

Modes

Modes are an ordered list of strings associated with a device. They have no server-side ID — they are plain strings. The server can push an updated mode list to a device; the device stores it locally and displays the active mode on the OLED.

When a button that observes modes is pressed, the currently active mode is attached to the click record.

Mode Refresh Demo

This demo shows the device refreshing its OLED mode list from the server.

Watch OLED mode update demo


Dashboard (button-dashboard)

A React 19 / Vite / Tailwind CSS single-page application.

Pages

Page Purpose
Dashboard Live card grid of all buttons with click counts and activity histograms
Device Setup Configure device names, button labels, images, and purposes
Reports Historical activity with per-button and per-device breakdowns

Dashboard Demo

This demo shows the React dashboard used to review devices, buttons, and activity.

Watch dashboard demo

Planned Views

  • Map — Physical layout of devices across a space; shows which buttons exist and where
  • Pouches — User-defined groupings of buttons across any devices, with freeform drag-and-drop layouts (powered by dnd-kit)