Skip to content

Disane87/printorb

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

30 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Release & Deploy GitHub all releases GitHub issues by-label GitHub contributors Platform semantic-release: conventionalcommits

๐Ÿ”ฎ PrintOrb

Hey there! ๐Ÿ‘‹ PrintOrb turns a tiny round Waveshare ESP32-S3-Touch-LCD-1.28 into a live 3D-printer status orb that sits on your desk. It talks to either Klipper (Moonraker) or Bambu Lab and shows you progress, temps, remaining time, layers and โ€” for Bambu โ€” the full AMS filament state. ๐Ÿ–จ๏ธโœจ

The best part? No recompiling to switch printers. Everything is configured at runtime through a built-in web portal, and the round screen is a swipeable, touch-driven carousel. Flash it once, set it up from your browser, done. ๐ŸŽ‰

Tip

๐Ÿงฉ No Home Assistant. No broker. No cloud. No companion server. PrintOrb is a fully standalone device that talks directly to your printer โ€” Bambu Lab over local MQTT (LAN mode) or Klipper via the Moonraker API. The only things between the orb and your printer are your WiFi and an access code. That's the whole point. โœจ

Tip

Don't want to install a toolchain? Jump straight to Flash from the browser โ€” plug in the board, click one button, and you're running. โšก

โœจ What Can This Thing Do?

Glad you asked! Here's the good stuff:

  • ๐Ÿงฉ Fully standalone โ€” no Home Assistant required: the orb connects directly to your printer over your LAN. No middleware hub, no MQTT broker, no cloud account, no companion server to keep running.
  • ๐Ÿ”€ Two backends, switchable at runtime: pick Klipper (HTTP polling of the Moonraker API) or Bambu Lab (local MQTT over TLS, port 8883, LAN mode) โ€” no reflash to swap.
  • ๐Ÿ‘† Touch carousel โ€” swipe left/right between five screens:
    1. ๐Ÿ“Š Status โ€“ progress ring, temps, time, layers (with crisp MDI icons)
    2. ๐Ÿ“„ Details โ€“ state, file, ETA (minimal & airy)
    3. โš™๏ธ System โ€“ WiFi/RSSI, IP, brightness (just tap โˆ’/+)
    4. ๐Ÿงต Filament (Bambu/AMS) โ€“ colored slot tiles, active slot, humidity; swipe up/down to switch AMS units (with a vertical dot indicator)
    5. ๐ŸŽ›๏ธ Control โ€“ Pause / Resume / hold-to-Stop
  • ๐ŸŒˆ Full Bambu AMS view: per-slot filament type, color and remaining %, active tray highlight, humidity, and multiple AMS units
  • ๐ŸŒ Web portal (baked into flash): live status, all settings, and a live device log for browser debugging
  • ๐Ÿ“ถ First-time setup made easy: a captive-portal AP (printorb-setup-xxxx) with a WiFi network scan and printer mDNS discovery
  • ๐Ÿท๏ธ mDNS: reachable as printorb.local; the printer address accepts an IP or a hostname (.local), and the hostname is configurable
  • ๐Ÿ’พ Persistence in NVS: survives reboots and re-flashes
  • ๐ŸŒ™ Scheduled dimming & power-save: time-aware backlight dimming and idle sleep (NTP-synced), so your orb isn't blazing at 3 AM
  • ๐Ÿš€ OTA updates: flash new firmware over WiFi (ArduinoOTA) or right from the browser Update tab โ€” first flash is USB, after that you're wireless

Note

The AMS screen only appears when the printer type is Bambu โ€” the carousel adapts itself to your backend at boot.

๐Ÿ› ๏ธ Hardware

Waveshare ESP32-S3-Touch-LCD-1.28

  • ๐Ÿง  ESP32-S3R2 (2 MB QSPI PSRAM)
  • ๐ŸŸข 1.28โ€ณ round LCD, 240ร—240, GC9A01 (SPI)
  • ๐Ÿ‘† CST816S capacitive touch (IยฒC)

