Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Changelog

## [unreleased] — emitter live-schema alignment and abstraction (feat/emitter-integration)
## 1.0.122026-07-30 — emitter live-schema alignment and abstraction

### Changed

Expand All @@ -11,4 +11,5 @@

### Fixed

- **Dev bootstrap dependency drift**: `scripts/dev-setup.sh` installed `ebus-emitter` with a bare `uv pip install --editable`, which re-resolves the emitter's dependency constraints against PyPI and ignores its `uv.lock`. A fresh bootstrap pulled `ebus-sdk` 0.12.0 — whose `Device` constructor is incompatible with the 0.1.x API the emitter targets — and panel startup died with `AttributeError: 'NoneType' object has no attribute 'get'` in `connect_broker()`. The script now installs the emitter's locked runtime dependencies first, then the emitter itself with `--no-deps`, so the venv matches what the emitter pins.
- **Type safety**: Fixed mypy error in simulator runtime (`_first_feed_for_device_type`) where template_name could be None.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "span-panel-simulator"
version = "1.0.11"
version = "1.0.12"
description = "Standalone eBus simulator for SPAN panels"
requires-python = ">=3.14"
dependencies = [
Expand Down
15 changes: 13 additions & 2 deletions scripts/dev-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,18 @@ fi
echo "Syncing simulator deps (excluding ebus-emitter, which is local)…"
uv sync --group dev --no-install-package ebus-emitter

echo "Installing ebus-emitter from ${EBUS_EMITTER_PATH} (editable)…"
uv pip install --editable "${EBUS_EMITTER_PATH}"
# Install the emitter's *locked* runtime deps, then the emitter itself with
# --no-deps. A bare `uv pip install --editable <path>` re-resolves the emitter's
# constraints against PyPI and ignores its uv.lock, so a fresh bootstrap can pull
# a transitive dependency the emitter was never tested against — that is how
# ebus-sdk 0.12.0 (whose Device constructor is incompatible with the 0.1.x API
# the emitter targets) landed in this venv and broke `span-simulator` at startup.
# Sourcing from the lock keeps this venv on exactly what the emitter pins.
echo "Installing ebus-emitter's locked runtime deps…"
uv export --project "${EBUS_EMITTER_PATH}" --no-dev --no-emit-project --no-hashes \
| uv pip install --requirements -

echo "Installing ebus-emitter from ${EBUS_EMITTER_PATH} (editable, no re-resolution)…"
uv pip install --no-deps --editable "${EBUS_EMITTER_PATH}"

echo "Done. Verify with: uv run python -c 'import ebus_emitter; print(ebus_emitter.__file__)'"
22 changes: 22 additions & 0 deletions span_panel_simulator/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# Changelog

## 1.0.12 — 2026-07-30

### Emitter & Homie Schema

- MQTT publishing and per-tick property emission now run through the external `ebus-emitter` package. The simulator builds a device manifest per panel and drives
the emitter each tick, replacing the built-in publisher
- Published topics follow the emitter's live SPAN panel Homie 5 schema — flat node layout with topology and properties matching real hardware, so downstream
consumers (span-panel-api, span-card) see the same structure a physical panel emits
- Lugs node IDs renamed to `lugs-upstream` and `lugs-downstream` to match the emitter convention
- Device metadata key `software-version` renamed to `firmware-version`
- Multiple EVSE devices per panel are now published: every circuit whose template is tagged `device_type: evse` gets its own EVSE device (`evse`, `evse-2`, …)
driven by that circuit's power, instead of a single hardcoded EVSE
- BESS and PV device feeds and metadata are derived from circuit templates via stable circuit UUIDs rather than being configured independently
- Each panel now owns its own MQTT connection and subscribes to its own `/set` topics, replacing the single shared connection and the central topic router
- Stopping a panel clears its retained topics, so a shut-down clone no longer leaves stale state on the broker

### Fixes

- Panel startup no longer fails with `AttributeError: 'NoneType' object has no attribute 'get'`. The developer bootstrap script re-resolved the emitter's
dependencies against PyPI instead of its lock file and pulled an `ebus-sdk` release incompatible with the `Device` API the emitter targets; setup now installs
the emitter's locked dependency set

## 1.0.11 — 2026-04-19

### Fixes
Expand Down
2 changes: 1 addition & 1 deletion span_panel_simulator/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ EXPOSE 18883 8081 18080
LABEL io.hass.name="SPAN Panel Simulator" \
io.hass.description="Simulates a SPAN electrical panel for testing and upgrade modeling" \
io.hass.type="addon" \
io.hass.version="1.0.11" \
io.hass.version="1.0.12" \
io.hass.arch="aarch64|amd64"

CMD ["/run.sh"]
2 changes: 1 addition & 1 deletion span_panel_simulator/config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: "SPAN Panel Simulator"
description: "Simulates a SPAN electrical panel for testing and upgrade modeling"
version: "1.0.11"
version: "1.0.12"
slug: "span_panel_simulator"
url: "https://github.com/SpanPanel/simulator"
image: "ghcr.io/spanpanel/simulator/{arch}"
Expand Down
2 changes: 1 addition & 1 deletion src/span_panel_simulator/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Standalone eBus simulator for SPAN panels."""

__version__ = "1.0.11"
__version__ = "1.0.12"