My 3D Printer Was Already Printing. I Just Wanted It in My Terminal.

Published on HivePostify by @tipy · Sat Sep 05 2026

> Vibe-coded project: I built this tool through an iterative conversation with an AI coding assistant. I described what I wanted, ran the results against my printer, and asked for changes. The assistant wrote and revised the code. This is a personal experiment, not an official Elegoo application or a production-ready tool.

The slicer was open. My Elegoo Centauri Carbon was printing. I also had a web page open with the printer’s status.

Everything I needed was already available, but I kept switching away from my terminal to check it. How far along was the print? How much time was left? Did everything still look okay?

I spend a lot of my time in the terminal. Having the printer’s status there felt natural. I wanted to glance at it, then carry on with what I was doing. And when the print finished, I wanted a notification so I could go collect it.

It was a small annoyance, and exactly the kind of personal tool I might normally put off building. Useful, yes, but did I really want to spend time working on it?

This time, I opened a conversation with Codex, using GPT-6 Astra.

The first request was simply to get the printer’s status in the CLI. Once that worked, I wanted a proper TUI. Then a progress bar. Then colors. Then I remembered the printer had a camera.

The scope grew one “can we also…” at a time.

Step 1: Read the printer’s status ---------------------------------

The AI chose pycentauri, which provides a CLI and a Python API for communicating with the printer. My printer’s local address is 192.168.2.89; replace that with your own IP if you try the commands.

First, we checked that we could retrieve its status:

centauri status --host 192.168.2.89

Then we watched for updates:

centauri watch --host 192.168.2.89

It worked. The printer was talking to the terminal.

That gave us a useful starting point: the connection and data were available, so the custom code could focus on presentation and notifications.

On the Python side, the basic connection looks like this:

async with await Printer.connect(host) as printer: st = await printer.status()

The returned status object provides values such as st.progress, st.filename, st.printstatus, and temperatures. For continuous updates, the library exposes printer.watch(), an asynchronous iterator.

Step 2: Give the data a layout ------------------------------

Once I could see the status, I wanted something easier to read at a glance.

We built the interface with Rich. The script’s dashboard() function takes a status object, the printer address, a rendered camera image, and a language code. It returns a layout for the whole screen.

Rich’s building blocks map neatly to the job:

Layout divides the screen into rows and columns.

Panel gives each section a border and title.

Table aligns labels and values.

Text supplies colors and styles.

Live keeps the interface displayed as data changes.

For example, the print details use a small grid:

info = Table.grid(expand=True, padding=(0, 1)) info.addcolumn(style="dim", width=12) info.addcolumn(style="bold brightwhite") info.addrow(words["file"], st.filename or "—")

The full dashboard puts the current state at the top, followed by progress. Below that are print details and temperatures on the left, with the camera on the right. Fan speeds sit in the footer.

The rendering function builds the screen; the main loop feeds it fresh data:

live.update(dashboard(st, host, frame, lang), refresh=True)

This made each visual adjustment straightforward. We could change the layout without changing how the printer connection worked.

Step 3: Make progress visible -----------------------------

My next request was a proper progress bar and some color.

The implementation is small enough to understand immediately:

value = max(0, min(100, value)) filled = round(width value / 100) colour = "green" if value >= 90 else "brightcyan"

bar = Text(justify="center") bar.append("█" filled, style=f"bold {colour}") bar.append("░" (width - filled), style="grey30")

The percentage is kept between zero and one hundred, then converted into filled cells across a default width of 56 characters. The bar stays cyan until 90%, when it turns green. The percentage appears above it.

Temperatures and printer states also get their own colors. A few emojis make states such as sleeping, printing, and completed easier to recognize.

These were small changes, but they made the dashboard much closer to what I had wanted: something I could check without interrupting my train of thought.

Step 4: Notify me when the print finishes -----------------------------------------

The notification needed a little memory. Checking whether the current state says “completed” on every update would risk announcing the same job repeatedly.

The script tracks whether it has observed an active print and remembers the previous status. Here is the completion branch, with the error-notification branch omitted for clarity:

if code in ACTIVE: seenactive = True

if seenactive and code != previous: if code == 9: notify( I18N[lang]["donenotification"].format( filename=st.filename or I18N[lang]["unknownfile"] ) ) seenactive = False

previous = code

When an observed print reaches status 9, the completed state used here, the script sends a notification and clears the active flag. Opening the TUI after a job has already finished does not immediately announce a completion it never observed.

On my Mac, notify() calls osascript to display a notification titled “Centauri Carbon,” with a sound. The application also handles the error state with a separate notification.

Tags: #hive-123993

View full post on HivePostify →

Join HivePostify — Pakistan's First Web3 Platform →