Pinout (in include/lgfx_device.h)

Function GPIO
LCD SCLK 10
LCD MOSI 11
LCD MISO 12
LCD DC 8
LCD CS 9
LCD RST 14
LCD Backlight 2
Touch SDA 6
Touch SCL 7
Touch INT 5
Touch RST 13

Warning

Backlight is GPIO 2 on this board revision. Some other Waveshare revisions use GPIO 40 โ€” if the screen stays dark, that's the very first thing to check (ORB_PIN_LCD_BL in include/lgfx_device.h, where all the pins live). ๐Ÿ”ฆ

๐Ÿ“ฆ Build & Flash

You'll need PlatformIO (CLI or the VS Code extension). Then it's three commands:

# in the project folder
pio run                 # compile
pio run -t upload       # flash (connect the board via USB-C)
pio device monitor      # serial output (115200 baud)

The web UI is embedded in flash โ€” no separate LittleFS upload needed. ๐ŸŽ‰

โšก Flash from the browser (no toolchain)

Every push to main builds the firmware and publishes a web flasher to GitHub Pages: disane87.github.io/printorb.

Open it in Chrome / Edge / Opera on desktop, plug the board in via USB-C and click Connect & Install โ€” it flashes the merged image over Web Serial, zero PlatformIO required. The same merged binary is attached to every GitHub Release. ๐Ÿš€

Note

Serial routing: the USB-C port goes through the on-board CH343 UART bridge, so Serial is routed to UART0 (ARDUINO_USB_CDC_ON_BOOT=0 in platformio.ini). The serial monitor and the web log show the same output.

Important

Flash size: the partition table only uses the first 4 MB and works on both 4 MB and 16 MB units. On a flash-size mismatch during upload, set board_upload.flash_size in platformio.ini to match your unit.

๐Ÿš€ First-Time Setup

Ready to roll? Here's the whole flow:

  1. Flash the firmware and power up the board.
  2. On first boot (no WiFi saved) PrintOrb opens a captive-portal access point: printorb-setup-xxxx (open network). Connecting with a phone should pop up the "sign in to network" page automatically โ€” otherwise just open http://192.168.4.1.
  3. In the Settings tab:
    • ๐Ÿ“ถ Scan for your WiFi, pick the network, enter the password
    • ๐Ÿท๏ธ Optionally set a hostname (default printorb โ†’ printorb.local)
    • ๐Ÿ–จ๏ธ Choose your printer type:
      • Klipper: IP/hostname, Moonraker port (default 7125), API key optional
      • Bambu Lab: IP/hostname, serial number, LAN access code
    • ๐Ÿ” Or use Discover (mDNS) to find a Klipper/Bambu printer on your LAN
    • ๐Ÿ’พ Save โ†’ the device reboots and connects.
  4. After that the UI lives at http://<device-ip>/ or http://printorb.local/. ๐ŸŽ‰

Bambu Lab โ€” prerequisites

  • โœ… Enable LAN mode on the printer; the serial number and access code are shown right there.
  • โœ… Works with P1/X1/A1/H2 over the local network for status + AMS. (Live camera is not supported on-device โ€” see Known limitations.)

๐Ÿ—‚๏ธ Project Structure

One responsibility per file โ€” easy to find your way around:

