MQTT: Einstellungen empfangen, Zustand veroeffentlichen

Topics (Praefix aus mqtt_config.py, Vorgabe "grossanzeige"):

    <PREFIX>/set/hell_prozent      60      eingehend, schreibt settings.json
    <PREFIX>/set/dunkel_prozent     5
    <PREFIX>/set/schwelle        1800
    <PREFIX>/set/hysterese        150

    <PREFIX>/status/ra        18h36m56s    ausgehend, retained
    <PREFIX>/status/dec      +38°47'01"
    <PREFIX>/status/ldr            2453
    <PREFIX>/status/helligkeit       50
    <PREFIX>/status/link              1
    <PREFIX>/status/online            1    mit Last Will auf 0

Eine empfangene Einstellung wird sofort wirksam: dieselbe Pruefung wie sonst
(settings.update), dann laedt der laufende BrightnessController sie per reload()
nach -- kein Neustart noetig.

Leitgedanke des Moduls: **MQTT darf die Anzeige nie aufhalten.** Die Anzeige ist
der Zweck des Geraets, MQTT ist Beiwerk. Deshalb faengt mqtt.py jeden Fehler
selbst ab und meldet ihn nur:

- Broker nicht erreichbar -> Versuch scheitert, Schleife laeuft weiter.
  Wiederholung mit wachsendem Abstand (5..120 s), sonst kostet ein dauerhaft
  toter Broker in jedem Schleifendurchlauf Zeit.
- Verbindungsabriss -> beim naechsten Senden/Empfangen bemerkt, Verbindung wird
  verworfen und spaeter neu aufgebaut. Danach geht der gesamte Status erneut
  raus, damit der Broker nicht auf veralteten Werten sitzenbleibt.
- Unsinniger Wert von aussen -> verworfen, settings.json bleibt unberuehrt.
- Geraet faellt aus -> Last Will meldet online=0. Ohne das bliebe online=1
  stehen, obwohl niemand mehr da ist.

Der Empfang blockiert nicht (check_msg). Statuswerte gehen nur bei Aenderung
raus -- die Koordinaten aendern sich staendig, LDR und Helligkeit kaum.

mqtt_config.py ist optional und gitignored (Vorlage mqtt_config_example.py);
fehlt sie, laeuft alles wie bisher ohne MQTT. deploy.sh weist nur darauf hin.

test_mqtt.py haengt einen Fake-Broker ein und prueft auch die Faelle, die man
mit einem echten Server schwer herbeifuehrt: Abriss beim Senden, Muell im Topic,
Broker der nicht antwortet. 143 Tests gruen.

