Repository navigation
OSConfig Helpers
Every OS setting a printer has is read and written here. The Moonraker API reference stops at the endpoint; this page picks up where it stops.
Source: NebulaOS-firmware at b95b156, scripts/build/overlay/usr/lib/nebulaos/python/nebulaos_osconfig/. 18 modules.
nebulaos-osconfig is a command-line program: argv in, one JSON object out. It is run by the Moonraker component as a subprocess, which is the whole reason the privilege boundary works - the component never writes a system file itself.
nebulaos-osconfig DOMAIN VERB [--option value]...
It prints {"ok": true, ...} merged with the helper's own result, or {"ok": false, "error": "<CODE>", "message": "..."}, and never a traceback - the dispatcher catches every exception and turns it into that contract. Read-only verbs are listed in cli.py's READ_ONLY set and are the only ones that skip the audit log; every change writes one line to the persistent system log.
Reached by is the DOMAIN VERB that routes to the function, taken from the dispatcher rather than from the function's name. A function with nothing there is not reachable from the command line: it is used by another module, by a boot service, or by a test.
Result keys are the keys that function's own return statements carry, extracted with ast. A blank means the returns could not be read - not that the function returns nothing.
No module here is hardware-verified. Everything is read from source.
nebulaos_osconfig.bootdisplay - userspace boot display: mode and image (GUI/service readiness mission, 2026-10-09). boot/display.json source of truth (schema 1): mode, image boot/display.env MODE= for S01splash (shell) printer_data/config/uploads/boot-logo/ images to pick from (G63 2026-10-16, inside the config root; was printer_data/uploads, before that boot/uploads) /usr/share/nebulaos/boot-logos/ the logos NebulaOS ships (G116, Run 21): listed with the uploads, read-only, never deleted boot/custom.png|bmp|jpg validated copy of the selected image boot/cache/splash.raw framebuffer-native render (derived) boot/cache/splash.meta geometry + source identity of the render Pillow runs only here (a short-lived helper process), never at boot: the boot script blits splash.raw when splash.meta matches the live framebuffer.
| Function | Reached by | Result keys |
|---|---|---|
builtin_image(width, height) |
- | - |
builtin_path() |
- | - |
custom_path() |
- | - |
default_config() |
- |
image, mode, schema
|
delete_image(filename) |
boot-display delete-image |
name, result
|
fb_geometry() |
- |
bpp, layout, stride, xres, yres
|
firmware_short_sha() |
- | - |
fresh_install_default() |
boot-display fresh-default |
config, reason, result
|
guppy_rotation() |
- | - |
import_usb(file_id) |
boot-display import-usb |
existing, name, result
|
list_images() |
boot-display list-images |
custom_active, images, selected, usb, usb_present
|
load_config() |
- | - |
preview(filename) |
boot-display preview |
height, path, result, width
|
render(if_stale, geo) |
boot-display render |
bytes, kind, result
|
reset_image() |
boot-display reset-image |
- |
resolve_image(filename) |
- | - |
resolve_upload(filename) |
- | - |
restore_original_logo() |
boot-display restore-original-logo |
- |
set_image(filename) |
boot-display set-image |
- |
set_mode(mode) |
boot-display set-mode |
applies, config, result
|
status() |
boot-display list-images, boot-display preview, boot-display status
|
cache, config, config_error, custom_image_present, formats, max_dimension, max_file_bytes, modes, power_on
|
to_framebuffer(img, geo) |
- | - |
validate_image_file(path) |
- | - |
validate_mode(value) |
- | - |
nebulaos_osconfig.camera - Creality Nebula Camera controls (G121, Run 22, The owner's list 2026-10-28; investigation _scratch/run22/G121-nebulacam-investigation.md). camera status stored settings, defaults, the camera camera set --json '{...}' change some settings (saved, then applied) camera defaults every setting back to the camera's defaults camera reset reboot the camera (XU selector 17) camera version the camera's firmware string (XU selector 15) camera apply [--device DEV] re-apply everything (S50webcam, when the camera appears - nothing persists in it) The camera (USB a108:2231, uvcvideo) keeps nothing over a reboot, power cycle or USB re-enumeration, so the settings live here (camera/camera.json, atomic) and are applied again each time it appears. Apply order (one control per ioctl): auto switches, manual values, the rest, then the IR mode. Exposure is one-way: the camera reads auto_exposure 0 (its own auto mode) but only accepts 1 (manual); the way back is a camera reset, which clears the stored manual flag BEFORE the reboot so the re-apply cannot switch it on. The vendor Extension Unit (GUID 41769ea2-04de-e347-8b2b-f4341aff003b, found in the USB descriptors, not assumed to be unit 6) is used ONLY through a frozen allow-list of (selector, query) pairs. Selector 13 (firmware update mode: the camera turns into a mass-storage device) is not in it and cannot be sent: no command-line or HTTP parameter carries a selector number. Flip stays in Mainsail. Gamma, hue, backlight compensation and focus (fixed lens) are never written.
| Function | Reached by | Result keys |
|---|---|---|
apply(device, ioctl) |
camera apply |
device, result
|
default_config() |
- |
brightness, contrast, exposure_manual, exposure_time, ir_mode, power_line, saturation, schema, sharpness, wb_auto, wb_temperature, zoom
|
defaults(ioctl, sleep, monotonic) |
camera defaults |
config, reenumerated, result
|
find_camera() |
- | - |
ioc_readwrite(type_char, nr, size, mips) |
- | - |
load_config() |
- | - |
reset(ioctl, sleep, monotonic) |
camera reset |
config, reenumerated, result
|
set_settings(changes, ioctl) |
camera set |
config, result
|
status() |
camera status |
config, config_error, defaults, device, firmware, ir_modes, power_line_modes, present, ranges
|
version(ioctl) |
camera version |
firmware, result
|
xu_unit(usb_dir) |
- | - |
nebulaos_osconfig.cleanup - storage overview and "Clean up Creality files" (G66, 2026-10-16; architecture review 2026-10-16 followed). The data drive (/usr/data) is shared: NebulaOS keeps everything in /usr/data/nebulaos plus the print files in /usr/data/printer_data/gcodes; the Creality system (and the community helper script's add-ons for it) keep their data next to it. "Clean up Creality files" removes that data from a FIXED list - never "everything else" - with these guards: - /usr/data/printer_data/gcodes (NebulaOS's print files, the USB stick mount below it) is never touched; of printer_data only the other entries go - nothing that is, or contains, a mount point; symlinks are removed as links, never followed; nothing outside /usr/data - the swap file only when it is not in use - Creality's timelapse videos only when asked for - refused while printing (the Moonraker component checks first) - the print statistics a later import reads (Run 23, 2026-11-02): Creality's lifetime print counter and print history, and the old Moonraker database (printer_data/database) - see STATISTICS_KEEP Everything not on the list stays: macaddr.txt, wpa_supplicant.conf, factory_test_result, .nebulaos-clean-reset*, .keep, nebulaos*, ... Whatever the other slot runs is allowed; when it is Creality the screen says plainly that it will stop working.
| Function | Reached by | Result keys |
|---|---|---|
clean_creality(include_videos, log) |
system cleanup-creality |
freed_bytes, kept, removed, result
|
clean_nebulaos(log) |
system cleanup-nebulaos |
freed_bytes, result
|
nebulaos_plan() |
system cleanup-nebulaos-plan |
bytes, items
|
other_slot_system() |
- | - |
plan(include_videos) |
system cleanup-plan |
bytes, include_videos, items, other_slot, videos_bytes
|
storage() |
system storage |
at, free_bytes, other_slot, parts, total_bytes
|
nebulaos_osconfig.cli - argv grammar and the JSON/exit-code contract (GUI/service readiness
mission, 2026-10-09). nebulaos-osconfig system info nebulaos-osconfig system clean-
reset|cancel-clean-reset|ack-clean-reset nebulaos-osconfig system swap-slot|keep-slot nebulaos-
osconfig system ack-notice --id ID nebulaos-osconfig system storage | cleanup-plan [--videos]
(read-only, walk the drive) nebulaos-osconfig system busy --profile
request|point_of_no_return|git|restart|recovery [--holder TOKEN] (G91 busy check, read-only)
nebulaos-osconfig system cleanup-creality [--videos] nebulaos-osconfig system cleanup-nebulaos-
plan (read-only) | cleanup-nebulaos nebulaos-osconfig stats baseline (print statistics from
before NebulaOS, imported once; read-only otherwise) nebulaos-osconfig image list|status|ack
nebulaos-osconfig image check --file ID nebulaos-osconfig image install --file ID --sha256 HEX
(starts "image worker") nebulaos-osconfig wifi status|scan nebulaos-osconfig wifi connect
--stdin {"ssid": ..., "password": ...} nebulaos-osconfig wifi forget --ssid SSID nebulaos-
osconfig network status|reset nebulaos-osconfig network set-hostname --hostname NAME nebulaos-
osconfig network set-ipv4 --json '{"mode":"static",...}' nebulaos-osconfig boot-display
status|reset-image nebulaos-osconfig boot-display set-mode --mode logo nebulaos-osconfig logs
status | set-level --level info|warning|debug | write-state | save nebulaos-osconfig logs
expire-debug (housekeeping: Debug ends after 24 h) nebulaos-osconfig settings status
nebulaos-osconfig settings snapshot --reason new-system|changed|manual [--db api|file|none]
[--if-changed] nebulaos-osconfig boot-display restore-original-logo nebulaos-osconfig boot-
display list-images | preview [--file NAME] nebulaos-osconfig boot-display import-usb --file
usb// | delete-image --file NAME nebulaos-osconfig boot-display set-image --file
NAME_IN_UPLOAD_ROOT nebulaos-osconfig boot-display render [--if-stale] nebulaos-osconfig boot-
display fresh-default (S04nebulaos-factory-seed, first seed only) nebulaos-osconfig display
status|sleep|wake nebulaos-osconfig display set-brightness --level 25|50|75|100 nebulaos-
osconfig spoolman status|remove | set --host HOST --port PORT (G125) nebulaos-osconfig camera
status|defaults|reset|version | set --json '{...}' | apply [--device /dev/videoN]
(G121) nebulaos-osconfig ota status | check [--force] | download | discard (G79: release check
over HTTPS; the download becomes the image source ota/, installed with image install)
nebulaos-osconfig mcu status|list nebulaos-osconfig mcu flash --file ID --sha256 HEX (ID and
HEX from list) nebulaos-osconfig updates readiness (the last check, read-
only) nebulaos-osconfig updates check-readiness [--if-changed] stdout: exactly one JSON object,
{"ok": true, ...} or {"ok": false, "error": CODE, "message": ...}. exit 0 ok, 1 invalid input
(nothing written), 2 operation failed, 3 refused because the printer is busy (G91: CODE is the
busy reason, "refused": true; nothing changed), 64 usage.
| Function | Reached by | Result keys |
|---|---|---|
main(argv) |
- | - |
nebulaos_osconfig.common - shared plumbing for the NebulaOS OS-settings helper (GUI/service readiness mission, 2026-10-09). The helper is the narrow layer behind the [nebulaos] Moonraker component: argv in, exactly one JSON object out, validated input, atomic persistent writes, one lock. It never runs a shell and never interpolates input into a command line.
| Function | Reached by | Result keys |
|---|---|---|
atomic_write(path, data, mode) |
- | - |
atomic_write_json(path, obj) |
- | - |
busy_result(profile, reason, message, klippy) |
- |
busy, klippy, message, profile, reason
|
busy_state(profile, holder, facts) |
system busy |
busy, klippy, message, profile, reason
|
clear_reboot_pending() |
- | - |
fsync_dir(path) |
- | - |
invalid(code, message) |
- | - |
klippy_facts(timeout) |
- |
klippy, moonraker, status, update_manager_busy
|
klippy_pid_alive() |
- | - |
klippy_settled_for() |
- | - |
klippy_socket_request(method, params, timeout) |
- | - |
lock_holder(path) |
- | - |
maintenance(name) |
- | - |
parse_kv(text) |
- | - |
read_json(path) |
- | - |
reboot_grace(sleep) |
- | - |
reboot_pending() |
- | - |
refuse_if_busy(profile, holder) |
- |
busy, klippy, message, profile, reason
|
render_env(pairs) |
- | - |
run(argv, timeout, env) |
- | - |
schema_readable(raw, schema) |
- | - |
set_reboot_pending(what) |
- | - |
status_reasons(status) |
- | - |
trial_pending() |
- | - |
nebulaos_osconfig.display - display backlight brightness and sleep/wake (GUI/service readiness mission, 2026-10-09). display/display.json source of truth (schema 1): brightness, touch_wake display/display.env scalars for the shell side (/etc/nebulaos-backlight.sh boot restore, and the S98 touch-wake gate) Hardware is driven only through /usr/libexec/nebulaos/nebulaos- backlight over the kernel controller's standard backlight class device (/sys/class/backlight/nebulaos_backlight) - see that library's header.
| Function | Reached by | Result keys |
|---|---|---|
default_config() |
- |
brightness, schema, touch_wake
|
hardware_status() |
- |
asleep, available, error, interface, level, selected_level, touch_wake_running
|
load_config() |
- | - |
set_brightness(value) |
display set-brightness |
backlight, config, result
|
sleep() |
display sleep |
backlight, result
|
status() |
display status |
backlight, config, config_error, interface, levels
|
validate_level(value) |
- | - |
wake() |
display wake |
backlight, result
|
nebulaos_osconfig.image - install a system image (NebulaOS or Creality .img) into the slot that
is NOT running, from the touchscreen (on-printer image updates, human decisions 2026-10-14): -
NebulaOS may occupy both A/B slots; an install always writes the inactive slot (kernel +
rootfs) and then switches the OTA marker to it. The running slot is never written. The RTOS
partitions are never written. - Sources: USB sticks, config/firmware/os (Mainsail upload) and
the image ota download fetched (G79, Run 23; sha256 checked against the release). - Integrity
checks only (no signing): the Creality OTA envelope (7z, the chained per-chunk MD5 scheme,
declared sizes and MD5s), a MIPS uImage kernel and a squashfs rootfs that fit their partitions,
and a read-back of the written partitions. - Older versions may be installed. Creality images
are accepted. - One automatic fallback after an install: the new slot boots as a trial;
S99nebulaos-image-trial confirms it, or switches back once. - G91 (2026-10-22): refused at the
request while the printer is busy (common.busy_state, request profile - a pending trial of the
running slot counts), under the one maintenance lock. Two stop points instead of G88's "wait
for the print": before the marker write (stop, blank the written slot) and after it, before the
reboot (marker back, read back, TRIAL deleted, slot blanked; if the marker cannot be put back,
nothing more is touched and the new system starts at the next power-on). The trial verdict
waits while a print runs. A slot confirms itself by its first passed trial: system/slot-
confirmed-, keyed on the slot's uImage header (name + CRCs) and squashfs superblock,
deleted when an install starts writing that slot. Every switch into an unconfirmed slot writes
a TRIAL record (system.swap_slot). image list .img files from the sources
image check --file ID open the package, report what it holds image install --file ID
--sha256 HEX start the install (background job) image status the
running/last job, slots, last result image ack the screen showed the last
result The format is the one scripts/package/build-img.py writes and Creality's own updater
reads: an encrypted 7z holding /ota_v/ with ota_update.in, and per payload
.NNNN.<md5 of the previous chunk, or of the whole payload for chunk 0000> plus
ota_md5_. listing the chunk MD5s.
| Function | Reached by | Result keys |
|---|---|---|
ack() |
image ack |
result |
check(file_id) |
image check |
build, date, file, has_rtos, kernel, kernel_size, result, rootfs_size, sha256, size, slots, system, target, version
|
chunk_names(members, payload_dir, name) |
- | - |
confirm_slot(slot) |
- | - |
count_start() |
image trial-count |
arm, attempts, result
|
describe(path) |
- |
build, images, kernel_arch, kernel_name, members, payload_dir, system, version
|
file_identity(file_id, size, mtime) |
- | - |
install(file_id, sha256) |
image install |
applies, result
|
layout_of(members) |
- | - |
list_files() |
image list |
files, slots, upload_dir, usb
|
list_members(path) |
- | - |
other_slot(slot) |
- | - |
parse_update_in(text) |
- |
images, version
|
remove_trial() |
- | - |
resolve(file_id) |
- | - |
root_identity(root) |
- |
build, date, nebulaos_version, version
|
run_job(file_id, sha256, holder) |
- | - |
sha256_file(path) |
- | - |
slot_bootable(slot) |
- | - |
slot_confirmed(slot) |
- | - |
slot_identity(slot, running, may_mount) |
- | - |
slot_key(slot) |
- | - |
slots_info(may_mount) |
- | - |
status() |
image status |
job, last, slots, trial
|
system_kind(kernel_name) |
- | - |
target_partitions(running) |
- | - |
trial() |
image trial |
removed_upload, result
|
uimage_name(head) |
- | - |
unconfirm_slot(slot) |
- | - |
write_trial(record) |
- | - |
nebulaos_osconfig.logs - the general log level, the status file and "Save logs to USB" (G60, 2026-10-16). log level info | warning | debug, one setting for the system log (syslogd -l), the screen and Moonraker (-v at debug). Klipper has no log levels. state file printer_data/logs/nebulaos-state.txt: versions, slots, MCU, boot, storage, memory - written at boot, every 30 minutes and before a log zip. In the logs folder so Mainsail's own "download as zip" carries it too. Never passwords or keys. save logs one zip on the USB stick with every log, the state file and the printer's config files - streamed file by file (little memory), lines that look like secrets blanked out.
| Function | Reached by | Result keys |
|---|---|---|
expire_debug(now) |
logs expire-debug |
level, moonraker, result, system_log
|
get_level() |
- | - |
last_reset() |
- | - |
redact(line) |
- | - |
redact_text(text) |
- | - |
save_logs() |
logs save |
bytes, file, files, result, safe_to_remove, usb
|
set_level(level) |
logs set-level |
level, moonraker, result, system_log
|
state_text() |
- | - |
status() |
logs status |
applies_to, debug_until, level, levels, not_applicable
|
write_state() |
logs write-state |
path, result
|
nebulaos_osconfig.mcu - MCU firmware from the touchscreen (development run 4, 2026-10-11):
"plug in USB, pick a compiled .bin, flash - no Creality bootloader knowledge needed". status
what the boot-time MCU guard found, who owns the MCU, last flash list candidate .bin files:
Mainsail uploads (config/firmware/mcu), a mounted USB stick (gcodes/USB/, /etc/usb-gcode-
media.sh) and the built-in NebulaOS firmware; each one checked offline flash one file, by id
and the sha256 the user confirmed Flashing is NOT reimplemented here. The file is checked and
prepared (mcu_image.prepare(): a raw NebulaOS-klipper-mcu build is packed into the Creality
format), snapshotted to tmpfs so a pulled USB stick or a new upload cannot change it mid-
flight, and handed to the existing CLI, nebulaos-mcu flash <file>, which refuses while
printing, stops Klipper, runs mcu_flash_file.py (bootloader entry, hardware-id allow-list,
transfer, app start) and restarts Klipper whatever happened.
| Function | Reached by | Result keys |
|---|---|---|
flash(file_id, expected_sha) |
mcu flash |
file, kind, log, managed, native, result
|
list_files() |
mcu list |
builtin, files, upload_dir, usb
|
resolve(file_id) |
- | - |
status() |
mcu status |
guard, last_flash, managed, upload_dir
|
nebulaos_osconfig.network - persistent hostname and DHCP/static IPv4 for wlan0 (GUI/service readiness mission, 2026-10-09). Files (all under the NebulaOS namespace on /usr/data): network/osconfig.json source of truth (schema 1) network/osconfig.lkg.json last configuration proven to reach its gateway network/boot.env scalars for /etc/nebulaos- network.sh (boot) A live change is: validate -> keep the current files as *.prev -> write the new files -> apply through nebulaos-netapply (the same shell library the boot uses) -> verify (static: the gateway answers ARP; DHCP: a lease) -> commit, or restore *.prev and re-apply. The caller gets the real outcome.
| Function | Reached by | Result keys |
|---|---|---|
boot_env_text(cfg) |
- | - |
default_config() |
- |
hostname, ipv4, schema
|
default_hostname() |
- | - |
live_state() |
- |
address, dns, gateway, hostname, interface, prefix, ssid, wpa_state
|
load_config() |
- | - |
reset() |
network reset |
config, result
|
set_hostname(value) |
network set-hostname |
config, mdns_restart_required, result
|
set_ipv4(spec) |
network set-ipv4 |
config, result
|
status() |
network status |
boot_state, config, config_error, last_known_good, live, mdns_name, mdns_note
|
validate_config(cfg) |
- |
hostname, ipv4, schema
|
validate_hostname(value) |
- | - |
validate_ipv4(spec) |
- |
address, dns, gateway, mode, prefix
|
nebulaos_osconfig.ota - NebulaOS system updates over the internet (G79). Design:
_scratch/run15/G79-ota-design.md; 2026-10-29 (Run 23): NO signing key - the printer downloads
only over HTTPS from github.com and checks the size and sha256 listed in the release record.
ota status the last check and the download (read-only) ota check [--force]
ask the release channel whether a newer NebulaOS is published (at most once per 24 h unless
forced; never while the printer is busy) ota download fetch the offered .img
(background job) into the "ota" image source; the install is then the ordinary image install --file ota/<name> (busy refusal, stop points, trial, rollback) ota discard
delete the downloaded image Trust: the stable channel is the latest GitHub release of NebulaOS-
KE/NebulaOS. Every request is HTTPS with certificate checks (the image's CA bundle), to
github.com / api.github.com and, through redirects, only to GitHub's release asset hosts. The
release record nebulaos-release.json (tools/release/ make-release-record.py) names the image,
its size and sha256; the image is kept only when both match. TLS needs a set clock: before
CLOCK_FLOOR nothing is fetched.
| Function | Reached by | Result keys |
|---|---|---|
allowed_url(url) |
- | - |
check(force, fetch, now) |
ota check |
- |
discard() |
ota discard |
result |
download(now) |
ota download |
downloaded, result
|
downloaded() |
- | - |
offer(rec, running) |
- | - |
parse_record(data) |
- | - |
parse_version(text) |
- | - |
run_download(opener) |
- | - |
running_version() |
- | - |
status() |
ota status |
channel, download, downloaded, last, running_version
|
nebulaos_osconfig.poweronlogo - the power-on logo: the picture the RTOS (zero.bin, in the running slot's rtos/rtos2 partition) draws before Linux starts. G58/G40 (human design, 2026-10-15): - always a logo, NebulaOS's by default; the only choice is an image the user uploaded to the boot logo folder (the same one becomes the Linux boot screen, bootdisplay.py);
- "Set NebulaOS logo" when the original logo is still in the RTOS; - "Restore Creality logo" - the original, saved on the printer before the first change (or copied from the other slot's RTOS, which still has it); - the running slot's RTOS, A or B: slot A too once it holds NebulaOS (G40). Only the logo slot inside zero.bin is written (rtos_logo.py: 480x272 baseline JPEG, 4:2:0, at most 10899 bytes at 0x5e50c). Before a write the whole image outside that slot must hash to FRAME_SHA256 - the stock image with the slot zeroed, the same for every logo - so an RTOS that is not the known one is never touched. Every write is read back. The Moonraker component refuses all of this while printing.
| Function | Reached by | Result keys |
|---|---|---|
check_writable() |
- | - |
classify(image) |
- | - |
convert(path) |
- | - |
nebulaos_slot_bytes() |
- | - |
restore_original() |
- |
applies, logo, result, slot
|
set_custom(path) |
- |
applies, logo, quality, result, slot
|
set_nebulaos() |
- |
applies, logo, result, slot
|
status() |
- |
logo, original_available, reason, slot, writable
|
write_slot(slot_bytes) |
- |
applies, logo, result, slot
|
nebulaos_osconfig.snapshot - copies of the user's settings (G65, 2026-10-16). config/backups/settings--/ visible in Mainsail printer.cfg moonraker.conf songs.conf (calibration is in printer.cfg) macros/ nebulascreen/nebulascreen.json calibration/ SNAPSHOT.txt what, why, which system, and where the database copy is Moonraker's database (Mainsail's settings - and login data and API keys, so never under config, which Mainsail can download): --db file copied straight from printer_data/database (S04, before Moonraker starts - a consistent copy) into system/settings- db// --db api Moonraker's own POST /server/database/backup, which writes printer_data/backup/database/.db (Moonraker refuses while printing - recorded, not hidden) When: at the first boot of every new or rolled-back system (S04, before any migration touches a setting) and from the housekeeping loop whenever the settings changed since the newest snapshot - so the newest copy always predates the next update (Moonraker updates components without a hook). The newest KEEP are kept, with their database copies.
| Function | Reached by | Result keys |
|---|---|---|
fingerprint() |
- | - |
prune(keep) |
- | - |
snapshots() |
- | - |
status() |
settings status |
keep, snapshots
|
take(reason, db, if_changed, now) |
settings snapshot |
database, files, name, newest, pruned, result
|
nebulaos_osconfig.spoolman - the Spoolman server Moonraker talks to (G125, Run 22, 2026-10-28:
Settings > Connections > Spoolman on the screen, the same layout as the printer entry).
spoolman status {configured, server, host, port} spoolman set --host
HOST --port PORT [spoolman] server: http://HOST:PORT spoolman remove
the [spoolman] section goes The setting lives where a user would put it by hand: the [spoolman]
section of the user's moonraker.conf (config root, editable in Mainsail). Only that section's
server line is touched - every other line, comment and option (sync_rate, ...) stays as it
is; the file is written atomically. Not an [include]: Moonraker refuses to start on an include
that matches no file. Moonraker reads it only at start: a change returns restart: "moonraker"
and the caller restarts it (machine.services.restart moonraker, like the hostname). Refused
while the printer is busy (G91 maintenance lock + request profile).
| Function | Reached by | Result keys |
|---|---|---|
remove() |
spoolman remove |
configured, host, port, restart, result, server
|
set_server(host, port) |
spoolman set |
configured, host, port, restart, result, server
|
status() |
spoolman status |
configured, host, port, server
|
nebulaos_osconfig.stats - print statistics from before NebulaOS (Run 23, 2026-11-02: Settings > Printer > Statistics). stats baseline what the printer printed before NebulaOS, imported once NebulaOS counts its own prints with Moonraker's history (on by default; the NebulaOS Moonraker component adds them up). What came before lives on the data drive, next to NebulaOS, and is read here - never written: creality Creality's lifetime print time: /usr/data/creality/userdata/ config/user_data_not_deleted.json, kept by Creality's master- server (stock 1.1.0.12: "total_time" in seconds, the sum of Klipper's print_stats.print_duration per print). The file is base64 of AES-128-CBC, zero-padded; key and IV are two 16-character strings in master-server (stock 1.1.0.12, offsets 0xc85e8 and 0xc862c), found against ke-dev's own counter (Run 23): '{ "total_time": 468971, "creality_num": 1 }'. With it userdata/history/print_history_record.json (plain JSON, the prints Creality still lists): count and filament. moonraker an earlier Moonraker's history (OpenKE, helper script): /usr/data/printer_data/database/moonraker-sql.db, tables job_totals and job_history (Moonraker's own schema). A source is imported once and then kept in /usr/data/nebulaos/system/ stats-baseline.json, so its numbers survive "Clean up Creality files" or a reinstall of Creality's system. A source that is absent or unreadable is looked at again next time. "Clean up Creality files" keeps both sources (cleanup.STATISTICS_KEEP, printer_data/database).
| Function | Reached by | Result keys |
|---|---|---|
baseline() |
stats baseline |
sources |
decrypt_creality(blob, key_hex, iv_hex) |
- | - |
read_creality_counter() |
- | - |
read_creality_history() |
- | - |
read_old_moonraker() |
- |
by_status, filament_mm, job_time, jobs, longest_print, print_time, reason, since, status
|
nebulaos_osconfig.system - read-only build/storage/service facts for the GUI (GUI/service readiness mission, 2026-10-09).
| Function | Reached by | Result keys |
|---|---|---|
ack_clean_reset() |
system ack-clean-reset |
result |
ack_notice(nid) |
system ack-notice |
id, result
|
boot_slot() |
- | - |
build_info() |
- | - |
cancel_clean_reset() |
system cancel-clean-reset |
result |
info() |
system busy, system cleanup-nebulaos-plan, system cleanup-plan, system info, system storage
|
after_clean_reset, build, clean_reset_pending, hostname, kernel, notices, sftp, slot, storage
|
keep_slot() |
system keep-slot |
next_boot, result
|
notices() |
- | - |
request_clean_reset() |
system clean-reset |
applies, result
|
storage_info() |
- |
boot_check, error, mount
|
swap_slot() |
system swap-slot |
applies, from, next_boot, result, trial
|
nebulaos_osconfig.updates - G73 (2026-10-17): is a pending app update installable on this
printer? Moonraker's update_manager installs Klipper and Moonraker updates with pip install -U -r <requirements> against the NebulaOS package index (ready-made packages only - there is no
compiler on the printer), and a Klipper update that changes klippy/chelper also needs a
matching c_helper.so (G72). When the index has not caught up yet (it builds daily), the update
fails and is rolled back. This check says so BEFORE the update button is pressed. Advisory
only: it never blocks an update. readiness the last result (read-only, cached file)
check-readiness run the check now and store it [--if-changed] Rules (architecture review
2026-10-17): - the target commit is Moonraker's own remote_hash; no ref guessing - no git fetch and no other write to the app repositories (Moonraker owns fetching) - only git show <remote_hash>:<file> / ls-tree - never started while update_manager is busy (pip in the same
venv) or printing; an update started DURING a check overlaps it (pip --dry-run only reads the
venv), which is accepted - read-only git: show, ls-tree, cat-file - never fetch - pip runs as
Moonraker runs it: the app's own venv, --dry-run, the index from /etc/pip.conf, temporary
files on /usr/data (not RAM)
| Function | Reached by | Result keys |
|---|---|---|
check(if_changed) |
updates check-readiness |
apps, checked_at, checked_epoch, message, result, targets
|
readiness() |
updates readiness |
- |
nebulaos_osconfig.wifi - Wi-Fi networks for wlan0 through wpa_supplicant's control socket (Q3, 2026-10-11). Replaces GuppyScreen's direct socket use: the GUI and Mainsail both go through machine.nebulaos.wifi.*. status association state and the saved networks scan a fresh scan (waits for the results) connect {"ssid", "password"} on stdin - never on a command line. A new network is only saved once it has connected; a wrong password or a timeout removes it again and returns to the previous one forget remove every saved entry for an SSID wpa_supplicant owns /usr/data/nebulaos/network/wpa_supplicant.conf (update_config=1, SAVE_CONFIG). The passphrase is turned into the 64-hex WPA PSK here, so it is never stored in plain text and never quoted into a control command. SSIDs are sent hex-encoded for the same reason.
| Function | Reached by | Result keys |
|---|---|---|
connect(spec) |
wifi connect |
address, address_mode, address_note, address_ok, result, ssid
|
decode_network_ssid(value) |
- | - |
decode_ssid_text(text) |
- | - |
forget(ssid) |
wifi forget |
removed, result, ssid
|
parse_scan_results(text) |
- | - |
psk_for(raw_ssid, password) |
- | - |
read_stdin_spec(stream) |
- | - |
saved_networks(ctrl) |
- | - |
scan() |
wifi scan |
complete, networks, status
|
security(flags) |
- | - |
ssid_name(raw) |
- | - |
status() |
wifi status |
interface, saved, status
|
validate_ssid(value) |
- | - |
wpa_status(ctrl) |
- |
address, frequency, id, key_mgmt, ssid, state
|
How it works
- Architecture: slots and boot
- Image install and the trial
- Recovery
- The black box
- Printer configuration
Reference (generated)
Build and install
Project