Logging Network Latency and Correlating It with the Weather
My ISP has a habit of getting worse during bad weather. Or at least, I thought it did. The problem with suspicions like that is they're hard to confirm — you're only ever noticing bad latency in the moment, not tracking it systematically over weeks.
Ping Logger and Grapher started as a simple latency monitor and evolved into something that overlays weather conditions on top of the data, so you can actually see whether the correlation is real or just confirmation bias. (It's real, at least for me.)
Architecture: why multiple scripts?
The project uses separate scripts rather than one monolithic tool, which makes it easier to run each piece on a schedule independently:
- ping.py — runs on a cron every 5 minutes, pings a target host, appends a timestamp and result to a CSV log
- currentplot.py — generates a graph of today's data on demand, good for a quick "how's my connection right now" view
- plot.py — compiles historical data across multiple archived log files into a longer-term graph
- rename.py — handles daily log rotation, archiving the previous day's file before ping.py starts writing a new one
# ping.py — simplified core loop
result = subprocess.run(["ping", "-n", "1", TARGET], capture_output=True, text=True)
latency = parse_latency(result.stdout)
weather = get_weather(OWM_API_KEY, CITY)
with open(LOG_FILE, "a") as f:
f.write(f"{datetime.now()},{latency},{weather['description']},{weather['temp']}\n")
OpenWeatherMap integration
Each ping log entry includes a weather snapshot — conditions (clear, rain, overcast, etc.) and temperature. The OpenWeatherMap free tier is more than sufficient for this: one API call per ping interval is nowhere near the rate limits.
When you generate a graph, the weather conditions are rendered as a shaded background layer. Rain periods show as light blue shading, storms as darker blue. It makes the correlation between bad weather and elevated latency visually obvious — or proves it's not there.
Path resolution
Earlier versions required you to manually set file paths in each script — a pain when running from cron where the working directory is unpredictable. The current version uses __file__-relative paths throughout, so scripts always find their data files regardless of where they're invoked from.
BASE_DIR = Path(__file__).parent
LOG_DIR = BASE_DIR / "logs"
ARCH_DIR = BASE_DIR / "archive"
The answer to "is my internet slow because of the weather?" turned out to be yes — specifically during heavy rain, average latency to my target host goes from ~12ms to ~35ms. Not crippling, but measurable and consistent.