A daily morning summary in Matrix
The Raspberry Pi I set up in Packer, Ansible and DietPi for my Raspberry PIs runs the Hermes agent and is already connected to Homeassistant and Matrix. So it is the best place for a small summary every morning at 7:00.
What I want to know in the morning:
Which waste is collected today and tomorrow.
The temperature range for today and when it rains.
The battery level of my car.
When my local library is open today.
Is there a VfB home game in Stuttgart today -- then I avoid public transport.
Are there unexpected issues with the S-Bahn or SSB, not the planned roadworks.
There is no section about my appointments or plans for the day. Hermes has no access to my calendar or my todo lists, so it cannot write about them.
This is a single Python script started by cron on the Pi. No LLM is involved, the agent is only used for sending the message.

The message goes to the Matrix room I mainly use for chatting with Hermes, so I can ask follow-up questions right there. For example the summary listed detours because of a demonstration, so I asked which demonstration it was. Hermes searched the web and answered with links to the Stuttgarter Nachrichten and the SSB:

Homeassistant
The Hermes agent already has a Homeassistant token in its .env, so the script reads HASS_URL and HASS_TOKEN from there.
Two REST API calls are enough:
class HomeAssistant: def __init__(self, url, token): self.url = url.rstrip("/") self.headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"} def state(self, entity_id): return fetch_json(f"{self.url}/api/states/{entity_id}", headers=self.headers) def forecast(self, kind): resp = fetch_json( f"{self.url}/api/services/weather/get_forecasts?return_response", data={"entity_id": WEATHER_ENTITY, "type": kind}, headers=self.headers, ) return resp["service_response"][WEATHER_ENTITY]["forecast"]
The waste sensors are the ones from Homeassistant Tracking Waste Collection Dates.
Their state is a date, so the script only compares it with today and tomorrow.
The car battery is a plain state too (sensor.r5_battery and sensor.r5_battery_autonomy for the range).
The weather forecast comes from the weather.get_forecasts service.
The script calls it twice: daily for the min/max temperature and hourly for the rain.
Consecutive hours with rain are grouped, so the message shows 22-24 Uhr 0.6 mm instead of a list of single hours.
Library opening hours
The opening hours of my local library branch are on its page on the Stadtbibliothek website. The hours are plain HTML:
<h2>Öffnungszeiten</h2><strong>Dienstag</strong> 14:00 - 19:00 Uhr <br><strong>Mittwoch</strong> 10:00 - 15:00 Uhr
A regular expression on the block after the heading returns a dict of weekday and hours. The hours rarely change, so fetching them every morning is a bit much and I may cache them later.
VfB home games
OpenLigaDB has an endpoint that returns the matches of a team for a number of weeks in the past and the future.
VfB Stuttgart has the team id 16 and the result contains Bundesliga, DFB-Pokal and Champions League matches.
A home game is a match where VfB is team1:
S-Bahn and SSB
The VVS has an EFA endpoint (XML_ADDINFO_REQUEST) that returns all current info messages as JSON.
On the day I tried it there were 414 messages, most of them with AlertCause: roadworks.
After removing roadworks and broken elevators, the script keeps only messages for S-Bahn, U-Bahn and SSB lines that are active today.
To filter out long planned changes, a message has to be published at most one day before it starts.
This is a heuristic and I will see if it is too noisy over the next weeks.
Sending the message
Hermes already has a CLI command for this, hermes send, which reuses the credentials of the agent: