Skip to content

Replace IntegrationSensor with native Left-Riemann EnergySensor - #1107

Open
Moustachauve wants to merge 9 commits into
dvd-dev:mainfrom
Moustachauve:refactor/native-energy-sensor
Open

Moustachauve wants to merge 9 commits into
dvd-dev:mainfrom
Moustachauve:refactor/native-energy-sensor

Conversation

@Moustachauve

@Moustachauve Moustachauve commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

EnergySensor previously subclassed Home Assistant Core's private IntegrationSensor class directly to estimate cumulative energy from device power readings. Because IntegrationSensor is an internal helper entity rather than a public base class, upstream constructor changes in Home Assistant 2026.2 and 2026.11 (#1106) repeatedly broke Hilo setups and required fragile version-checking branches, entity registry workarounds to resolve the source power entity_id, and state machine listeners.

Having EnergySensor inherit directly from HiloEntity and RestoreSensor removes all coupling to homeassistant.components.integration and avoids future breakage when Home Assistant Core modifies its internal helper classes. Instead of watching another entity in the state machine by string ID, EnergySensor now computes the Left-Riemann sum directly from the in-memory HiloDevice power attribute whenever the device updates (via SignalR or coordinator polling) as well as on a 5-minute fallback timer for constant-power periods. Full Decimal precision is retained across intervals internally while rounding native_value to 2 decimal places so small energy increments are never lost to per-tick rounding.

Existing installations migrate seamlessly without losing historical statistics or requiring reconfiguration: entity unique_ids, device classes, and TOTAL_INCREASING state classes are unchanged, and async_added_to_hass restores previous totals from both standard RestoreSensor native data and legacy IntegrationSensor extra data (last_valid_state). Moving the accumulation state onto pyhilo's HiloDevice is noted for a follow-up refactor once device update lifecycles are consolidated in the library.

Pros Cons
No longer subclasses HA's internal IntegrationSensor, which broke in 2026.2 and 2026.11 (#1106) and needed version checks. We maintain the Left-Riemann calculation (power * dt / 3,600,000) ourselves instead of delegating it to HA.
Reads power directly from HiloDevice in memory instead of watching a sibling sensor.*_power entity in the state machine.
Renaming or disabling a power sensor entity in HA no longer breaks energy tracking.
Updates on every SignalR push and coordinator poll (plus a 5-min fallback timer instead of 15-min), even when wattage is constant.
Keeps existing unique_ids and restores state from both RestoreSensor and legacy IntegrationSensor storage.
Easier to move into pyhilo later since it only depends on device power updates.

EnergySensor previously subclassed Home Assistant Core's private
IntegrationSensor class directly to estimate cumulative energy from
device power readings. Because IntegrationSensor is an internal helper
entity rather than a public base class, upstream constructor changes in
Home Assistant 2026.2 and 2026.11 repeatedly broke Hilo setups and
required fragile version-checking branches, entity registry workarounds
to resolve the source power entity_id, and state machine listeners.

Have EnergySensor inherit directly from HiloEntity and RestoreSensor
instead, computing the Left-Riemann sum in-process whenever the
underlying HiloDevice updates (via SignalR or coordinator polling) as
well as on a 5-minute fallback timer for constant-power periods.
Accumulating directly from the in-memory device power attribute removes
all coupling to homeassistant.components.integration, preserves existing
entity unique_ids and restored states (including seamless fallback for
states persisted by IntegrationSensor), and retains full Decimal
precision across intervals while rounding native_value to 2 decimal
places.
tests/test_sensor.py previously constructed mock Hilo and HiloDevice
instances manually in each test and asserted individual entity metadata
properties in Python code.

Use setup_with_selected_platforms with Platform.SENSOR and Syrupy
snapshots (snapshot_platform) instead, matching the testing pattern used
across the switch and light platform tests while exercising the full
sensor platform setup and retaining 100% coverage of EnergySensor.
Home Assistant 2026.3+ (Python 3.14) prepends the device name to
original_name and friendly_name on entities whose name does not already
start with the device name (such as Gateway sensors), causing full-
platform snapshots to diverge from Home Assistant 2026.2 (Python 3.13).
Additionally, leaving invalid power values on the shared Smart Plug
device at test teardown caused PowerSensor.state to raise during the
Python 3.13 teardown coordinator refresh.

Scope test_energy_sensor_entities snapshots to the EnergySensor entities
and restore valid device power before teardown so the test suite passes
on both Python 3.13 and Python 3.14.
EnergySensor previously subclassed Home Assistant Core's private
IntegrationSensor class directly to estimate cumulative energy from
device power readings. Because IntegrationSensor is an internal helper
entity rather than a public base class, upstream constructor changes in
Home Assistant 2026.2 and 2026.11 repeatedly broke Hilo setups and
required fragile version-checking branches, entity registry workarounds
to resolve the source power entity_id, and state machine listeners.

Have EnergySensor inherit directly from HiloEntity and RestoreSensor
instead, computing the Left-Riemann sum in-process whenever the
underlying HiloDevice updates (via SignalR or coordinator polling) as
well as on a 5-minute fallback timer for constant-power periods.
Accumulating directly from the in-memory device power attribute removes
all coupling to homeassistant.components.integration, preserves existing
entity unique_ids and restored states (including seamless fallback for
states persisted by IntegrationSensor), and retains full Decimal
precision across intervals while rounding native_value to 2 decimal
places.
tests/test_sensor.py previously constructed mock Hilo and HiloDevice
instances manually in each test and asserted individual entity metadata
properties in Python code.

Use setup_with_selected_platforms with Platform.SENSOR and Syrupy
snapshots (snapshot_platform) instead, matching the testing pattern used
across the switch and light platform tests while exercising the full
sensor platform setup and retaining 100% coverage of EnergySensor.
Home Assistant 2026.3+ (Python 3.14) prepends the device name to
original_name and friendly_name on entities whose name does not already
start with the device name (such as Gateway sensors), causing full-
platform snapshots to diverge from Home Assistant 2026.2 (Python 3.13).
Additionally, leaving invalid power values on the shared Smart Plug
device at test teardown caused PowerSensor.state to raise during the
Python 3.13 teardown coordinator refresh.

Scope test_energy_sensor_entities snapshots to the EnergySensor entities
and restore valid device power before teardown so the test suite passes
on both Python 3.13 and Python 3.14.
ic-dev21 and others added 3 commits November 8, 2026 19:29
Commit 8803d86 (PR dvd-dev#1001) added "Disconnected": false to the
Thermostat 1 fixture entry in tests/fixtures/all_devices.json so the
baseboard thermostat starts online during test setup. As a result,
sensor.thermostat_1_hilo_energy initializes to "0.00" rather than
"unavailable".
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