lr-lumentest-cli
CLI for the LumenRadio LumenTest production test station server.
Installation
pip install lr-lumentest-cli
Quick Start
# Point the CLI at your station server and identify yourself by scanning
# your badge (the handheld scanner types the badge id at the prompt)
lumentest login --base-url http://10.0.0.1:17080 --badge-id LOP0000001
# Check server health, login state, and which station you're pointed at
lumentest status
# Scan and list imported products
lumentest product scan
lumentest product list
# Run a full test sequence interactively (prompts on ALERT steps)
lumentest test start --serial SN-00001
# Run a single step (for development / debugging)
lumentest test step production-test flash-firmware --serial SN-00001
Command Reference
lumentest login [--base-url URL] --badge-id ID
# ID is the scanned QR badge; the server resolves it to your operator id.
lumentest logout
lumentest status [--output rich|json]
# Names the station that answers ([station].id from its config.toml), so you
# can confirm which bench you are pointed at, alongside login state and
# server health.
lumentest --version
lumentest product list [--output rich|json]
# Table includes a Build Words column — see doc/build-words.md. The manifest
# digest is not shown: read it from --output json when you need the digest.
lumentest product active
lumentest product set ARTICLE [REVISION]
lumentest product remove ARTICLE [REVISION] [--yes]
lumentest product scan [--rescan] [--output rich|json]
# Scans the station's artifact_cache/, registers every valid package, and
# reports each package's declared env variables (from parameters.toml) —
# the value a run will see, where it came from (config.toml's [env], the
# station's own environment, or the package default) and which are still
# unconfigured — alongside its prerequisites (the external tools its
# sequences need) against the station itself. Each unconfigured variable's
# line carries the exact `lumentest config set env.NAME <VALUE>` command to
# fix it; a set value applies to the running station immediately, so
# re-running scan is enough to confirm it, for a variable and for a tool
# newly installed on PATH alike — no restart needed either way. --output
# json emits the raw payload.
lumentest product import PATH [--update] [--bundle] [--invalidate] [--output rich|json]
# PATH: directory or .zip/.tar.gz archive.
# --update: recompute SHA-256 checksums in artifact-manifest.json before
# uploading — useful during step development to skip manual hashing.
# --bundle: pack PATH into <PATH>.tar.gz (manifest + declared files only)
# next to it instead of uploading — for email/USB delivery;
# import the archive later with the same command. Requires a
# directory; passing an archive file just warns and exits.
# Prints the package's Build Words (doc/build-words.md) so a
# technician can read them off a locally built bundle without a
# running server; --output json carries them as "build_words".
# --invalidate: discard whatever the station has staged for this
# article/revision before preflighting, so every declared file
# uploads again instead of reusing what's already there. The
# escape hatch when an import keeps failing at commit on a file
# the manifest no longer declares — the staged tree only ever
# grows, so a package fixed in Arena after a first failed
# upload can otherwise leave an orphan file behind forever.
# Requires a directory; an archive import never touches the
# station's staging tree, so there is nothing to invalidate.
# Reports the package's declared env variables the same way `product scan`
# does: the value a run will see, where it came from, and which still need
# a value. Fix an unconfigured one with the `lumentest config set` command
# printed on its line, then re-run `product scan` to confirm — same as
# confirming a newly installed prerequisite tool, neither needs a restart.
# Only artifact-manifest.json's declared files (and declared extra
# sequences) are packed and uploaded — the manifest is the contract for
# what the package needs. A package that needs a file its manifest does
# not declare must have that file added to the manifest, not bundled some
# other way.
# A directory import first checks with the station which files it already
# has (by digest, including across every other cached revision) — a
# retry after an interrupted upload resumes instead of re-sending
# everything. Only what's actually missing is uploaded, with a progress
# bar over just those bytes; the command then reports how many files were
# reused, e.g. "12 of 24 files already on the station (302 MB reused)".
# An existing .zip/.tar.gz archive still uploads as a single one-shot
# transfer. --output json moves all of the above to stderr so stdout
# carries nothing but the final JSON — see "Machine-readable output".
lumentest sequence list [--article ARTICLE] [--output rich|json]
lumentest sequence steps [SEQUENCE] [--article ARTICLE]
lumentest sequence selection get [SEQUENCE] [--article ARTICLE]
lumentest sequence selection set [SEQUENCE] [--article ARTICLE] --steps 1,2,5
lumentest sequence selection clear [SEQUENCE] [--article ARTICLE]
# SEQUENCE is optional when the article declares exactly one; --article
# defaults to the active product.
lumentest test start [--serial SN] [--article ARTICLE] [--sequence ID]
# Blocks with an interactive Rich UI; handles ALERT prompts; exits with
# the run's terminal status: 0 PASS, 1 FAIL, 2 ABORTED, 3 ERROR (outcome
# undetermined — station unreachable or run gone). The operator comes
# from the bearer token established by `lumentest login`, not a flag.
# Without --serial it prompts for a scan, except on a sequence that reads
# the serial off the unit part-way through the run (`serial_read_in_sequence`),
# which the station reports on GET /api/sequences and which refuses a
# supplied serial with 422 — there the run starts straight away.
# The run header shows the package's Build Words when the station reports
# them.
lumentest test step SEQUENCE STEP [--article ARTICLE] [--serial SN]
# Runs one step via the same interactive UI. STEP is a name or 0-based
# index. SEQUENCE — like --sequence above — is the ID column of
# `sequence list`, not its Name: the two differ once a sequence declares
# a name of its own.
lumentest test status [--output rich|json]
# One-shot snapshot of the currently active test run.
lumentest result list [--limit N] [--serial SN] [--output rich|json]
# --serial SN filters to runs for one device (exact dut_id match); the station
# filters server-side so high-throughput stations don't ship the full history.
lumentest result show [RUN_ID]
# RUN_ID is optional: omit it to show the most recent run.
lumentest result logs [RUN_ID] [--step IDX] [--stream stdout|stderr|traceback]
[--download DIR] [--output rich|json]
# RUN_ID is optional: omit it to fetch the most recent run's logs.
# Without --step: fetches the complete log bundle via GET /logs/all — run error,
# structured journal, and every step's stdout/stderr/traceback. --output json
# emits the raw JSON bundle; --download DIR writes the tree to DIR/<run_id>/
# (error.txt, log.jsonl, steps/<name>/{stdout,stderr,traceback}.txt, omitting
# empty files). --output json takes precedence when both flags are given.
# With --step IDX: shows that step's stdout, stderr, and traceback (or a single
# stream via --stream).
lumentest result export [RUN_ID] [--all] [--serial SN] [--limit N]
[--out DIR] [--output rich|json]
# Downloads one .tar.gz station snapshot via GET /api/results/export: the
# selected run(s) verbatim under results/ (run.json, qrm-payload.json, the
# journal, every step's captured streams) plus the station's own log,
# state.json, operator_stats.json and effective config under station/ —
# laid out exactly as the station stores them on disk. RUN_ID / --all /
# --serial / --limit govern results/ only; the station context is always
# included. Bare `result export` packs only the most recent run; --all
# opts into every retained run. RUN_ID is mutually exclusive with --all,
# --serial and --limit.
# --out DIR: directory to write the archive into (default: the current
# directory). The filename is stamped by the station itself from its own
# [station].id and a UTC timestamp, so an export stays identifiable once
# it is off the station.
# artifact_cache/ package binaries are never packed — represented instead by
# an inventory (article, revision, size, file count); Arena is the system
# of record for firmware. Re-send a run to QRM by hand with
# `qrm result upload <run>/qrm-payload.json` against the extracted tree.
# An export contains the station's QRM service password, session token
# hashes, operator identities, and whatever a step or tool printed. Treat
# an archive as a secret — see doc/troubleshooting.md § Collecting a
# station snapshot for support.
lumentest config list [--output rich|json]
# Flattens config.toml to dotted keys (station.id, env.NRF_TOOLS,
# timeouts.default_step_s, ...) so a technician can scan the whole
# effective configuration in one table. Secrets (qrm.password,
# serial.client_secret, user password hashes) show as "<redacted>" and are
# marked in the Notes column, alongside keys that need a station restart
# to take effect (station.host, station.port, debug.results_dir).
lumentest config get KEY [--output rich|json]
lumentest config set KEY VALUE [--json] [--output rich|json]
# VALUE is sent as a raw string and coerced through the server's pydantic
# validation (e.g. "90" -> the int 90); pass --json to send VALUE parsed
# as JSON instead, for list/dict/explicitly-typed values. This is how a
# newly required package env variable gets set without restarting the
# station: `lumentest config set env.SOME_VAR value` then
# `lumentest product scan`. A key flagged restart-required still saves,
# but a visible warning says it only takes effect after the next restart.
# Setting a secret back to its own masked "<redacted>" value is rejected,
# so a `config get` / `config set` round trip can never silently
# overwrite a credential.
lumentest config unset KEY
# Resets KEY to its model default; for the free-form [env] and
# [test].fake_tools maps this removes the entry instead. A required key
# with no default (e.g. station.id) is rejected. A restart-required key
# carries the same warning `config set` gives — the reset is saved, but
# the running station keeps the old value until it restarts.
lumentest operator whoami [--output rich|json]
# Resolve the operator behind the stored token via GET /api/auth/whoami.
# Exits 1 if the token is missing, unknown, or expired.
lumentest operator stats [OPERATOR_ID] [--stations URL1,URL2,...] [--output rich|json]
# Per-operator statistics aggregated across stations (counters add,
# last_login = max). Omit OPERATOR_ID to list every operator seen.
# --stations defaults to the logged-in station.
Machine-readable output
Every command above that takes --output json writes exactly one JSON document
to stdout and nothing else, so a caller can pipe it straight into a parser:
lumentest product import --bundle --output json ./400-1011_A | jq -r .build_words
Everything meant for a human — progress bars, warnings, "generated the
manifest" — goes to stderr in JSON mode, and errors always do. Redirect it
away with 2>/dev/null, or keep it to watch a long import while still capturing
the result.
A command that finds nothing to report emits null rather than staying silent,
so stdout parses unconditionally.
result logs --step IDX is the one exception: it has no JSON form, so --output
is inert there and the step's captured streams go to stdout either way. Piping
that output works with the flag or without it.
In --output rich (the default) the human output goes to stdout as usual.
Server URL
The CLI reads the server URL from (in order of priority):
--base-urlflag onlumentest loginLUMENTEST_URLenvironment variable- Stored value in
~/.config/lumentest/login.json - Default:
http://127.0.0.1:17080
Release files for lr-lumentest-cli 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| lr_lumentest_cli-0.7.0.tar.gz | 145.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lr_lumentest_cli-0.7.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 224.0 kB
Release files / lr_lumentest_cli-0.7.0.tar.gz
| Download URL | lr_lumentest_cli-0.7.0.tar.gz |
|---|---|
| Size | 145.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0b77fee62166885a14ad2e209ba40ea1dcdd3963f76db0351b8e852a73e46499
|
|
BLAKE2b-256 checksum How to use checksums |
14e81f3052f16fe9094db77317cc303e3e1b3ae9bf9f0eae499b170b007595a5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|
Release files / lr_lumentest_cli-0.7.0-py3-none-any.whl
| Download URL | lr_lumentest_cli-0.7.0-py3-none-any.whl |
|---|---|
| Size | 78.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0ae9ca0b1e504ff82ddb038427bd14b609ac356e6227bf86c75e5a8db155f7a6
|
|
BLAKE2b-256 checksum How to use checksums |
bd1937138a5b5340996b4a4017491154bf996d18db67637b69598bf8b08a4f62
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|