- Python 100%
| .gitignore | ||
| LICENSE | ||
| README.md | ||
| sota-trip-planner-detail.png | ||
| sota-trip-planner-overview.png | ||
| sota-trip-planner-terminal.png | ||
| sota_trip_planner.py | ||
SOTA Trip Planner
Finds the best SOTA areas reachable from a configurable home location within a given drive time window. Ranks clusters by total points or number of activatable summits, filters out already-activated summits, and optionally generates a self-contained HTML report with trail data.
Written with help from Claude (Anthropic).
How It Works
1. Load and filter the summit database. The SOTA summit list CSV is downloaded automatically from sotadata.org.uk on first run and kept up to date via conditional HTTP requests (ETag/If-Modified-Since). Around 170,000 entries are filtered down to active summits within a straight-line pre-filter distance.
2. Fetch real driving times via OSRM. The script queries the OSRM public routing server using the Table API (one-to-many, batches of 100). Results are cached locally — re-running with different parameters costs nothing.
3. Cluster summits into areas. Summits within 40 km of each other are grouped into a cluster and scored by total points or summit count. The top clusters are ranked in a table with a detail view per area.
4. Exclude already-activated summits. With --callsign, the script fetches your activation history for the current year from the official SOTA API (api-db2.sota.org.uk) and removes those summits before clustering. A locally downloaded log CSV works as a fallback. Thanks to Manuel (HB9DQM) for the pointers on the API.
5. Fetch trail data. When generating an HTML report, the script queries the SOTA SMP API (api-db.sota.org.uk/smp/gpx/summit) for route data and adds path length, ascent, and descent to the detail view where available. The same API is used by sotl.as to display routes. Track data is uploaded by users to sotamaps.org.
Requirements
Python 3.8+, no external libraries needed.
Usage
# From Duisburg, 4h window, sort by points
python3 sota_trip_planner.py
# Sort by number of activations instead
python3 sota_trip_planner.py --mode summits
# Different QTH, wider window
python3 sota_trip_planner.py --home "Munich, Germany" --hours 5
# Exclude summits already activated this year
python3 sota_trip_planner.py --callsign DA2PK --hours 4
# Generate an HTML report
python3 sota_trip_planner.py --callsign DA2PK --hours 4 --html report.html
# Use a local log file instead of the API
python3 sota_trip_planner.py --callsign DA2PK --log DA2PK_activator.csv --hours 4
# Re-analyse cached data without any network requests
python3 sota_trip_planner.py --analyse-only
All options:
--home Home location as place name (default: Duisburg, Germany)
--lat/--lon Manual coordinates (override --home)
--hours Maximum drive time in hours (default: 4.0)
--mode points or summits (default: points)
--top Number of areas in the overview table (default: 20)
--radius Cluster radius in km (default: 40)
--callsign Exclude summits already activated this year
--all-time Excludes summits already activated
--log Local activator log CSV instead of API
--html Write a self-contained HTML report to this path
--no-cache Ignore cached drive times and re-query OSRM
--analyse-only Skip OSRM, use cached data only
Terminal Output
The script prints a ranked overview table followed by a detail section for the top three clusters.
HTML Report
--html generates a self-contained HTML file with a light/dark mode toggle. It includes an overview table of the top 20 areas with colour-coded drive times.
The detail section lists every summit in each cluster with altitude, points, drive time, and, where available, path length and elevation data from the SMP API.
Notes
The OSRM public server is a shared resource. The script sleeps 500ms between batches. Re-running with --analyse-only makes no OSRM requests at all.
Drive time results are cached in sota_drivetime_cache_<lat>_<lon>.json. Trail data is cached in sota_trail_cache.json. Both files are location- and run-specific and are not included in the repository.
License
GPL


