fix(sensor): use TOTAL state class for computed e_consumption_today#143
Conversation
The sensor is derived (PV gen + grid-in - grid-out - AC-charge) from registers polled at slightly different times, so a reading can transiently dip by a few Wh when one component updates before the others. TOTAL_INCREASING's strictly-increasing guard fires a spurious HA warning in that case. TOTAL is the correct class for a computed daily cumulative that may briefly fluctuate; direct hardware counters (PV, grid, battery day totals) are unaffected and stay TOTAL_INCREASING. Fixes #142 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request changes the state class of the 'House Consumption Today' (e_consumption_today) sensor from SensorStateClass.TOTAL_INCREASING to SensorStateClass.TOTAL. This prevents transient dips in computed values, caused by registers being polled at slightly different times, from triggering Home Assistant's strictly-increasing guard. There are no review comments, and I have no feedback to provide.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
|
I’ve started reviewing this PR. |
| native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, | ||
| device_class=SensorDeviceClass.ENERGY, | ||
| state_class=SensorStateClass.TOTAL_INCREASING, | ||
| state_class=SensorStateClass.TOTAL, |
There was a problem hiding this comment.
TOTAL only starts a new recorder statistics cycle when the entity supplies a changed last_reset; this entity does not supply one. With this change, the normal midnight drop from the day’s final consumption to zero is therefore recorded as a negative delta and subtracts the whole day from the accumulated sum, whereas TOTAL_INCREASING currently detects that drop as a reset automatically. Brief intra-day dips would cancel once the derived value catches up, but the daily reset will not. I think this needs a matching daily last_reset implementation (or a different approach that preserves reset detection) before switching the state class.
…sion The sensor is computed from several registers (PV gen + grid-in - grid-out - AC-charge) polled at slightly different times. When one component updates before the others the result can transiently dip by a few Wh, tripping HA's strictly-increasing guard (#142). Adds a `monotonic: bool` flag to `GivEnergyInverterSensorDescription` and tracks a `_monotonic_max` in the entity. When set, `native_value` returns `max(new, session_max)` so intra-day dips are invisible to HA's recorder. Keeping `TOTAL_INCREASING` is important: switching to `TOTAL` (as in the reverted #143) silently corrupts the accumulated `sum` on the midnight reset to zero, because `TOTAL` requires an explicit `last_reset` attribute to distinguish a reset from a decrease. Fixes #142 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…umption_today The sensor is computed from several registers (PV gen + grid-in - grid-out - AC-charge) polled at slightly different times. When one component updates before the others the result can transiently dip by a few Wh, tripping HA's strictly-increasing guard (#142). Adds a `monotonic: bool` flag to `GivEnergyInverterSensorDescription` and tracks `_monotonic_max` and `_monotonic_date` on the entity. When set, `native_value`: - resets both fields when the calendar day changes (in HA's timezone), so the legitimate midnight drop to zero is emitted as a real decrease and TOTAL_INCREASING starts a new recorder cycle; - otherwise returns `max(new, session_max)`, hiding intra-day dips. Keeping `TOTAL_INCREASING` is important: switching to `TOTAL` (as in the reverted #143) silently corrupts the accumulated `sum` on the midnight reset to zero, because `TOTAL` requires an explicit `last_reset` attribute to distinguish a reset from a decrease. Fixes #142 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ore for e_consumption_today The sensor is computed from several registers (PV gen + grid-in - grid-out - AC-charge) polled at slightly different times. When one component updates before the others the result can transiently dip by a few Wh, tripping HA's strictly-increasing guard (#142). Adds a `monotonic: bool` flag to `GivEnergyInverterSensorDescription` and tracks `_monotonic_max` and `_monotonic_date` on the entity. When set, `native_value`: - resets both fields when the calendar day changes (in HA's timezone), so the legitimate midnight drop to zero is emitted as a real decrease and TOTAL_INCREASING starts a new recorder cycle; - otherwise returns `max(new, session_max)`, hiding intra-day dips. `GivEnergyInverterSensor` now also inherits `RestoreEntity` and seeds `_monotonic_max` from the last persisted state in `async_added_to_hass` (only when the persisted state is from today). Without this, the first transient-dip reading after an HA restart or integration reload would become the new baseline, allowing the TOTAL_INCREASING warning to recur until consumption caught up naturally. Keeping `TOTAL_INCREASING` is important: switching to `TOTAL` (as in the reverted #143) silently corrupts the accumulated `sum` on the midnight reset to zero, because `TOTAL` requires an explicit `last_reset` attribute to distinguish a reset from a decrease. Fixes #142 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…, and reset-threshold The sensor is computed from several registers (PV gen + grid-in - grid-out - AC-charge) polled at slightly different times. When one component updates before the others the result can transiently dip by a few Wh, tripping HA's strictly-increasing guard (#142). Adds a `monotonic: bool` flag to `GivEnergyInverterSensorDescription` and tracks `_monotonic_max` and `_monotonic_date` on the entity. When set, `native_value` applies three layers of logic: 1. Day boundary: when HA's local date changes, reset both fields so the midnight drop to zero passes through as a real decrease and TOTAL_INCREASING starts a new recorder cycle. 2. Large-drop reset (clock-drift guard): if the value drops by more than _MONOTONIC_RESET_THRESHOLD (0.5 kWh) on the same HA date, treat it as a genuine source reset. This handles inverter clocks that lag HA's midnight by one scan interval — the actual counter reset arrives on a subsequent read after the day boundary has already been committed. 3. Intra-day clamp: otherwise, return max(new, session_max) to hide the transient few-Wh dips that triggered the original warning. `GivEnergyInverterSensor` also inherits `RestoreEntity` and seeds `_monotonic_max` from the last persisted state in `async_added_to_hass` (only when the persisted state is from today) so a transient-dip first reading after an HA restart does not undercut the recorder's prior value. Keeping `TOTAL_INCREASING` is important: switching to `TOTAL` (as in the reverted #143) silently corrupts the accumulated `sum` on the midnight reset to zero, because `TOTAL` requires an explicit `last_reset` attribute to distinguish a reset from a decrease. Fixes #142 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…, and reset-threshold (#144) The sensor is computed from several registers (PV gen + grid-in - grid-out - AC-charge) polled at slightly different times. When one component updates before the others the result can transiently dip by a few Wh, tripping HA's strictly-increasing guard (#142). Adds a `monotonic: bool` flag to `GivEnergyInverterSensorDescription` and tracks `_monotonic_max` and `_monotonic_date` on the entity. When set, `native_value` applies three layers of logic: 1. Day boundary: when HA's local date changes, reset both fields so the midnight drop to zero passes through as a real decrease and TOTAL_INCREASING starts a new recorder cycle. 2. Large-drop reset (clock-drift guard): if the value drops by more than _MONOTONIC_RESET_THRESHOLD (0.5 kWh) on the same HA date, treat it as a genuine source reset. This handles inverter clocks that lag HA's midnight by one scan interval — the actual counter reset arrives on a subsequent read after the day boundary has already been committed. 3. Intra-day clamp: otherwise, return max(new, session_max) to hide the transient few-Wh dips that triggered the original warning. `GivEnergyInverterSensor` also inherits `RestoreEntity` and seeds `_monotonic_max` from the last persisted state in `async_added_to_hass` (only when the persisted state is from today) so a transient-dip first reading after an HA restart does not undercut the recorder's prior value. Keeping `TOTAL_INCREASING` is important: switching to `TOTAL` (as in the reverted #143) silently corrupts the accumulated `sum` on the midnight reset to zero, because `TOTAL` requires an explicit `last_reset` attribute to distinguish a reset from a decrease. Fixes #142 Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
What
Changes
e_consumption_todayfromSensorStateClass.TOTAL_INCREASINGtoSensorStateClass.TOTAL.Why
e_consumption_todayis a computed field — givenergy-modbus derives it asPV gen + grid-in - grid-out - AC-chargefrom several registers polled at slightly different times. When one component updates before the others, the result can transiently dip by a few Wh, triggering HA's strictly-increasing guard and logging the warning reported in #142.The other daily energy sensors (
e_pv_day,e_grid_in_day,e_grid_out_day, the battery day totals) are direct hardware counters that only increment, so they correctly stayTOTAL_INCREASING. Only the computed sensor needs the relaxed class.Both
TOTALandTOTAL_INCREASINGproduce sum-type long-term statistics in HA's recorder, so existing history is unaffected.Fixes #142