printorb/
โ”œโ”€ platformio.ini          Build configuration & libraries
โ”œโ”€ partitions.csv          Partition table (4/16 MB)
โ”œโ”€ include/
โ”‚  โ”œโ”€ lv_conf.h            LVGL configuration
โ”‚  โ””โ”€ lgfx_device.h        LovyanGFX panel/touch definition (PINS HERE)
โ””โ”€ src/
   โ”œโ”€ main.cpp             Setup/loop, boot sequence, wiring
   โ”œโ”€ config.{h,cpp}       Settings + NVS persistence
   โ”œโ”€ display.{h,cpp}      LVGL bring-up (flush + touch)
   โ”œโ”€ ui.{h,cpp}           LVGL screens: boot, setup, and the touch carousel
   โ”œโ”€ orb_icons.{h,c}      Embedded Material Design icon font (nozzle/bed/โ€ฆ)
   โ”œโ”€ printer.h            Shared status model (+ AMS) + client interface
   โ”œโ”€ klipper_client.{h,cpp}  Moonraker HTTP client (+ pause/resume/stop)
   โ”œโ”€ bambu_client.{h,cpp}    Bambu MQTT/TLS client (+ AMS, controls)
   โ”œโ”€ wifi_manager.{h,cpp}    STA + captive AP, DNS, mDNS, host resolution
   โ”œโ”€ timekeeper.{h,cpp}      SNTP local time for scheduled dimming
   โ”œโ”€ ota.{h,cpp}             ArduinoOTA (espota) WiFi flashing
   โ”œโ”€ web_portal.{h,cpp}      Async web server (API + scan/discover/log/update)
   โ”œโ”€ web_index.h          Embedded config UI (HTML/CSS/JS)
   โ””โ”€ logbuf.{h,cpp}       In-memory log ring buffer (served at /api/log)

Tip

Adding a new printer backend? Implement the PrinterClient interface and instantiate it in createPrinter() โ€” the shared shape is PrinterStatus, so the UI and web portal pick it up for free. ๐Ÿ”Œ

๐ŸŒ Web API

Method Path Purpose
GET / Config/status UI
GET /api/status Current printer status (JSON)
GET /api/config Current settings (without WiFi password)
POST /api/config Save settings โ†’ reboot
POST /api/restart Restart the device
GET /api/scan Async WiFi network scan (JSON)
GET /api/discover mDNS discovery of Klipper/Bambu printers
GET /api/sysinfo Diagnostics (IP, memory, flash, chip, uptime, NTP)
GET /api/log Live device log (plain text)
POST /api/update Firmware upload (raw .bin, HTTP Basic auth) โ†’ reboot

๐Ÿ“ก Flashing Over WiFi (OTA)

Once your orb is on the network, you don't need the USB cable anymore. ๐ŸŽ‰

OTA requires an Update / OTA password set in the web UI (Settings โ†’ Security). With no password, OTA is disabled as a secure default (Ota::begin() returns early and /api/update always 401s). The first flash is still USB.

  • ๐Ÿ’ป Dev push: pio run -e esp32-s3-touch-lcd-128-ota -t upload (ArduinoOTA / espota; set --auth in platformio.ini to the device password). Uses a deviceโ†’host reverse TCP connection โ€” a host firewall or crossing subnets breaks it, so use the browser path instead.
  • ๐ŸŒ Browser: the Update tab uploads the raw .bin to POST /api/update with HTTP Basic auth (user admin, the OTA password). The raw body (not multipart) keeps memory low, so big uploads don't reset the device while the Bambu MQTT buffer is live.

โš ๏ธ Known Limitations & Notes

  • ๐Ÿ“ท Camera: not available on-device. The Bambu H2 series streams H.264 over RTSPS (port 322), which the ESP32-S3 simply cannot decode. The simple JPEG chamber protocol (port 6000) only exists on X1/P1/A1. A live view would need an external transcoding proxy (e.g. go2rtc/ffmpeg โ†’ JPEG snapshots).
  • ๐Ÿ“ฆ Bambu MQTT buffer: the initial pushall report (with AMS) is large โ€” ~32 KB observed โ€” so the PubSubClient buffer is set to 48 KB in bambu_client.cpp. Too small a buffer makes PubSubClient silently drop the report and the status stays stuck on "Offline".
  • ๐Ÿ”’ TLS unvalidated: the Bambu LAN broker uses a self-signed certificate; the client connects with setInsecure() (common on the local network).
  • ๐Ÿงฑ Klipper layers: current/total layer only appear if your slicer writes them to print_stats.info (e.g. via SET_PRINT_STATS_INFO).
  • ๐Ÿ” mDNS discovery only works in STA mode (on your LAN). In first-time AP setup, enter the IP/hostname manually; resolution then works after reboot.
  • ๐Ÿ“ถ AP mode is an open network purely for easy setup and is not active after the initial WiFi configuration.

