Web Push ohne App, E-Mail, das gerechnete Geraet und der zweite Weg ueber MQTT - samt der Stolpersteine (sw.js gehoert ins Wurzelverzeichnis, iPhone erst ab Home-Bildschirm, Endpoint ist das Geheimnis, Schluessel nie neu erzeugen solange Abos daran haengen). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
150 lines
5.8 KiB
Markdown
150 lines
5.8 KiB
Markdown
# Benachrichtigungen
|
|
|
|
Automatiken können melden: als Nachricht auf dem Handy oder als E-Mail.
|
|
Beides ohne eine eigene App — die Meldung aufs Handy kommt über **Web Push**
|
|
aus dem Dashboard selbst.
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
A["Automatik<br/><small>Aktion: Benachrichtigungen</small>"] --> R
|
|
P["Probe aus den Einstellungen"] -->|"MQTT benachrichtigung/#"| R
|
|
R["autoaction_runner.py<br/><small>BenachrichtigungTransport</small>"] --> PUSH["Push-Dienst<br/><small>Google, Mozilla, Apple</small>"] --> H["Handy / Browser<br/><small>sw.js zeigt die Meldung</small>"]
|
|
R --> MAIL["SMTP"] --> M["Postfach"]
|
|
DB[("homeMesh.push_abos")] --> R
|
|
KEY[["push_vapid.json<br/><small>Schlüsselpaar</small>"]] --> R
|
|
```
|
|
|
|
---
|
|
|
|
## 1. Das Gerät „Benachrichtigungen“
|
|
|
|
Ein gerechnetes Gerät wie „Zeitpunkt“: Es hängt an keinem Netzwerkanschluss,
|
|
sondern bündelt Kommandos, die der Runner selbst ausführt. Angelegt wird es
|
|
vom Gerätesuchlauf (`benachrichtigung_module.py`), Aktor-URL
|
|
`Benachrichtigung`.
|
|
|
|
| Kommando | `command_url` | Parameter |
|
|
|---|---|---|
|
|
| Nachricht aufs Handy | `push` | Titel, Text |
|
|
| E-Mail | `mail` | Betreff, Text |
|
|
|
|
**Warum als Gerät und nicht als eigener Aktionstyp?** Weil der Editor, die
|
|
Übersicht und die Zeitleiste damit nichts Neues lernen müssen: Für sie ist es
|
|
ein Gerät mit Kommandos wie jedes andere. Eine Meldung ist deshalb eine
|
|
gewöhnliche Aktion — sie lässt sich mit anderen Aktionen mischen, im Rahmen
|
|
begrenzen und verketten.
|
|
|
|
**Keine Empfängerliste je Automatik.** Wer eine Meldung bekommt, steht an
|
|
einer Stelle: die Handys in `homeMesh.push_abos`, die Mailadressen in der
|
|
`config.ini` des Runners. Ein Empfängerfeld je Aktion wäre eine zweite
|
|
Liste, die mit der ersten auseinanderläuft.
|
|
|
|
---
|
|
|
|
## 2. Web Push — ohne App
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant B as Browser (Handy)
|
|
participant W as ajax/push.php
|
|
participant DB as homeMesh.push_abos
|
|
participant R as Runner
|
|
participant D as Push-Dienst
|
|
|
|
B->>B: sw.js registrieren, Erlaubnis holen
|
|
B->>D: subscribe(VAPID-Public-Key)
|
|
D-->>B: Abo (endpoint + 2 Schlüssel)
|
|
B->>W: POST ?action=anmelden
|
|
W->>DB: INSERT … ON DUPLICATE KEY UPDATE
|
|
Note over R: Automatik löst aus
|
|
R->>DB: Abos lesen
|
|
R->>D: verschlüsseltes Paket, VAPID-signiert
|
|
D->>B: push-Ereignis → showNotification()
|
|
```
|
|
|
|
Drei Teile, die zusammengehören:
|
|
|
|
| Teil | Wo | Aufgabe |
|
|
|---|---|---|
|
|
| Service Worker | `sw.js` (Wurzelverzeichnis!) | nimmt das `push`-Ereignis an und zeigt die Meldung; ein Klick holt die Seite nach vorn |
|
|
| Abo | `homeMesh.push_abos` | Endpoint plus zwei Schlüssel je Gerät |
|
|
| Schlüsselpaar | `SolarManager/push_vapid.json` | der private Teil unterschreibt jede Meldung, der öffentliche steckt im Abo |
|
|
|
|
Wissenswertes:
|
|
|
|
* **`sw.js` muss im Wurzelverzeichnis liegen.** Ein Service Worker gilt nur
|
|
für Adressen unterhalb seines eigenen Ortes.
|
|
* **Er speichert nichts zwischen.** Das Dashboard lebt von aktuellen Werten;
|
|
ein Cache wäre hier keine Beschleunigung, sondern eine Fehlerquelle.
|
|
* **iPhone:** Safari erlaubt Web Push erst, wenn die Seite über
|
|
„Teilen ▸ Zum Home-Bildschirm“ abgelegt und von dort geöffnet wurde.
|
|
* **Das Abo gehört dem Browser, nicht dem Konto.** Jedes Gerät meldet sich
|
|
einzeln an; in den Einstellungen stehen alle nebeneinander.
|
|
* **Der Endpoint ist das Geheimnis.** Wer ihn hat, kann dem Gerät schreiben —
|
|
deshalb geht er nie an den Browser zurück, auch nicht in der Liste.
|
|
* **Tote Abos räumt der Runner selbst weg:** Antwortet der Dienst mit 404
|
|
oder 410, gibt es das Gerät nicht mehr.
|
|
* Der Schlüssel wird **nie neu erzeugt**, solange Abos daran hängen —
|
|
`vapid_erzeugen.py` überschreibt eine vorhandene Datei nicht.
|
|
|
|
---
|
|
|
|
## 3. E-Mail
|
|
|
|
Ein gewöhnlicher SMTP-Versand aus dem Runner, eingetragen in dessen
|
|
`config.ini`:
|
|
|
|
```ini
|
|
[mail]
|
|
server = smtp.example.net
|
|
port = 587 ; 587 = STARTTLS, 465 = von Anfang an verschlüsselt
|
|
benutzer =
|
|
passwort =
|
|
von =
|
|
an = einer@example.net, zweiter@example.net
|
|
```
|
|
|
|
Unverschlüsselten Versand gibt es nicht: Bei 465 wird die Verbindung
|
|
verschlüsselt aufgebaut, sonst mit STARTTLS gewechselt. Fehlen Server oder
|
|
Empfänger, meldet die Automatik einen Fehler ins Protokoll (`automation_log`),
|
|
statt still nichts zu tun.
|
|
|
|
---
|
|
|
|
## 4. Der zweite Weg: MQTT
|
|
|
|
Der Runner hört zusätzlich auf `benachrichtigung/#`:
|
|
|
|
| Topic | Nutzlast | Wirkung |
|
|
|---|---|---|
|
|
| `benachrichtigung/push` | `{"titel": "...", "text": "..."}` | Meldung an alle Geräte |
|
|
| `benachrichtigung/mail` | `{"betreff": "...", "text": "..."}` | Mail an die eingetragenen Empfänger |
|
|
|
|
Darüber schickt die **Probe** aus den Einstellungen — die Weboberfläche muss
|
|
so nichts verschlüsseln und braucht den privaten Schlüssel nie. Denselben Weg
|
|
kann jedes Skript auf der NAS nehmen.
|
|
|
|
Zugestellt wird im Haupttakt des Runners, nicht im MQTT-Faden: Eine
|
|
Datenbankverbindung gehört einem Faden, und der Rückruf des Brokers läuft in
|
|
einem eigenen.
|
|
|
|
---
|
|
|
|
## 5. Die Pakete
|
|
|
|
`pywebpush`, `py_vapid` und `http_ece` liegen wie alle übrigen Fremdpakete
|
|
**im SolarManager-Ordner**, nicht in `site-packages`. Weil der Runner aus
|
|
`autoActions/` startet, hängt `transports.py` diesen Ordner an den Suchpfad.
|
|
|
|
---
|
|
|
|
## 6. Wo fange ich an, wenn ich …
|
|
|
|
| Vorhaben | Ort |
|
|
|---|---|
|
|
| … einen weiteren Kanal (Telegram, Signal, WhatsApp) | ein Kommando in `benachrichtigung_module.py`, ein `elif` in `BenachrichtigungTransport.senden()` |
|
|
| … den Text einer Meldung ändern | in der Automatik selbst — Titel und Text sind Parameter der Aktion |
|
|
| … ein Handy loswerden | Einstellungen → Meldungen → Papierkorb; oder auf dem Gerät selbst abmelden |
|
|
| … den Schlüssel erneuern | `push_vapid.json` löschen, `vapid_erzeugen.py` laufen lassen, danach müssen sich **alle** Geräte neu anmelden |
|
|
| … nachsehen, warum nichts ankam | `autoActions.log` auf der NAS und die Spalten `zuletzt`/`fehler` in `push_abos` |
|