Skip to content

SPAN Official v2 API Ebus integration#104

Merged
cayossarian merged 18 commits intomainfrom
ebus_integration
Feb 27, 2026
Merged

SPAN Official v2 API Ebus integration#104
cayossarian merged 18 commits intomainfrom
ebus_integration

Conversation

@cayossarian
Copy link
Member

v2 eBus integration

NickBorgers and others added 18 commits February 24, 2026 15:50
When parallel requests share a client via get_all_data(), one request
failing can destroy the shared client while others are in-flight. Those
requests then fail with ReadError, WriteError, or CloseError (all
subclasses of NetworkError) which were not being caught by the retry
logic.

This fix extends the exception handling in _retry_with_backoff() to
catch these network errors alongside RemoteProtocolError, applying the
same immediate retry with client recreation strategy.

Fixes #89

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove REST client (~1430 lines), generated OpenAPI client (~2000 lines),
virtual circuits, delay registry, and all v1-specific code. SPAN Panel
v2 firmware users get MQTT/Homie transport exclusively.

Retained: SpanPanelSnapshot contract, simulation engine, phase validation,
3 PEP 544 protocols (SpanPanelClientProtocol, CircuitControlProtocol,
StreamingCapableProtocol).

Removed: SpanRestClient, SpanPanelClient shim, generated_client/,
CircuitCorrelationProtocol, REST-only exceptions, ~22 REST test files,
example scripts. Circuit correlation moves to integration layer.

Dependencies: paho-mqtt now required (was optional), attrs and
python-dateutil removed. 217 tests passing, 86.5% coverage.
…b synthesis

Branches were a v1 REST concept. Simulation now uses the same unmapped tab
synthesis pattern as the MQTT transport — gaps in occupied tab positions are
filled with zero-power SpanCircuitSnapshot entries (circuit_id=unmapped_tab_N).
Replace thread-based paho-mqtt wrapper with event-loop-driven
architecture matching Home Assistant core:
- Add AsyncMQTTClient with NullLock replacing paho's 7 internal locks
- Drive socket I/O via add_reader/add_writer instead of loop_start()
- Remove threading.Lock, call_soon_threadsafe from MQTT callbacks
- Use loop_misc() periodic timer for keepalive
- Manage reconnection in async loop with exponential backoff
- Add hand-rolled MQTT mock fixture in conftest following HA core pattern
- Add paho-mqtt to pre-commit mypy/pylint additional_dependencies
Test files should describe what they test, not which migration
phase created them. Names are stable beyond the refactor.
Add Step 7 documenting the AsyncMqttBridge refactor to match
HA core's event-loop-driven MQTT pattern.
…it power units

- Fix LUGS node type detection: actual types are
  energy.ebus.device.lugs.upstream/downstream (not generic .lugs)
- Correct energy field mapping for LUGS: imported-energy = consumed,
  exported-energy = produced (was swapped)
- Fix circuit active-power units: values are in watts, not kW
  (removes erroneous * 1000 multiplication)
- Treat PV/EVSE as metadata nodes: extract device_type and
  relative_position from feed references instead of building
  them as circuits directly
- Add relative_position field to SpanCircuitSnapshot for
  detecting lug-based vs breaker-connected PV/EVSE
…ice types

- Append UUID suffix to client name for panel uniqueness
- Use hopPassphrase field name per SPAN v2 API spec
- Support optional passphrase (None for door-bypass registration)
- Wait up to 10s for circuit name retained messages after device ready
- Derive device_type from simulation template energy profile mode
Remove the Last Will and Testament that published "lost" (retained) to the
panel's Homie $state topic. A consumer must never publish to the device's
state topic — when our client disconnected ungracefully, the LWT overwrote
the panel's retained $state=ready with "lost", making all subsequent
connections time out waiting for a ready state that would never arrive.
Recovery required a panel power cycle.

Also move tls_set() into the executor alongside connect() to avoid
blocking the event loop with ssl.SSLContext.load_verify_locations().
Parse PV inverter metadata (vendor-name, product-name, nameplate-capacity)
into new SpanPVSnapshot model. Extend SpanBatterySnapshot with BESS metadata
fields. Parse upstream/downstream lugs per-phase current (l1-current,
l2-current). Parse power-flows node (pv, battery, grid, site). Improve
dsm_grid_state multi-signal heuristic and run_config tri-state derivation.

- New SpanPVSnapshot model on SpanPanelSnapshot.pv
- SpanBatterySnapshot gains vendor_name, product_name, nameplate_capacity_kwh
- SpanPanelSnapshot gains power_flow_*, upstream/downstream l1/l2_current_a
- homie.py: _build_pv(), extended _build_battery(), improved derivations
- Simulation engine updated for new snapshot fields
Panel MQTT topics use dashless UUIDs (e.g. 941d6a8b41ab4c57a6b8be14b5981fe6)
but denormalize_circuit_id was adding dashes, publishing to non-existent
topics. Relay and priority set commands now use the circuit_id as-is.
- Define format-markdown as Poetry script in pyproject.toml
- Create scripts/__init__.py to make scripts directory importable
- Fixes task failure when running 'poetry run format-markdown'
Add snapshot_interval parameter (default 1.0s) that rate-limits
build_snapshot() + callback dispatch using asyncio.TimerHandle.
MQTT messages continue updating the Homie property store immediately;
only the expensive snapshot rebuild is gated. Set to 0 for no debounce.
Resolves Bandit B108 (insecure temp file/directory usage).
Replace assert in connection.py with a proper RuntimeError to avoid
removal under optimised bytecode (Bandit B101). Update CI matrix and
standalone jobs from Python 3.12 to 3.13.
….14 to CI

numpy has no 3.14 wheels, causing source compilation that hangs CI.
It was never imported in source code — leftover from v1. Also removes
attrs and python-dateutil which were removed in the v2 rewrite.
Adds Python 3.14 to CI matrix with allow-prereleases.
@cayossarian cayossarian merged commit e03e884 into main Feb 27, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants