Skip to content

feat(home-assistant): split HSEM into 7 per-subsystem devices - #910

Draft
woopstar wants to merge 1 commit into
mainfrom
feat/875-hsem-device-split
Draft

feat(home-assistant): split HSEM into 7 per-subsystem devices#910
woopstar wants to merge 1 commit into
mainfrom
feat/875-hsem-device-split

Conversation

@woopstar

@woopstar woopstar commented Sep 3, 2026

Copy link
Copy Markdown
Owner

Summary

Splits the single HSEM Home Assistant device into 7 per-subsystem devices: Controller, Battery & Energy, Hourly Consumption Profile, Financial, Forecast, EV Primary, and EV Secondary. Previously every entity (~220+, including the 168 dynamically-created per-hour-block entities) shared one device page, making it impossible to scope automations/dashboards or Areas around a single subsystem.

What changed

  • custom_components/hsem/devices.py (new)HSEMDevice enum (7 members) and get_device_info(entry_id, device) dispatcher. CONTROLLER keeps the original (DOMAIN, entry_id) identifier for backward compatibility; every other device gets (DOMAIN, f"{entry_id}_<device>").
  • entity.pyHSEMEntity.device_info now dispatches via a self._hsem_device attribute (defaults to CONTROLLER). Every entity subclass sets it — as a fixed class-level device for single-device entities, or resolved per-instance for entities that come in EV primary/secondary pairs (EV target-SoC number, EV calculated-power/current-limit sensors, OCPP charger sensors keyed by charger_index, and description-driven switches/times).
  • utils/sensornames/ev.py / ocpp.py + translations/en.json — EV Secondary and OCPP entity names drop the redundant "Second"/"2" marker (e.g. "OCPP Charger Status""Charger Status", rendered as "EV Secondary Charger Status" via _attr_has_entity_name). unique_id and entity_id getters are untouched.
  • device_migration.py (new) — one-time entity-registry migration run at the end of async_setup_entry. classify_entity_device(unique_id) offline-classifies each pre-existing registry entry from its frozen unique_id (mirroring the live _hsem_device assignments) and reassigns device_id via entity_registry.async_update_entity. Gated by a hsem_device_migration_version flag stored in entry.data so it runs exactly once per config entry; unique_id is never touched. Also implements (and tests) the new_entity_id rename primitive HA's recorder uses to follow long-term statistics, even though no current entity needs a rename (entity_id getters were kept frozen — only names and device attachment changed).
  • Docsdocs/sensors-reference.md (new "Devices" section with the full mapping table), docs/home.md (Devices section + upgrade note), AGENTS.md (Home Assistant Compliance → Device Topology subsection).

Device → entity mapping

Device Entities
Controller working mode, degraded mode, read-only, hardware-writes, missing-entities, force-mode, last/next-updated, update-interval, applier-status, plan-explanation, daily-plan-vs-actual, recommendation-interval, force-working-mode selector, extended-attributes/verbose-logging/ML switches
Battery & Energy battery SoC, effective discharge floor, net consumption, PV curtailment, charge/discharge efficiency numbers, battery schedule 1/2/3 switches + times, dynamic discharge floor switch
Hourly Consumption Profile all 168 per-hour-block entities
Financial export income, import cost, net grid balance, savings
Forecast forecast accuracy, prediction accuracy, solar confidence, Solcast likelihood selector
EV Primary EV charging/plan sensors, calculated power, current limit, target SoC number, deadline time, EV switches, OCPP charger_index=1
EV Secondary same set as EV Primary for charger_index=2

Tests

  • tests/test_device_split.py (new): devices.py DeviceInfo construction, per-entity device_info dispatch (one test per device including dynamic dispatch cases), classify_entity_device unique_id classification (parametrized across every entity family), and async_migrate_devices (device reassignment, already-correct-device no-op, second-run no-op, entity_id rename primitive, unique_id-never-touched guard).
  • tests/custom_sensors/test_ocpp_per_ev.py updated for the new get_ocpp_charger_power_sensor_name() signature/output.

Test & lint results

./scripts/quality.sh lint     # pass
./scripts/quality.sh typing   # pass (0 mypy errors)
./scripts/quality.sh quality  # pass (0 pyright errors; vulture informational-only, pre-existing)
./scripts/quality.sh test     # 3149 passed

Breaking change

⚠️ Existing installs will see entities move to new devices on first startup after upgrading. Dashboards or automations that reference the old single device_id need to be re-pointed to the new devices. unique_ids and entity history/long-term statistics are preserved automatically — the migration never touches unique_id, and no entity_id actually changes in this PR (only display names and device attachment).

Known limitations / out of scope

  • Stays within the current hardcoded EV primary/secondary model — generalizing to N arbitrary EVs via config subentries is explicitly out of scope per the issue.

Fixes #875

Splits the single HSEM device into Controller, Battery & Energy, Hourly
Consumption Profile, Financial, Forecast, EV Primary, and EV Secondary
devices, so each subsystem can be scoped independently in dashboards,
automations, and Areas instead of sharing one ~220-entity device page.

- Add devices.py (HSEMDevice enum + get_device_info dispatcher) and wire
  every entity class's device_info to its target device via a new
  _hsem_device attribute on HSEMEntity (fixed per-class or resolved
  per-instance for EV primary/secondary and OCPP charger_index pairs).
- Drop redundant "Second"/"2" name markers from EV/OCPP entity names
  (utils/sensornames/ev.py, ocpp.py, translations/en.json) now that the
  device name disambiguates them.
- Add a one-time entity-registry migration (device_migration.py) that
  reassigns device_id for pre-existing entities, gated by a
  migration-version flag on the config entry so it runs exactly once.
  unique_id is never touched.
- Update docs/sensors-reference.md, docs/home.md, and AGENTS.md for the
  new topology.
- Add tests/test_device_split.py (per-entity device_info assertions,
  unique_id classification, migration idempotency/rename behavior).

Fixes #875

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions github-actions Bot added the enhancement New feature or request label Sep 3, 2026
@woopstar woopstar self-assigned this Sep 3, 2026
@woopstar
woopstar marked this pull request as draft September 3, 2026 06:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(home-assistant): split single HSEM device into per-subsystem devices

1 participant