Watchue
active · since 2026A self-hosted watcher for Philips Hue. It records every light that goes on or off and pings you on Telegram or Discord.
- ▸Go 1.27, Echo v5
- ▸Vue 3, TypeScript
- ▸SQLite (pure Go, no cgo), sqlc, goose
- ▸Hue CLIP v2 event stream
- ▸Docker (single binary image)
- ▸source ↗
- ▸license: MIT


What it does
Pick the zones, rooms or lights you care about from your Hue bridge, and Watchue records every on/off, then notifies you on Telegram or Discord, whichever one you configured. A resource can be muted: its history keeps filling up, it just stops pinging you. One global switch turns the whole channel off without losing anything.
The detection doesn't care where the change came from. The official Hue app, a physical switch on the wall, another automation: it all shows up, because Watchue listens to the bridge itself rather than polling its own API.
Pairing is the awkward part of anything Hue: the bridge only hands out an app
key after someone presses the physical button on it. Rather than documenting a
curl command, Watchue ships a /setup wizard: start it with no key, it detects
the button press by itself, stores the key and restarts. The notification
provider gets the same treatment, with a test message before you save.
How it's built
Go for the backend, Vue 3 for the web app, both shipped as one binary with the
frontend embedded (go:embed), on top of a single SQLite file. Same skeleton as
Postr
: Echo v5, sqlc for the queries, goose for the
migrations, a pure-Go SQLite driver so the image stays small.
The interesting bit is the plumbing between two event streams. The bridge exposes its own CLIP v2 event stream (SSE) that Watchue holds open, with retries, and that's what makes a switch flipped by hand show up here. Each event is recorded, matched against the watch list, and pushed to the browser over a second SSE stream, so the dashboard follows the house in real time without a single page refresh. Notification providers sit behind one interface; Telegram and Discord are just two implementations of it, and exactly one can be active at a time: configure both and the app refuses to start rather than quietly picking one.
Why
A small, genuinely useful question: did someone leave the garage light on? What made it worth building is that it's a tidy little event-driven system: one upstream stream in, storage, fan-out, one downstream stream to the browser, small enough to keep in your head and finish.