This release is a pre-release and may not be stable for production use.
ppk2lab
See exactly where your device's power goes. ppk2lab turns the Nordic Power Profiler Kit II into a scriptable measurement lab: record current and eight digital signals on one timeline, decode low-speed UART and SPI, and attribute energy to individual protocol events. Everything is reachable from Python, the command line, or an AI agent, so a power regression can fail a CI build the same way a failing test does.
[!IMPORTANT] This project is experimental and is not affiliated with or endorsed by Nordic Semiconductor ASA.
Highlights
ppk2lab lets humans and agents:
- discover and configure one or more PPK2 devices;
- capture calibrated current and all D0-D7 digital states on one synchronized timeline;
- detect dropped samples instead of silently compressing time;
- decode low-speed UART and SPI traffic (9,600 baud / 10 kHz validated);
- measure charge, energy, peak current, and latency for each decoded event;
- trigger captures from current, digital state, UART content, or SPI transactions;
- run reproducible power assertions in local automation and CI;
- try everything without hardware via
--simulate.
Install
The core package requires Python 3.11 or newer. The final runtime dependency set will be frozen before the first PyPI release.
pipx install ppk2lab # recommended for the CLI
# or inside a virtual environment:
pip install ppk2lab
ppk2lab --version
ppk2lab doctor --json
The package is not on PyPI yet. Until the 0.1.0 release, install it from a source checkout as shown below; the current version is 0.1.0.dev0.
Run from a development checkout:
git clone https://github.com/tipoLi5890/ppk2lab
cd ppk2lab
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
ppk2lab doctor --json
Claude Code plugin
After installing the ppk2lab CLI, add this repository as a Claude Code marketplace and install its skills:
/plugin marketplace add tipoLi5890/ppk2lab
/plugin install ppk2lab@ppk2lab
During plugin development, load the checkout directly with claude --plugin-dir ./.
Codex plugin and loose skills
Open the Codex plugin browser with /plugins, add the repository marketplace, and install ppk2lab. Exact non-interactive commands will be verified against the current Codex release before publishing.
For repository-scoped loose skills, place them in .agents/skills/. For a user-wide installation:
mkdir -p ~/.agents/skills
cp -R skills/* ~/.agents/skills/
Claude Code can use the same skill sources from .claude/skills/ or through the bundled plugin. Full setup and troubleshooting lives in INSTALL.md.
Quickstart
Every command also runs without hardware by adding --simulate, which uses a built-in simulated PPK2 to exercise the toolchain. A simulated run is not a measurement.
Inspect the environment and connected devices without changing hardware state:
ppk2lab doctor --json
ppk2lab discover --json
ppk2lab info --device <serial> --json
Capture current and D0-D7 without automatically enabling DUT power:
ppk2lab capture --device <serial> --duration 5s --digital D0-D7 --output capture.ppk2a
Decode a supported low-speed UART signal and measure energy by frame:
ppk2lab decode capture.ppk2a --uart D0 --baud 9600 --output uart.jsonl
ppk2lab measure capture.ppk2a --annotations uart.jsonl --group-by frame --json
Run a reproducible power assertion:
ppk2lab assert capture.ppk2a \
--rule 'after uart("TX_DONE"), within 20ms, avg_current < 10uA' \
--format json
These commands are implemented today. Every JSON contract carries schema_version 1 and remains subject to change until the 0.1.0 release.
What it does
| Command | Purpose | Hardware state |
|---|---|---|
discover, info |
Find devices and inspect firmware, metadata, calibration, and current state | Read-only |
capabilities, schema |
Return machine-readable commands, limits, decoders, and JSON schemas | Read-only |
doctor |
Diagnose USB permissions, busy ports, stream rate, metadata, and dropped samples | Read-only by default |
configure |
Select mode, source voltage, and DUT power with before/after state reporting | State-changing |
capture |
Record raw current, range, sequence counter, and D0-D7 with triggers | Measurement; power changes are opt-in |
decode |
Produce UART, SPI, edge, pulse, and transaction annotations | Offline by default |
measure |
Calculate current, charge, energy, peaks, and latency for a time range or annotation | Offline |
assert |
Apply reproducible power and protocol regression rules | Offline by default |
export |
Create CSV, VCD, JSONL, and other derived views without replacing raw evidence | Offline |
Scope and physical limits
PPK2 samples its digital inputs at 100 kS/s. Protocol decoding is therefore intended for low-speed signals. The initial validated targets are:
- UART up to 9,600 baud;
- SPI clock up to 10 kHz;
- all eight digital inputs D0-D7;
- higher rates only when explicitly marked conditional or experimental.
This project is not intended to replace a MHz-class logic analyzer. A frame that crosses a missing-sample interval is reported as incomplete or invalid, never as a confident decode.
| Protocol | Initial support level |
|---|---|
| UART at 1,200-9,600 baud | Validated target |
| UART at 19,200 baud | Conditional |
| UART at 38,400 baud | Experimental |
| UART at 57,600/115,200 baud | Not claimed as decodable |
| SPI clock up to 10 kHz | Validated target |
| SPI at 10-20 kHz | Conditional |
| SPI above 20 kHz | Experimental or unsupported |
Hardware safety
configureis a dry run unless the user explicitly applies the change.- Capture does not enable DUT power unless a user-approved profile or explicit option requests it.
- Source voltage is expressed as
voltage_mv, checked against device capabilities, and never inferred from a DUT name. - Mode changes, DUT power, source voltage, and reset operations report the previous and resulting state.
- On completion or failure, the library attempts to restore the session's starting power state and records whether restoration succeeded.
- No plugin hook or skill may automatically enable DUT power, change voltage, or reset a device.
Use with AI agents
Every operation is available as a typed Python API and as a CLI command with stable JSON output. Read-only inspection is separated from operations that change hardware state.
Command surface:
ppk2lab discover
ppk2lab info
ppk2lab capabilities
ppk2lab schema
ppk2lab configure
ppk2lab capture
ppk2lab decode
ppk2lab measure
ppk2lab assert
ppk2lab export
ppk2lab doctor
Commands that enable DUT power, change source voltage, or reset hardware are explicitly identified as state-changing. Voltage arguments include their unit in the API name, such as voltage_mv.
An optional agent adapter may be provided as a separate package. The core driver and file formats do not depend on one agent framework.
Every JSON result carries a schema version, stable error code, remediation hint, completion state, and sample-gap information. ppk2lab capabilities --json describes the live command and decoder surface so an agent does not need to infer unsupported behavior.
Bundled agent skills
The plugin ships two skills built on progressive disclosure instead of one oversized prompt: each SKILL.md is a thin router that keeps the safety contract inline and maps tasks to per-topic reference notes the agent reads only when needed. Live knowledge — commands, options, decoder rate tiers, schemas, error codes — is never duplicated into prompts; agents query the self-describing CLI (capabilities --json, schema, doctor --json) instead.
| Skill | Covers | On-demand references |
|---|---|---|
ppk2lab-operate |
Measuring with a PPK2: setup and troubleshooting, safe configuration and capture, long recordings, triggers, UART/SPI/logic decoding, energy analysis, CI power regression, hardware diagnostics | setup, capture, triggers, decode, analysis, regression, diagnostics |
ppk2lab-maintain |
Maintaining this repository: observation-only protocol research, release-gate auditing | protocol-research, release-gating |
Skills provide workflow guidance; the ppk2lab CLI remains the deterministic execution and validation layer. Installation never enables DUT power or starts a capture automatically.
Architecture
USB CDC transport
-> device discovery and capability query
-> streaming frame assembler
-> raw sample parser and sequence-gap detector
-> calibration and synchronized D0-D7 transitions
-> trigger engine
-> UART/SPI decoder plugins
-> event-level charge and energy analysis
-> capture files, CSV, VCD, JSONL, Python, and CLI
The canonical capture format preserves raw samples, calibration metadata, device and firmware identity, capture configuration, timestamps, and data-loss markers. Processed exports never replace the original evidence.
Official references
PPK2 functionality is based on Nordic Semiconductor's official PPK2 documentation and the official Power Profiler app repository. These official materials define the product behavior and compatibility reference for this project.
The project does not distribute Nordic firmware binaries. Firmware installation and updates should be performed with Nordic's official tools unless separate redistribution permission is established.
Nordic Semiconductor, Power Profiler Kit, and PPK2 may be trademarks or product names of Nordic Semiconductor ASA. Their use here is solely to identify compatible hardware.
See docs/sources.md and docs/protocol-spec.md for the Nordic official references and documented PPK2 behavior used by the project.
Roadmap
The following work remains open before the first release:
- a hardware compatibility matrix covering Windows, macOS, and Linux across firmware versions, multiple devices, and hot unplug;
- a calibration cross-check against the official Power Profiler app using known loads;
- UART and SPI decoder validation on real signals against defined error-rate thresholds;
- long-duration soak tests for streaming, memory use, and recovery;
- release gates: a frozen public API baseline, a dependency license audit, a release rehearsal, and the PyPI publish itself.
See ROADMAP.md for versioned exit criteria and the hardware compatibility matrix.
Documentation
| Document | Covers |
|---|---|
| INSTALL.md | Python, USB permissions, Claude Code, Codex, CI, and troubleshooting |
| ROADMAP.md | Milestones, support levels, and release exit criteria |
| docs/SPEC.md | Public data model, states, API, and schema contracts |
| docs/api-baseline.md | Frozen public API surface and stability policy |
| docs/cli-reference.md | CLI commands, flags, JSON output, and exit codes |
| docs/protocol-spec.md | Documented PPK2 protocol, commands, fields, and device behavior |
| docs/capture-format.md | Canonical loss-aware capture artifact |
| docs/calibration.md | Raw-sample to current conversion formula and units |
| docs/logic-port.md | D0-D7 wiring, Logic VCC, levels, and usable bandwidth |
| docs/decoders.md | UART/SPI contracts, confidence, gaps, and physical limits |
| docs/triggers.md | Trigger types and pre/post-trigger capture windows |
| docs/energy-analysis.md | Charge, energy, peak-current, and latency definitions |
| docs/agent-interface.md | JSON, tools, state-changing operations, and context budgets |
| docs/sources.md | Nordic official documentation and repository references |
| SECURITY.md | Hardware, USB, file, and untrusted-input security model |
Contact
Questions, bugs, compatibility reports, and feature requests should be filed through GitHub Issues.
License
Released under the MIT License. It covers the original material in this repository only — PPK2 hardware, Nordic firmware, Nordic documentation, and trademarks remain with their owners.
Development
This project is developed with assistance from Claude Code and OpenAI Codex.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ppk2lab-0.1.0.dev0.tar.gz.
File metadata
- Download URL: ppk2lab-0.1.0.dev0.tar.gz
- Upload date:
- Size: 105.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4d4bc39e57432a57a6627131163e94f441589ea95911779c29dd03c5f70c5efc
|
|
| MD5 |
3c4181c18d0a298eadee6dbbe31e3c03
|
|
| BLAKE2b-256 |
e3aeea92b15ee21b860518b94d19f65da63723a226ffddf7c5f9520d65bfcb4c
|
Provenance
The following attestation bundles were made for ppk2lab-0.1.0.dev0.tar.gz:
Publisher:
release.yml on tipoLi5890/ppk2lab
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ppk2lab-0.1.0.dev0.tar.gz -
Subject digest:
4d4bc39e57432a57a6627131163e94f441589ea95911779c29dd03c5f70c5efc - Sigstore transparency entry: 2515718829
- Sigstore integration time:
-
Permalink:
tipoLi5890/ppk2lab@8069a0c2f90a61393122cfc7ae68c57e42d2c725 -
Branch / Tag:
refs/tags/v0.1.0.dev0 - Owner: https://github.com/tipoLi5890
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8069a0c2f90a61393122cfc7ae68c57e42d2c725 -
Trigger Event:
release
-
Statement type:
File details
Details for the file ppk2lab-0.1.0.dev0-py3-none-any.whl.
File metadata
- Download URL: ppk2lab-0.1.0.dev0-py3-none-any.whl
- Upload date:
- Size: 99.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
67c34ccc944c8254c51ec46b3f871ccce801f06f2e289454eda39efdbd6917d9
|
|
| MD5 |
7db942b4109869d7e349891ef9de7710
|
|
| BLAKE2b-256 |
eded8950f182b0d61cdfdfd3b0a7a814c755054256c47e5b8740f054d96b6e76
|
Provenance
The following attestation bundles were made for ppk2lab-0.1.0.dev0-py3-none-any.whl:
Publisher:
release.yml on tipoLi5890/ppk2lab
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ppk2lab-0.1.0.dev0-py3-none-any.whl -
Subject digest:
67c34ccc944c8254c51ec46b3f871ccce801f06f2e289454eda39efdbd6917d9 - Sigstore transparency entry: 2515718927
- Sigstore integration time:
-
Permalink:
tipoLi5890/ppk2lab@8069a0c2f90a61393122cfc7ae68c57e42d2c725 -
Branch / Tag:
refs/tags/v0.1.0.dev0 - Owner: https://github.com/tipoLi5890
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8069a0c2f90a61393122cfc7ae68c57e42d2c725 -
Trigger Event:
release
-
Statement type: