Adresse der Montierung per MQTT umstellbar und gespeichert
Zwischen Mock und echter GM4000 umschalten, ohne zu deployen und ohne Neustart:
mosquitto_pub -t grossanzeige/set/mount_host -m 192.168.1.115
mosquitto_pub -t grossanzeige/set/mount_host -m 192.168.178.26
mosquitto_pub -t grossanzeige/set/mount_host -m ''
Die Adresse liegt in settings.json auf dem Geraet und uebersteht damit
Stromausfall und Watchdog-Neustart. deploy.sh kopiert die Datei bewusst nicht
mit, die Einstellung ueberlebt also auch ein Deployen.
**Leer heisst: config.MOUNT_HOST gilt.** mount_client.resolve_host loest auf in
der Reihenfolge: ausdruecklich mitgegebener Host (REPL, run_display --host) ->
mount_host aus settings.json -> config.MOUNT_HOST. Ohne diesen Rueckweg wuerde
eine einmal per MQTT gesetzte Adresse die Zeile in config.py fuer immer
verdecken, auch nach einem Deployen mit geaendertem Code.
Pruefung: settings._pruefe unterscheidet jetzt Zahl und Text am Typ der Vorgabe
in DEFAULTS -- eine neue Einstellung wird weiterhin an genau einer Stelle
eingetragen. Fuer mount_host sind nur Buchstaben, Ziffern, Punkt und
Bindestrich erlaubt, hoechstens 63 Zeichen: Der Wert geht ungeprueft in
socket.getaddrinfo, und von MQTT kommt alles Moegliche. Ungueltiges wird
verworfen, settings.json bleibt unberuehrt.
Sofort wirksam: Der Rueckruf traegt die neue Adresse in den MountClient ein und
trennt nur die bestehende Verbindung -- neu verbindet die Poll-Schleife im
naechsten Durchlauf, mit der gewohnten Fehlerbehandlung. Antwortet dort niemand,
steht "KEIN LINK", und eine weitere Nachricht holt das Geraet zurueck.
grossanzeige/status/mount_host meldet, welche Adresse gerade abgefragt wird --
die Rueckmeldung steht direkt hinter bridge.check() und nicht im Erfolgspfad,
kommt also auch dann, wenn die Montierung schweigt.
Der on_change-Rueckruf ist als run_esp32.make_on_change aus main() herausgeloest.
test_mqtt.py prueft ihn bisher als Abschrift ("Dieselbe Logik wie in
run_esp32.main"); jetzt laeuft der echte Code durch die Tests.
201 Tests gruen. Neu, unter anderem:
- TestUmschaltenImLaufendenBetrieb faehrt die ganze Kette an echten Sockets:
erst "KEIN LINK" an einer toten Adresse, nach dem set/mount_host die
Koordinaten vom Mock.
- TestAdresswahl (test_lx200) haelt die Reihenfolge von resolve_host fest.
- test_esp32: main() ohne host nimmt nach einem Neustart, was gespeichert ist.
Nicht angefasst: run_display.py auf dem Mac behaelt config.MOUNT_HOST als
Vorgabe fuer --host. Dort gibt es keine MQTT-Bruecke, und settings.json ist
Zustand des Geraets, nicht des Macs.
Am Geraet bestaetigt (2026-07-29), am Broker mitgeschnitten. Umschalten im
laufenden Betrieb, mit dem Mock auf dem Mac als Ausgangslage:
0.0s status/mount_host 192.168.178.26 Ausgangslage, link = 1
-> set/mount_host = 192.168.178.99
5.1s status/mount_host 192.168.178.99 Rueckmeldung
5.9s status/link 0 dort antwortet niemand
-> set/mount_host = ''
17.8s status/mount_host 192.168.178.26 Vorgabe aus config.py
18.6s status/link 1 Koordinaten laufen wieder
Und ueber den Neustart hinweg -- der eigentliche Zweck des Speicherns:
-> set/mount_host = 192.168.178.99
1.6s status/mount_host 192.168.178.99
settings.json auf dem Geraet:
{"hysterese": 150, "mount_host": "192.168.178.99", "schwelle": 1800, ...}
-> Hardware-Reset
8.6s status/online 0 Last Will
15.5s status/online 1 Autostart durch
15.5s status/mount_host 192.168.178.99 aus der Datei, nicht aus config.py
Die alte settings.json ohne mount_host wird beim Laden einfach um die Vorgabe
ergaenzt; die eingestellten Helligkeiten bleiben unberuehrt. Eine Migration war
nicht noetig.
set/mount_host wird ohne Retain-Flag geschickt: Das ist ein Befehl, kein
Zustand. Retained laege er im Broker und wuerde bei jedem Reconnect erneut
zugestellt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+51
-27
@@ -28,7 +28,7 @@ import displayloop
|
||||
import wifi
|
||||
from brightness import BrightnessController, raw_to_ldr
|
||||
from display import open_display
|
||||
from mount_client import MountClient
|
||||
from mount_client import MountClient, resolve_host
|
||||
|
||||
try: # MicroPython
|
||||
from machine import ADC, Pin
|
||||
@@ -75,7 +75,7 @@ def selftest(host=None, port=None, log=print):
|
||||
cfg = wifi.connect(log=log)
|
||||
log(" IP %s, Gateway %s" % (cfg[0], cfg[2]))
|
||||
|
||||
host = config.MOUNT_HOST if host is None else host
|
||||
host = resolve_host(host, log=log)
|
||||
port = config.MOUNT_PORT if port is None else port
|
||||
log("2) Montierung %s:%d ..." % (host, port))
|
||||
client = MountClient(host, port, timeout=config.MOUNT_TIMEOUT)
|
||||
@@ -115,12 +115,55 @@ def make_watchdog(timeout=None, log=None):
|
||||
return wdt.feed
|
||||
|
||||
|
||||
def make_on_change(display, client, dimmer=None, log=None):
|
||||
"""Rueckruf fuer mqtt.MqttBridge: geaenderte Einstellungen sofort wirksam
|
||||
machen. settings.json ist zu diesem Zeitpunkt schon geschrieben.
|
||||
|
||||
**Helligkeit:** 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.)
|
||||
|
||||
**Adresse der Montierung:** Die wirkt erst, wenn die bestehende Verbindung
|
||||
faellt. Hier wird darum nur getrennt -- neu verbindet die Poll-Schleife im
|
||||
naechsten Durchlauf von selbst, mit derselben Fehlerbehandlung wie sonst
|
||||
auch: Antwortet unter der neuen Adresse niemand, steht "KEIN LINK", und ein
|
||||
weiteres set/mount_host holt das Geraet wieder zurueck.
|
||||
|
||||
Eigene Funktion und nicht als Verschachtelung in main(), damit die Tests
|
||||
genau diese Logik pruefen koennen statt einer Abschrift davon.
|
||||
"""
|
||||
log = log or (lambda *a: None)
|
||||
|
||||
def uebernehmen(werte):
|
||||
try:
|
||||
if dimmer is not None:
|
||||
dimmer.reload()
|
||||
if dimmer.level is not None:
|
||||
display.set_brightness(dimmer.percent(dimmer.level))
|
||||
else:
|
||||
# Ohne LDR gibt es keine Stufen -- dann gilt "hell".
|
||||
display.set_brightness(werte["hell_prozent"])
|
||||
except Exception as e:
|
||||
log("Anzeige: %s" % e)
|
||||
|
||||
neuer_host = resolve_host(werte.get("mount_host"))
|
||||
if neuer_host != client.host:
|
||||
log("Montierung: Adresse %s -> %s" % (client.host, neuer_host))
|
||||
client.host = neuer_host
|
||||
client.close()
|
||||
|
||||
return uebernehmen
|
||||
|
||||
|
||||
def main(host=None, port=None, with_ldr=False, fake_display=False,
|
||||
once=False, with_mqtt=True, feed=None, log=print):
|
||||
"""WLAN aufbauen, Anzeige oeffnen und die Poll-Schleife fahren.
|
||||
|
||||
host/port Montierung; Vorgabe aus config.py. Zum Testen gegen den Mock
|
||||
auf dem Mac dessen LAN-Adresse angeben.
|
||||
host/port Montierung. Ohne host gilt die per MQTT gesetzte Adresse aus
|
||||
settings.json, sonst config.MOUNT_HOST (siehe
|
||||
mount_client.resolve_host). Zum Testen gegen den Mock auf dem
|
||||
Mac dessen LAN-Adresse angeben.
|
||||
with_ldr Helligkeitsregelung ueber den ADC dazuschalten. Die Schwellen
|
||||
sind am realen LDR gemessen (2026-07-27, siehe brightness.py),
|
||||
aber am Schreibtisch, nicht in der Sternwarte -- deshalb bleibt
|
||||
@@ -137,9 +180,10 @@ def main(host=None, port=None, with_ldr=False, fake_display=False,
|
||||
ihn an.
|
||||
"""
|
||||
d = open_display(fake=fake_display)
|
||||
client = MountClient(config.MOUNT_HOST if host is None else host,
|
||||
client = MountClient(resolve_host(host, log=log),
|
||||
config.MOUNT_PORT if port is None else port,
|
||||
timeout=config.MOUNT_TIMEOUT)
|
||||
log("Montierung: %s:%d" % (client.host, client.port))
|
||||
|
||||
dimmer = read_ldr = None
|
||||
if with_ldr:
|
||||
@@ -160,28 +204,8 @@ def main(host=None, port=None, with_ldr=False, fake_display=False,
|
||||
|
||||
if with_mqtt:
|
||||
import mqtt
|
||||
|
||||
def uebernehmen(werte):
|
||||
"""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)
|
||||
|
||||
bridge = mqtt.connect_from_config(log=log, on_change=uebernehmen)
|
||||
bridge = mqtt.connect_from_config(
|
||||
log=log, on_change=make_on_change(d, client, dimmer, log=log))
|
||||
|
||||
displayloop.poll_loop(d, client,
|
||||
once=once,
|
||||
|
||||
Reference in New Issue
Block a user