Skip to content

Latest commit

 

History

History
315 lines (267 loc) · 9.35 KB

File metadata and controls

315 lines (267 loc) · 9.35 KB

Deployment Guide

Prerequisites

Device OS Python Notes
Laptop/Server Linux / macOS / Windows 3.11+ / Node 20+ Server + React web UI
Raspberry Pi 5 Raspberry Pi OS (64-bit) 3.11+ Display client
Smartwatch ESP32 Arduino toolchain Firmware flashing

1. Central Server (Laptop / Dedicated PC)

Install

cd padel_system/server
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Install Web UI

cd ../web
npm install
npm run build
cd ../server

Configure

cp ../.env.example .env
# Edit .env:
#   DATABASE_URL=sqlite:///./padel.db
#   DEVICE_TOKEN=your-secret-token
#   MEDIA_DIR=./uploads
#   SERVER_PUBLIC_URL=http://YOUR_SERVER_LAN_IP:8000
#   SERVER_HOST=0.0.0.0
#   SERVER_PORT=8000
#   SECRET_KEY=change-this-long-random-value
#   DEFAULT_ADMIN_EMAIL=admin@padel.local
#   DEFAULT_ADMIN_PASSWORD=change-this-password
#   DEFAULT_CLIENT_EMAIL=client@padel.local
#   DEFAULT_CLIENT_PASSWORD=change-this-too
#   DEFAULT_CLIENT_COURTS=["court_01"]

Run

# Development (auto-reload)
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload

# Production (no reload, workers=1 for SQLite)
uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 1

Verify

Friendly local address (no more http://192.168.x.x:8000)

The server already supports any hostname through SERVER_PUBLIC_URL. Pick the option that fits the venue:

Option A — mDNS (recommended for Linux/macOS server, no router config)

Works on any LAN where Avahi/Bonjour is allowed (most home and small-club networks).

sudo apt install -y avahi-daemon
sudo hostnamectl set-hostname padel
sudo systemctl enable --now avahi-daemon

Set in server/.env:

SERVER_PUBLIC_URL=http://padel.local:8000

Restart the server. Now everyone on the same Wi-Fi opens http://padel.local:8000 and Pi displays use ws://padel.local:8000. macOS, Windows 10+ and most Android phones resolve *.local natively. iPhones, iPads and Linux desktops with Avahi do too.

Option B — Router DNS / DHCP reservation (most stable)

Better for permanent installations or networks where mDNS is blocked.

  1. Reserve the server's MAC address to a fixed IP on the router.
  2. Add a local DNS entry (e.g. padel, padel-server, or scoreboard).
  3. Use that hostname in SERVER_PUBLIC_URL, the Pi SERVER_*_URL, and the watch firmware SERVER_HOST.

Option C — Drop the :8000 with a reverse proxy

If you want plain http://padel.local, run a tiny reverse proxy on port 80. This does not change the FastAPI server — keep it on 0.0.0.0:8000.

Caddy (single-line config):

sudo apt install -y caddy
sudo tee /etc/caddy/Caddyfile <<'EOF'
:80 {
    reverse_proxy 127.0.0.1:8000
}
EOF
sudo systemctl reload caddy

Nginx (/etc/nginx/sites-available/padel):

server {
    listen 80;
    server_name padel.local _;
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 86400;
    }
}

After enabling, also set SERVER_PUBLIC_URL=http://padel.local (no port) so download URLs sent to displays match.

For ESP32 watches: prefer Option B (router DNS or reserved IP). The arduinoWebSockets library does not perform mDNS resolution reliably across all Wi-Fi chipsets.

Run Tests

cd server
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 .venv/bin/python -m pytest tests/ -v

Initial Setup via Admin UI

  1. Open http://{SERVER_IP}:8000.
  2. Sign in with DEFAULT_ADMIN_EMAIL / DEFAULT_ADMIN_PASSWORD.
  3. Create a court from the admin dashboard.
  4. Register/assign watch and display devices with the device token.
  5. Start a match from the court card.
  6. Upload ads from the admin dashboard; online displays receive media_sync.

Moving to another site / network

  1. Connect laptop/server, Pi displays, and watches to the new Wi-Fi.
  2. Find the new server IP, or configure the router DNS name again.
  3. Update SERVER_PUBLIC_URL in server/.env.
  4. Update Pi SERVER_WS_URL and SERVER_HTTP_URL.
  5. On watches, use the NET panel for Wi-Fi credentials. If SERVER_HOST changed and you do not use stable DNS, reflash firmware with the new host.
  6. Restart server and displays, then verify /health and one test score.

