Every guide I found stops at “use the 12864 emulation menu” or “just use KlipperScreen”. I wanted the actual colour Touch UI on my BTT TFT35 E3 V3 with a real progress bar for prints started from Mainsail — so I wrote a proper bridge and open-sourced it:
https://github.com/oterek/klipper-btt-tft-bridge
Single Klipper extras module (no socat, no extra daemon). Fixes the classic stuff:
ACK timed out / pending gcode released → gone (usual bridges send a double ok; this sends exactly one).
Temps / position / feed / flow answered locally from Klipper’s object model.
G28 / heating / bed mesh kept alive with busy: processing (no timeout while homing).
Marlin->Klipper translations (G29->BED_MESH_CALIBRATE, pause/resume/cancel…).
Print progress for host-started prints — the bit nobody had cracked.
The trick: the TFT only polls M27 once it thinks a print is active, and M27_always_active doesn’t actually start it while idle. Digging through the firmware source, an unsolicited File opened: Size: flips the TFT into its print screen and starts M27 polling — so the bridge watches Klipper’s print_stats and sends that on print start. You also need onboard_sd:1 in the TFT config.ini.
Setup: drop tftbridge.py in klippy/extras/, add a tiny [tftbridge] section, set ~4 keys in the TFT
config.ini, restart + power-cycle the TFT. Full README in the repo.
Tested: Ender 3 Pro, SKR Mini E3 V3, Klipper 0.13, Pi Zero 2 W, TFT35 E3 V3.0 GD, CH340 USB-TTL u/115200.
Known limitation: a host Klipper restart drops the serial ~9 s > the TFT’s ~5 s ACK timeout → one modal ACK timed out to dismiss. Restarting just the printer/MCU is fine. A separate-process version would be fully restart-proof
-– PRs welcome. Would love testers on other BTT TFTs (24/28/35/43/50)!