Caution

The web portal is intentionally unauthenticated on a trusted LAN, and /api/update accepts a firmware upload โ€” keep your orb on a network you trust, and set the OTA password to guard the update endpoint.

๐Ÿ” Reset

Need a clean slate? Call Config::reset() (e.g. temporarily in setup()), flash, boot once, then remove it again. The device starts back up in the setup AP, ready for a fresh config. ๐Ÿงน

๐Ÿท๏ธ Releases & Versioning

Versioning is fully automated with semantic-release, driven by Conventional Commits. On every push to main, CI (.github/workflows/release-and-deploy.yml) builds the firmware, then semantic-release figures out the next version from your commit messages, writes CHANGELOG.md, tags the repo, and creates a GitHub Release with the firmware attached โ€” and the web flasher on GitHub Pages is redeployed at that version. ๐ŸŽ‰

Commit prefixes that drive the version bump:

Prefix Example Release
fix: fix: correct AMS slot color mapping patch (x.y.Z)
feat: feat: add scheduled display dimming minor (x.Y.0)
feat!: / BREAKING CHANGE: footer feat!: drop legacy config keys major (X.0.0)
chore: / docs: / refactor: / ci: โ€ฆ docs: update wiring notes no release

So: phrase commits as type: summary and the changelog + releases take care of themselves. No conventional commits since the last tag โ†’ no new release (the Pages site just redeploys at the current version).


๐Ÿ”— Related Projects

Building your printer stack? Check out these other projects from the same workshop:

Project Description
๐ŸŽฏ Spoolman Home Assistant Bring your Spoolman filament inventory into Home Assistant โ€” 25+ sensors per spool, run-out predictions and low-filament alerts.
๐Ÿงต Spoolman MCP MCP Server for Spoolman โ€” manage your filament inventory through AI assistants like Claude. Available on npm.
๐ŸŒ Klipper Sphere Sibling project exploring Klipper status on round displays.
๐Ÿ“Š FilaPulse / Open Maker Database Community database & tooling for the maker ecosystem.

๐Ÿค Contributing

Want to make PrintOrb even better? Awesome โ€” PRs and issues are very welcome! ๐ŸŽ‰

A few things worth knowing:

  • ๐Ÿ’พ Use conventional commits so semantic-release can do its thing (feat:, fix:, feat!:, chore:, โ€ฆ).
  • โœ… Anything touching src/ or include/ must still pass pio run โ€” the current baseline builds clean (โ‰ˆ44 % RAM, โ‰ˆ44 % of the 3 MB app partition).
  • ๐Ÿ‡ฌ๐Ÿ‡ง Comments, identifiers, docs and on-screen strings are all in English.
  • โš™๏ธ Keep settings in OrbConfig/NVS โ€” no hardcoded IPs, SSIDs or codes.

Curious how the project came to be? The original request and design decisions live in docs/CONVERSATION.md. ๐Ÿ“–

๐ŸŽ‰ Cheers!

Thanks for checking out PrintOrb! If your printer now has a glowing little orb keeping an eye on it, give the repo a โญ on GitHub โ€” it really helps! ๐Ÿ™Œ

Found a bug? Got an idea? Open an issue and let's make it better together! ๐Ÿš€

About

๐Ÿ”ฎ Live 3D-printer status orb for the round Waveshare ESP32-S3-Touch-LCD-1.28 โ€” Klipper (Moonraker) or Bambu Lab (LAN MQTT), AMS view, touch carousel, web portal & browser flasher.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors