Repository navigation
Architecture
Working on the code? Working on NebulaScreen covers the logic/LVGL split that makes most of it testable without a printer, how to drive the UI in the simulator, and the UI API contract that stops a mismatched build from starting.
NebulaScreen is a single C++17 program on LVGL 8. It is based on GuppyScreen by ballaswag (GPL-3);
see History and credits. Some internal names keep the upstream spelling (for
example the GuppyScreen class in src/guppyscreen.cpp).
This page and the other developer pages are written against fd47cb6, which is
NebulaScreen v1.0.1 and the screen NebulaOS 1.0.2 ships
(NEBULASCREEN_PIN / NEBULASCREEN_VERSION in NebulaOS-firmware/manifests/dependencies.conf
at tag v1.0.2).
main has moved past that pin, but only by documentation and a comment-only privacy pass
(3c710c2 and two wiki commits), so the shipped binary and the newest source behave
identically - checked by reading the diff, not inferred from the dates. When that stops being
true, the pin is what ships and the tip is not.
-
UI — LVGL v8 widgets. Each screen is a
*_panel.cppinsrc/(e.g.print_status_panel,bedmesh_panel,calibration_menu_panel,finetune_panel).src/main.cppsets up the display and input drivers and reads the config;src/guppyscreen.cppsets up logging and the theme and wires the app together. The Settings pages share helpers insrc/settings_ui.cpp. -
Display / input —
lv_drivers(submodule,NebulaOS-KE/lv_drivers): framebuffer and evdev on the printer, SDL2 in the simulator. -
Moonraker —
libhvprovides the websocket client (src/websocket_client.cpp, JSON-RPC).src/notify_consumer.cppdispatches Moonraker notifications to the panels;src/state.cppholds the merged printer state. -
NebulaOS contract — everything that touches the operating system goes through Moonraker
JSON-RPC methods provided by NebulaOS (
machine.nebulaos.*: Wi-Fi, network, display, image, reset, boot logo, ...). The app does not run system commands for these itself. The logic for each is in plain, LVGL-free files that the host tests cover:src/nebulaos_*.cpp,src/plr_status.cpp. -
Klipper workflows — guided calibrations, power-loss recovery and TMC autotune call commands from
NebulaOS's Klipper extensions (
NEBULAOS_*, objectnebulaos_calibration,nebulaos_power_loss_recovery). -
Paths and image contract —
src/nebulascreen_paths.hholds every device path and name (/opt/nebulascreen/...,S58nebulascreen, the log path) and thenebulaos_ui_apilevel (1) this build needs. The app reads/opt/nebulaos-version.jsonand refuses to run on an image that states a different level. Once connected it reports its version withmachine.nebulaos.screen.report. -
Config —
src/config.cppreads and savesnebulascreen.json(power-cut safe, via a journal file);src/theme.cppreads the theme JSON. See Configuration. -
Logging —
spdlog, rotating file (10 MB × 3). -
Print-state safety —
src/utils.cpp:is_printing(),notify_locked(),confirm_if_printing(). -
Buzzer — owned by Klipper's
nebulaos_beeperextra (kernel PWM channel); the touch click is a request to it over the Klippy API socket (src/touch_beep_client.*).k1/k1_mods/buzzer/guppybeep.cbuildsnebulabeep, now only a compatibility client that forwards to Klipper. - Packaging — both programs are statically linked (musl on MIPS), so there are no shared-library dependencies on the printer.
Panels are gated by print state (print_stats/state is printing or paused):
- Blocked with a message mid-print: homing, extrude, the calibration rows, bed mesh changes, TMC autotune, clean reset and slot swap.
- Confirm first mid-print: console commands, macros, Klipper/MCU restart, limits, power.
- Always available: Fine Tune, Z offset, fans, LED, print status, file browsing.
.
├── src/ Application source (panels, NebulaOS contract logic, config, networking)
├── tests/ Host tests (make test, tests/test_nebulascreen_release.py)
├── assets/ Compiled fonts and icon sets (material, material_46, svg sources)
├── themes/ Colour theme JSON files
├── lvgl/ LVGL v8 (submodule; patched)
├── lv_drivers/ Display/input drivers (submodule)
├── libhv/ Network library (submodule)
├── spdlog/ Logging library (submodule; patched)
├── lv_touch_calibration/ Touch calibration
├── patches/ Patches applied to submodules before building
├── k1/k1_mods/buzzer/ Buzzer player source (nebulabeep)
├── scripts/
│ ├── build-release.sh The release build (CI and NebulaOS-firmware use it)
│ ├── build-mips.sh MIPS cross-build, called by build-release.sh
│ ├── nebulascreen_release.py Packages and checks the release zip
│ └── build-*-mipsel.sh, vendor/, lib/ Inherited vendoring scripts, see Vendored-Dependencies
├── docker/ Standalone toolchain image and k1-bash-build reconstruction
├── docs/ Developer notes (partly historical)
├── wiki/ This wiki
├── lv_conf.h, lv_drv_conf.h LVGL configuration
├── Makefile Build entry point
└── .github/workflows/ build.yml, pull_request.yml, wiki.yml
| Path | Purpose |
|---|---|
/opt/nebulascreen/ |
nebulascreen, nebulabeep, themes/ (read-only image) |
/opt/nebulascreen/nebulascreen.json |
Config, bind-mounted from /usr/data/nebulaos/nebulascreen/nebulascreen.json
|
/opt/printer_data/logs/nebulascreen.log |
Log |
/etc/init.d/S58nebulascreen |
Service script (start-stop-daemon) |
/usr/data/nebulaos/apps/nebulascreen |
A downloaded release, bound over the image's files at start (see Releases and deployment) |
Get started
Get great prints
- Calibration guide (4 steps)
- Calibration walkthrough (A→Z)
- Bed tramming
- Load cell calibration (water bottle)
- Axis Twist Compensation
- Adaptive meshing + purge
- Square parts (Skew Correction)
- Quieter steppers (TMC Autotune)
Using the screen
Help
- Working on NebulaScreen
- Build from source
- Dev & simulator
- Architecture
- Configuration
- Releases & deployment
- Testing
- CI
- Contributing
- Publishing this wiki
NebulaOS