Skip to main content

SP-Base

CI Release codecov PyPI version Python versions PyPI Downloads License: MIT Ruff Conventional Commits

Web UI and REST API for configuring and monitoring a u-blox GPS RTK base station and its RTCM correction data relay.

SP-Base wraps the sp-rtk-base-relay engine with a browser-based operator console, adds full u-blox device configuration (survey-in, fixed base, GNSS constellations, RTCM message selection), a centimetre-level Corrected survey-in from an NTRIP Correction source, and exposes everything through a REST API — all from a phone, tablet, or desktop browser.

Features

Relay Control

  • Dashboard — real-time relay status, input metrics, throughput stats, GPS device summary, live event log
  • Destination Management — add/edit/delete/hot-toggle SurePath, NTRIP, and TCP Server outputs (zero-downtime)
  • Input Sources — configure TCP, serial, or Bluetooth RTCM input (serial port auto-detect with GPS flagging, Bluetooth scan + pair + test-connection)
  • Config Import/Export — YAML download/upload with validation

GPS Device Management (u-blox)

  • Connect / Disconnect — serial port auto-detect (u-blox / FTDI / Prolific / Silicon Labs flagged with ⭐), driver selector, MON-VER device info
  • Survey-In — configure duration + accuracy target, live convergence chart (ECharts), auto-promote to fixed base on completion + save-to-flash; on a receiver without a survey-in of its own, the station averages the position itself
  • Corrected Survey-In — survey in as an RTK rover against a saved NTRIP Correction source: the station pulls the source's RTCM 3 through its own Relay instance, feeds it to the receiver, averages only settled RTK Fixed solutions on fresh corrections, and commits a centimetre-level fixed base. Live RTK status, correction age, source state and Fixed time; clear failure rules (stall abort, Fixed-jump restart) and no silent fallback
  • Correction Sources & Verify — save NTRIP sources (v1/v2, TLS, write-only password) and Verify one Stage by Stage (connect → caster → auth → mountpoint → data) before surveying
  • Signal Quality — Good / Marginal / Poor from L1/L2 band strength and usable satellites, from the receiver during survey-in or from the Relay's MSM while it runs
  • Fixed Base — read-back current config, edit/commit coordinates, save-to-flash
  • Named Position Profiles — save surveyed or manual base positions to YAML, restore them directly to device RAM + flash
  • Live Position — NAV-PVT display (fix type, RTK status, lat/lon/alt, accuracy, satellites, speed, heading, PDOP) auto-polled every 2 s
  • GNSS Constellation Selection — toggle GPS / GLONASS / Galileo / BeiDou / SBAS / QZSS
  • RTCM Message Selection — per-port RTCM3 message enable/disable
  • Save to Flash — persist any configuration change for reboot survival
  • Device → Relay Handoff — disconnect device and start the relay on the same serial port with one click

Monitoring & API

  • REST API — full programmatic control (relay, destinations, settings, events, device, config)
  • Prometheus Metrics — GET /metrics endpoint for Grafana / Prometheus monitoring
  • WebSocket Events — real-time event streaming at WS /api/events/ws
  • Responsive UI — mobile-first layout, 44 px touch targets, tablet/desktop breakpoints

Quick Start

sp-rtk-base is published on PyPI — install it the way that fits your host best.

Production deploy on a Raspberry Pi (or any Debian host)

One-shot installer creates a sp-rtk-base system user, an isolated venv at /opt/sp-rtk-base/, config in /etc/sp-rtk-base/, state in /var/lib/sp-rtk-base/, and a hardened systemd service.

Deployment modes

The installer requires an explicit --mode — it never guesses, because guessing wrong is destructive (seizing wlan0 on a box something else manages, or shipping a device with no way to join a network):

Mode Installs Use for
appliance App + relay plus a full NetworkManager takeover: fixed setup-AP, WiFi-picker captive portal, polkit rule, and the independent sp-rtk-base-net-provision.service A dedicated Pi shipped to a customer — sp-rtk-base owns the network stack
managed-host App + relay only — no NetworkManager install, no AP, no polkit, no net-provision unit; the host's own network stack is left completely alone A co-tenant Pi/NUC/VM where something else already manages networking
# Dedicated appliance — full network takeover, fixed setup-AP
curl -fsSL https://raw.githubusercontent.com/rodenj1/sp-rtk-base/main/deploy/install.sh \
    | sudo bash -s -- --mode appliance

