10 Zeichen pro Zeile: Zellenbreite am Geraet gemessen, Zeilen zentriert

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>
This commit is contained in:
2026-07-27 15:56:15 +02:00
parent 42fc7f52d4
commit 4f7375add3
8 changed files with 292 additions and 106 deletions
+52 -32
View File
@@ -191,6 +191,8 @@ festgehalten sind (`test_esp32.py`, `test_display.py`):
- **Feste Anzeigetexte müssen in `CHARS_PER_LINE` passen.** `NOLINK_LINES` hieß
zuerst „MONTIERUNG" (10 Zeichen) und erschien als „MONTIERUN"; `_emit_line`
schneidet stillschweigend ab. `test_display.py` prüft die Breite jetzt.
(Seit `CHARS_PER_LINE = 10` würde „MONTIERUNG" wieder passen — die Texte sind
aber bei „KEIN LINK"/„TELESKOP" geblieben.)
Was MicroPython 1.28 entgegen der Erwartung **doch** kann (am Gerät nachgeprüft):
`%0*d` mit dynamischer Feldbreite, `%-11s`, `bytes.hex()`, `str.strip`/`lstrip`,
@@ -245,9 +247,6 @@ Mac:
## Offene Punkte
- **RS232-Strecke zur Anzeige.** Als einziges Stück der Kette noch nicht am
ESP32 erprobt: Der Aufbau mit MAX3232 und Anzeige fehlt. Alles davor ist
bestätigt, die Telegramme stimmen byteweise — es geht nur noch um die Pegel.
- **LDR-Schwellen nachmessen.** Die Grenzen in `brightness.py` stammen vom alten
MSP430-Aufbau. Sobald der LDR am ESP32 hängt, die Rohwerte bei Tag und Nacht
ablesen und `HELL_LOW`/`HELL_HIGH`/`HELL_MAX` anpassen. Bis dahin läuft die
@@ -265,40 +264,55 @@ Gradzeichen (deckt sich mit dem alten Programm, `asciitaf.h`: Code 0xAF → per
`& 0x7F` = 0x2F in Zeichensatz 1). Zur Ausgabe wird für dieses eine Zeichen kurz
auf Zeichensatz 1 umgeschaltet und wieder zurück (`config.DEGREE_*`, `display._emit_degree`).
**Fallstrick:** Ein Zeichensatzwechsel mitten im Telegramm beschädigt die Home-Zelle
(0,0) — das erste Zeichen der obersten Zeile wird zerstört. Deshalb zeichnet
`show_lines` die Zeilen **von unten nach oben** (oberste Zeile zuletzt), damit sie
diese Zelle überschreibt.
**Fallstrick:** Ein Zeichensatzwechsel beschädigt die Home-Zelle (0,0) — das erste
Zeichen der obersten Zeile wird zerstört. Deshalb schreibt `show_lines` die Zeilen
**von unten nach oben** (oberste Zeile zuletzt), damit sie diese Zelle überschreibt.
Das gilt weiterhin, seit jede Zeile ihr eigenes Telegramm bekommt: dann entscheidet
die Reihenfolge der Telegramme statt der Reihenfolge innerhalb eines Telegramms.
## Geometrie und Darstellung
- **9 Zeichen pro Zeile** in Sperrschrift (`CHARSET_SPACED = True`, am Gerät
ausgemessen 2026-07-15).
- **10 Zeichen pro Zeile zu 6 px** (`CHARS_PER_LINE = 10`, `CELL_WIDTH = 6`), am
Gerät entschieden mit `probe.py pitch 6` (2026-07-27).
Das widerspricht der naheliegenden Rechnung: Die Anzeige ist 64 px breit, und
eine 5×7-Matrix mit 1 px Lücke wäre 6 px pro Zelle — das gäbe 10 Zeichen
(60 px). Die Erklärung ist vermutlich, dass die Sperrschrift eben sperrt:
bei 2 px Lücke sind es 7 px pro Zelle und damit 9 Zeichen (63 von 64 px).
Dazu passt auch die Beobachtung, dass die *proportionale* Schrift `ESC Z`
rund 11 Zeichen schafft (≈ 5,8 px/Zelle).
Vorher stand hier 9 — das war am Zeilenumbruch abgezählt und maß etwas
anderes, als es zu messen schien. `probe.py pitch` stellt den Auto-Vorschub
der Anzeige gegen feste Pixelpositionen `x = i·cell` und trennt damit beides:
**Nachgeprüft ist das nicht.** `probe.py pitch` entscheidet es direkt, statt
am Umbruch abzuzählen: Es schreibt zehn Ziffern einmal mit dem Auto-Vorschub
der Anzeige und einmal auf feste Pixelpositionen `x = i·cell`. Ein Unterschied
von 1 px summiert sich über zehn Zeichen auf 9 px und ist unübersehbar.
- Der **Auto-Vorschub** der Sperrschrift `ESC z` ist **7 px**. Eine Zeile in
einem Stück geschrieben bricht deshalb nach 9 Zeichen um (9·7 = 63 von 64 px).
- Die **Zeichenmatrix** ist aber nur **6 px** breit. Zehn Ziffern, einzeln auf
`x = i·6` gesetzt, stehen sauber getrennt nebeneinander (60 von 64 px).
Deshalb positioniert `display._emit_line` jedes Zeichen selbst, statt den
Auto-Vorschub laufen zu lassen. Der Preis sind längere Telegramme (rund 10 Byte
je Zeichen statt 1), der Gewinn ein volles Zeichen mehr pro Zeile.
```bash
python3 probe.py pitch 6 # stehen beide Zeilen untereinander -> 10 Zeichen
python3 probe.py pitch 7 # ... -> 9 Zeichen
python3 probe.py pitch 6 # stehen beide Zeilen untereinander -> 6 px/Zelle
python3 probe.py pitch 7 # ... -> 7 px/Zelle
```
Sollten es doch 6 px sein, passt die Deklination mit abschließendem `"` in
voller Form (`+38°47'01"`, 10 Zeichen) — `coords.format_dec` wählt sie dann
von selbst, es genügt `CHARS_PER_LINE = 10`.
- Die Deklination wird deshalb als **9-Zeichen-Form ohne abschließendes `"`**
ausgegeben (`+38°47'01`) — Gradzeichen und Bogenminuten bleiben, die Bogensekunden
stehen als Ziffern da. `coords.format_dec` wählt automatisch die breiteste Form,
die in `CHARS_PER_LINE` passt.
- **Ein Telegramm je Zeile.** Früher gingen beide Zeilen in einem Telegramm raus.
Mit Einzelpositionierung kämen sie mit Gradzeichen und Vollbild-Löschen auf
224 der erlaubten 230 Bytes (`migra.MAX_DATA_UNIT`) — zu wenig Reserve für ein
Gerät, das monatelang durchläuft. Getrennte Telegramme halten jedes bei rund
der Hälfte; die Flusskontrolle über das Antworttelegramm macht die zweite
Sendung unproblematisch. Die Reihenfolge bleibt **unten vor oben** (Home-Zelle).
- Die Deklination passt damit in **voller Form mit abschließendem `"`**
(`+38°47'01"`, 10 Zeichen). `coords.format_dec` wählt automatisch die breiteste
Form, die in `CHARS_PER_LINE` passt — bei Niedrigpräzision entsprechend
`+38°47'` ohne Sekunden.
- **Zeilen werden zentriert** (`CENTER_LINES = True`). Das wirkt auf zwei Ebenen:
`LINE_X` rückt den Zeichenblock in die Mitte (10·6 = 60 px lassen je 2 px Rand),
und kürzere Texte werden beidseitig mit Leerzeichen aufgefüllt. Der Block bleibt
dabei immer gleich breit und an derselben Stelle — so überschreibt er bei jedem
Durchlauf denselben Bereich und lässt keine Reste stehen. Ein pixelgenau
mitwandernder Offset könnte das nicht; dafür ist die Zentrierung nur auf eine
halbe Zelle (3 px) genau, wenn die Restbreite ungerade ist.
- **Zyklische Updates flimmerfrei:** `show_lines` löscht nicht bei jeder Aktualisierung,
sondern überschreibt die Zeilen an Ort und Stelle (auf volle Breite aufgefüllt).
`clear=True` nur beim ersten Bild. Wichtig: Zeilen dürfen **nicht breiter** als
@@ -380,12 +394,18 @@ gegeneinander (verschliffener ~3-V-Pegel am Oszi). `loopback.py` grenzt so etwas
## Erledigt
- **RS232-Strecke ESP32 → MAX3232 → Anzeige bestätigt (2026-07-27).** Das war das
letzte ungetestete Kettenglied. Die Anzeige quittiert jedes Telegramm mit
Fehlercode 0, die volle Kette (Mock → WLAN → ESP32 → UART1 → MAX3232 → Anzeige)
läuft im Sekundentakt ohne Aussetzer. Damit ist die Portierung funktional
komplett; offen sind nur noch Betriebsthemen (LDR, Netzwerk, Autostart).
- **Phase 1 + 2 am Gerät bestätigt (2026-07-15/16):** Koordinaten erscheinen korrekt,
inkl. echtem Gradzeichen; im `run_display`-Betrieb aktualisieren beide Zeilen
laufend, sauber und ohne Flimmern, mit Antwort-Handshake der Anzeige. Protokoll,
19200 8E1, Zeichensatz und Zeilengeometrie stimmen.
- Schrift: Sperrschrift (`ESC z`, `CHARSET_SPACED = True`), 9 Zeichen/Zeile.
(Hier stand ursprünglich „10 Zeichen/Zeile" — das war die Annahme vor der
Messung vom 15.07., siehe *Geometrie und Darstellung*.)
Die schmale `1` wirkt dadurch etwas luftig — Font-Eigenschaft, nur per eigenem
- Schrift: Sperrschrift (`ESC z`, `CHARSET_SPACED = True`), **10 Zeichen/Zeile**
bei fester Positionierung auf 6 px (gemessen 27.07., siehe *Geometrie und
Darstellung*). Zwischenzeitlich stand hier 9 — das war am Umbruch abgezählt und
traf den Auto-Vorschub (7 px), nicht die Zeichenbreite.
Die schmale `1` wirkt etwas luftig — Font-Eigenschaft, nur per eigenem
Font (microSYST-PC-Software) änderbar.