Am Geraet bestaetigt ist bisher der Fall OHNE Broker: mqtt.py importiert,
connect_from_config liefert None, ein unerreichbarer Broker wirft keine
Ausnahme. Der Test gegen einen echten Broker steht noch aus.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-27 16:48:41 +02:00
parent 0a893d0684
commit bf39b75ac1
9 changed files with 754 additions and 7 deletions
+81 -3
View File
@@ -63,8 +63,10 @@ beiden Startprogrammen.
| `mount_client.py` | TCP-Client zur GM4000 (LX200). | ✓ |
| `lx200.py` | LX200-Kommandorahmen. | ✓ |
| `wifi.py` | WLAN-Anbindung des ESP32 (verbinden, Verbindung halten). | ✓ |
| `mqtt.py` | MQTT: Einstellungen empfangen, Zustand veröffentlichen. | ✓ |
| `run_esp32.py` | Startprogramm auf dem ESP32: WLAN, Anzeige, Schleife. | ✓ |
| `wifi_config.py` | WLAN-Zugangsdaten, **nicht im Git** (Vorlage `wifi_config_example.py`). | ✓ |
| `mqtt_config.py` | MQTT-Zugangsdaten, **nicht im Git** (Vorlage `mqtt_config_example.py`). | ✓ |
| `run_display.py` | Startprogramm auf dem Mac: dieselbe Schleife mit Kommandozeile. | |
| `show_coords.py` | Testprogramm (Koordinaten von Hand). | |
| `mount_mock.py` | Simulator der Montierung (LX200) fürs Testen ohne Teleskop. | |
@@ -161,6 +163,7 @@ mpremote repl
>>> import run_esp32
>>> run_esp32.main() # ohne Helligkeitsregelung
>>> run_esp32.main(with_ldr=True) # mit LDR über den ADC
>>> run_esp32.main(with_mqtt=False) # ohne MQTT (sonst an, sofern konfiguriert)
```
Bewusst **kein** `main.py`: MicroPython startet eine Datei dieses Namens nach
@@ -253,9 +256,10 @@ Mac:
Schreibtisch. Vor Ort bei Tag und Nacht die Rohwerte ablesen und die Schwelle in
`settings.json` bestätigen. Bis dahin läuft die Anzeige mit fester Helligkeit
(`run_esp32.main()` ohne `with_ldr`).
- **MQTT-Anbindung.** Die Einstellungen liegen bereits zur Laufzeit änderbar in
`settings.json` (`settings.update(...)`, geprüft auf Typ und Bereich); der
MQTT-Client, der sie von außen setzt, fehlt noch.
- **MQTT gegen einen echten Broker prüfen.** Der Client ist fertig und gegen einen
Fake-Broker getestet (`test_mqtt.py`), am Gerät ist bisher nur der Fall *ohne*
Broker bestätigt: kein Absturz, Anzeige läuft weiter. Sobald ein Broker steht,
`mqtt_config.py` anlegen und gegenprüfen.
- **Netzwerk zur echten Montierung.** Die GM4000 steht in `192.168.1.115`, das
Heimnetz des ESP32 ist `192.168.178.x` — der Mac erreicht sie per VPN, der
ESP32 so nicht. Muss geklärt werden, bevor es an die echte Montierung geht.
@@ -438,6 +442,80 @@ Die Schwellen sind am Aufbau gemessen, aber **am Schreibtisch, nicht in der
Sternwarte**. Vor dem Echteinsatz dort bei Tag und Nacht gegenprüfen — deshalb
bleibt `with_ldr` in `run_esp32.main` vorerst auf `False`.
## MQTT
Der ESP32 nimmt Einstellungen über MQTT entgegen und veröffentlicht seinen
Zustand. Zugangsdaten kommen aus `mqtt_config.py` (gitignored, Vorlage
`mqtt_config_example.py`):
```bash
cp mqtt_config_example.py mqtt_config.py # Broker, Port, ggf. Benutzer/Passwort
./deploy.sh
```
**Fehlt die Datei, läuft die Anzeige einfach ohne MQTT** — `deploy.sh` weist nur
darauf hin und kopiert sie nicht.
### Topics
Empfangen (`<PREFIX>/set/<name>`, Nutzlast als Zahl):
| Topic | Beispiel | Wirkung |
|---|---|---|
| `grossanzeige/set/hell_prozent` | `60` | Helligkeit über der Schwelle |
| `grossanzeige/set/dunkel_prozent` | `5` | Helligkeit unter der Schwelle |
| `grossanzeige/set/schwelle` | `1800` | Umschaltpunkt (LDR-Wert) |
| `grossanzeige/set/hysterese` | `150` | Breite um den Umschaltpunkt |
Gesendet (`<PREFIX>/status/<name>`, alle *retained*):
| Topic | Beispiel |
|---|---|
| `grossanzeige/status/ra` | `18h36m56s` |
| `grossanzeige/status/dec` | `+38°47'01"` |
| `grossanzeige/status/ldr` | `2453` |
| `grossanzeige/status/helligkeit` | `50` |
| `grossanzeige/status/link` | `1` (Montierung erreichbar) |
| `grossanzeige/status/online` | `1` — **Last Will** setzt es auf `0` |
Zum Ausprobieren:
```bash
mosquitto_sub -h <broker> -t 'grossanzeige/#' -v
mosquitto_pub -h <broker> -t grossanzeige/set/hell_prozent -m 60
```
Eine empfangene Einstellung wird sofort wirksam: Sie geht durch dieselbe Prüfung
wie jede andere (`settings.update`), landet in `settings.json` und der laufende
`BrightnessController` lädt sie über `reload()` nach — ein Neustart ist nicht nötig.
### Was dabei schiefgehen kann, und warum es nichts ausmacht
**Grundsatz: MQTT darf die Anzeige nie aufhalten.** Die Anzeige ist der Zweck des
Geräts, MQTT ist Beiwerk. Deshalb fängt `mqtt.py` seine Fehler selbst ab:
- **Broker nicht erreichbar** → Der Verbindungsversuch schlägt fehl, wird notiert,
und die Schleife läuft weiter. Wiederholt wird mit **wachsendem Abstand**
(5 s bis 120 s) — sonst würde ein dauerhaft toter Broker in *jedem*
Schleifendurchlauf Zeit kosten.
- **Verbindung bricht mitten im Betrieb ab** → Wird beim nächsten Senden oder
Empfangen bemerkt, die Brücke verwirft die Verbindung und baut sie später neu
auf. Nach dem Reconnect wird der gesamte Status erneut gesendet, damit der
Broker nicht auf veralteten Werten sitzenbleibt.
- **Unsinniger Wert von außen** (`hell_prozent = 500`, `schwelle = -1`, Text statt
Zahl, unbekanntes Topic) → wird verworfen und protokolliert; `settings.json`
bleibt unberührt. Genau dafür prüft `settings.py` jeden Wert auf Typ und Bereich.
- **Gerät fällt aus** → Der **Last Will** sorgt dafür, dass der Broker von sich aus
`online = 0` meldet. Ohne das bliebe `online = 1` stehen, obwohl niemand mehr da ist.
`test_mqtt.py` prüft all diese Fälle gegen einen eingehängten Fake-Broker — auch
die, die sich mit einem echten Server nur schwer herbeiführen lassen. Der wichtigste
Test ist `test_toter_broker_haelt_die_anzeige_nicht_auf`.
Der Empfang blockiert nicht: `check_msg()` kehrt sofort zurück, wenn nichts anliegt.
Statuswerte werden nur bei Änderung gesendet — die Koordinaten ändern sich ständig,
LDR und Helligkeit kaum.
## Antwortleitung (RX)
Der Rückkanal ist verdrahtet und verifiziert (2026-07-16): Anzeige Pin 3 (TxD) →