Homeassistant Tracking Waste Collection Dates

I want to have the next waste disposal dates in Homeassistant. There is an all-solved-solution (hacs_waste_collection_schedule) that also supports the city I live in. But this is a lot of code to copy around when not using Home Assistant Community Store, which I try to not use. The following solution has a lot less code and when it breaks it is easy for me to fix.

In February I wrote a bit of code to parse the ical for waste collection dates from the city of Stuttgart and documented it in a blog post. Let us modify this script to generate the json we need for a template webhook upload in homeassistant.

But first the homeassistant configuration that is needed:

  - trigger:
      - platform: webhook
        webhook_id: !secret waste-disposal
          - POST
        local_only: true
    unique_id: "waste"
      - name: "waste: residual"
        state: "{{ trigger.json.waste_residual }}"
        device_class: date
        unique_id: "waste_residual"
      - name: "waste: paper"
        state: "{{ trigger.json.waste_paper }}"
        device_class: date
        unique_id: "waste_paper"
      - name: "waste: yellow bag"
        state: "{{ trigger.json.waste_yellow_bag }}"
        device_class: date
        unique_id: "waste_yellow_bag"

The script to upload will run on the same host as my homeassistant instance, so local_only can be true.

Now the script that downloads the calendar and uploads to home assistant:

import datetime
import json
import sys
from pathlib import Path
import requests

def parse(stream):
    ds = {}
    for line in stream.split("\n"):
        if line.strip() == "BEGIN:VEVENT" and ds:
            yield ds
            ds = {}
        if line.startswith("DTSTART"):
            ds["date"] = str(
                    line.split(":")[-1].split("T")[0], "%Y%m%d"
        if line.startswith("SUMMARY"):
            ds["summary"] = line.split(":")[-1].strip()

if __name__ == "__main__":
    # copy webhook secret into file .secret
    secret = (Path(__file__).parent / ".secret").open().read().strip()

    # url is set in the first commandline argument
    r = requests.get(url=sys.argv[1])
    key_map = {
        "Restmüll 02-wöchentl.": "waste_residual",
        "Altpapier 03-wöchentl.": "waste_paper",
        "Gelber Sack 03-wöchentl.": "waste_yellow_bag",
    dataset = {}
    for item in parse(r.text):
        _k = item.get("summary")
        if _k in key_map:
            dataset[key_map[_k]] = item.get("date")
            del key_map[_k]

    r = requests.post(f"http://localhost:8123/api/webhook/{secret}", json=dataset)
    assert r.status_code == 200

The parsing part is exactly the same as in the old blog post. The modifications to the February version are:

  • using requests -- because it is already installed

  • the addition of a key_map to rename the keys to the ones expected by the sensor template

  • code to push to homeassistant

The result in homeassistant looks like this:

screenshot of waste collection dates in homeassistant dashboard

I use a cron that runs every day at 4am to push the current collection dates to homeassistant.