Files
PrintControl/README.md

225 lines
10 KiB
Markdown

# printcontrol
A keyboard-driven TUI for monitoring and controlling a 3D printer over USB
serial. One static Go binary, zero runtime dependencies, theme-aware via
your terminal's 16-colour palette — designed to feel at home on Omarchy
alongside `wiremix`, `lazygit`, `lazydocker`, and friends.
The model: **the printer is in charge during an SD print, we observe and
adjust.** Start a print from the LCD, the SD card, or printcontrol's own
SD picker — then live-monitor temps, progress, and ETA, and tweak feedrate,
flow, fan, hotend / bed setpoints, or babystep Z without ever leaving the
keyboard. Quit and come back later; the printer keeps printing and
printcontrol rediscovers the in-progress job on reconnect.
```
┌─ printcontrol · 3D printer TUI ────────────────────────────────────────┐
│ ● Status │ ● Temperatures │
│ Connection: /dev/ttyUSB1 @ 115200 │ Hotend: 201.3 / 210.0 °C │
│ · Marlin 2.1.2 │ Bed: 60.2 / 60.0 °C │
│ File: benchy.gcode SD PRINT │ │
│ Progress: [██████████··········] │ set hotend: [h] │
│ ETA: 1h 12m │ set bed: [b] │
├─────────────────────────────────────┴────────────────────────────────────┤
│ ● Controls │
│ Feedrate: 110% [-/+] [0] Flow: 100% [ [ / ] ] Fan: 30% [f/F] │
│ Babystep Z: -0.050 [{ / }] [Z] │
│ press [g] to send raw G-code │
├──────────────────────────────────────────────────────────────────────────┤
│ ● Log │
│ > M105 │
│ < ok T:201.3 /210.0 B:60.2 /60.0 @:127 B@:0 │
├──────────────────────────────────────────────────────────────────────────┤
│ [c] connect [d] disconnect [s] sd start [p] pause [r] resume [x] cancel │
│ [h] hotend [b] bed [g] gcode [q] quit │
└──────────────────────────────────────────────────────────────────────────┘
```
## Install
Build from source — needs Go 1.22+. The repo's canonical install target is
`~/.local/bin` (matches Omarchy's PATH); adjust `GOBIN` if you want it
elsewhere.
```bash
cd go
GOBIN=$HOME/.local/bin go install ./cmd/printcontrol
```
You need permission to open the serial port. On Arch / Omarchy that means
membership in the `uucp` group:
```bash
groups | grep -q uucp || sudo usermod -aG uucp "$USER" # then log out and back in
```
Verify the printer is visible:
```bash
ls /dev/ttyACM* /dev/ttyUSB* 2>/dev/null
```
## Run
```bash
printcontrol # auto-detect port AND baud
printcontrol -port /dev/ttyUSB1 # lock the port, still auto-baud
printcontrol -port /dev/ttyUSB1 -baud 250000
printcontrol -no-connect # launch without touching serial
```
### Flags
| Flag | Default | Description |
|---------------|----------|----------------------------------------------------------|
| `-port` | *(auto)* | Serial device path. Scans `/dev/ttyACM*` + `/dev/ttyUSB*` if empty. |
| `-baud` | `0` | Baud rate. `0` = auto-detect from `[250000, 115200, 230400, 500000, 57600]`. |
| `-no-connect` | `false` | Skip auto-connect on launch. |
### Auto-detect
With no flags, printcontrol scans every plausible serial device and probes
each candidate baud until something replies with an unmistakably
printer-shaped line (`Marlin`, `FIRMWARE_NAME`, `RepRapFirmware`, `Klipper`,
or a `T:.../...` temperature report). Two-letter tokens like `"ok"` are
*not* accepted as a match because they appear too easily in
misaligned-baud garbage. Worst-case probe time is ~15 s; first match wins
and the rest are skipped.
The connect flash at the bottom of the screen reports the chosen
combination — e.g. `connected: /dev/ttyUSB1 @ 115200`.
### Keys (top-level)
| Key | Action |
|-----------|-----------------------------------------|
| `c` | Connect / reconnect |
| `d` | Disconnect |
| `s` | List SD card and pick a file to print |
| `p` | Pause SD print (`M25`) |
| `r` | Resume (`M24`) |
| `x` | Cancel SD print (`M524`) |
| `h` | Focus hotend setpoint input |
| `b` | Focus bed setpoint input |
| `g` | Focus raw G-code input |
| `+` / `-` | Feedrate ±10% |
| `0` | Feedrate back to 100% |
| `[` / `]` | Flow ±5% (`M221`) |
| `f` / `F` | Fan ±10% |
| `{` / `}` | Babystep Z ∓0.05 mm (`M290`, Marlin) |
| `Z` | Reset babystep to zero |
| `q` | Quit |
When a text input is focused: type the value, `Enter` to commit, `Esc` to
cancel.
### SD start workflow (key: `s`)
1. Press `s`. printcontrol sends `M21` (mount SD) and `M20` (list files).
2. A picker appears in place of the Log panel.
3. `↑`/`↓` (or `k`/`j`) to highlight, `Enter` to start the print, `Esc` to
dismiss without printing.
4. Selecting a file sends `M23 <filename>` then `M24`. The print runs from
the SD card, autonomously of printcontrol.
5. You can `q` immediately after — the printer doesn't care. Reconnect any
time; the `M27` poll discovers the in-progress print within ~5 seconds
and Status / Progress / ETA repopulate.
Notes:
- The picker shows the long filename if the firmware reports one, but
always passes the **short 8.3 name** to `M23` (that's what Marlin
requires).
- Nested folders are listed but can't currently be entered. File a request
if you need it.
## Register with the Omarchy launcher
Once you're happy with it, drop a desktop entry so SUPER+SPACE finds it:
```bash
omarchy-tui-install printcontrol printcontrol float <icon-url>
```
`float` makes Hyprland treat it as a floating window — usually the right
call for a single-pane TUI. Switch to `tile` if you'd rather have it in
your tiling layout.
## What works · what doesn't
**Works today**
- Auto-detect serial port and baud rate
- Connect / disconnect over USB serial (multi-port scan)
- Live temperatures (hotend, bed, chamber if present) every 2 s
- SD-card print detection, progress %, ETA
- SD card file listing (`M20`) and start (`M23` + `M24`) from the TUI
- Pause / resume / cancel (`M25` / `M24` / `M524`)
- Temperature setpoints (`M104` / `M140`)
- Fan, feedrate, flow controls (`M106` / `M220` / `M221`)
- Babystep Z (`M290` — Marlin)
- Raw G-code entry
- Firmware identification (`M115`)
- Adaptive log panel (footer stays visible on short terminals)
**Not yet**
- Host-side print streaming (sending a `.gcode` file from the computer).
Needs the line-numbered protocol with checksum + resend handling.
- Klipper-specific babystep (`SET_GCODE_OFFSET`). Sends `M290` today, which
Klipper rejects.
- SD folder navigation (`M20 <dir>`).
- Octoprint / Moonraker backends. Architecture supports it; see
`ARCHITECTURE.md`.
- Persisted profiles (per-printer last setpoints, preferred port).
## Troubleshooting
**"no responsive printer on \[...]"** — Auto-detect probed every
`ttyACM`/`ttyUSB` device at every common baud and didn't find a printer
signature. Most often this means another program (OctoPrint, Klipper's
`klippy`, `pronsole`) already owns the port. Quit it first, or pass
`-port` explicitly. If you have an unusual baud (e.g. `1000000`), pass
`-baud` to override the probe.
**"could not auto-detect baud rate"** — printcontrol *opened* the port but
saw no recognisable reply at any candidate baud. Confirm the device is
actually a printer (`screen /dev/ttyUSB1 115200`, then send `M115`); also
common: the printer is mid-firmware-flash, or the USB cable is power-only.
**Temps show but progress stays at 0%**`M27` only reports SD progress.
If you started the print from a host (OctoPrint, etc.) progress won't
appear here.
**Babystep does nothing** — You're likely on Klipper, which doesn't
implement `M290`. Klipper support is on the roadmap.
**Mangled lines like `TT::57.4957.49`** — This was the symptom of Marlin's
auto-temperature report colliding with our explicit `M105` poll. Fixed
upstream: the prime block now sends `M155 S0` / `M27 S0` to disable
auto-reports.
## Layout
```
printcontrol/
├── go/
│ ├── cmd/printcontrol/main.go # entry point, flag parsing
│ ├── internal/printer/ # serial driver + G-code state machine
│ │ ├── state.go # State / PrintState / TempPair / SDFile
│ │ ├── parse.go # line parsing (M105, M27, M115, M20, ...)
│ │ ├── printer.go # Connect/Disconnect, owning goroutine, probe
│ │ └── parse_test.go
│ └── internal/tui/ # Bubble Tea model + Lipgloss styling
│ ├── model.go # Model, key handling, SD picker, layout
│ └── style.go
├── README.md
└── ARCHITECTURE.md # protocol + design notes
```
See `ARCHITECTURE.md` for the wire protocol, the state model, the
auto-detect probe strategy, and why things are wired the way they are.
## License
GPL-3.0-or-later (matches Printrun, which inspired the protocol layer).