Skip to content

Energy Prediction health check ignores the active consumption strategy (always validates 'sensor') #160

Description

@johanzander

Summary

The "Energy Prediction" health check — shown under Settings → System tab (diagnostics/health section) and described in code as "Solar and consumption forecasting for optimization" — always validates the sensor consumption strategy, regardless of which strategy the user has actually selected (sensor / fixed / influxdb_7d_avg / ha_statistics).

As a result the health card does not reflect the chosen forecast provider. It can show a passing/flat consumption value while the optimizer is using a completely different (correct) source, or it can flag consumption as broken when the optimizer doesn't even use the checked sensor.

Where it is

  • UI: Settings → System tab → health/diagnostics.
  • Code: core/bess/sensor_collector.py:745-756 (check_prediction_health):
    return perform_health_check(
        component_name="Energy Prediction",
        description="Solar and consumption forecasting for optimization",
        is_required=False,
        controller=self.ha_controller,
        all_methods=[
            "get_estimated_consumption",   # hardcoded -> 'sensor' strategy
            "get_solar_forecast",
        ],
    )
  • Health-check registry entry: core/bess/ha_api_controller.py:224-230 maps get_estimated_consumption → name "Average Hourly Power Consumption", sensor key 48h_avg_grid_import.
  • get_estimated_consumption itself (ha_api_controller.py:1049-1071) reads the single 48h_avg_grid_import sensor and returns a flat 96-period array — this is the sensor strategy's data source only.

Root cause

There are three consumers of consumption-forecast data, and only the health check is not strategy-aware:

Consumer Source Strategy-aware?
Optimizer — _get_consumption_forecast() (battery_system_manager.py:969-1023) dispatches on consumption_strategy ✅ yes
Forecast comparison view — get_consumption_forecast_comparison() (battery_system_manager.py:895-967) computes all 4 strategies, marks is_active ✅ yes
Energy Prediction health checksensor_collector.py:745-756 hardcoded get_estimated_consumption (sensor) no

Impact / failure modes

  1. False positive (observed): With ha_statistics (or fixed/influxdb_7d_avg) selected, the card shows the flat sensor value. This masks whether the chosen strategy is actually delivering a varying profile — and specifically hides the case where ha_statistics silently falls back to fixed due to insufficient HA Recorder data (battery_system_manager.py:1001-1021). This directly caused real confusion: switching to ha_statistics looked like it did nothing because the health card stayed flat.
  2. False negative: With ha_statistics selected but the 48h_avg_grid_import sensor not configured, the health check flags consumption as failing even though the optimizer never uses that sensor.

In both cases a component literally described as "consumption forecasting for optimization" is validating something other than what the optimizer uses.

Proposed fix

Make the consumption portion of the Energy Prediction health check follow the active strategy — i.e. validate the same path the optimizer uses (_get_consumption_forecast()), or reuse the is_active entry from get_consumption_forecast_comparison() (which already knows all four strategies and whether each is available).

Desired behaviour:

  • The card passes/fails based on the user's selected forecast provider.
  • It reflects the actual forecast the optimizer will use (varying for ha_statistics/influxdb_7d_avg, flat for sensor/fixed).
  • It surfaces when ha_statistics has fallen back to fixed (insufficient data), rather than hiding it behind a flat sensor reading.

Design considerations

  • The health-check framework (perform_health_check + the registry in ha_api_controller.py) is currently keyed by static sensor-method names. Making the consumption check strategy-aware is therefore more than a one-line swap: the consumption check needs to dispatch on the active strategy instead of pointing at a fixed method. Decide whether to:
    • special-case the consumption check to call _get_consumption_forecast() / the comparison's active entry, or
    • extend the framework to support a "resolve method by active strategy" check type.
  • Keep get_solar_forecast validation as-is.
  • Consider whether the registry name "Average Hourly Power Consumption" should be relabeled to reflect that it represents the active forecast, not specifically the 48h-average sensor.

Acceptance criteria

  • With each consumption strategy selected, the Energy Prediction health check validates that strategy's forecast path.
  • Selecting ha_statistics with sufficient data shows a varying profile (not the flat sensor value); with insufficient data it indicates the fallback to fixed.
  • Selecting ha_statistics without the 48h_avg_grid_import sensor does NOT report a consumption failure (that sensor is irrelevant to the active strategy).
  • Tests cover the health check under all four strategies (available, unavailable, and ha_statistics fallback).

Relevant references

  • core/bess/sensor_collector.py:745-756
  • core/bess/ha_api_controller.py:224-230, :1049-1071
  • core/bess/battery_system_manager.py:895-967 (comparison), :969-1023 (optimizer dispatch + ha_statistics fallback)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bot-analyzedTriage bot has processed this issuebugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions