Skip to content

v2.0.4#194

Open
cayossarian wants to merge 25 commits intomainfrom
2_0_4
Open

v2.0.4#194
cayossarian wants to merge 25 commits intomainfrom
2_0_4

Conversation

@cayossarian
Copy link
Member

Remove simulator
Add simulator service
Fix mDNS MQQT cross VLAN issue #193

Update sensor to use UnitOfPower.WATT to match the actual firmware
value. Bump version to 2.0.3 and require span-panel-api>=2.2.5.
Compare span-panel-api field metadata against sensor definitions at
startup to detect unit mismatches and unmapped fields. All output is
DEBUG-level log-only — no sensor behavior changes.

- schema_expectations.py: SENSOR_FIELD_MAP (sensor key → field path)
- schema_validation.py: unit cross-check, unmapped field reporting,
  collect_sensor_definitions()
- coordinator.py: one-shot _run_schema_validation() after first refresh
- docs/dev/schema_driven_changes.md: phased plan documentation
- tests/test_schema_validation.py: 14 tests covering mapping, cross-check,
  unmapped detection, and no-op behavior
- Add Versioning Model section: library as semantic contract layer,
  schema-only vs value-change scenarios, human-gated version sequence
- Add schema version vs firmware version distinction, note v2 API beta
- Add new-fields-require-human-review policy
- Remove auto-entity concept from Phase 2 (override table only for
  reviewed fields)
- Update Phase 3 to clarify codegen does not bypass review gate
Replace the local YAML generation approach with a WebSocket-based
flow that delegates clone work to the simulator.  The integration
now discovers simulators via mDNS (looking for cloneWssPort in
_ebus._tcp TXT records), falls back to manual host/port entry,
and sends the panel's credentials over WSS.  The simulator handles
eBus scraping, translation, and config writing.

- Rewrite simulation_utils.py with discover_clone_simulators() and
  execute_clone_via_simulator() backed by aiohttp WSS
- Update OptionsFlowHandler clone step: mDNS pre-fill, v2-only gate
- Remove simulation_generator.py (dead code) and services.yaml
  (unimplemented export_synthetic_config service)
- Clean up export_config references from strings.json and all
  translation files; add clone error strings
Documents the WebSocket-based clone architecture where the simulator
scrapes a real panel's eBus, translates retained messages to YAML,
and writes the simulation config.  Covers the WSS contract, mDNS
discovery, eBus-to-YAML translation rules, and implementation phases.
The script was hardcoding >= and ^ operators when syncing versions from
manifest.json to ci.yml, ignoring the actual specifier (e.g. ==2.3.0).
Now extracts and writes the full specifier as-is.

Also removes unused ci-simulation-example.yml workflow.
socketio was only in manifest.json (runtime) but missing from dev
dependencies, breaking test collection.
- Extract shared _sio_call helper to eliminate duplicated Socket.IO
  connect/call/disconnect pattern in simulation_utils.py
- Move clone-then-profile orchestration from simulation_utils into
  config_flow.py where it belongs (OptionsFlowHandler._apply_usage_profiles)
- Replace bare except Exception with narrower exception types
- Use DOMAIN constant instead of raw string in simulator_profile_builder
- Add Literal types for statistics_during_period parameters
- Remove all lazy imports in favor of top-level imports
The coordinator is stored in config_entry.runtime_data, not
hass.data[DOMAIN][entry_id]. Also guard against runtime_data being
absent if the entry hasn't completed setup yet.
Instead of opening separate connections for clone and profiles,
keep the connection open after clone_panel and wait for the
simulator to emit clone_ready before sending apply_usage_profiles.
This eliminates the race where profiles are sent before the
simulator has registered the clone config.

Profiles are built before connecting and passed into
clone_with_profiles so the entire operation runs on one session.
HA requires database access to go through the recorder's own executor,
not the general hass.async_add_executor_job. Fixes the "Detected code
that accesses the database without the database executor" warning.
- statistics_during_period returns start as float (Unix timestamp),
  not datetime — isinstance(start, datetime) silently failed so
  hour_factors and monthly_factors were never computed
- Convert UTC timestamps to HA's local timezone before bucketing
  by hour, since the simulator engine uses local time
- Replace mean with median throughout to handle sensor glitch spikes
  (e.g. 400kW on a 15A circuit) that destroy mean-based calculations
- Use IQR-based power_variation instead of coefficient of variation
- Use recorder executor for database queries per HA requirements
Exposes an authoritative circuit-to-entity manifest so the simulator
add-on can query HA recorder stats and build usage profiles without
reverse-engineering entity IDs from the states API.

