gps-mouse 🛰️
A lightweight Python library for reading data from U-Blox GPS devices and distributing it to multiple projects via ZMQ, REST API, MQTT, or file logging.
Features
- Read NMEA sentences (GGA, RMC, VTG) from any serial GPS device
- Auto-reconnect when device is unplugged and re-plugged
- ZMQ pub/sub — distribute to multiple projects simultaneously
- REST API + Live map dashboard — browser-based Leaflet.js map
- MQTT — publish to any MQTT broker (Home Assistant, Node-RED, etc.)
- CSV + GPX logging — record tracks for later analysis
- gpsd support — use the standard Linux GPS daemon
- CLI tools —
gps-server,gps-read,gps-log,gps-api - Docker — single-command deployment
- Sync and async support
Tested Device
| Device | Interface | Default Port |
|---|---|---|
| U-Blox 7 (USB) | /dev/ttyACM0 |
9600 baud |
Works with any NMEA-compatible GPS device.
Installation
# Core library
pip install gps-mouse
# With REST API + dashboard
pip install "gps-mouse[api]"
# With MQTT support
pip install "gps-mouse[mqtt]"
# With YAML config support
pip install "gps-mouse[yaml]"
# Everything
pip install "gps-mouse[all]"
System permission (Linux)
sudo usermod -aG dialout $USER
newgrp dialout
Quick Start
CLI
# Read and print GPS data
gps-read
# Start server with ZMQ + live map
gps-server --api
# Log to CSV + GPX
gps-log --csv track.csv --gpx track.gpx
# REST API + dashboard only
gps-api
Python — read data
import time
from gps_mouse import GPSReader
def on_data(data):
if data.has_fix:
print(f"lat={data.latitude:.6f} lon={data.longitude:.6f} alt={data.altitude}m")
with GPSReader() as reader:
reader.add_callback(on_data)
time.sleep(60)
Python — ZMQ broadcast + subscribe
# Server (reads GPS, broadcasts)
from gps_mouse import GPSReader, GPSPublisher
reader = GPSReader()
pub = GPSPublisher()
pub.attach(reader)
reader.start()
# Client (any other project)
from gps_mouse import GPSSubscriber
for data in GPSSubscriber().iter_fixes():
print(data.latitude, data.longitude)
Python — REST API + live map
from gps_mouse import GPSReader
from gps_mouse.api import GPSApi
reader = GPSReader()
reader.start()
GPSApi(reader, port=8080).serve()
# Open http://localhost:8080 in browser
Python — MQTT
from gps_mouse import GPSReader
from gps_mouse.mqtt import GPSMQTTPublisher
reader = GPSReader()
mqtt = GPSMQTTPublisher(broker="localhost", topic="gps/data")
mqtt.attach(reader)
reader.start()
Python — CSV + GPX logging
import time
from gps_mouse import GPSReader
from gps_mouse.logger import GPSLogger
with GPSLogger(csv_path="track.csv", gpx_path="track.gpx") as log:
with GPSReader() as reader:
reader.add_callback(log.record)
time.sleep(3600)
Config file
cp config.example.yml config.yml
# Edit config.yml
gps-server --config config.yml
Docker
# Start with docker-compose
docker compose up -d
# Open dashboard
open http://localhost:8080
systemd Service
sudo cp systemd/gps-mouse.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now gps-mouse
sudo journalctl -u gps-mouse -f
Architecture
GPS Device (/dev/ttyACM0 or gpsd)
│
GPSReader ─────────────────────────────────────────
│
├──► GPSPublisher (ZMQ PUB :5557)
│ └─► Project A, B, C (GPSSubscriber)
│
├──► GPSMQTTPublisher → MQTT Broker
│ └─► Home Assistant, Node-RED, …
│
├──► GPSApi (FastAPI :8080)
│ ├─► GET /gps (latest fix JSON)
│ ├─► GET /gps/stream (SSE stream)
│ ├─► WS /gps/ws (WebSocket)
│ └─► GET / (live map)
│
└──► GPSLogger → CSV / GPX files
GPSData Fields
| Field | Type | Description |
|---|---|---|
latitude |
float | None |
Decimal degrees (negative = South) |
longitude |
float | None |
Decimal degrees (negative = West) |
altitude |
float | None |
Metres above mean sea level |
speed |
float | None |
Speed in m/s |
speed_kmh |
float | None |
Speed in km/h (property) |
heading |
float | None |
True North heading in degrees |
fix_quality |
FixQuality |
GPS fix type (NO_FIX, GPS, DGPS, RTK…) |
num_satellites |
int |
Number of satellites in use |
hdop |
float | None |
Horizontal dilution of precision |
timestamp |
datetime |
UTC timestamp from device |
has_fix |
bool |
True if a valid position fix exists |
Examples
| File | Description |
|---|---|
examples/01_basic_read.py |
Print GPS values to terminal |
examples/02_zmq_server.py |
Read GPS and broadcast over ZMQ |
examples/03_zmq_client.py |
Subscribe from another project |
examples/04_async_stream.py |
Async producer/consumer |
examples/05_wait_for_fix.py |
Block until first fix |
Requirements
- Python 3.10+
- pyserial, pynmea2, pyzmq (core)
- fastapi, uvicorn (optional —
[api]) - paho-mqtt (optional —
[mqtt]) - pyyaml (optional —
[yaml])
Contributing
See CONTRIBUTING.md.
Changelog
See CHANGELOG.md.
License
MIT © 2026 erelbi
Metadata
Release files for gps-mouse 0.1.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| gps_mouse-0.1.3.tar.gz | 25.9 kB | Without provenance | Details for gps_mouse-0.1.3.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| gps_mouse-0.1.3-py3-none-any.whl | Python 3 | none | any | Details for gps_mouse-0.1.3-py3-none-any.whl |
Total release size: 50.4 kB
Release files / gps_mouse-0.1.3.tar.gz
| Download URL | gps_mouse-0.1.3.tar.gz |
|---|---|
| Size | 25.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a108adce11c09a6343e8aac8e205ee23942deee04d3663eacf698ad579314c91
|
|
BLAKE2b-256 checksum How to use checksums |
51e5875b9a574aa7868bb8f4a6e9af305fa6acc5452a669c38328800fa99c232
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Release files / gps_mouse-0.1.3-py3-none-any.whl
| Download URL | gps_mouse-0.1.3-py3-none-any.whl |
|---|---|
| Size | 24.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2c808f65a85942196b0a7eda22910896fcc26f768ac8e0e8aa935542f1877c29
|
|
BLAKE2b-256 checksum How to use checksums |
73172b643a6008dc9e7977d6b02c191cb230343df60145133ee7afccb820be8b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Security for gps-mouse 0.1.3
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.