BTT TFT35 in Touch Mode on Klipper — full functionality incl. host print progress (no more "ACK timed out")

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:

  • :cross_mark: ACK timed out / pending gcode released → gone (usual bridges send a double ok; this sends exactly one).
  • :thermometer: Temps / position / feed / flow answered locally from Klipper’s object model.
  • :hourglass_not_done: G28 / heating / bed mesh kept alive with busy: processing (no timeout while homing).
  • :repeat_button: Marlin->Klipper translations (G29->BED_MESH_CALIBRATE, pause/resume/cancel…).
  • :white_check_mark: 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)!

Welcome garagescunny,

nice work, thanks. One thing. Your tftbridge.py should lead to a “dirty” flag in the klippy.log. You might consider to mention that in your Github repository.
You might also consider to open a Klipper PR (see also Contributing to Klipper - Klipper documentation ). Let’s see what others think.

Thanks @hcet14, and cheers for the welcome! :slightly_smiling_face:
Good catch on the -dirty flag — you’re right. Dropping tftbridge.py into klippy/extras/ leaves
an untracked file in Klipper’s git repo, so Moonraker reports the version as …-dirty and its
update manager can balk at auto-updating Klipper. I’ve added a note to the README with the fix
— tell git to ignore the module locally:
echo ‘klippy/extras/tftbridge.py’ >> ~/klipper/.git/info/exclude
(and keep any backup copies outside klippy/extras/, since leftover files dirty the repo the
same way). Thanks for flagging it.
On a PR to mainline Klipper — appreciate the nudge, and I’ll read the contribution guidelines.
My hunch is that a device-specific bridge for a third-party touchscreen is unlikely to land
in core Klipper (that kind of thing usually stays as an external/community module), so the
standalone repo is probably the right home — but happy to be told otherwise by folks who know
the project’s direction. Open to ideas!

Thanks again for the thoughtful feedback. :folded_hands:

Really, that works?

Keeping Klipper’s git repo clean (avoid the -dirty flag)

Copying tftbridge.py into klippy/extras/ adds an untracked file to Klipper’s git repo, so Moonraker reports the Klipper version as …-dirty and its update manager may refuse to auto-update Klipper. Tell git to ignore the module locally:

echo 'klippy/extras/tftbridge.py' >> ~/klipper/.git/info/exclude

Also keep any backup copies (tftbridge.py.bak, …) outside klippy/extras/ — leftover files there dirty the repo the same way.

GitHub - oterek/klipper-btt-tft-bridge: Klipper <-> BigTreeTech TFT Touch Mode bridge with host print progress (fixes ACK timed out, no extra daemon) · GitHub

if yes, amazing!