Skip to content

Fix transient resets in cloud power statistics - #2900

Open
Wuty-zju wants to merge 3 commits into
al-one:masterfrom
Wuty-zju:fix/cloud-power-statistics-reset
Open

Fix transient resets in cloud power statistics#2900
Wuty-zju wants to merge 3 commits into
al-one:masterfrom
Wuty-zju:fix/cloud-power-statistics-reset

Conversation

@Wuty-zju

@Wuty-zju Wuty-zju commented Jul 27, 2026

Copy link
Copy Markdown

Problem

Cloud-backed daily and monthly energy entities can transiently report resets or stale values:

17.3 -> 0 -> 17.5 kWh

Missing current-period data can also leave the previous period's final value visible after a day/month boundary. In addition, restored native values could be passed through value_ratio again for models that use scaled cloud statistics.

Root cause

  • micloud_statistics_power_cost initialized missing daily/monthly values to 0.
  • Parsed None or decreasing values reached self.props before entity-level validation.
  • Restore extra data contains the already-normalized HA native value, while the normal cloud path expects an unscaled source value. Reusing the cloud conversion path can apply value_ratio twice.

Invariants

  • Missing data is not a measured zero.
  • Power statistics must be finite and non-negative.
  • Daily energy is monotonic within one HA-local calendar day.
  • Monthly energy is monotonic within one HA-local calendar month.
  • At an observed local period boundary, the corresponding accumulated value is zero.
  • After an offline boundary, stale restored data is discarded; the first current-period cloud sample may be non-zero.
  • A restored HA native value must not be scaled again.

Solution

  1. core/templates.py preserves missing current-day/current-month values as None, while retaining an explicit numeric zero.
  2. core/device.py filters missing, invalid, and same-period decreasing power statistics before self.props.update() and dispatch. Other cloud statistics remain unchanged.
  3. core/utils.py contains the shared power-cost attribute matching, period calculation, and finite non-negative numeric validation used by both layers.
  4. sensor.py retains the entity boundary as a second guard, performs local day/month rollover, discards stale cross-period restores, and directly restores the already-normalized HA native value without reapplying value_ratio.
  5. Suffixed attributes such as power_cost_today_2 are tracked independently.

The device and entity guards are intentionally separate: the device guard protects the shared property store, while the entity guard covers HA restore state and direct entity updates.

Scope

This PR does not change:

  • Xiaomi cloud endpoints, request parameters, or polling intervals;
  • device customizations, units, ratios, device class, or state class;
  • unrelated cloud statistics or sensors;
  • the integration version;
  • Recorder data or historical database rows.

Historical raw states are not rewritten automatically. Permanent long-term statistic errors should be reviewed through Home Assistant's supported statistics tools.

Validation

Focused replay passed for:

  • missing, empty, non-numeric, negative, boolean, NaN, and infinite values;
  • same-day and same-month decreases;
  • day/month rollover with zero and non-zero first samples;
  • independent suffixed attributes;
  • stale cross-period restore;
  • scaled restore (1750 * 0.01 = 17.5, restored as 17.5, not 0.175).

Repository validation:

  • Existing pytest suite on Home Assistant 2026.2.3: 170 passed.
  • python -m compileall -q custom_components/xiaomi_miot: passed.
  • git diff --check: passed.

Examples

Missing update:       17.5 -> ignored -> 17.6
Same-day decrease:    17.5 -> 16.8 ignored
Online day boundary:  14.0 -> 0.0 -> 1.2
Offline day boundary: 14.0 -> unavailable -> 1.2
Same-month decrease:  488.1 -> 470.0 ignored
Month boundary:       488.1 -> 0.0 -> first valid sample
Scaled restore:       17.5 -> restart -> 17.5

Copilot AI review requested due to automatic review settings July 27, 2026 04:20
@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

Copilot AI left a comment

Copy link
Copy Markdown

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 hardens cloud-backed daily/monthly energy (“power cost”) statistics updates to prevent transient missing/invalid cloud responses from being emitted as 0, which Home Assistant interprets as a reset for total_increasing sensors and can lead to double-counted long-term statistics.

Changes:

  • Update the micloud_statistics_power_cost template to distinguish missing data (None) from a measured zero and to ignore invalid/negative record values.
  • Add device-side validation and filtering for power statistics responses, including monotonicity enforcement within the current local day/month and independent handling of suffixed keys (_2, _3, …).
  • Add focused tests covering missing/malformed responses, explicit zeros vs missing records, monotonicity rules, suffix handling, and DST fallback.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
tests/test_power_cost_statistics.py Adds regression/unit tests for missing data handling, monotonicity, suffix independence, and failure modes.
custom_components/xiaomi_miot/core/templates.py Changes the cloud power-cost template to output None for missing periods and ignore invalid record values.
custom_components/xiaomi_miot/core/device.py Adds response validation, template error handling for power-cost stats, and an attribute filter to reject invalid/decreasing same-period updates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread custom_components/xiaomi_miot/core/templates.py
@Wuty-zju
Wuty-zju force-pushed the fix/cloud-power-statistics-reset branch from 412f5e8 to 4097393 Compare July 29, 2026 08:31
@Wuty-zju
Wuty-zju force-pushed the fix/cloud-power-statistics-reset branch from 4097393 to 462797b Compare July 29, 2026 08:41
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