For deployments, consider shipping a small dedicated router with a fixed SSID and DHCP reservation. That keeps the system address stable at every venue.


2. Raspberry Pi 5 Display

Install system dependencies

sudo apt update
sudo apt install -y python3-pip python3-venv libgl1 libglib2.0-0 \
     gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \
     python3-pyside6

Install Python dependencies

cd padel_system/pi_display
python3 -m venv .venv --system-site-packages
source .venv/bin/activate
pip install -r requirements.txt

Configure

# Create /opt/padel_display/media directory
sudo mkdir -p /opt/padel_display/media
sudo chown $USER:$USER /opt/padel_display/media

# Set environment variables (or create .env in pi_display/)
export DISPLAY_ID=display_01
export DISPLAY_COURT_ID=court_01
# Match whatever hostname you chose for the server. Fall back to a LAN IP
# only if mDNS or router DNS is unavailable.
export SERVER_WS_URL=ws://padel.local:8000
export SERVER_HTTP_URL=http://padel.local:8000
export DEVICE_TOKEN=your-secret-token
export MEDIA_CACHE_DIR=/opt/padel_display/media

Run

cd padel_system/pi_display
python3 -m app.main

Auto-start on boot (systemd)

# /etc/systemd/system/padel-display.service
[Unit]
Description=Padel Display
After=network-online.target graphical.target

[Service]
User=pi
WorkingDirectory=/home/pi/padel_system/pi_display
Environment=DISPLAY=:0
Environment=DISPLAY_ID=display_01
Environment=DISPLAY_COURT_ID=court_01
Environment=SERVER_WS_URL=ws://padel.local:8000
Environment=DEVICE_TOKEN=your-secret-token
ExecStart=/home/pi/padel_system/pi_display/.venv/bin/python3 -m app.main
Restart=always
RestartSec=5

[Install]
WantedBy=graphical.target
sudo systemctl enable padel-display
sudo systemctl start padel-display

3. Smartwatch Firmware (ESP32)

Arduino IDE Setup

  1. Install Arduino IDE 2.x
  2. Add ESP32 board package: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
  3. Select board: ESP32S3 Dev Module (or specific Waveshare board if available)

Required Libraries (Library Manager)

  • arduinoWebSockets by Markus Sattler (WebSocketsClient)
  • lvgl (version matching lv_conf.h)
  • Arduino_GFX_Library
  • Arduino_DriveBus_Library
  • XPowersLib
  • SensorPCF85063 (or include from Waveshare SDK)

Hardware-specific files

Copy pin_config.h and Waveshare board support files into the sketch folder (same as the original SmartWatch.ino project).

Configure

Edit config.h before flashing:

#define WATCH_ID        "watch_01"    // unique per device
#define COURT_ID        "court_01"    // matches admin assignment
#define DEVICE_TOKEN    "your-secret-token"
#define SERVER_HOST     "10.144.186.211"
#define SERVER_PORT     8000
#define DEFAULT_WIFI_SSID     "YourSSID"
#define DEFAULT_WIFI_PASSWORD "YourPassword"

Flash

  1. Connect watch via USB
  2. Open smartwatch.ino in Arduino IDE
  3. Select correct port
  4. Upload

First boot

  • Watch will try to connect to DEFAULT_WIFI_SSID
  • Tap NET button on screen to change WiFi credentials
  • After connecting, it auto-connects to the WebSocket server
  • Score with BOOT button or touch buttons

Button Mapping (default)

Gesture Action
Single click point_a
Double click point_b
Triple click undo
Long press (0.7s) timer_toggle

Change mapping in config.h:

#define MAP_BOOT_SINGLE  "point_a"
#define MAP_BOOT_DOUBLE  "point_b"
#define MAP_BOOT_TRIPLE  "undo"
#define MAP_BOOT_LONG    "timer_toggle"

Validation Checklist

Server

  • GET /health returns {"status":"ok"}
  • Admin dashboard loads at http://{SERVER_IP}:8000
  • Can create court, register devices, create match

Watch

  • Watch connects (Serial prints [WS] Server accepted hello — READY)
  • BOOT single-click → server logs action=point_a applied
  • Admin dashboard shows watch online

Display

  • Display connects and shows court name / team names
  • Score updates within ~150 ms of watch button press
  • Upload image to media → display shows it within next cycle

Fake Watch (no hardware)

cd server
# First create court and match via admin UI, then:
python tests/fake_watch_client.py \
  --host localhost --port 8000 \
  --watch-id watch_01 --court-id court_01 \
  --token padel-secret-token-change-me
# Press 'a' + Enter to score point_a
# Open display app or admin dashboard to see score update live