Watchue

active · since 2026

A self-hosted watcher for Philips Hue. It records every light that goes on or off and pings you on Telegram or Discord.

stack
  • ▸Go 1.27, Echo v5
  • ▸Vue 3, TypeScript
  • ▸SQLite (pure Go, no cgo), sqlc, goose
  • ▸Hue CLIP v2 event stream
  • ▸Docker (single binary image)
links
Watchue, dashboard in dark theme
Watched resources and their history, updating live.
Watchue, dashboard in light theme
Watched resources and their history, updating live.

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.

← back to projects