Updated Weather monitor
A while back I built myself a simple weather alert. It worked quite well for a while, but then I turned it off for some reason. I don't remember why.
Yesterday I learnt about Gotify, which is a self-hosted message server. So, all the ease of telegram message sending, none of the administrative hassle. I had to try it out.
Also, I had found a new weather API, open-meteo.com, which uses synthesized data from a handful of sources, and I'd wanted to give that one a spin for some time, too.
So, the perfect time to do something about it. I sat down yesterday evening and in an hour had all I needed. Sure, it's completely kludged together, does have 0% test coverage and will probably break in a few weeks, but until then, I'll get the daily weather message and rain alerts to my cell.
While implementing the script, I found the nice little python module sched
in the standard library. This is an event scheduler, where I can add functions to be called at specific times. Since I want the watcher to run at all times, I schedule a new task every time one task finishes. That, too, is a bit kludged, but that, too, works.
Calling OpenMeteo is very simple. You just go to their site, plop in your locations and the fields you need and off you go. No API keys, no signup, no nothing: one requests
call later and there is your data. Now to disassemble it: I parse forecast timestamps into datetimes for easier handling first, then do my searching around those timestamps. It's not super-clean, but it works. And then I just format the stuff around and send a notification to the gotify backend.
I have two tasks: one looks at the weather data for the next hour, on the hour, and sends a message when there is rain in the forecast.
The other samples temperature and precipitation over the day and gives me a summary. This one runs every morning, so I get a very small weather report each morning.
All in all, a very simple little tool that will now tell me the about the weather when I need to.
Here's the code, in case you need it:
import sched
import time
from datetime import datetime
import requests
import config
from messages import send
s = sched.scheduler(time.time, time.sleep)
weather_info = {}
fmt = '%Y-%m-%dT%H:%M'
def get_new_weather():
"""Get new weather information."""
global weather_info
last_get = weather_info.get('timestamp', 0)
if time.time() - last_get > 3 * 3600:
info = requests.get(config.url)
weather_info = info.json()
weather_info["timestamp"] = time.time()
weather_info["hourly"]["time"] = [
datetime.strptime(t, fmt)
for t in weather_info["hourly"]["time"]
]
return
def check_weather():
"""Check whether it will rain in the next hour, send message if appropriate."""
get_new_weather()
# find precipitation
now = datetime.now()
for index, t in enumerate(weather_info["hourly"]["time"]):
if t > now:
precip = weather_info["hourly"]["precipitation"][index]
if precip > 0.1:
send(f"rain: {precip}")
break
s.enter(3600 - time.time() % 3600, 2, check_weather)
def send_report():
"""Send the daily wake-up report."""
try:
# find the 7-o-clock index
start_time = datetime.now().replace(hour=7, minute=0, second=0, microsecond=0)
index = weather_info["hourly"]["time"].index(start_time)
# measure the next 12h
temps = weather_info["hourly"]["temperature_2m"][index:index+12]
temp_min, temp_max = min(temps), max(temps)
precip_total = sum(weather_info["hourly"]["precipitation"][index:index+12])
# send report
send(f"{temp_min} °C -- {temp_max} °C, {precip_total} mm")
except ValueError:
pass
s.enterabs(get_next_abs(), 2, send_report)
def get_next_abs():
next_abs = int(datetime.now().replace(hour=6, minute=30, second=0).timestamp())
if next_abs < time.time():
next_abs += 86400
return next_abs
def run():
get_new_weather()
send_report()
s.enter(1, 1, check_weather)
s.enterabs(get_next_abs(), 2, send_report)
s.run()
if __name__ == '__main__':
try:
send("starte Wetter-Service")
run()
finally:
send("beende Wetter-Service")
The code is also available on my utilities repository.
Now, as I hyped myself up last time, what other events could I watch and notify myself about?