bergclimber.deTURZX-Display

TURZX USB-Display selbst ansteuern

9,2-Zoll-USB-Bildschirm (TURZX / Turing Smart Screen) unter Linux, Raspberry Pi und macOS: Protokoll, die fünf Fallen, ein Python-Skript zum Mitnehmen und ein Testbild direkt aus dem Browser.

Im Browser testen

Beta · WebUSB

Display per USB-C anstecken, verbinden, Testbild senden. Der Browser fragt einmal, welches Gerät er nutzen darf. Unter Linux braucht es die udev-Regel (siehe Anleitung), unter Windows einen WinUSB-Treiber per Zadig, unter macOS nichts.

35 %

Ohne Verbindung wird nur die Vorschau gerendert.

Vorschau 1920×462 (so liegt es quer im Gehäuse)

Gesendet wird ein JPEG 464×1920, also um 90° gedreht und auf ein Vielfaches von 8 gepolstert. Modelle: 2.8" rund, 4.6", 5.2", 8.0", 8.8", 9.2" ✓, 12.3". Erkennung über die USB-Produkt-ID.

Stand: Der Protokollteil ist am 9,2"-Modell seit Monaten im Dauerbetrieb (Python). Der WebUSB-Pfad dieser Seite wurde dagegen noch nicht am Gerät ausprobiert, nur die erzeugten Pakete sind Byte für Byte mit dem laufenden Python-Dienst abgeglichen. Zeigt das Display nach „Testbild" nichts oder Unsinn: USB-Kabel ziehen, neu einstecken, nochmal. Rückmeldung gern an contact@bergclimber.de.

Worum es geht

Die TURZX-Displays (baugleich mit „Turing Smart Screen", USB-Vendor-ID 0x1CBE) sind schmale IPS-Bildschirme, die per USB-C Strom und Bild bekommen und eigentlich als PC-Statusanzeige gedacht sind. Die Hersteller-Software gibt es nur für Windows. Wer das Display an einen Raspberry Pi, einen Linux-Server oder einen Mac hängen will, muss das Protokoll selbst sprechen. Es ist einfach: ein 500-Byte-Kommandokopf, DES-verschlüsselt mit einem festen Schlüssel, danach ein JPEG. Die Details stehen unten, inklusive der fünf Dinge, die beim ersten Versuch garantiert schiefgehen.

Verifiziert ist das alles am 9,2"-Modell (1920×462, Produkt-ID 0x0092), das seit Monaten an einem Pi 5 als Dashboard läuft. Für die Schwestermodelle (4,6", 5,2", 8", 8,8", 12,3") nutzt die Bibliothek turing-smart-screen-python dasselbe Protokoll; dort ist nur die Auflösung anders.

Schnellstart auf Linux / Raspberry Pi

# 1. Prüfen, ob das Display erkannt wird
lsusb | grep 1cbe
#   Bus 002 Device 002: ID 1cbe:0092 Luminary Micro Inc. TURZX1.0

# 2. Zugriff ohne root: udev-Regel, danach Kabel neu einstecken
sudo curl -o /etc/udev/rules.d/99-turzx.rules https://bergclimber.de/turzx/dl/99-turzx.rules
sudo udevadm control --reload-rules && sudo udevadm trigger

# 3. Abhängigkeiten und Skript
pip3 install pyusb pillow pycryptodome          # Debian/RPi OS evtl. --break-system-packages
curl -o turzx.py https://bergclimber.de/turzx/dl/turzx.py

# 4. Testbild
python3 turzx.py --brightness 40 test
python3 turzx.py image foto.jpg
python3 turzx.py text "Hallo\nWelt"

Auf dem Mac genügt brew install libusb vor dem pip-Schritt, eine udev-Regel gibt es dort nicht. Auf Windows braucht pyusb einen WinUSB-Treiber für das Gerät (Zadig), das ist aber nicht der Weg, für den diese Seite gedacht ist.

Die fünf Fallen

1. Die Init-Sequenz ist Pflicht

Ohne die Kommandos 111, 112, 13 und 41 nach dem Verbinden werden eigene Bilder halbtransparent über das Werks-Theme gelegt. Reihenfolge: 10 (Sync) → 111 (Bulk-Video-Modus, schaltet Theme-Ebene 1 ab) → 112 (Partial-Modus aus, Theme-Ebene 2) → 13 (Cache leeren) → 41 (Raw-Image-Modus, ohne Parameter).

2. Immer JPEG, nie PNG

PNG (Kommando 102) wird vom Display als Overlay mit Alphakanal composited, alte Inhalte scheinen durch. JPEG (Kommando 101) überschreibt den Framebuffer vollständig.

3. 464 statt 462 Pixel

