"""Die Poll-Schleife: Koordinaten holen, formatieren, anzeigen. Herausgeloest aus run_display.py, damit Mac und ESP32-C3 wirklich denselben Ablauf fahren. Auf dem Mac kommt drumherum die Kommandozeile (run_display.py), auf dem ESP32 das WLAN-Setup (run_esp32.py) -- die Schleife selbst ist gleich. Reines Python ohne Abhaengigkeiten ausser den Projektmodulen; argparse und sys.stderr bleiben bewusst draussen, beides gibt es unter MicroPython nicht. """ import time import config import coords import migra from mount_client import MountError class LinkError(Exception): """Die Netzverbindung fehlt (auf dem ESP32: kein WLAN).""" def format_coordinates(ra_raw, dec_raw): """Rohstrings der Montierung fuer die Anzeige aufbereiten.""" return coords.format_ra(ra_raw), coords.format_dec(dec_raw) def poll_loop(display, client, interval=None, once=False, read_ldr=None, dimmer=None, ensure_link=None, log=None, bridge=None): """Zyklisch die Montierung abfragen und die Anzeige nachfuehren. display offenes Display-Objekt client MountClient (wird bei Bedarf selbst verbunden) interval Sekunden zwischen zwei Abfragen (Vorgabe config.POLL_INTERVAL) once nur ein Durchlauf, dann zurueck read_ldr optional: Funktion ohne Argumente, liefert einen LDR-Rohwert in der Zaehlrichtung "hoch = hell" (siehe brightness.raw_to_ldr) dimmer optional: BrightnessController; noetig, wenn read_ldr gesetzt ist ensure_link optional: Funktion, die vor jeder Abfrage die Netzverbindung sicherstellt (auf dem ESP32 das WLAN) log optional: Ausgabefunktion, Vorgabe print; None-freies Logging erlaubt es, auf dem ESP32 still zu laufen (log=lambda *a: None) bridge optional: mqtt.MqttBridge -- empfaengt Einstellungen und veroeffentlicht den Zustand. Faellt der Broker aus, laeuft die Anzeige unveraendert weiter (mqtt.py faengt seine Fehler selbst). Laeuft bis KeyboardInterrupt oder -- bei once=True -- genau einmal. Fehler von Anzeige und Montierung werden abgefangen: die Schleife meldet sie und versucht es beim naechsten Durchlauf erneut, statt abzustuerzen. """ if interval is None: interval = config.POLL_INTERVAL if log is None: log = print last_shown = None while True: try: # Zuerst MQTT abholen: So wirkt eine gerade gesetzte Helligkeit noch # in diesem Durchlauf, statt eine Runde hinterherzuhinken. if bridge is not None: bridge.check() if ensure_link is not None: ensure_link() if not client.connected: client.connect() # Helligkeit nachfuehren -- nur senden, wenn sich die Stufe aendert. if read_ldr is not None and dimmer is not None: raw = read_ldr() level, percent, changed = dimmer.update(raw) if changed: display.set_brightness(percent) log("LDR %d -> %s = %d %%" % (raw, "HELL" if level else "DUNKEL", percent)) if bridge is not None: bridge.publish("ldr", raw) bridge.publish("helligkeit", percent) ra_raw, dec_raw = client.get_coordinates() ra_line, dec_line = format_coordinates(ra_raw, dec_raw) if (ra_line, dec_line) != last_shown: # Bei jeder Aenderung beide Zeilen neu zeichnen. Kein Vollbild- # Loeschen (kein Flimmern); die umgekehrte Zeilenreihenfolge in # show_lines schuetzt die Home-Zelle vor dem Gradzeichen- # Zeichensatzwechsel, auch bei staendiger Aktualisierung. first = last_shown is None or last_shown in (config.NOLINK_LINES, config.NOWIFI_LINES) display.show_lines(ra_line, dec_line, clear=first) last_shown = (ra_line, dec_line) log("RA %-11s DEC %-12s -> %s | %s" % (ra_raw, dec_raw, ra_line, dec_line)) if bridge is not None: bridge.publish("ra", ra_line) bridge.publish("dec", dec_line) if bridge is not None: bridge.publish("link", 1) except LinkError as e: # Kein Netz (WLAN): die Montierung gar nicht erst versuchen. log("Netz: %s" % e) client.close() last_shown = _show_notice(display, config.NOWIFI_LINES, last_shown, log) except migra.MigraError as e: # Anzeige-/Antwortfehler (z.B. gestoerte Antwort): nicht abstuerzen, # nur melden und beim naechsten Durchlauf neu zeichnen. log("Anzeige: %s" % e) last_shown = None except (MountError, ValueError) as e: log("Montierung: %s" % e) client.close() last_shown = _show_notice(display, config.NOLINK_LINES, last_shown, log) if bridge is not None: bridge.publish("link", 0) if once: return last_shown time.sleep(interval) def _show_notice(display, lines, last_shown, log): """Hinweiszeilen anzeigen, wenn sie nicht schon stehen.""" if lines == last_shown: return last_shown try: display.show_lines(lines[0], lines[1], clear=True) except migra.MigraError as e: log("Anzeige: %s" % e) return None return lines