# Managed host — app only, host network stack untouched
curl -fsSL https://raw.githubusercontent.com/rodenj1/sp-rtk-base/main/deploy/install.sh \
    | sudo bash -s -- --mode managed-host

In appliance mode, if AP_PASSWORD isn't set the installer falls back to a fixed fleet default (sp-rtk-base1234!) and prints a warning — override it per fleet in production:

curl -fsSL https://raw.githubusercontent.com/rodenj1/sp-rtk-base/main/deploy/install.sh \
    | sudo AP_PASSWORD='your-sticker-password' bash -s -- --mode appliance

A bare re-run with no --mode preserves whichever mode is already recorded in config.yaml, so version-bump re-runs don't need the flag repeated. A future container mode (app-only, published image) is planned but not yet built — see docs/deployment-pi.md for details, the full behavior matrix, and how to switch modes on an existing install.

Open http://<pi-ip>:8080 in your browser when it finishes.

sudo systemctl status sp-rtk-base       # service status
sudo journalctl -u sp-rtk-base -f       # live logs
sudo ./deploy/upgrade.sh                # later: upgrade in place

See docs/deployment-pi.md for the full runbook (layout, nginx reverse proxy, backup/restore, troubleshooting, fleet management).

Single-user install on your workstation

If you just want to try it out locally:

pipx install sp-rtk-base
sp-rtk-base

Or with uv:

uv tool install sp-rtk-base
sp-rtk-base

Open http://localhost:8080 in your browser.

From source (developers only)

git clone https://github.com/rodenj1/sp-rtk-base.git
cd sp-rtk-base
uv sync
uv run sp-rtk-base

Demo Mode

Run with a simulated RTCM source and mock destinations (no hardware needed):

uv run python tools/demo_with_simulator.py

This starts:

  • TCP source simulator — streams synthetic RTCM3 data on port 19800
  • Mock NTRIP caster — accepts NTRIP v1.0 connections (ephemeral port)
  • SP-Base — pre-configured with TCP input, a tcp_server destination on port 19876, and an NTRIP destination pointing to the mock caster

The relay auto-starts on launch. Open http://localhost:8080 and you'll see live data flowing on the Dashboard immediately.

Local NTRIP Caster (Dev / Testing)

A lightweight Python asyncio NTRIP caster is included for developing and testing NTRIP v1.0 and v2.0 destinations without depending on a public caster:

cd docker/ntrip-caster
docker compose up

See docs/local-ntrip-caster.md for auth, mountpoint, and protocol details.

CLI Utilities

In addition to the main sp-rtk-base server, the package installs:

  • sp-rtk-base-gps-audit — non-destructive audit tool for ZED-F9P (u-blox Gen9) receivers. Reads the current RAM configuration and the factory defaults via CFG-VALGET, then prints every setting that differs from default. Read-only — never writes to the receiver.

    sp-rtk-base-gps-audit --port /dev/ttyUSB0 --baud 57600
    # or from a source checkout:
    uv run sp-rtk-base-gps-audit --port /dev/ttyUSB0
    

UI Pages

Route Page Purpose
/ Dashboard Relay status, input/output metrics, GPS device summary, event log
/input Input Input source config (TCP / serial / Bluetooth) with discovery helpers
/outputs Outputs Destination CRUD + enable/disable toggles
/survey Survey-In Connect to GPS, run survey-in with live chart, fixed-base config, position profiles
/settings Settings Application settings (auto-start, dark mode, metrics toggle)
/gps-config Advanced GPS RTCM message selection, GNSS constellations, save-to-flash, relay handoff

API Endpoints

Health

Method Path Description
GET /api/health Health check

Relay

Method Path Description
GET /api/relay/status Relay engine status
POST /api/relay/start Start the relay
POST /api/relay/stop Stop the relay

Destinations

Method Path Description
GET /api/destinations List all destinations
POST /api/destinations Create a destination
GET /api/destinations/{name} Get destination details
PUT /api/destinations/{name} Update a destination
DELETE /api/destinations/{name} Delete a destination

Settings

Method Path Description
GET /api/settings Get application settings
PUT /api/settings Update application settings
GET /api/input Get input source config
PUT /api/input Update input source config

