MQTT alert daemon with pluggable notification backends
Project description
mqtt-alerts
mqtt-alerts is a small daemon-style CLI that subscribes to MQTT topics, evaluates alert rules, and sends notifications through pluggable backends.
It exists separately from mtr2mqtt on purpose:
mtr2mqttpublishes measurement data to MQTT.mqtt-alertsconsumes MQTT data and turns sustained threshold violations into notifications.
That separation keeps the data publishing path simple while allowing alerting and notification behavior to evolve independently.
What It Does
- subscribes to configured MQTT topics
- parses JSON payloads and extracts a configured value field
- evaluates multiple independent rules per sensor
- tracks alert timing per rule with a hold duration such as
15m - persists minimal per-rule state in SQLite so restart recovery is correct
- sends notifications through pluggable backends
- sends automatic recovery notifications when triggered rules return to normal
What It Does Not Do
This MVP intentionally does not include:
- arbitrary expressions or a custom rule language
- multiple payload extraction syntaxes
- dashboards or a web UI
- acknowledgements, silencing windows, or schedules
- repeated reminders or escalation chains
- non-
ntfynotification backends yet
The architecture is prepared for more backends later, but only ntfy is implemented in the first release.
Installation
Using pip
pip install mqtt-alerts
Using uv for development
uv sync --group dev
Basic Usage
Create a config file and run:
mqtt-alerts --config sample_config.yml
CLI flags:
--config,-c: path to the YAML configuration file--debug,-d: enable debug logging--quiet,-q: only log warnings and errors--version,-v: print the installed version
Environment variables:
MQTT_ALERTS_CONFIG_FILEMQTT_ALERTS_DEBUGMQTT_ALERTS_QUIET
Configuration
The configuration is YAML and keeps MQTT input, persisted state, sensors and rules, and notification backends separate.
mqtt:
host: localhost
port: 1883
topic_prefix: measurements
state:
database: ./mqtt-alerts.sqlite3
notifications:
backends:
- id: main_ntfy
type: ntfy
server: https://ntfy.sh
topic: some-secret-topic
sensors:
- id: freezer_1
name: Freezer 1
topic: receiver1/freezer1
value_field: temperature
rules:
- id: high_warn
direction: above
threshold: 5.0
hysteresis: 0.5
for: 15m
severity: low
backend: main_ntfy
enabled: true
title: Freezer 1 warning
message: Temperature is above limit
recovery_enabled: true
recovery_title: Freezer 1 recovered
recovery_message: Temperature is back within range
- id: high_critical
direction: above
threshold: 8.0
for: 10m
severity: critical
backend: main_ntfy
enabled: true
Notes:
mqtt.topic_prefixis optional. If set, sensor topics are resolved under that prefix unless already fully prefixed.- each sensor can have many rules
- each rule has its own severity, backend, timing, and enabled flag
- each rule can define
hysteresisto avoid alert/recovery flapping near the threshold - each rule can customize automatic recovery messages (
recovery_enabled,recovery_title,recovery_message) - state is tracked per
(sensor_id, rule_id)pair
Notification Backends
The core evaluator emits a generic notification object. Delivery is handled by a backend abstraction so new backends can be added later without redesigning rule evaluation or persistence.
The MVP ships with one backend:
ntfy
The ntfy backend supports:
- server URL
- topic
- title
- message body
- severity mapping to
ntfypriority and tags
How It Fits With mtr2mqtt
A typical setup looks like this:
mtr2mqttreads measurements from physical sensors and publishes JSON to MQTT topics.mqtt-alertssubscribes to selected measurement topics.mqtt-alertsextracts the configured value field and evaluates one or more rules per sensor.- When a condition stays active for long enough,
mqtt-alertssends a notification through a configured backend.
Architecture
The code is intentionally split into small modules:
mqtt_alerts.config: YAML loading and validationmqtt_alerts.engine: per-rule threshold and duration evaluationmqtt_alerts.persistence: SQLite state storagemqtt_alerts.notifications: backend abstraction andntfydeliverymqtt_alerts.runtime: MQTT subscription loop and application wiringmqtt_alerts.cli: CLI entrypoint
The persisted state stores only the minimum required fields for restart recovery:
- latest value
- latest timestamp
- whether the condition is active
- when the condition became active
- whether the alert has already triggered
- when the alert triggered
- last notification timestamp
Docker
Pull the latest image:
docker pull tvallas/mqtt-alerts:latest
Run it with a mounted config:
docker run --rm \
-v "$(pwd)/sample_config.yml:/config/config.yml:ro" \
-v "$(pwd)/state:/state" \
tvallas/mqtt-alerts:latest \
--config /config/config.yml
There is also a sibling docker-compose.yml example in the repository.
Development
Common commands:
make install
make lint
make test
make build
Release Flow
The repository mirrors the current mtr2mqtt approach:
- pull request CI for lint, tests, and package build
- Docker build smoke test for pull requests
- semantic-release driven GitHub and PyPI release flow
- Docker publish after a successful tagged release
- Dependabot for Python, Docker, and GitHub Actions updates
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mqtt_alerts-0.1.0.tar.gz.
File metadata
- Download URL: mqtt_alerts-0.1.0.tar.gz
- Upload date:
- Size: 20.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7f25376929d7adaf945c78e07bcbfa2980e895e570fa3d3171fb6b29ae4e163e
|
|
| MD5 |
ee978da4e99589779a24ee07559a2580
|
|
| BLAKE2b-256 |
f7ef24301d1ec1efc5c55812763456d44c34b4348f7a5c89c83468bd19104afb
|
Provenance
The following attestation bundles were made for mqtt_alerts-0.1.0.tar.gz:
Publisher:
semantic_release.yml on tvallas/mqtt-alerts
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mqtt_alerts-0.1.0.tar.gz -
Subject digest:
7f25376929d7adaf945c78e07bcbfa2980e895e570fa3d3171fb6b29ae4e163e - Sigstore transparency entry: 1342567469
- Sigstore integration time:
-
Permalink:
tvallas/mqtt-alerts@1f45b9299cdf841ffa63839344194bb8904c01a6 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/tvallas
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
semantic_release.yml@1f45b9299cdf841ffa63839344194bb8904c01a6 -
Trigger Event:
push
-
Statement type:
File details
Details for the file mqtt_alerts-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mqtt_alerts-0.1.0-py3-none-any.whl
- Upload date:
- Size: 16.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7596c9a16cf93af19b44030395d90551935dd881ca6e90903472cacb0093c6c0
|
|
| MD5 |
cb85774df0a6d7c0cc1d15f6082387b8
|
|
| BLAKE2b-256 |
25ee0e62d3a83d660d3d9dc06f82d0eb1a7032f4a2737fc3a50ab4f2657fed93
|
Provenance
The following attestation bundles were made for mqtt_alerts-0.1.0-py3-none-any.whl:
Publisher:
semantic_release.yml on tvallas/mqtt-alerts
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mqtt_alerts-0.1.0-py3-none-any.whl -
Subject digest:
7596c9a16cf93af19b44030395d90551935dd881ca6e90903472cacb0093c6c0 - Sigstore transparency entry: 1342567482
- Sigstore integration time:
-
Permalink:
tvallas/mqtt-alerts@1f45b9299cdf841ffa63839344194bb8904c01a6 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/tvallas
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
semantic_release.yml@1f45b9299cdf841ffa63839344194bb8904c01a6 -
Trigger Event:
push
-
Statement type: