Helianthus VRC Explorer is a professional CLI tool for scanning Vaillant VRC-series heating regulators/controllers (e.g. VRC 700/720) via eBUS (B5 24 / B524 GetExtendedRegisters). It focuses on safe, read-oriented discovery and produces a high-quality JSON artifact.
This repository has no relation to VRChat.
- Scan VRC regulators using the B524 protocol family (groups, instances, registers).
- Provide a polished terminal experience (rich formatting, progress, summaries).
- Produce complete JSON artifacts with metadata.
- Keep non-code assets (CSV/JSON fixtures, schemas) as editable data files, not hardcoded into Python.
- CI-gated development: lint + format + tests for every PR.
- Shipping a full Home Assistant integration from this repository.
- Writing to devices by default. Any write/control functionality must be explicit and reviewed.
You need a working eBUS stack before this tool can talk to a regulator:
Vaillant VRC regulator on eBUS -> eBUS adapter -> ebusd daemon -> helianthus-vrc-explorer
Minimum setup:
- A supported eBUS-to-host adapter (hardware), wired to your eBUS.
ebusdinstalled, running, and reachable over TCP (defaults to127.0.0.1:8888).ebusdmust have thehexcommand enabled (--enablehex), since this tool uses raw telegram exchange.- Network reachability from the machine running this tool to the
ebusdTCP endpoint.
- Home automation users and integrators who already have
ebusdworking and want a safe, read-first register explorer. - Contributors reverse-engineering Vaillant VRC-series behavior and building mappings/decoders from real scans.
python -m helianthus_vrc_explorer scan \
--planner-ui auto \
--preset recommendedscan auto-discovers the destination (--dst auto) by default. Use --dst 0x.. to force an address.
Namespace contract for implementers:
- Stable B524 namespace invariants (identity, discovery authority, constraint scope, artifact keys, fixture compatibility):
docs/b524-namespace-invariants.md - This README remains user-facing; invariant-level semantics are documented in the file above once implementation behavior is stable.
Key scan UX flags:
--planner-ui auto|textual|classic--preset recommended|full|research|custom--probe-constraints(optional live opcode0x01GG/RR rescan; off by default and research-only)--b509-dump(B509 is opt-in;--b509-rangerequires this flag)--no-tips--redact(redact identity fields like serial number from console output)--trace-file /path/to/trace.log--ebusd-csv-path /path/to/15.720.csv(optional enrichment: adds eBUSd register names)--myvaillant-map-path /path/to/myvaillant_register_map.csv(optional enrichment: adds myVaillant-style leaf names)
If startup fails on default transport (tcp://127.0.0.1:8888) in an interactive TTY, scan opens a retry dialog so you can adjust protocol/host/port and retry or cancel.
Transport note:
- On shared live
ebusd-tcpsetups, the first B524 directory probe (GG=0x00) can transiently return a status-only00. The scanner treats this as transient noise and continues discovery instead of declaring B524 unsupported immediately. - On
ebusd-tcp,ERR: timeout,ERR: arbitration lost,ERR: SYN received, andERR: wrong symbol receivednow trigger a fixed 5-second quiet backoff before retry so the bus can settle. - On
ebusd-tcp,ERR: no signalnow triggers a fixed 15-second quiet backoff before retry so the eBUS side can recover instead of being polled aggressively. - Classic GG directory-probe results are retained as advisory metadata for semantic identity and namespace topology. They are useful evidence for reverse-engineering and debugging, but they do not define those semantics once a group is a scan candidate (see
docs/b524-namespace-invariants.md). Discovery no longer filters ondescriptor_type == 0.0; all non-NaN groups returned by the directory probe are scan candidates. - Instance availability is namespace-specific. Dual-namespace radio groups (
0x09,0x0A) are discovered independently per opcode namespace instead of sharing remote results across local and remote. - Artifacts retain the availability contract plus raw per-slot probe evidence under
availability_contractandavailability_probes, including the opcode0x06generic header block (RR=0x0001..0x0004) used for remote namespace occupancy. - Empty ACK / 0-byte B524 register replies are preserved as
response_state="empty_reply"(rendered as “empty reply / dormant”), not as transport errors. - B524 register replies expose protocol-level
reply_kindannotations derived from the DT byte (RK, effective 2-bit domain0..3).OP=0x02: bit1=config, bit0=volatile/stable (simple_volatile,simple_stable,config_volatile,config_stable)OP=0x06: bit1=config, bit0=invalid/valid (simple_invalid,simple_valid,config_invalid,config_valid)
- OP
0x06register-map fallbacks include a generic device header forRR=0x0001..0x0004, but BASV2 heat-source inventory is 1-indexed onGG=0x01(primary / type 1) andGG=0x02(secondary / type 2).GG=0x00is local-only on BASV2. - GG
0x09is intentionally dual-use: local/control semantics on0x02, remote radio-device semantics on0x06. - Scanner annotations include the integer sentinel
0x7FFFFFFFasvalue_display="sentinel_invalid_i32 (0x7FFFFFFF)"when decoded in integer contexts. - Unknown groups are namespace-classified from live opcode responsiveness evidence. There is no implicit unknown-group
[0x02, 0x06]fallback. - Contextual enum annotations are local-namespace scoped: group
0x02local (0x02) register context never relabels remote (0x06) entries. - Canonical namespace identity is always an opcode hex key (
0x02,0x06, ...). Labels likelocal/remoteare presentation metadata only. - Browse UI, CLI summary, and HTML report derive namespace labels from opcode identity and render them as qualified displays (for example
Local (0x02),Remote (0x06)). - Legacy artifacts that still carry mixed opcodes inside a single non-dual group are rendered per-namespace in browse/report surfaces to prevent local/remote intermixing and override bleed.
- Persisted per-operation namespace topology is authoritative for consumers. Do not infer or rewrite namespace shape from descriptors.
- B524 browse/report row identity is namespace-aware even for single-namespace groups: dedupe key
<group>:<namespace>:<instance>:<register>and path formatB524/<section>/<operation>/<group-name>/<namespace-display>/<instance>/<register-name>are round-trip stable. - Artifact schema contract is versioned (
schema_version: "2.3"current, operations-first layout). Readers keep backward compatibility by migrating unversioned,2.0,2.1, and2.2artifacts in-memory. - CI enforces these rules with
python scripts/check_b524_namespace_guardrails.py.
Constraint note:
- Normal scans use a bundled static BASV2 constraint catalog and flag values that fall outside it.
--probe-constraintsis a separate live rescan path for opcode0x01; it can add hundreds of extra requests and should only be used when you need to confirm a mismatch or do research work.- Constraint scope decision:
opcode_0x02_default. The bundled static catalog is seeded from opcode0x01probe evidence, but it is only applied to opcode0x02by default. Remote opcode0x06requires explicit scope or live confirmation via--probe-constraints. - Artifacts record this decision in
meta.constraint_scopeand per-entry fields (constraint_scope,constraint_provenance) so report/UI consumers do not guess scope semantics. --preset fullis intentionally expensive: it expands all instance slots and full RR ranges and can take hours on BASV2.--preset researchenables all groups (including those not found by directory probing) with expanded RR ranges; intended for reverse-engineering sessions. Legacy aliases:aggressive->full,exhaustive->research,conservative->recommended.
Output:
- JSON artifact:
b524_scan_0x??_<timestamp>.json - HTML report:
b524_scan_0x??_<timestamp>.html - Interactive terminals: after scan, the new fullscreen browse UI opens automatically (
qto exit back to summary).
Replay an ENH/ENS trace (no live bus I/O) into a fresh schema-2.3 JSON artifact plus matching HTML:
python -m helianthus_vrc_explorer replay-trace /path/to/captured.trace --output-dir .Replay limitations (v1):
- Only current
EnhancedTcpTransportENH/ENS trace format is supported. - Reconstruction is deterministic and only for fields derivable from captured request/response bytes.
- Metadata requiring live probing (for example runtime identity enrichment) is not replayed.
Browse a saved artifact in fullscreen Textual UI:
python -m helianthus_vrc_explorer browse --file b524_scan_0x15_<timestamp>.jsonEnable safe write mode in browse UI:
python -m helianthus_vrc_explorer browse \
--file b524_scan_0x15_<timestamp>.json \
--allow-writeBy default the tool is read-only.
scan is always read-only.
browse --allow-write enables edit actions in the fullscreen UI, and requires per-write confirmation
(old value -> new value -> confirm).
In browse --file mode, edits do not write to the device (they only update the UI view). Live
device writes are planned.
- Session preface with regulator identity and transport endpoint.
- Phased scanner progress: Group Discovery, Instance Discovery, Register Scan.
- Bundled static BASV2 constraint catalog with mismatch warnings in scan artifacts and summaries.
- Optional live
0x01constraint probing (Constraint Probe) when explicitly enabled. - Interactive planner (
textualor classic) with presets and per-group overrides. - Register decoding with raw payload retention and TT/metadata annotations in JSON.
- Auto-generated HTML report alongside JSON scan output.
- Fullscreen register browser with B524 operation-first sections:
- Group Directory
- Register Constraints
- Controller Registers
- Timer Programs
- Device Slots
- Register Tables
- Tabbed register views:
Config,Config-Limits,State. - Watch/pin/rate controls and safe write workflow (
--allow-write+ confirmation).
This tool can enrich raw scan output with human-readable names:
- myVaillant map (
--myvaillant-map-path): a small curated CSV mapping(GG,II,RR)to myVaillant-style leaf names.- Default: bundled in this repo as
data/myvaillant_register_map.csv(also packaged undersrc/helianthus_vrc_explorer/data/). - Opcode-aware namespace policy:
0x06mappings must be explicit; generic opcode-less fallback rows are local0x02defaults only.
- Default: bundled in this repo as
- eBUSd CSV schema (
--ebusd-csv-path): adds register names from an eBUSd configuration CSV (e.g.15.720.csv).- Source: typically taken from an
ebusd-configurationcheckout (not bundled here).
- Source: typically taken from an
Capture first 5 minutes of autorun, sped up 10x (300s -> 30s):
./scripts/capture_tui_preview.sh --capture-seconds 300 --speedup 10
./scripts/capture_planner_preview.sh
./scripts/capture_browse_preview.shPreview script options (all three capture scripts):
--output-seconds 45override final animation duration.--cols 132 --rows 40tune terminal geometry.--font-size 18control render font size (pixels).--poster-percent 40choose which moment becomes<name>.png.--command "python -m helianthus_vrc_explorer ..."capture a different run.--font-path "/path/to/Anonymous Pro.ttf"force font selection.
Dependencies for preview generation:
asciinemaaggexpectPillow(available in project dev environment)
Requirements: Python 3.12+
python -m venv venv
source venv/bin/activate
pip install -e ".[dev]"
ruff check .
ruff format .
pytestIf you need to add or update non-code data (schemas, fixtures, CSV/JSON dumps), keep it as data under data/ so non-programmers can review and edit it via PRs.
GPL-3.0-or-later. See LICENSE.