Das 9,2"-Panel hat 462 Pixel auf der kurzen Seite, JPEG arbeitet aber in 8×8-Blöcken. 462 Pixel ergeben Artefakte am linken Rand, 468 oder 480 Artefakte rechts. Mit 464 (je ein schwarzer Pixel oben und unten) ist es beidseitig sauber. Allgemein: kurze Seite auf das nächste Vielfache von 8 polstern.

4. 90° drehen

Das Panel ist nativ hochkant (462×1920), im Gehäuse liegt es quer. Das Querformatbild muss um 90° im Uhrzeigersinn gedreht werden (PIL: ROTATE_270), sonst steht alles auf dem Kopf oder quer.

5. Ghosting nach Neustart

Nach einem Neustart des eigenen Dienstes bleibt der alte Inhalt im Display-Puffer. Direkt nach der Init-Sequenz ein schwarzes JPEG senden. Hält sich ein Geisterbild hartnäckig: USB-Kabel ziehen, fünf Sekunden warten, wieder einstecken.

Wenn es trotzdem komisch aussieht

  • Werks-Hintergrund scheint durch: Init-Sequenz fehlt oder PNG statt JPEG. Dienst neu starten, notfalls Kabel ziehen.
  • Bild vierfach gestapelt: Kommando 41 wurde mit Parametern gesendet (z. B. MADCTL). 41 muss ohne Parameter raus.
  • „Resource busy": ein anderer Prozess hält das USB-Interface. Alte Instanz beenden, kurz warten.
  • Gar nichts: Kabel oder Port wechseln; manche USB-C-Kabel führen nur Strom. Das Display zieht bis 1,6 W.

Das Python-Skript

turzx.py ist ein einzelnes Skript ohne Konfiguration: es erkennt das Modell über die Produkt-ID, polstert und dreht das Bild passend und spricht nur die fünf Init-Kommandos, Helligkeit und JPEG-Upload. Abhängigkeiten: pyusb, pillow, pycryptodome. Playwright nur für den Webseiten-Modus.

turzx.py test                           Testbild
turzx.py image foto.jpg [--fit contain] Bild (Standard: füllen und beschneiden)
turzx.py text "Zeile 1\nZeile 2"        Textkarte
turzx.py clear                          schwarz
turzx.py brightness 40                  Helligkeit 0–100
turzx.py url http://localhost:3000/     Webseite als Screenshot-Loop, --interval 2
                                        (pip3 install playwright && playwright install chromium)

Als Dienst (Dashboard-Betrieb)

Für ein Dashboard rendert der url-Modus eine beliebige Webseite in Chromium headless und schiebt alle zwei Sekunden einen Screenshot aufs Display. Ein Pi 5 ist damit praktisch unbelastet (Screenshot ~0,3 s, USB ~0,2 s, ~30 MB RAM). Beispiel-Unit: turzx.service, udev-Regel: 99-turzx.rules.

sudo mkdir -p /opt/turzx && sudo cp turzx.py /opt/turzx/
sudo curl -o /etc/systemd/system/turzx.service https://bergclimber.de/turzx/dl/turzx.service
sudo nano /etc/systemd/system/turzx.service      # User= und URL anpassen
sudo systemctl daemon-reload && sudo systemctl enable --now turzx
journalctl -u turzx -f

Zwei Lehren aus dem Dauerbetrieb: Playwright nicht mit wait_until="networkidle" laden, wenn die Seite selbst pollt (der Loop hängt dann in Timeouts, bei uns zwölf Stunden eingefrorenes Display). Und nicht pro Frame neu laden, nur screenshotten; ein Reload alle paar Minuten als Hygiene reicht. Wer es ganz robust will, gibt dem Dienst einen systemd-Watchdog.

Protokoll-Referenz

Reines USB-Bulk auf Interface 0, ein OUT- und ein IN-Endpunkt. Jedes Kommando ist ein 512-Byte-Paket, bei Bildern folgt der JPEG-Payload in demselben Transfer. Das Display antwortet mit 512 Bytes, Byte 1 oder Byte 8 = 0xC8 (200) heißt OK; die Antwort kann man lesen und verwerfen.

Paketaufbau

Klartext-Header, 500 Bytes, mit Nullen gefüllt:
  [0]      Kommando-ID
  [2..3]   Magic 0x1A 0x6D
  [4..7]   Zeitstempel: Millisekunden seit lokaler Mitternacht, Little-Endian
  [8..11]  nur bei 101/102: Payload-Größe, Big-Endian
  [8]      nur bei 14: Helligkeit 0–102

→ DES-CBC verschlüsseln, Key = IV = "slv3tuzx" (Null-Padding auf 504 Bytes)
→ in 512 Bytes legen, Bytes 510/511 = 0xA1 0x1A
→ danach bei 101: die rohen JPEG-Bytes anhängen

