From 41f5eb1821e34640ea7ca8cc8675eeb4da7a8771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reinhard=20X=2E=20F=C3=BCrst?= Date: Mon, 27 Jul 2026 16:59:09 +0200 Subject: [PATCH] Per MQTT gesetzte Helligkeit sofort an die Anzeige senden Am echten Broker aufgefallen: "hell_prozent = 100 uebernommen" stand im Log, die Anzeige blieb aber auf 50 %. Der Wert landete korrekt in settings.json und der Dimmer las ihn per reload() auch nach -- nur ging kein Helligkeitstelegramm raus. Grund: Ein Telegramm wird nur beim *Wechsel* der Stufe gesendet (so war es schon im alten MSP430-Programm gedacht, und fuer die LDR-Regelung ist das richtig). Aendert man die Helligkeit von aussen, waehrend die Stufe dieselbe bleibt, gibt es keinen Wechsel -- die Aenderung waere erst beim naechsten zufaelligen Stufenwechsel sichtbar geworden. run_esp32.main setzt nach dem reload() jetzt die Helligkeit der aktuellen Stufe neu. Ohne Dimmer (kein LDR) gilt weiterhin direkt hell_prozent. test_mqtt.TestHelligkeitWirdSofortSichtbar haelt das fest. Gegenprobe gemacht: mit der alten Fassung schlaegt der Test fehl (keine Helligkeit gesendet), mit der neuen geht genau ein Telegramm mit dem gesetzten Wert raus. Am Geraet bestaetigt, Broker "nuccy": Verbindung steht, Status (ra/dec/ldr/ helligkeit/link/online) kommt retained an, Einstellungen werden uebernommen, ungueltige Werte (500, Text) abgelehnt ohne settings.json anzufassen, und die Anzeige reagiert jetzt sichtbar auf 100 % -> 15 % -> 50 %. 145 Tests gruen. Co-Authored-By: Claude Opus 5 (1M context) --- README.md | 13 ++++++---- run_esp32.py | 28 ++++++++++++++-------- test_mqtt.py | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 7cb8b4e..617eae2 100644 --- a/README.md +++ b/README.md @@ -256,10 +256,9 @@ 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 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. +- **MQTT im Dauerbetrieb beobachten.** Die Strecke ist am echten Broker in beide + Richtungen bestätigt (2026-07-27); offen ist nur, wie sie sich über Tage verhält + (Reconnect nach Broker-Neustart, WLAN-Aussetzer). - **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. @@ -489,6 +488,12 @@ Eine empfangene Einstellung wird sofort wirksam: Sie geht durch dieselbe Prüfun 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. +**Wichtig dabei:** Nach dem Nachladen muss die Helligkeit auch *neu an die Anzeige +gesendet* werden. Ein Helligkeitstelegramm geht sonst nur beim *Wechsel* der Stufe +raus — eine per MQTT gesetzte Helligkeit bliebe unsichtbar, solange die Stufe +dieselbe bleibt. Das ist am Gerät aufgefallen (2026-07-27) und wird von +`test_mqtt.py` (`TestHelligkeitWirdSofortSichtbar`) festgehalten. + ### Was dabei schiefgehen kann, und warum es nichts ausmacht **Grundsatz: MQTT darf die Anzeige nie aufhalten.** Die Anzeige ist der Zweck des diff --git a/run_esp32.py b/run_esp32.py index ed311a1..c2415f2 100644 --- a/run_esp32.py +++ b/run_esp32.py @@ -136,18 +136,26 @@ def main(host=None, port=None, with_ldr=False, fake_display=False, if with_mqtt: import mqtt - # Kommt per MQTT eine neue Helligkeit, muss der Dimmer sie sofort - # sehen -- sonst wirkte sie erst nach einem Neustart. + def uebernehmen(werte): - if dimmer is not None: - dimmer.reload() - # Ohne LDR gibt es keinen Stufenwechsel, der die Helligkeit - # nachzieht: dann direkt die helle Stufe setzen. - if dimmer is None: - try: + """Per MQTT geaenderte Einstellungen sofort sichtbar machen. + + Der Dimmer muss die neuen Werte nicht nur lesen -- die Helligkeit + muss auch neu an die Anzeige. Sonst bliebe eine gesetzte + Helligkeit unsichtbar, solange die Stufe dieselbe bleibt: ein + Telegramm geht sonst nur beim *Wechsel* raus. (Am Geraet + aufgefallen, 2026-07-27.) + """ + try: + if dimmer is not None: + dimmer.reload() + if dimmer.level is not None: + d.set_brightness(dimmer.percent(dimmer.level)) + else: + # Ohne LDR gibt es keine Stufen -- dann gilt "hell". d.set_brightness(werte["hell_prozent"]) - except Exception as e: - log("Anzeige: %s" % e) + except Exception as e: + log("Anzeige: %s" % e) bridge = mqtt.connect_from_config(log=log, on_change=uebernehmen) diff --git a/test_mqtt.py b/test_mqtt.py index 399b249..5336374 100644 --- a/test_mqtt.py +++ b/test_mqtt.py @@ -272,6 +272,74 @@ class TestStoerungen(MqttTest): self.assertFalse(b.publish("ra", "x")) # wirft nicht +class TestHelligkeitWirdSofortSichtbar(MqttTest): + """Am Geraet aufgefallen (2026-07-27): Einstellung uebernommen, Anzeige blieb. + + Ein Helligkeitstelegramm geht nur beim *Wechsel* der Stufe raus. Wird per + MQTT hell_prozent geaendert, die Stufe bleibt aber dieselbe, muss die + Helligkeit trotzdem neu gesetzt werden -- sonst wirkt die Aenderung erst + beim naechsten zufaelligen Stufenwechsel. + """ + + def _dimmer_und_display(self): + import brightness + from display import Display + from transport import FakeTransport + + d = Display(FakeTransport(echo=False), response=True) + dimmer = brightness.BrightnessController(pfad=self.pfad) + dimmer.update(3000) # einschwingen auf HELL + return d, dimmer + + def _uebernehmen_bauen(self, d, dimmer, log): + """Dieselbe Logik wie in run_esp32.main.""" + def uebernehmen(werte): + try: + if dimmer is not None: + dimmer.reload() + if dimmer.level is not None: + d.set_brightness(dimmer.percent(dimmer.level)) + else: + d.set_brightness(werte["hell_prozent"]) + except Exception as e: + log("Anzeige: %s" % e) + return uebernehmen + + def _helligkeiten(self, transport): + """Aus den Telegrammen die gesendeten Helligkeitswerte herausziehen.""" + out = [] + for frame in transport.frames: + i = frame.find(b"\x1bH") + if i >= 0: + out.append(int(frame[i + 3:i + 6])) + return out + + def test_geaenderte_helligkeit_geht_an_die_anzeige(self): + d, dimmer = self._dimmer_und_display() + self.bridge._on_change = self._uebernehmen_bauen(d, dimmer, + self.meldungen.append) + self.bridge.connect() + d._t.frames.clear() + + self.sende("ga/set/hell_prozent", "100") + + self.assertEqual(self._helligkeiten(d._t), [100], + "Helligkeit wurde nicht an die Anzeige gesendet") + + def test_ohne_dimmer_gilt_die_helle_stufe(self): + from display import Display + from transport import FakeTransport + d = Display(FakeTransport(echo=False), response=True) + self.bridge._on_change = self._uebernehmen_bauen(d, None, + self.meldungen.append) + self.bridge.connect() + d._t.frames.clear() + + self.sende("ga/set/hell_prozent", "80") + + self.assertEqual(self._helligkeiten(d._t), [80]) + + class TestOhneKonfiguration(unittest.TestCase): def test_fehlende_mqtt_config_liefert_none(self):