4f7375add3
Die RS232-Strecke ESP32 -> MAX3232 -> Anzeige ist am Geraet bestaetigt; damit war "probe.py pitch" moeglich und hat die offene Zeichenbreiten-Frage geklaert. Das Ergebnis korrigiert eine Annahme: Bisher stand CHARS_PER_LINE = 9, abgezaehlt am Zeilenumbruch. Gemessen wurde damit aber der Auto-Vorschub der Sperrschrift (7 px), nicht die Zeichenbreite. Die Zeichenmatrix ist 6 px breit -- zehn Ziffern, einzeln auf x = i*6 gesetzt, stehen sauber getrennt nebeneinander. - display._emit_line positioniert jedes Zeichen selbst, statt den Auto-Vorschub laufen zu lassen. CHARS_PER_LINE = 10, CELL_WIDTH = 6. - Die Deklination passt dadurch in voller Form: +38°47'01" statt +38°47'01. - show_lines sendet ein Telegramm je Zeile. Mit Einzelpositionierung kaemen beide zusammen auf 224 der erlaubten 230 Bytes -- zu wenig Reserve fuer den Dauerbetrieb. Die Reihenfolge bleibt unten vor oben (Home-Zelle). - Zeilen werden zentriert (CENTER_LINES, LINE_X). Der Zeichenblock bleibt dabei gleich breit und an derselben Stelle, damit keine Reste stehen bleiben. - probe.py kommt mit aufs Geraet: Die Anzeige haengt jetzt am ESP32, nur von dort laesst sich die Geometrie noch ausmessen. Die Tests pruefen nicht mehr auf zusammenhaengenden Text im Telegramm -- den gibt es nicht mehr -- sondern rechnen ueber die Cursor-Sequenzen zurueck, was wirklich auf welcher Zelle landet. 97 Tests gruen, Kette am Geraet im Sekundentakt bestaetigt. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
111 lines
3.5 KiB
Python
111 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Tests fuer LX200-Protokoll, Mock und Client (Phase 2).
|
|
|
|
python3 -m unittest -v test_lx200
|
|
"""
|
|
|
|
import unittest
|
|
|
|
import coords
|
|
import lx200
|
|
import mount_mock
|
|
from mount_client import MountClient, MountError
|
|
|
|
|
|
class TestLX200(unittest.TestCase):
|
|
|
|
def test_command_rahmen(self):
|
|
self.assertEqual(lx200.command("GR"), ":GR#")
|
|
self.assertEqual(lx200.command(":GR#"), ":GR#")
|
|
self.assertEqual(lx200.command("GR#"), ":GR#")
|
|
self.assertEqual(lx200.command(":GR"), ":GR#")
|
|
|
|
def test_command_leer(self):
|
|
with self.assertRaises(lx200.LX200Error):
|
|
lx200.command(":#")
|
|
|
|
def test_strip_terminator(self):
|
|
self.assertEqual(lx200.strip_terminator("18:36:56#"), "18:36:56")
|
|
with self.assertRaises(lx200.LX200Error):
|
|
lx200.strip_terminator("18:36:56")
|
|
|
|
|
|
class TestAntwortParsen(unittest.TestCase):
|
|
"""Die LX200-Rohantworten muessen direkt in den coords-Parser passen."""
|
|
|
|
def test_ra_antwort(self):
|
|
self.assertEqual(coords.parse_ra("18:36:56"), (18, 36, 56))
|
|
|
|
def test_dec_antwort_mit_stern(self):
|
|
self.assertEqual(coords.parse_dec("+38*47:01"), ("+", 38, 47, 1))
|
|
|
|
def test_dec_antwort_mit_gradzeichen_0xDF(self):
|
|
# Meade-Stil: 0xDF als Gradzeichen
|
|
self.assertEqual(coords.parse_dec("-07\xdf15:30"), ("-", 7, 15, 30))
|
|
|
|
|
|
class TestMockFormat(unittest.TestCase):
|
|
|
|
def test_ra_roundtrip(self):
|
|
self.assertEqual(mount_mock._fmt_ra(mount_mock._parse_ra("18:36:56")), "18:36:56")
|
|
|
|
def test_dec_roundtrip(self):
|
|
s = mount_mock._parse_dec("-07*15:30")
|
|
self.assertEqual(mount_mock._fmt_dec(s), "-07*15:30")
|
|
|
|
def test_ra_wrap(self):
|
|
# 23:59:59 + 2s -> 00:00:01
|
|
self.assertEqual(mount_mock._fmt_ra(mount_mock._parse_ra("23:59:59") + 2), "00:00:01")
|
|
|
|
|
|
class TestClientGegenMock(unittest.TestCase):
|
|
"""Vollstaendiger Weg: Client <-> Mock ueber echtes TCP."""
|
|
|
|
def setUp(self):
|
|
self.mock = mount_mock.MountMock(host="127.0.0.1", port=0,
|
|
ra="18:36:56", dec="+38:47:01")
|
|
self.mock.start()
|
|
self.client = MountClient("127.0.0.1", self.mock.port, timeout=2.0)
|
|
self.client.connect()
|
|
|
|
def tearDown(self):
|
|
self.client.close()
|
|
self.mock.stop()
|
|
|
|
def test_get_ra(self):
|
|
self.assertEqual(self.client.get_ra(), "18:36:56")
|
|
|
|
def test_get_dec(self):
|
|
self.assertEqual(self.client.get_dec(), "+38*47:01")
|
|
|
|
def test_get_coordinates_und_formatierung(self):
|
|
ra_raw, dec_raw = self.client.get_coordinates()
|
|
self.assertEqual(coords.format_ra(ra_raw, high_precision=True), "18h36m56s")
|
|
# Seit CHARS_PER_LINE = 10 passt die volle Form mit abschliessendem ".
|
|
self.assertEqual(coords.format_dec(dec_raw, high_precision=True), "+38°47'01\"")
|
|
|
|
def test_produktname(self):
|
|
self.assertEqual(self.client.query(lx200.GET_PRODUCT), mount_mock.PRODUCT)
|
|
|
|
def test_unbekanntes_kommando_haengt_nicht(self):
|
|
# Muss eine (leere) abgeschlossene Antwort liefern, nicht blockieren.
|
|
self.assertEqual(self.client.query(":GXYZ#"), "")
|
|
|
|
|
|
class TestClientFehler(unittest.TestCase):
|
|
|
|
def test_verbindung_verweigert(self):
|
|
# Port, auf dem nichts lauscht
|
|
c = MountClient("127.0.0.1", 1, timeout=0.5)
|
|
with self.assertRaises(MountError):
|
|
c.connect()
|
|
|
|
def test_query_ohne_verbindung(self):
|
|
c = MountClient("127.0.0.1", 3490)
|
|
with self.assertRaises(MountError):
|
|
c.get_ra()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main(verbosity=2)
|