225 lines
10 KiB
Markdown
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).
|