Dieses Projekt verbindet DiVeRa 24/7 mit ntfy:
- Das Gateway pollt Alarme aus DiVeRa.
- Neue Alarme werden als Push an ein ntfy-Topic gesendet.
- Optional kannst du Alarme zusätzlich per Webhook auslösen.
Die README ist so aufgebaut, dass du das Projekt auch ohne Vorwissen schnell betreiben kannst.
Für alle, die ohne Google-Dienste arbeiten möchten:
- Die DiVeRa-App nutzt für ihre Push-Alarmierung Google FCM (Firebase Cloud Messaging), was in manchen Umgebungen nicht gewünscht oder nicht zulässig ist.
- Dieses Gateway holt Alarme zentral über die DiVeRa-API ab und verteilt sie über ntfy – unabhängig von Google Push-Infrastruktur.
- Damit kannst du eigene, datensparsame Benachrichtigungswege aufbauen (z. B. self-hosted ntfy).
- Optional lässt sich das Ganze hochverfügbar mit mehreren Standorten bzw. Nodes betreiben.
- DiVeRa Polling mit einstellbarem Intervall.
- ntfy Versand inkl. Token-Auth.
- Fallback-ntfy-Server und Retry-Logik bei Ausfällen.
- Cluster-/HA-Modus: nur der aktive Node sendet, die anderen bleiben Standby.
- Webhook-Endpunkte (POST + einfacher GET-Trigger) für externe Systeme.
- Optionaler Replay-Schutz (HMAC + Timestamp) für Webhook-Requests.
- Health- und Prometheus-Metriken auf separatem Port.
- Audit-Logging als JSON-Lines.
- Keyword-basierte Priorität (case-insensitive), z. B.
MANV=4. - Web-Konfigurationsseite zum Bearbeiten aller bekannten ENV-Parameter im Browser.
- Update-Button im Webinterface (führt optional ein konfiguriertes Update-Kommando aus).
- Erweiterte Deduplizierung verhindert erneute Zustellung bereits bekannter Alarme (z. B. bei nächtlichem Reset im Quellsystem).
Diese Anleitung ist für Einsteiger gedacht. Wenn du die Befehle 1:1 übernimmst, hast du in wenigen Minuten ein laufendes System.
- Genau ein Host mit Linux für den Betrieb (z. B. Raspberry Pi oder ein vServer)
- Root-Rechte (oder ein Benutzer mit
sudo) - Keine öffentliche IP-Adresse erforderlich, wenn du den öffentlichen ntfy-Server
ntfy.shnutzt - Die ntfy App auf dem Smartphone
- Netzwerkzugriff auf:
- DiVeRa API
- ntfy Server
Als Server für dieses Skript reicht in der Praxis ein Raspberry Pi vollkommen aus. Alternativ kannst du auch einfach einen vServer im Internet bei einem Hoster deiner Wahl buchen.
sudo apt update && sudo apt full-upgrade -y && sudo apt install nano htop git -ygit clone https://github.com/dataklo/divera-ntfy-gateway.git
cd divera-ntfy-gatewaybash scripts/install.shDas Install-Script richtet den Dienst ein und erstellt die Konfigurationsdatei unter:
/etc/alarm-gateway/alarm-gateway.env
Wichtig: Nach
bash scripts/install.shmusst du deine Zugangsdaten in der ENV-Datei eintragen.
sudo nano /etc/alarm-gateway/alarm-gateway.envMindestens diese Werte setzen:
DIVERA_ACCESSKEY="<dein-divera-accesskey>"
NTFY_URL="https://ntfy.example.com"
NTFY_TOPIC="<dein-topic>"sudo systemctl restart alarm-gateway
sudo systemctl status alarm-gateway
journalctl -u alarm-gateway -fWenn im Log keine Fehler erscheinen, läuft dein Gateway korrekt.
DIVERA_ACCESSKEY: API-Key für DiVeRaNTFY_URL: Basis-URL deines ntfy ServersNTFY_TOPIC: Ziel-Topic für Push-Nachrichten
Hinweis zur Migration:
POLL_INTERVAL_SECONDSwird weiterhin als Fallback unterstützt, ist aber deprecated. Bitte künftigPOLL_SECONDSverwenden.
Wenn dein primärer ntfy-Server nicht erreichbar ist, können automatisch Fallback-Server verwendet werden.
NTFY_URL="https://ntfy-primary.example.de"
NTFY_FALLBACK_URLS="https://ntfy-backup1.example.de,https://ntfy-backup2.example.de"
NTFY_RETRY_ATTEMPTS="3"
NTFY_RETRY_DELAY_SECONDS="1.0"
NTFY_RETRY_JITTER_SECONDS="0.3"Optional für Logging:
LOG_LEVEL="INFO"NTFY_PRIORITY_KEYWORDS arbeitet case-insensitive. MANV, manv oder ManV werden gleich behandelt.
NTFY_DEFAULT_PRIORITY="3"
NTFY_PRIORITY_KEYWORDS="Probealarm=1,MANV=4"- Der Node mit der höchsten
NODE_PRIORITYist aktiv und sendet. - Andere Nodes bleiben im Standby.
- Bei gleicher Priorität entscheidet
NODE_ID. - Wertebereich für
NODE_PRIORITY:1= niedrigste Priorität,100= höchste Priorität.
Beispiel:
NODE_ID="gateway-standort-a"
NODE_PRIORITY="100"
PEER_NODES="10.8.0.12:8081,gateway-b.example.de:8081"
CLUSTER_SHARED_TOKEN="<optional-shared-secret>"# --- Pflichtwerte ---
DIVERA_ACCESSKEY="divera_accesskey_hier"
NTFY_URL="https://ntfy.example.com"
NTFY_TOPIC="feuerwehr-alarm"
# --- Optional ntfy Auth ---
NTFY_AUTH_TOKEN=""
# --- Polling ---
POLL_SECONDS="15"
# --- Priorität ---
NTFY_DEFAULT_PRIORITY="3"
NTFY_PRIORITY_KEYWORDS="Probealarm=1,MANV=4"
# --- Webhook (standardmäßig aktiv) ---
WEBHOOK_ENABLED="true"
WEBHOOK_PORT="8080"
WEBHOOK_PATH="/webhook/alarm"
WEBHOOK_TRIGGER_PATH="/webhook/trigger"
WEBHOOK_TOKEN=""
# --- Health/Metrics ---
HEALTH_PORT="8081"
# --- HA/Cluster aus ---
NODE_ID="gateway-single"
NODE_PRIORITY="100"
PEER_NODES=""
CLUSTER_SHARED_TOKEN=""Node A und Node B nutzen identische DiVeRa-/ntfy-Zugangsdaten,
aber unterschiedliche NODE_ID und abgestufte NODE_PRIORITY.
Node A (/etc/alarm-gateway/alarm-gateway.env)
DIVERA_ACCESSKEY="divera_accesskey_hier"
NTFY_URL="https://ntfy.example.com"
NTFY_TOPIC="feuerwehr-alarm"
POLL_SECONDS="15"
WEBHOOK_ENABLED="true"
WEBHOOK_PORT="8080"
WEBHOOK_PATH="/webhook/alarm"
WEBHOOK_TRIGGER_PATH="/webhook/trigger"
HEALTH_PORT="8081"
NODE_ID="gateway-node-a"
NODE_PRIORITY="100"
PEER_NODES="10.10.0.22:8081"
CLUSTER_SHARED_TOKEN="gemeinsames_cluster_secret"Node B (/etc/alarm-gateway/alarm-gateway.env)
DIVERA_ACCESSKEY="divera_accesskey_hier"
NTFY_URL="https://ntfy.example.com"
NTFY_TOPIC="feuerwehr-alarm"
POLL_SECONDS="15"
WEBHOOK_ENABLED="true"
WEBHOOK_PORT="8080"
WEBHOOK_PATH="/webhook/alarm"
WEBHOOK_TRIGGER_PATH="/webhook/trigger"
HEALTH_PORT="8081"
NODE_ID="gateway-node-b"
NODE_PRIORITY="90"
PEER_NODES="10.10.0.21:8081"
CLUSTER_SHARED_TOKEN="gemeinsames_cluster_secret"Kurz erklärt:
- Solange
Node Aerreichbar ist, sendet nurNode A(höhere Priorität). - Fällt
Node Aaus, übernimmtNode Bautomatisch. - Nach Recovery geht die aktive Rolle wieder an den Node mit höherer Priorität.
Das Webinterface ist standardmäßig aktiv (WEBHOOK_ENABLED="true").
Default-Werte:
WEBHOOK_PORT="8080"WEBHOOK_UI_PATH="/"WEBHOOK_CONFIG_PATH="/admin/config"
Damit sind die Seiten ohne weitere Anpassung hier erreichbar:
- UI (Alarm-Formular):
http://<HOST>:8080/ - Admin-Konfiguration:
http://<HOST>:8080/admin/config
Falls du das Webinterface nicht nutzen möchtest, setze:
WEBHOOK_ENABLED="false"Wenn WEBHOOK_TOKEN gesetzt ist, ist zusätzlich Authentifizierung per
Authorization: Bearer <token> oder ?token=<token> nötig.
Webhook-Funktion (Default-Konfiguration):
WEBHOOK_ENABLED="true"
WEBHOOK_PORT="8080"
WEBHOOK_PATH="/webhook/alarm"
WEBHOOK_TRIGGER_PATH="/webhook/trigger"
WEBHOOK_TOKEN="<optional-token>"
WEBHOOK_CONFIG_PATH="/admin/config"
WEBHOOK_UPDATE_PATH="/admin/update"
UPDATE_COMMAND="sudo /opt/alarm-gateway/scripts/update.sh"
UPDATE_REPO="dataklo/divera-ntfy-gateway"
UPDATE_BRANCH="main"
UPDATE_CHECK_INTERVAL_SECONDS="300"
DEDUP_RETENTION_HOURS="48"Bei WEBHOOK_PORT=8080, HEALTH_PORT=8081:
- POST JSON:
http://<HOST>:8080/webhook/alarm - GET Trigger:
http://<HOST>:8080/webhook/trigger?... - UI:
http://<HOST>:8080/ - Admin-Konfiguration:
http://<HOST>:8080/admin/config - Health:
http://<HOST>:8081/healthz - Metrics:
http://<HOST>:8081/metrics
POST:
curl -X POST "http://<HOST>:8080/webhook/alarm" \
-H "Content-Type: application/json" \
-d '{"title":"MANV extern","text":"Alarm von Standort B","address":"Musterstr. 1","priority":4}'GET-Trigger:
curl "http://<HOST>:8080/webhook/trigger?title=Einsatz%20extern&text=URL%20Trigger&address=Hauptstrasse%201&priority=4"Wenn Webhooks aus externen Netzen kommen, solltest du Replay-Schutz aktivieren:
WEBHOOK_REPLAY_PROTECTION="true"
WEBHOOK_HMAC_SECRET="<secret>"
WEBHOOK_MAX_SKEW_SECONDS="120"Dann muss der Aufruf einen Timestamp (ts) und eine Signatur (sig) enthalten
(oder die Header X-Webhook-Timestamp und X-Webhook-Signature).
sudo bash /opt/alarm-gateway/scripts/update.sh
sudo systemctl status alarm-gatewayDas Script prüft GitHub (UPDATE_REPO + UPDATE_BRANCH), lädt bei Bedarf den aktuellen Stand herunter, installiert ihn und startet den Dienst neu.
Für den Status im Admin-Webinterface gibt es einen automatischen Hintergrund-Check (standardmäßig alle 5 Minuten):
UPDATE_COMMAND="sudo /opt/alarm-gateway/scripts/update.sh"
UPDATE_REPO="dataklo/divera-ntfy-gateway"
UPDATE_BRANCH="main"
UPDATE_CHECK_INTERVAL_SECONDS="300"Der Update-Button im Admin-Webinterface nutzt standardmäßig sudo /opt/alarm-gateway/scripts/update.sh und kann bei Bedarf über UPDATE_COMMAND angepasst werden.
cd /pfad/zu/divera-ntfy-gateway
sudo bash scripts/uninstall.shOptional: Wenn du auch die Konfiguration löschen möchtest:
sudo rm -rf /etc/alarm-gatewayDanach ist der Gateway-Dienst entfernt.
- Dienst startet nicht:
systemctl status alarm-gatewayjournalctl -u alarm-gateway -n 200 --no-pager
- Keine Push-Nachrichten:
NTFY_URL,NTFY_TOPIC,NTFY_AUTH_TOKENprüfen- Erreichbarkeit des ntfy-Servers testen
- Cluster sendet doppelt:
NODE_IDje Node eindeutig setzenNODE_PRIORITYsauber abstimmenPEER_NODESinkl. korrektem Health-Port prüfen
alarm_gateway.py– Hauptanwendungscripts/install.sh– Installation als systemd-Servicescripts/update.sh– Updatescripts/uninstall.sh– Deinstallationsystemd/alarm-gateway.service– systemd Unittests/– automatisierte Tests
Dieses Projekt ist ein privates Freizeit-/Hobbyprojekt. Die Nutzung erfolgt vollständig auf eigene Verantwortung.
Es wird keine Haftung übernommen, insbesondere nicht für:
- direkte oder indirekte Schäden,
- Datenverlust,
- Fehlalarme, ausbleibende Alarme oder verspätete Benachrichtigungen,
- Folgeschäden durch Fehlkonfiguration, Ausfall von Drittanbietern (z. B. DiVeRa/ntfy) oder Systemstörungen.
Bitte prüfe das Verhalten vor dem produktiven Einsatz gründlich in einer Testumgebung und sorge für geeignete Fallback-Prozesse.
Für den Betrieb des Servers selbst bist du selbstverständlich ebenfalls eigenverantwortlich.