The Things Stack Community Edition doesn’t alert you when a device goes quiet, and I don’t think it should — it’s a network server, not a monitoring stack. But it leaves a gap that catches most of us eventually: a sensor stops sending uplinks and nothing anywhere says so. For a long time my first notification was a customer asking why a graph had been flat for a fortnight. ChirpStack has the same gap, for the same good reason.
The usual answers didn’t fit. Prometheus and Grafana work, but that’s a lot of moving parts to answer “tell me when a sensor goes quiet”. Subscribing to MQTT and writing something yourself is closer — but then you’re writing it yourself, and everyone writes it again.
So here’s my method: GitHub - geosensor-tech/uplink-watchdog: Tell me when a LoRaWAN device stops sending. One Python file, no dependencies, works with ChirpStack and The Things Stack. · GitHub
One Python file, standard library only, Python 3.8+. No install, no database, no container.
curl -O https://raw.githubusercontent.com/geosensor-tech/uplink-watchdog/main/uplink_watchdog.py
python3 uplink_watchdog.py --selftest # proves the detection logic offline
python3 uplink_watchdog.py --ntfy my-secret-topic-name
Then point a webhook at it — Integrations ▸ Webhooks ▸ Add webhook ▸ Custom webhook, with the base URL http://your-host:8000 and the uplink message path /uplink. It also takes ChirpStack’s HTTP integration and, honestly, any JSON POST carrying a device EUI or id.
The part I think is worth stealing even if you never run the script: it doesn’t use a fixed timeout. A flat “alert if nothing for 60 minutes” is wrong for almost every fleet, because a device reporting every 15 minutes and one reporting twice a day need completely different thresholds, and nobody wants to configure that per device. So it learns each device’s own interval as a moving average and derives the silence threshold from that. Devices appear the first time they send something; there is nothing to register.
Alerts go to ntfy for phone push, a webhook for Slack/Teams/your own endpoint, or email. State is a JSON file, so restarting it doesn’t re-alert on everything.
Full disclosure: I run an IoT company, and I also built a hosted version at watch.geosensor.tech, because some of my clients didn’t want another thing to self-host. The script above is the whole detection logic, not a crippled demo — it never phones home, and if self-hosting suits you then self-host it. I’d rather the gap got filled either way.
I’ve only run it against The Things Stack v3 and ChirpStack v4. If it mishandles your payload shape I’d like to know — that’s the kind of thing I can’t find on my own fleet.