Kommandos

IDBedeutungParameter
10Sync / Handshake—
13Cache leeren—
14HelligkeitByte 8 = 0–102 (entspricht 0–100 %)
41Raw-Image-Modusohne Parameter senden
101JPEG-UploadBytes 8–11 = Größe, Big-Endian; JPEG folgt direkt nach dem 512-Byte-Paket
102PNG-Uploadnicht verwenden (Alpha-Compositing)
111Bulk-Video-Modus an— (schaltet Werks-Theme ab)
112Partial-Modus aus—

Init-Sequenz und Bild-Pipeline

Verbinden:  10 → 111 → 112 → 13 → 14 (Helligkeit) → 41 → schwarzes JPEG

Bild (9,2"): Querformat 1920×462
  → auf 1920×464 polstern (1 px schwarz oben und unten)
  → 90° im Uhrzeigersinn drehen (PIL ROTATE_270) → 464×1920
  → JPEG, Qualität 90, typisch 70–150 KB
  → Header 101 mit Größe + JPEG in einem Bulk-Write

Modelle (Vendor-ID 0x1CBE)

Produkt-IDModellnativ (hochkant)JPEG-MaßStatus
0x00282.8" rund480×480480×480laut Bibliothek, hier ungetestet
0x00464.6"320×960320×960laut Bibliothek, hier ungetestet
0x00505.2"720×1280720×1280laut Bibliothek, hier ungetestet
0x00808.0"800×1280800×1280laut Bibliothek, hier ungetestet
0x00888.8"480×1920480×1920laut Bibliothek, hier ungetestet
0x00929.2"462×1920464×1920am Gerät verifiziert
0x012312.3"720×1920720×1920laut Bibliothek, hier ungetestet

Quelle des Protokollwissens: eigenes Mitschneiden plus die Bibliothek turing-smart-screen-python (GPL-3.0), die diese Modelle inzwischen als „Turing USB" unterstützt und zusätzlich H.264-Video, Dateiablage und das Werks-Theme kann. Wer das volle Monitoring-Programm will, nimmt die Bibliothek. Wer nur ein Bild oder eine Webseite aufs Display will, kommt mit den acht Kommandos oben aus.

Häufige Fragen

Funktioniert das TURZX-Display am Raspberry Pi?

Ja. Das 9,2"-Modell läuft hier an einem Pi 5 im Dauerbetrieb als Dashboard. Benötigt werden nur Python 3 mit pyusb, pillow und pycryptodome sowie eine udev-Regel für den Zugriff ohne root. Für den Webseiten-Modus zusätzlich Playwright mit Chromium.

Gibt es die TURZX-Software für Linux oder Mac?

Nein, vom Hersteller nur für Windows. Das Skript auf dieser Seite und die Bibliothek turing-smart-screen-python ersetzen sie für Bilder, Text und Webseiten. Die Themes und Animationen der Windows-App gibt es damit nicht.

Das Display zeigt mein Bild nur halb durchsichtig über dem Werksbild. Warum?

Die Init-Sequenz fehlt (Kommandos 111, 112, 13, 41) oder es wurde ein PNG statt JPEG gesendet. Siehe „Die fünf Fallen".

Warum 464 Pixel, wenn das Display 462 hat?

JPEG kodiert in 8×8-Blöcken. Bei 462 Pixeln ist der letzte Block unvollständig und das Display rendert einen Streifen am Rand. 464 Pixel mit je einem schwarzen Pixel oben und unten sind sauber.

Welches USB-C-Kabel?

Ein Kabel, das Daten führt, nicht nur Strom. Das Display braucht bis zu 1,6 W, ein USB-2-Port reicht. Erkennbar ist es dann als „Luminary Micro Inc. TURZX1.0" in lsusb.

Kann ich das Display als zweiten Monitor nutzen?

Nicht als echten Monitor: es gibt keine Bildschirmerweiterung, sondern nur Bild-Uploads per USB. Mit etwa zwei Bildern pro Sekunde taugt es für Dashboards, Statusanzeigen und Fotos, nicht für Video oder Mausbedienung.

Was passiert mit dem Browser-Werkzeug, wenn ich ein anderes Modell anschließe?

Es erkennt die Produkt-ID und wählt die Auflösung aus der Tabelle. Das Protokoll ist laut Bibliothek gleich, geprüft ist hier aber nur das 9,2"-Modell. Rückmeldungen zu anderen Modellen sind willkommen.

Werden Daten übertragen oder gespeichert?

Nein. Das Browser-Werkzeug rendert und sendet alles lokal per WebUSB. Die Seite lädt keine Skripte von Dritten und setzt keine Cookies.