"""Zentrale Einstellungen fuer die Ansteuerung der Grossanzeige. Laeuft unveraendert unter CPython (Mac) und MicroPython (XIAO ESP32-C3); was sich zwischen beiden unterscheidet, haengt an MICROPYTHON. """ import sys import migra # True auf dem ESP32-C3, False auf dem Mac. Steuert, welchen Transport # display.open_display waehlt und ob der LDR ueber den ADC gelesen werden kann. MICROPYTHON = sys.implementation.name == "micropython" # -- Serielle Schnittstelle ----------------------------------------------- # Auslieferzustand der Anzeige laut Handbuch (Kap. 4.1) und identisch zur # UART-Init des alten MSP430-Programms: 19200 8E1. BAUDRATE = 19200 PARITY = "E" BYTESIZE = 8 STOPBITS = 1 # CPython: Geraetedatei des USB-RS232-Wandlers. PORT = "/dev/cu.usbserial-120" # ESP32-C3: UART1 mit frei zugeordneten Pins. Die Nummern stammen aus dem # Schaltplan (Hardware/KiCad/Grossanzeige) -- am XIAO ist Pad 7 = D6 = GPIO21 # und Pad 8 = D7 = GPIO20. Von dort geht es an den MAX3232: # GPIO21 (TX) -> T2IN, T2OUT -> J5 Pin 3 -> Anzeige RxD (Sub-D Pin 2) # GPIO20 (RX) <- R2OUT, R2IN <- J5 Pin 2 <- Anzeige TxD (Sub-D Pin 3) # UART0 bleibt frei, das ist die REPL-Konsole ueber USB. UART_ID = 1 UART_TX = 21 UART_RX = 20 # -- Telegramm ------------------------------------------------------------ DISPLAY_ADDR = 1 # Zieladresse der Anzeige (DA = 0x81) HOST_ADDR = 0 # unsere Quelladresse (SA = 0x80) USE_CHECKSUM = False # das alte Programm fuhr ohne Pruefsumme # Antworttelegramm als Flusskontrolle: Rueckweg verdrahtet und verifiziert # (2026-07-16), Anzeige liefert 02 80 81 80 30 03. Nach Erhalt der Antwort darf # sofort das naechste Telegramm folgen; der Fehlercode wird ausgewertet. WANT_RESPONSE = True RESPONSE_TIMEOUT = 1.0 # Sekunden (nur relevant, wenn WANT_RESPONSE = True) QUIET_TIME = 0.4 # Pause zwischen Telegrammen, wenn ohne Antwort gefahren wird # -- Darstellung ---------------------------------------------------------- # Zeichensatz 0, Zeile 1 ab Pixelzeile 0, Zeile 2 ab Pixelzeile 9 (aus dem alten # C-Programm). Am echten Geraet ausgemessen (2026-07-15): # CHARSET_SPACED=True -> ESC z (Sperrschrift, alle Zeichen gleich breit) -- vom # Nutzer bevorzugt, weil sich sonst schmale Ziffern beruehren. # CHARSET_SPACED=False -> ESC Z (proportional, schmaler, ~11 Zeichen, aber die "1" # klebt an Nachbarn). CHARSET = 0 CHARSET_SPACED = True LINE_Y = (0, 9) # 6 px pro Zeichenzelle -- mit "probe.py pitch 6" am Geraet gemessen (2026-07-27). # # Die Messung stellt den Auto-Vorschub der Anzeige gegen feste Pixelabstaende und # hat beides zugleich gezeigt: # - Auto-Vorschub der Sperrschrift ESC z ist 7 px. Eine Zeile aus einem Stueck # bricht deshalb nach 9 Zeichen um (9*7 = 63 von 64 px). Frueher stand hier # darum 9 -- das war der Vorschub, nicht die Zellenbreite. # - Die Zeichenmatrix selbst ist nur 6 px breit: zehn Ziffern, einzeln auf # x = i*6 gesetzt, stehen sauber und getrennt nebeneinander (60 von 64 px). # # Deshalb positioniert display._emit_line jedes Zeichen selbst, statt den # Auto-Vorschub laufen zu lassen. CELL_WIDTH = 6 # Pixel pro Zeichenzelle DISPLAY_WIDTH = 64 # Pixelbreite der Anzeige # Obergrenze in *Zeichen*. Die harte Grenze ist DISPLAY_WIDTH in Pixeln: Seit # schmale Zeichen weniger Platz brauchen (CELL_NARROW), haengt die Breite einer # Zeile davon ab, welche Zeichen darin stehen. 11 gehen nur auf, wenn mindestens # eines schmal ist -- "RA:18h51.0m" braucht mit seinem Dezimalpunkt 63 der 64 px, # "DE:+38°47'" waere als 11 volle Zellen dagegen 66 px und damit zu breit. # display._aufbereiten schneidet deshalb nach Pixeln ab, nicht nach Zeichen. CHARS_PER_LINE = 11 # Breite, die die Anzeige beim Schreiben eines Zeichens tatsaechlich bemalt -- # mehr als CELL_WIDTH. Daher auch der Auto-Vorschub von 7 px. Wichtig fuer das # Nachfuehren einzelner Zellen: Ein neu geschriebenes Zeichen loescht die erste # Pixelspalte seines rechten Nachbarn, der muss also mitgeschrieben werden # (siehe display._zelle_faellig). GLYPH_WIDTH = 7 # Zeichen, die weniger Platz brauchen als eine volle Zelle -- in der Sperrschrift # stehen sie sonst sehr luftig zwischen den Ziffern. Je 3 px am Geraet # ausprobiert (2026-07-27); weil jedes Zeichen ohnehin einzeln positioniert wird, # kostet das nichts. # "." Dezimalpunkt der Zehntelminuten (RA 18h37.1m) # " " Abstand zwischen Beschriftung und Wert (RA 18h37.1m) # Achtung: Das gilt auch fuer die Leerzeichen, mit denen eine Zeile aufgefuellt # wird. display._aufbereiten rechnet beim Auffuellen darum bewusst mit der vollen # Zellenbreite -- sonst reichte die letzte Zelle ueber den Rand hinaus. CELL_NARROW = {".": 3, " ": 3} # Alle Zeilen beginnen linksbuendig bei LINE_X. Bis 2026-07-27 gab es einen # Schalter zum Zentrieren; er ist entfallen, weil die Zeilen seit den schmalen # Zeichen (CELL_NARROW) unterschiedlich breit sind und zentriert um wenige Pixel # gegeneinander versetzt standen. Mit der Beschriftung "RA:" / "DE:" sollen sie # buendig untereinander beginnen. # # LINE_X = 0, ganz am Rand: Die RA-Zeile braucht mit der Minutenangabe am Ende # ("RA:18h51.0m") 63 der 64 Pixel -- fuer einen Rand ist da kein Platz mehr. LINE_X = 0 COLOR = migra.RED # einfarbig rote Anzeige BACKGROUND = migra.BLACK BRIGHTNESS = 100 # Prozent # Gradzeichen: Im Standard-Zeichensatz 0 der Anzeige fehlt es. Der von der # Sternwarte geladene Zeichensatz 1 hat an Position "/" (0x2F) ein hochgestelltes # Gradzeichen -- verifiziert 2026-07-15, deckt sich mit dem alten Programm # (asciitaf.h: Code 0xAF, per & 0x7F = 0x2F in Zeichensatz 1). Zur Ausgabe wird # fuer dieses eine Zeichen kurz auf DEGREE_CHARSET umgeschaltet. DEGREE_MARKER = "°" # Platzhalter im formatierten Text (siehe coords.py) DEGREE_CHARSET = 1 # Zeichensatz mit dem Gradzeichen; None -> Fallback nutzen DEGREE_CHAR = "/" # Zeichen, das in DEGREE_CHARSET als Grad erscheint DEGREE_FALLBACK = "d" # Ersatz, falls DEGREE_CHARSET = None # -- Montierung (Phase 2) ------------------------------------------------- # 10Micron GM4000 HPS II: LX200-Protokoll ueber TCP. Die IP der Montierung # eintragen, sobald sie erreichbar ist; Port 3490 ist die Vorgabe von 10Micron. # # MOUNT_HOST ist nur die **Vorgabe**: Im Betrieb laesst sich die Adresse ueber # MQTT umstellen (/set/mount_host), sie liegt dann in settings.json und # ueberlebt einen Stromausfall. Eine leere Nachricht an dieses Topic holt die # Adresse von hier zurueck. Wer wissen will, was gerade gilt, liest # /status/mount_host oder ruft mount_client.resolve_host(). # Vorübergehend auf den Mock auf dem Mac gestellt (2026-07-27), weil die echte # Montierung vom ESP32 aus nicht erreichbar ist: Sie steht in 192.168.1.115, der # ESP32 im Heimnetz 192.168.178.x. Zum Umstellen die beiden Zeilen tauschen. MOUNT_HOST = "192.168.178.26" # Mock auf dem Mac (mount_mock.py --lan --move --low) # MOUNT_HOST = "192.168.1.115" # echte GM4000 (eingetragen 2026-07-18) MOUNT_PORT = 3490 MOUNT_TIMEOUT = 3.0 # Sekunden fuer Verbindung/Antwort POLL_INTERVAL = 1.0 # Sekunden zwischen zwei Koordinatenabfragen # Koordinaten-Praezision der Montierung. # False = Niedrigpraezision (10Micron-Standard): RA als HH:MM.T (Zehntel-Minuten), # DEC als sDD MM (ganze Bogenminuten) -- die Montierung sendet keine Sekunden. # Die Anzeige zeigt entsprechend RA mit Zehntel-Minute und DEC ohne Sekunden. # True = Hochpraezision (Montierung mit ":U#" umgestellt): RA/DEC mit Sekunden. HIGH_PRECISION = False # Beschriftung der beiden Zeilen: # # RA 18h37.1m # DE +38°47' # # Der Abstand ist ein Leerzeichen, das ueber CELL_NARROW nur 3 px breit gesetzt # wird -- ein Doppelpunkt stand hier zwischenzeitlich, wirkte in Zeichensatz 0 # aber zu wuchtig (2026-07-27). # # Die Beschriftung gibt es nur bei Niedrigpraezision: Dort liefert die Montierung # ohnehin nur Zehntelminuten und ganze Bogenminuten, das laesst den Platz. Bei # Hochpraezision braucht die Deklination alle Zellen (+38°47'01") -- dann # entfaellt sie. LABEL_RA = "RA " LABEL_DEC = "DE " # Anzeige, wenn die Montierung (noch) nicht erreichbar ist. # Achtung: hoechstens CHARS_PER_LINE Zeichen, sonst wird abgeschnitten -- # "MONTIERUNG" stand hier zuerst und erschien am Geraet als "MONTIERUN". NOLINK_LINES = ("KEIN LINK", "TELESKOP") # -- Dauerbetrieb (nur ESP32-C3) ------------------------------------------ # Watchdog: Kommt die Poll-Schleife so lange nicht mehr durch, startet die # Hardware das Geraet neu. 120 s sind reichlich bemessen -- im Normalbetrieb # wird jede Sekunde gefuettert. Der Wert muss ueber allem liegen, was regulaer # blockieren darf: WLAN-Aufbau bis WIFI_TIMEOUT (20 s), Montierung # MOUNT_TIMEOUT (3 s), dazu ein MQTT-Verbindungsversuch. Sonst startet das # Geraet mitten im normalen Betrieb neu. # # Achtung: Ein einmal gestarteter Watchdog laesst sich nicht mehr abschalten. # Deshalb legt ihn nur main.py an, nicht der Handbetrieb ueber die REPL. WDT_TIMEOUT = 120.0 # Sekunden # Wartezeit beim Autostart, bevor main.py die Schleife startet. In diesem # Fenster bricht Ctrl-C ab und man kommt an die REPL -- ohne das waere ein # Geraet mit fehlerhaftem main.py nur noch ueber ein Neuflashen erreichbar. AUTOSTART_DELAY = 3.0 # Sekunden # Nach einem Absturz in main.py: so lange warten, dann neu starten. Die Pause # verhindert eine Neustart-Schleife im Sekundentakt, wenn etwas dauerhaft # kaputt ist (und gibt Zeit, mit Ctrl-C einzugreifen). RESTART_DELAY = 10.0 # Sekunden # -- WLAN (nur ESP32-C3) -------------------------------------------------- # Zugangsdaten stehen in wifi_config.py (nicht im Git, siehe # wifi_config_example.py). Hier nur das Zeitverhalten. WIFI_TIMEOUT = 20.0 # Sekunden aufs Verbinden warten WIFI_RETRY = 5.0 # Pause vor einem neuen Verbindungsversuch # Anzeige, solange noch kein WLAN steht. NOWIFI_LINES = ("KEIN WLAN", " ... ") # -- Helligkeitssensor (LDR, nur ESP32-C3) -------------------------------- # LDR an Pad 1 (D0/A0) = GPIO2, auf dem C3 ein Kanal von ADC1. LDR_PIN = 2 # Der Spannungsteiler auf der Platine ist 3V3 --[R2 2k]-- A0 --[LDR]-- GND. # Der LDR wird bei mehr Licht niederohmiger, die Spannung an A0 sinkt also mit # steigender Helligkeit -- genau andersherum als beim alten MSP430-Aufbau, auf # den die Schwellen in brightness.py zugeschnitten sind. Deshalb wird der # Rohwert gespiegelt (siehe brightness.raw_to_ldr). LDR_INVERTED = True LDR_MAX = 4095 # 12-bit-ADC, voller Ausschlag