RA in Zehntelminuten mit Beschriftung: "RA 18h36.9m" / "DE +38°47'"

Die GM4000 liefert im Auslieferzustand keine Sekunden, sondern Zehntelminuten.
Bisher wurde daraus eine Sekundenanzeige gerechnet -- die sprang in
6-Sekunden-Schritten, weil die Rohdaten sie gar nicht hergeben. Die Zehntelform
ist ehrlicher und kuerzer, und der gewonnene Platz traegt die Beschriftung:

    RA 18h36.9m
    DE +38°47'

Bei Hochpraezision entfaellt die Beschriftung, dort braucht die Deklination mit
+38°47'01" alle Zellen.

Der Mock konnte das gar nicht nachstellen -- er sendete immer das
Hochpraezisionsformat. Neu: "mount_mock.py --low" bildet den Auslieferzustand ab
(RA als HH:MM.T, DEC ohne Bogensekunden). Vorgabe bleibt hoch, damit die
bestehenden Tests mit ihren festen Erwartungen unveraendert durchlaufen.

Zur Darstellung, alles am Geraet ausprobiert:

- **Schmale Zeichen** (config.CELL_NARROW): Dezimalpunkt und der Abstand
  zwischen Beschriftung und Wert bekommen 3 statt 6 px -- in der Sperrschrift
  standen sie sonst sehr luftig. Fuer die Leerzeichen am Zeilenende gilt das
  nicht, die sollen den Rest der Zeile ueberschreiben.
- Damit entscheidet die **Pixelbreite** ueber das Abschneiden, nicht mehr die
  Zeichenzahl: "RA 18h36.9m" sind 11 Zeichen und trotzdem nur 60 px.
- **Linksbuendig ab LINE_X = 0**, der Schalter zum Zentrieren ist entfallen.
  Zentriert standen die Zeilen um wenige Pixel gegeneinander versetzt, weil die
  RA-Zeile mit ihrem schmalen Punkt kuerzer ist als die DEC-Zeile.

Ein Zwischenschritt, der wieder verworfen wurde und als Warnung im Code steht:
Ein Doppelpunkt als Trenner ("RA:18h36.9m") sah in Zeichensatz 0 zu wuchtig aus;
der aus Zeichensatz 1 ist schlanker, steht aber mitten in der obersten Zeile --
und jeder Zeichensatzwechsel zerstoert die Home-Zelle. Das erste Zeichen danach
noch einmal zu schreiben machte es schlimmer: Das nachgezogene Zeichen bemalt
GLYPH_WIDTH Pixel und frisst die linke Spalte seines rechten Nachbarn. Deshalb
steht in der obersten Zeile jetzt bewusst kein Sonderzeichen.

161 Tests gruen, am Geraet bestaetigt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-27 18:23:07 +02:00
parent dae7694a07
commit 433c53aabd
10 changed files with 468 additions and 140 deletions
+40 -12
View File
@@ -58,31 +58,54 @@ def _numbers(text):
return [int(x) for x in out]
def _fmt_ra(total_s):
def _fmt_ra(total_s, high=True):
"""Rektaszension wie die GM4000.
high=True -> HH:MM:SS (Hochpraezision, nach ":U#")
high=False -> HH:MM.T (Zehntelminuten -- so liefert die Montierung im
Auslieferzustand, verifiziert 2026-07-18)
"""
total_s %= 86400
h, rest = divmod(total_s, 3600)
m, s = divmod(rest, 60)
return "%02d:%02d:%02d" % (h, m, s)
if high:
return "%02d:%02d:%02d" % (h, m, s)
zehntel = (total_s * 10 + 30) // 60 # in Zehntelminuten, gerundet
minuten, t = divmod(zehntel, 10)
h, m = divmod(minuten, 60)
return "%02d:%02d.%d" % (h % 24, m, t)
def _fmt_dec(total_arcsec):
def _fmt_dec(total_arcsec, high=True):
"""Deklination wie die GM4000.
high=True -> sDD*MM:SS (Hochpraezision)
high=False -> sDD*MM (ganze Bogenminuten, Auslieferzustand)
Gradzeichen als '*', Minuten/Sekunden mit ':' -- der coords-Parser kommt mit
beiden Trennzeichen klar. (Die echte Montierung sendet 0xDF als Gradzeichen.)
"""
sign = "-" if total_arcsec < 0 else "+"
total_arcsec = abs(total_arcsec)
d, rest = divmod(total_arcsec, 3600)
m, s = divmod(rest, 60)
# Gradzeichen als '*', Minuten/Sekunden mit ':' -- der coords-Parser
# kommt mit beiden Trennzeichen klar.
return "%s%02d*%02d:%02d" % (sign, d, m, s)
if high:
return "%s%02d*%02d:%02d" % (sign, d, m, s)
return "%s%02d*%02d" % (sign, d, m)
class MountMock:
"""Simuliert die Montierung auf TCP-Ebene."""
def __init__(self, host="127.0.0.1", port=3490,
ra="18:36:56", dec="+38:47:01", move=False):
ra="18:36:56", dec="+38:47:01", move=False, high=True):
self._ra0 = _parse_ra(ra)
self._dec = _parse_dec(dec)
self._move = move
# high=False bildet den Auslieferzustand der GM4000 nach: keine Sekunden,
# RA als Zehntelminuten. Vorgabe bleibt True, damit bestehende Tests mit
# ihren festen Erwartungen unveraendert durchlaufen.
self._high = high
self._tick = 0 # zaehlt bei --move pro RA-Abfrage hoch
self._dectick = 0 # zaehlt bei --move pro DEC-Abfrage hoch
self._lock = threading.Lock()
@@ -116,9 +139,9 @@ class MountMock:
def _reply_for(self, cmd):
"""Antwort (inkl. '#') fuer ein Kommando ohne ':' und ohne '#'."""
if cmd == "GR":
return _fmt_ra(self._current_ra()) + "#"
return _fmt_ra(self._current_ra(), self._high) + "#"
if cmd == "GD":
return _fmt_dec(self._current_dec()) + "#"
return _fmt_dec(self._current_dec(), self._high) + "#"
if cmd == "GVP":
return PRODUCT + "#"
if cmd == "GVN":
@@ -204,13 +227,18 @@ def main(argv=None):
p.add_argument("--ra", default="18:36:56")
p.add_argument("--dec", default="+38:47:01")
p.add_argument("--move", action="store_true", help="RA laeuft mit der Zeit hoch")
p.add_argument("--low", action="store_true",
help="Niedrigpraezision wie im Auslieferzustand der GM4000: "
"RA als HH:MM.T, DEC ohne Bogensekunden")
args = p.parse_args(argv)
host = "0.0.0.0" if args.lan else args.host
mock = MountMock(host=host, port=args.port, ra=args.ra, dec=args.dec,
move=args.move)
print("Mock-Montierung auf %s:%d (RA=%s DEC=%s%s)"
% (mock.host, mock.port, args.ra, args.dec, ", move" if args.move else ""))
move=args.move, high=not args.low)
print("Mock-Montierung auf %s:%d (RA=%s DEC=%s%s, %s)"
% (mock.host, mock.port, args.ra, args.dec,
", move" if args.move else "",
"Niedrigpraezision" if args.low else "Hochpraezision"))
if host == "0.0.0.0":
ip = lan_address()
if ip: