Some idiot set himself a challenge in 2026 to activate every POTA park within 20 miles of home. That’s great, except that when January 1st rolled around I had 14 left to do—and now, a month and four activations later, I have… 23 left. Unlike SOTA, with its relatively constant list of peaks and monthly update schedule for those where data is incomplete, or WWBOTA, with its quarterly updates debated on the group, POTA parks can be requested and added to the system at any time, and it seems that our other local activators have plenty of enthusiasm for pastures new.
My New Park Finder is great for finding out where these new parks have cropped up, but I have caught myself quite obsessively reloading it every day to see if anything has changed. This is a waste of my frayed attention span and POTA’s web server resources, so to replace that daily check, I have written a Python script.
It’s designed to run as a daily cron job (e.g. 0 0 * * * python3 newparksalert.py), and queries the POTA servers for a current list of parks nearby. It uses a temp file to track the highest-numbered park it has so far told me about, and if any parks with higher numbers appear within range, it prints the details to stdout. If no new parks are found, it returns silently. On my system this means that it sends me an email when new parks are found, and keeps quiet if there aren’t any.
In the vanishingly unlikely chance that this is useful for you, here’s the code:
import json
import urllib.request
import math
YOUR_LAT = 50
YOUR_LON = -1
DISTANCE_KM = 32.2
COUNTRY = "GB"
TEMP_FILE = "/tmp/last-park-number.txt"
# Quick and dirty Haversine distance function to avoid this script needing external dependencies. Degrees in, km out
def haversine(lat1, lon1, lat2, lon2):
lat1, lon1, lat2, lon2 = map(math.radians, [lat1, lon1, lat2, lon2])
dlat = lat2 - lat1
dlon = lon2 - lon1
a = math.sin(dlat / 2) ** 2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2
c = 2 * math.asin(math.sqrt(a))
r = 6371
return c * r
# Figure out the highest number of park that we last alerted you to
last_max_park_number = 0
try:
file = open(TEMP_FILE, "r")
last_max_park_number = int(file.read())
file.close()
except:
pass
# Fetch list of parks within +-0.5 degree lat/lon of your location. Should be enough for ~30km circle if your home
# location is anywhere under ~60 degrees latitude
parks = json.loads(urllib.request.urlopen(
"https://api.pota.app/park/grids/" + str(YOUR_LAT - 0.5) + "/" + str(YOUR_LON - 0.5) + "/" + str(
YOUR_LAT + 0.5) + "/" + str(YOUR_LON + 0.5) + "/0").read())["features"]
# For each park, calculate its distance and store it with the rest of the data
for park in parks:
park["properties"]["distance_from_home_km"] = haversine(YOUR_LAT, YOUR_LON, park["geometry"]["coordinates"][1],
park["geometry"]["coordinates"][0])
# Limit to the distance we are interested in
parks = [p for p in parks if p["properties"]["distance_from_home_km"] <= DISTANCE_KM]
# Limit to the right country
parks = [p for p in parks if p["properties"]["reference"].split("-")[0] == COUNTRY]
# Limit to park numbers higher than the newest one we found last time
parks = [p for p in parks if int(p["properties"]["reference"].split("-")[1]) > last_max_park_number]
# Print a list of any new parks
if parks:
print("New parks found:")
for p in parks:
print(p["properties"]["reference"] + " " + p["properties"]["name"] + " (" + str(
round(p["properties"]["distance_from_home_km"])) + "km away)")
# If we have seen any newer parks, store the highest number reference
if parks:
try:
file = open(TEMP_FILE, 'w+')
file.write(str(max([int(p["properties"]["reference"].split("-")[1]) for p in parks])))
file.close()
except:
print("Error writing to file")
Comments