Events

Method Path Description
GET /api/events Poll recent events
WS /api/events/ws WebSocket event stream

Correction Sources

Method Path Description
GET /api/correction-sources List saved NTRIP Correction sources (passwords never returned)
POST /api/correction-sources Save a Correction source
GET /api/correction-sources/{name} Get one source
PUT /api/correction-sources/{name} Change a source (blank password keeps the saved one)
DELETE /api/correction-sources/{name} Delete a source (refused while a survey uses it)
POST /api/correction-sources/verify Verify a source, Stage by Stage

Metrics & Config

Method Path Description
GET /metrics Prometheus metrics
GET /api/config/export Download full YAML configuration
POST /api/config/import Upload and validate a YAML configuration

GPS Device (u-blox)

Method Path Description
GET /api/device/ports List available serial ports (GPS-flagged)
POST /api/device/connect Connect to GPS receiver
POST /api/device/disconnect Disconnect from GPS receiver
GET /api/device/status Device connection state + MON-VER info
GET /api/device/capabilities List driver capabilities
GET /api/device/position Live NAV-PVT position snapshot
GET /api/device/survey-in Survey-in progress, whoever averages (receiver or station), incl. Corrected survey-in state
POST /api/device/configure/survey-in Start a survey-in
POST /api/device/configure/corrected-survey-in Start a Corrected survey-in against a saved Correction source
POST /api/device/cancel-survey-in Cancel a survey-in (the receiver stays a rover)
POST /api/device/configure/fixed-base Configure fixed-base coordinates
POST /api/device/configure/rtcm Configure RTCM output messages
GET /api/device/base-config Read current base mode (survey/fixed/disabled)
GET /api/device/gnss Get GNSS constellation config
PUT /api/device/gnss Update GNSS constellation config
POST /api/device/save Save current config to device flash
POST /api/device/promote-survey-in Promote completed survey-in to fixed base
POST /api/device/handoff Disconnect device and start relay on same serial port
GET /api/device/base-positions List saved base-station position profiles
POST /api/device/base-positions Save a named base-station position
DELETE /api/device/base-positions/{name} Delete a saved position
POST /api/device/base-positions/{name}/restore Restore a saved position to the device

Prometheus Integration

SP-Base serves Prometheus metrics at GET /metrics on the same port (8080).

Example prometheus.yml scrape config:

scrape_configs:
  - job_name: "sp-rtk-base"
    scrape_interval: 10s
    static_configs:
      - targets: ["localhost:8080"]

Key metrics include:

  • sp_rtk_base_relay_running — relay engine state (1/0)
  • sp_rtk_base_relay_uptime_seconds — engine uptime
  • sp_rtk_base_input_connected — input source connection state
  • sp_rtk_base_input_bytes_received — total bytes from input
  • sp_rtk_base_active_destinations / sp_rtk_base_total_destinations
  • sp_rtk_base_dest_connected{destination="name"} — per-destination status
  • sp_rtk_base_dest_bytes_sent{destination="name"} — per-destination throughput

Development

Run Tests

Default pytest runs the unit suite only — integration and e2e suites are excluded via norecursedirs in pyproject.toml and must be invoked explicitly. The default unit run enforces --cov-fail-under=90.

# Unit tests (default — fast, mocked, coverage-gated)
uv run pytest

# Integration tests — real relay engine + TCP simulator
uv run pytest tests/integration/ --no-cov

# End-to-end tests — Playwright browser suites (requires Chromium)
uv run pytest tests/e2e --no-cov

Type Checking

uv run pyright src/

