helianthus-ebusreg
helianthus-ebusreg is the registry and projection layer for Helianthus eBUS integrations. It turns discovered devices into typed planes, exposes method/schema metadata, and provides routing helpers for invoke and broadcast flows.
Purpose and Scope
What belongs in this repository
- Device discovery, scan flow, and registry indexing (
registry/).
- Method/schema modeling and selector decoding (
schema/).
- Invoke and broadcast routing (
router/).
- Default provider wiring and Vaillant plane implementations (
providers/, vaillant/).
What does not belong in this repository
- Byte-level transport, framing, and low-level bus primitives (use
helianthus-ebusgo).
- Gateway runtime/API process wiring and live deployment orchestration (use
helianthus-ebusgateway).
Status and Maturity
- Active, CI-validated library with stable package-level tests.
- Suitable for contributor onboarding and issue-focused feature work.
- Live adapter smoke runs are executed from
helianthus-ebusgateway; this repo provides the registry/projection core used there.
Helianthus Dependency Chain
helianthus-ebusgo -> helianthus-ebusreg -> helianthus-ebusgateway -> integrations/add-ons
(transport) (registry/schema) (runtime/api/smoke)
Method safety/routing metadata is exposed via registry.ResolveMethodMetadata(method).
mutability: read_only, mutating, or unknown
danger: safe, dangerous, or unknown
routable: true or false
Backward-compatible defaults for legacy registry.Method implementations:
mutability: inferred from ReadOnly() (true -> read_only, false -> mutating)
danger: inferred from mutability (read_only -> safe, otherwise -> dangerous)
routable: defaults to true
Methods can override defaults by implementing optional interfaces in registry:
MethodMutabilityProvider, MethodDangerProvider, and MethodRoutableProvider.
Method Contract Semantics
Normalization semantics are stable and test-backed:
| Input |
Result |
no mutability provider + ReadOnly()==true |
mutability=read_only |
no mutability provider + ReadOnly()==false |
mutability=mutating |
explicit mutability provider (unknown/read_only/mutating) |
provider value is preserved |
| invalid mutability provider value |
fallback to ReadOnly() inference |
| no danger provider |
derived from mutability (read_only -> safe, otherwise dangerous) |
explicit danger provider (safe/dangerous) |
provider value is preserved |
danger provider returns unknown or invalid |
fallback to derived danger |
| no routable provider |
routable=true |
| explicit routable provider |
provider value is preserved |
Shared Service Projections
For MCP and GraphQL service-layer reuse, registry exposes projection helpers:
ProjectRegistryDevices(iter EntryIterator)
ProjectDeviceEntry(entry DeviceEntry)
ProjectPlane(plane Plane)
ProjectMethod(method Method)
Projected method data includes frame template bytes plus normalized method metadata (mutability, danger, routable) through ResolveMethodMetadata.
Deterministic ordering guarantees for projected views:
- devices:
address ascending, then manufacturer/device/hardware/serial (case-insensitive)
- planes: name ascending (case-insensitive)
- methods: name ascending (case-insensitive), then template
(primary, secondary)
Quickstart (copy/paste)
1) Clone and baseline checks
git clone https://github.com/d3vi1/helianthus-ebusreg.git
cd helianthus-ebusreg
go test ./...
go vet ./...
go build ./...
2) CI-parity test run
./scripts/ci_local.sh
go test -race -count=1 ./...
3) Repository notes
# library-only repo; no main packages are expected
go list -f '{{if eq .Name "main"}}{{.ImportPath}}{{end}}' ./... | sed '/^$/d'
Local Smoke-Test Configuration Examples
helianthus-ebusreg is consumed by a runtime service, but these are the core values you typically set during local smoke wiring:
scan:
initiator: 0x10
targets: [0x08, 0x09, 0x15]
providers:
- vaillant_system
- vaillant_heating
- vaillant_dhw
- vaillant_solar
invoke_defaults:
source: 0x10
target: 0x08
Equivalent Go wiring in this repository:
deviceRegistry := registry.NewDeviceRegistry(vaillantproviders.Default())
entries, err := registry.Scan(ctx, bus, deviceRegistry, 0x10, []byte{0x08, 0x09, 0x15})
if err != nil {
return err
}
eventRouter := router.NewBusEventRouter(bus)
eventRouter.SetPlanes(planesFromEntries(entries))
Focused Validation Commands
| Area |
Command |
| terminology gate (CI parity) |
`if grep -RInwi --exclude-dir=.git -E 'm[a]ster |
| compile |
go build ./... |
| vet |
go vet ./... |
| all tests (CI parity) |
go test -race -count=1 ./... |
| registry scan/indexes |
go test ./registry -count=1 |
| router invoke/broadcast |
go test ./router -count=1 |
| schema selectors/loaders |
go test ./schema -count=1 |
| Vaillant providers/planes |
go test ./vaillant/... -count=1 |
| lint (if installed locally) |
golangci-lint run |
| TinyGo CI parity |
`mains=$(go list -f '{{if eq .Name "main"}}{{.ImportPath}}{{end}}' ./... |
Link Map
Core repos
Architecture and smoke docs
Issues and workflow conventions