I got tired of missing recordings, so I built channels2mqtt
I run Channels DVR and Home Assistant. For a long time, they had nothing to say to each other. Recordings would pile up and my phone stayed silent. My dashboard knew nothing about what was sitting unwatched on my DVR.
So I built channels2mqtt.
What it does
channels2mqtt is a Python service that polls your Channels DVR server on a configurable interval and publishes recording data to an MQTT broker. Home Assistant picks up those messages via MQTT Discovery and surfaces them as native sensors.
On startup, it publishes discovery config payloads so Home Assistant automatically creates three sensors — no yaml editing required:
- Latest Recording — fires when a new recording completes
- All Recordings — live count and full library payload
- Upcoming Recordings — scheduled recordings with program details, auto-expired when their start time passes
From there it enters a poll loop, fetching fresh data from the Channels DVR API and publishing any changes.
How I use it
The main one is push notifications. The moment a new recording lands, my phone knows about it.
I also have a Lovelace popup that shows my current recordings — title, episode, artwork. But once data is in Home Assistant, you can do whatever you want with it. Automations, dashboards, notification routing based on who in the house would care about a particular show.
A bug worth explaining
Early versions tracked the latest recording by position — whatever was at the top of the list. The problem: watch a recording, it gets removed, the next one slides up, and you'd get a notification for a show that's been in your library for a week.
The fix was to stop tracking position and start tracking identity. channels2mqtt now maintains a set of every recording ID it has ever seen. A notification only fires when an ID appears that wasn't there before. On startup, all existing recordings are seeded into that set so a restart doesn't flood you with stale notifications.
# Before
last_recording_id = None
# After
seen_recording_ids = set()
for r in get_all_recordings():
seen_recording_ids.add(r.get("id"))
Small change. Makes it feel right instead of just functional.
Getting started
services:
channels2mqtt:
image: zackwag/channels2mqtt:latest
container_name: channels2mqtt
restart: unless-stopped
environment:
- CHANNELS_HOST=192.168.x.x
- MQTT_HOST=192.168.x.x
- MQTT_USER=your_mqtt_username
- MQTT_PASS=your_mqtt_password
Within one poll cycle, the sensors appear in Home Assistant.
Notable optional variables: POLL_INTERVAL (default: 60 seconds), LATEST_INCLUDE_WATCHED, ALL_INCLUDE_WATCHED, and LATEST_INCLUDE_IN_PROGRESS. Full details on Docker Hub and GitHub.