Skip to main content

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 and login state
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]
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] [--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".
  # 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      ARTICLE SEQUENCE
lumentest sequence selection get   ARTICLE SEQUENCE
lumentest sequence selection set   ARTICLE SEQUENCE --steps 1,2,5
lumentest sequence selection clear ARTICLE SEQUENCE

lumentest test start   [--serial SN] [--article ARTICLE] [--sequence NAME]
  # 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.
  # 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.
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):

  1. --base-url flag on lumentest login
  2. LUMENTEST_URL environment variable
  3. Stored value in ~/.config/lumentest/login.json
  4. Default: http://127.0.0.1:17080

Release files for lr-lumentest-cli 0.5.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lr-lumentest-cli 0.5.2
File Size Uploaded
lr_lumentest_cli-0.5.2.tar.gz 138.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for lr-lumentest-cli 0.5.2
File Interpreter ABI Platform
lr_lumentest_cli-0.5.2-py3-none-any.whl Python 3 none any Details

Total release size: 213.5 kB

Release files / lr_lumentest_cli-0.5.2.tar.gz

Download URL lr_lumentest_cli-0.5.2.tar.gz
Size 138.1 kB
Tags Source
SHA-256 checksum
How to use checksums
fe96bb7bffc1a225c08175a85689b06eef4554308c73ef8ed120b3e64abdab31
BLAKE2b-256 checksum
How to use checksums
943de383ec3dae9b9005c7ac0aa53c02462da58c5f686874d6b3f7ddea163c4e
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.5.2-py3-none-any.whl

Download URL lr_lumentest_cli-0.5.2-py3-none-any.whl
Size 75.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
30dafd97893068c0dc4c8c5c4d9a7cf0bf0042bdac98da80d6891016d6aca413
BLAKE2b-256 checksum
How to use checksums
5453835d6fbd750d1e7cd291f668867d585dc0298df04f5d9da0f9395dd4c967
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.14

Release history Release notifications | RSS feed

0.8.0

2 release files

0.7.0

2 release files

0.6.1

2 release files

0.6.0

2 release files

This release

0.5.2 This release

2 release files

0.5.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page