The service iterates all loaded SPAN panel config entries, resolves
each circuit's power sensor entity_id via the entity registry, computes
clone template names from breaker tabs, and returns a flat list per
panel — ready for the add-on to consume directly.
Move service registration from async_setup_entry to async_setup so the
service is available even when no config entries are loaded. The handler
raises ServiceValidationError with an informative message instead of
silently not existing. Remove service unregistration from
async_unload_entry — services stay registered for the lifetime of the
domain per HA quality-scale action-setup rule.

Also add host field to per-panel manifest response (entry.data[CONF_HOST])
and iterate async_loaded_entries instead of async_entries.
Panel cloning is now handled by the export_circuit_manifest service
for the simulator add-on. With clone removed, general options is the
only option so the menu is eliminated — the options gear goes straight
to the general options form.

Also adds missing v2.0.3 changelog entry.
The MQTT broker runs on the panel itself. The panel advertises its
own mDNS hostname (.local) as ebusBrokerHost, but mDNS does not
resolve across VLAN boundaries. Use the user-configured panel host
(IP or FQDN) which is known reachable.

Fixes #193
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the SPAN Panel Home Assistant integration to remove the built-in simulator, add a new export_circuit_manifest service to support an external simulator, and fix MQTT connectivity when the panel advertises an mDNS broker hostname that won’t resolve across VLANs (Issue #193).

Changes:

  • Remove built-in simulation mode (config flow, options, utilities, and test scaffolding) and block migration of simulation entries.
  • Fix cross-VLAN MQTT broker host resolution by using the user-configured panel host instead of the panel-advertised mDNS hostname.
  • Add schema validation (Phase 1) plus new tests, and add an export_circuit_manifest service for external simulator tooling.

Reviewed changes

Copilot reviewed 52 out of 53 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
custom_components/span_panel/__init__.py Config entry migration bump to v6, remove simulation setup path, add manifest export service, and fix broker host selection across VLANs.
custom_components/span_panel/config_flow.py Remove simulator flow and add HTTP port handling (including zeroconf TXT parsing).
custom_components/span_panel/config_flow_utils/validation.py Thread port through host/version detection and v2 registration calls.
custom_components/span_panel/coordinator.py Remove simulation polling/offline logic and add one-shot schema validation after first refresh.
custom_components/span_panel/schema_validation.py / schema_expectations.py New schema validation layer and mapping between sensors and snapshot field paths.
custom_components/span_panel/services.yaml Replace synthetic export service with export_circuit_manifest service definition.
custom_components/span_panel/sensor_definitions.py Fix PV nameplate capacity to report in watts and use new snapshot field name.
custom_components/span_panel/strings.json + translations/*.json Remove simulator UI/options strings (but port field strings need to be added).
scripts/sync-dependencies.py Update dependency syncing to preserve specifiers (regex needs correction for ==).
tests/* Remove simulation factory/provider/docs and add new tests for schema validation and circuit manifest service.
custom_components/span_panel/util.py / sensor.py / binary_sensor.py / sensor_evse.py / entity.py Remove simulator-specific device identifier logic and simplify to serial-based identifiers.

Guard against non-numeric httpPort values in zeroconf TXT records
that would crash discovery with a ValueError. Add missing UI label
and description for the http_port field in the user config step.
No integration code imports socketio — it was left over from
removed functionality. Also drops 4 transitive dependencies.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Release v2.0.4 for the SPAN Panel Home Assistant custom integration, focusing on removing the built-in simulator, adding a simulator-supporting service, and addressing MQTT broker hostname resolution failures across VLANs (Issue #193).

Changes:

  • Fix cross-VLAN MQTT connection failures by using the user-configured panel host instead of the panel-advertised .local broker hostname.
  • Remove built-in simulation mode/config/options and reject simulation config entries during migration (v5→v6).
  • Add schema-driven validation (Phase 1) and an export_circuit_manifest service to support an external simulator workflow; correct PV nameplate capacity units to watts.

Reviewed changes

Copilot reviewed 51 out of 52 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/test_v2_config_flow.py Updates config flow tests to remove simulator inputs and reflect config version bump.
tests/test_schema_validation.py Adds test coverage for schema validation and sensor-to-field mapping.
tests/test_promoted_sensors.py Updates PV nameplate capacity expectations to watts.
tests/test_factories/span_panel_simulation_factory.py Removes simulation factory used for YAML-backed simulator test data.
tests/test_dps_and_bess.py Renames/adjusts a test to reflect missing-client-method behavior (not simulator-specific).
tests/test_circuit_manifest_service.py Adds tests for the new export_circuit_manifest service behavior.
tests/providers/integration_data_provider.py Removes simulation data provider that bridged simulator data into coordinator logic.
tests/docs/simulation_test_documentation.md Removes documentation specific to the removed built-in simulation testing approach.
tests/conftest.py Removes simulator-related fixture wiring and references.
scripts/sync-dependencies.py Improves dependency specifier parsing/preservation when syncing manifest→CI config.
pyproject.toml Adds python-socketio to dev dependencies.
poetry.lock Updates locked deps (notably span-panel-api) and adds socketio-related transitive packages.
docs/dev/schema_driven_changes.md Adds developer documentation for schema-driven sensor validation phases.
docs/dev/mqtt-sensor-topic.md Updates PV metadata naming/unit documentation to nameplate_capacity_w.
custom_components/span_panel/util.py Simplifies device info creation now that simulator identifiers are removed.
custom_components/span_panel/translations/pt.json Removes simulator-related strings; adjusts host-required messaging.
custom_components/span_panel/translations/ja.json Removes simulator-related strings; adjusts host-required messaging.
custom_components/span_panel/translations/fr.json Removes simulator-related strings; adjusts host-required messaging.
custom_components/span_panel/translations/es.json Removes simulator-related strings; adjusts host-required messaging.
custom_components/span_panel/translations/en.json Replaces simulator UI strings with http_port field strings; adjusts messaging.
custom_components/span_panel/switch.py Updates warning text to be client-capability-based (not simulator-based).
custom_components/span_panel/strings.json Replaces simulator UI strings with http_port field strings; adjusts messaging.
custom_components/span_panel/simulation_utils.py Removes simulator utilities (clone-to-sim, template inference, YAML writing).
custom_components/span_panel/simulation_generator.py Removes simulation YAML generator.
custom_components/span_panel/simulation_factory.py Removes simulation mode factory/wrapper logic.
custom_components/span_panel/simulation_configs/simulation_config_8_tab_workshop.yaml Removes bundled simulation config.
custom_components/span_panel/simulation_configs/simulation_config_40_circuit_with_battery.yaml Removes bundled simulation config.
custom_components/span_panel/simulation_configs/simulation_config_32_circuit.yaml Removes bundled simulation config.
custom_components/span_panel/simulation_configs/simple_test_config.yaml Removes bundled simulation config.
custom_components/span_panel/simulation_configs/migration_test_config.yaml Removes bundled simulation config.
custom_components/span_panel/services.yaml Replaces prior synthetic export service docs with export_circuit_manifest service docs.
custom_components/span_panel/sensor_evse.py Removes simulator-specific panel identifier logic for EVSE sub-devices.
custom_components/span_panel/sensor_definitions.py Fixes PV nameplate capacity sensor to W and uses nameplate_capacity_w.
custom_components/span_panel/sensor.py Removes simulator-specific panel identifier logic for EVSE/BESS device info.
custom_components/span_panel/select.py Updates warning text to be client-capability-based (not simulator-based).
custom_components/span_panel/schema_validation.py Adds schema validation logic for unit cross-checking + unmapped field reporting.
custom_components/span_panel/schema_expectations.py Introduces sensor-key → snapshot-field-path mapping used by schema validation.
custom_components/span_panel/manifest.json Bumps integration version to 2.0.4 and pins span-panel-api==2.3.1.
custom_components/span_panel/helpers.py Removes simulator serial generator helper.
custom_components/span_panel/entity.py Removes simulator-specific device identifier plumbing.
custom_components/span_panel/coordinator.py Removes simulation coordinator behavior and adds one-shot schema validation on first refresh.
custom_components/span_panel/const.py Removes simulation constants; adds CONF_HTTP_PORT.
custom_components/span_panel/config_flow_utils/validation.py Adds port support to host/auth validation helpers; removes simulation time validation.
custom_components/span_panel/config_flow_utils/simulation.py Removes simulation config discovery/validation helpers.
custom_components/span_panel/config_flow_utils/options.py Removes simulation option schemas/defaults.
custom_components/span_panel/config_flow_utils/init.py Removes simulation exports and validation from config flow utils exports.
custom_components/span_panel/config_flow.py Removes simulator flows/options; adds http_port support and TXT-record parsing for zeroconf.
custom_components/span_panel/button.py Updates warning text to be client-capability-based (not simulator-based).
custom_components/span_panel/binary_sensor.py Removes simulator-specific EVSE/BESS device identifier logic.
custom_components/span_panel/init.py Adds domain async_setup + circuit manifest service; rejects simulation entry migration; fixes broker host selection across VLANs.
CHANGELOG.md Adds 2.0.4 release notes covering simulator removal, VLAN fix, PV unit correction, schema validation.
.github/workflows/ci.yml Updates CI dependency replacement to span-panel-api==2.3.1.
.github/workflows/ci-simulation-example.yml Removes the simulation CI example workflow.

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