Files
smart-serow/pi/backend
Mikkeli Matlock 4a830dde91 pi: GPIO-controlled theme switch
- apt dependencies (RPI.GPIO somehow needs to be installed from apt to work & re-establish uv venv with --system-site-packages
- GPIO 20 triggers mode switching (can link to a photodiode or just switch)
2026-02-04 11:13:07 +09:00
..
2026-02-04 11:13:07 +09:00
2026-02-04 11:13:07 +09:00
2026-01-26 16:50:52 +09:00

Backend

Python GPS and Arduino telemetry service for Smart Serow. Connects to gpsd and Arduino serial, buffers data, exposes HTTP API.

Setup

# Install uv if you haven't
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install system dependencies (GPIO)
sudo apt install python3-rpi.gpio

# Create venv with access to system packages, then sync
cd pi/backend
uv venv --system-site-packages
uv sync

Run

uv run python main.py

Or for development:

uv run flask --app main run --host 0.0.0.0 --port 5000 --reload

API

Endpoint Description
GET /health Health check, shows gpsd and Arduino connection status
GET /gps Latest GPS fix (lat, lon, alt, speed, track)
GET /gps/history Last 100 buffered GPS positions
GET /arduino Latest Arduino telemetry (voltage, rpm, eng_temp, gear)
GET /arduino/history Last 100 buffered Arduino readings

Test from SSH

curl http://localhost:5000/health
curl http://localhost:5000/gps
curl http://localhost:5000/gps/history | jq
curl http://localhost:5000/arduino
curl http://localhost:5000/arduino/history | jq

gpsd Setup (Pi)

# Install
sudo apt install gpsd gpsd-clients

# Configure (edit DEVICES to match your GPS serial port)
sudo nano /etc/default/gpsd

# Example /etc/default/gpsd:
# DEVICES="/dev/ttyUSB0"
# GPSD_OPTIONS="-n"
# START_DAEMON="true"

# Restart
sudo systemctl restart gpsd

# Test gpsd directly
gpsmon
cgps -s

Arduino Setup (Pi)

The Arduino Nano connects via USB serial (typically /dev/ttyUSB0 or /dev/ttyACM0).

# Check available ports
ls /dev/tty*

# May need dialout group for serial access
sudo usermod -aG dialout $USER
# Then log out and back in

Arduino Protocol

Production format (JSON at 115200 baud):

{"v":12.45,"rpm":4500,"eng":85,"gear":3}

Legacy text format (also supported):

V_bat: 12.45V
RPM: 4500
ENG: 85C

The parser tries JSON first, falls back to regex for legacy format.

Configuring the Port

Edit main.py to change the default port:

arduino = ArduinoService(port="/dev/ttyACM0", baudrate=115200)

Stub Mode

  • GPS: If gpsdclient isn't installed or gpsd isn't running, generates fake GPS data
  • Arduino: If pyserial isn't installed or serial port unavailable, generates fake telemetry
  • GPIO: If RPi.GPIO isn't available, runs in mock mode (always returns default state)

All services run in stub mode for UI testing without hardware.

GPIO Setup

The gpio_service.py handles physical switch inputs (e.g., theme toggle on GPIO20).

Known Quirks

Use apt-installed RPi.GPIO, not pip:

sudo apt install python3-rpi.gpio

The pip version (RPi.GPIO) requires compilation with python3-dev headers. The apt package is pre-compiled and Just Works. The venv must be created with --system-site-packages to see it.

gpiozero doesn't work (TODO):

gpiozero is the "modern" GPIO library but has issues in this setup:

  • Requires a pin factory backend (lgpio, rpigpio, pigpio, or native)
  • lgpio/rpi-lgpio via pip needs swig to compile
  • native backend breaks under gevent monkey-patching (select.epoll missing)
  • May revisit if we need gpiozero-specific features

Software pull-up/down conflicts with external resistors:

If using an external pull-down resistor (especially high values like 1MΩ), disable the software pull:

GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_OFF)

The Pi's internal pull-down (~50kΩ) will overpower high-value external resistors, causing unexpected voltage divider behavior.

Debouncing:

Physical switches/connectors need debouncing. Current implementation requires 15 consecutive identical readings (~750ms at 20Hz) before accepting a state change. Tune required_consecutive in gpio_service.py as needed.

Deploy

TODO: Add to scripts/deploy.py as second target + systemd service.