Quality Snapshot

  • Unit tests: 554 passing across 32 test files
  • Integration tests: 3 suites (end-to-end + destination management + NTRIP)
  • E2E tests: 12 Playwright browser suites
  • Coverage: ≥90% gate on measured code (NiceGUI UI pages, shared layout/components, and cli/config_audit.py excluded — they can't be meaningfully unit-tested and are covered by e2e instead)
  • Pyright (strict): 0 errors, 0 warnings
  • Python: 3.10+ with modern type hints (dict, list, X | None)

Project Structure

sp-rtk-base/
├── src/sp_rtk_base/
│   ├── api/              # FastAPI REST endpoints
│   │   ├── config.py        # YAML import/export
│   │   ├── destinations.py  # Destination CRUD
│   │   ├── device.py        # GPS device endpoints
│   │   ├── events.py        # Events + WebSocket
│   │   ├── health.py
│   │   ├── metrics.py       # Prometheus
│   │   ├── relay.py
│   │   └── settings.py
│   ├── models/           # Pydantic config, device & API models
│   ├── services/         # Business logic
│   │   ├── config_service.py
│   │   ├── device_service.py
│   │   ├── metrics_service.py
│   │   ├── relay_events.py  # live relay events, one stream per client
│   │   ├── relay_service.py
│   │   └── drivers/         # GPS driver layer
│   │       ├── base.py      # GpsReceiverDriver ABC
│   │       └── ublox.py     # u-blox driver (PyUBX2)
│   └── ui/               # NiceGUI browser UI
│       ├── layout.py        # Shared navigation layout
│       ├── validators.py    # Shared form validators
│       ├── components/      # Reusable UI components
│       └── pages/           # Dashboard, Input, Outputs, Survey, Settings, GPS Config
├── tests/
│   ├── unit/             # Fast unit tests with mocks
│   ├── integration/      # End-to-end tests with real relay
│   ├── e2e/              # Playwright browser suites
│   └── fixtures/         # TCP simulators, mock NTRIP caster, test helpers
├── docker/
│   └── ntrip-caster/     # Local NTRIP caster for dev/testing
├── docs/                 # Architecture, planning, device config reference
└── tools/                # Demo and hardware test scripts

Architecture

SP-Base is built on FastAPI (REST API + WebSocket) and NiceGUI (browser UI) sharing a single ASGI server on port 8080. Core components:

  • sp-rtk-base-relay — RTCM relay engine with TCP / serial / Bluetooth inputs and SurePath / NTRIP / TCP Server outputs, hot destination management, and in-process event bus
  • GPS driver layer — abstract GpsReceiverDriver base with a u-blox implementation via PyUBX2 (UBX-MON-VER, CFG-VALSET/VALGET, NAV-PVT, NAV-SVIN, CFG-GNSS, survey-in, fixed-base, RTCM selection, save-to-flash)
  • Services — async orchestrators bridging the synchronous relay engine and GPS driver to FastAPI's event loop via asyncio.to_thread() and daemon-thread event queues
  • Operator console — 6-page workflow (Dashboard → Input → Outputs → Survey-In → Settings → Advanced GPS) driven by a shared navigation layout; the browser renders status and requests actions, while authoritative runtime state lives in the relay engine and backend services

Graceful shutdown is wired through app.on_shutdown so Ctrl+C cleanly stops the event bridge, relay engine, destination threads, and any active GPS connection before uvicorn exits.

License

MIT

Metadata

Release files for sp-rtk-base 0.10.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sp-rtk-base 0.10.0
File Size Uploaded
sp_rtk_base-0.10.0.tar.gz 387.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sp-rtk-base 0.10.0
File Interpreter ABI Platform
sp_rtk_base-0.10.0-py3-none-any.whl Python 3 none any Details

Total release size: 826.6 kB

Release files / sp_rtk_base-0.10.0.tar.gz

Download URL sp_rtk_base-0.10.0.tar.gz
Size 387.6 kB
Tags Source
SHA-256 checksum
How to use checksums
085869b4d98370ace0089446232d712fc67d700b04d7188652a50aebc53b7e81
BLAKE2b-256 checksum
How to use checksums
19c64aaf030d256ea3c612ea3f335a6bac3e597e5ad6718aeb862e13d1c4f99e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release files / sp_rtk_base-0.10.0-py3-none-any.whl

Download URL sp_rtk_base-0.10.0-py3-none-any.whl
Size 439.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6aecb926ab674277a950daace7f01c3d8dea985749a619be829e813ee0f7b3ad
BLAKE2b-256 checksum
How to use checksums
28c82d7892749018d34dd296b4ff0603d34171e00347363abdc39912c53fd436
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.10.0 This release

2 release files

0.9.0

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.17

2 release files

0.3.16

2 release files

0.3.15

2 release files

0.3.14

2 release files

0.3.13

2 release files

0.3.12

2 release files

0.3.11

2 release files

0.3.10

2 release files

0.3.9

2 release files

0.3.8

2 release files

0.3.7

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page