Skip to content

Commit fbf875b

Browse files
authored
Deprecate has_mean in favor of mean_type in recorder statistic API (home-assistant#154093)
1 parent fcea5e0 commit fbf875b

File tree

10 files changed

+162
-95
lines changed

10 files changed

+162
-95
lines changed

homeassistant/components/recorder/core.py

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,7 @@
7878
StatisticsShortTerm,
7979
)
8080
from .executor import DBInterruptibleThreadPoolExecutor
81-
from .models import (
82-
DatabaseEngine,
83-
StatisticData,
84-
StatisticMeanType,
85-
StatisticMetaData,
86-
UnsupportedDialect,
87-
)
81+
from .models import DatabaseEngine, StatisticData, StatisticMetaData, UnsupportedDialect
8882
from .pool import POOL_SIZE, MutexPool, RecorderPool
8983
from .table_managers.event_data import EventDataManager
9084
from .table_managers.event_types import EventTypeManager
@@ -621,17 +615,6 @@ def async_import_statistics(
621615
table: type[Statistics | StatisticsShortTerm],
622616
) -> None:
623617
"""Schedule import of statistics."""
624-
if "mean_type" not in metadata:
625-
# Backwards compatibility for old metadata format
626-
# Can be removed after 2026.4
627-
metadata["mean_type"] = ( # type: ignore[unreachable]
628-
StatisticMeanType.ARITHMETIC
629-
if metadata.get("has_mean")
630-
else StatisticMeanType.NONE
631-
)
632-
# Remove deprecated has_mean as it's not needed anymore in core
633-
metadata.pop("has_mean", None)
634-
635618
self.queue_task(ImportStatisticsTask(metadata, stats, table))
636619

637620
@callback

homeassistant/components/recorder/statistics.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2595,6 +2595,13 @@ def _async_import_statistics(
25952595
statistics: Iterable[StatisticData],
25962596
) -> None:
25972597
"""Validate timestamps and insert an import_statistics job in the queue."""
2598+
if "mean_type" not in metadata:
2599+
metadata["mean_type"] = ( # type: ignore[unreachable]
2600+
StatisticMeanType.ARITHMETIC
2601+
if metadata.pop("has_mean", False)
2602+
else StatisticMeanType.NONE
2603+
)
2604+
25982605
# If unit class is not set, we try to set it based on the unit of measurement
25992606
# Note: This can't happen from the type checker's perspective, but we need
26002607
# to guard against custom integrations that have not been updated to set
@@ -2661,6 +2668,12 @@ def async_import_statistics(
26612668
if not metadata["source"] or metadata["source"] != DOMAIN:
26622669
raise HomeAssistantError("Invalid source")
26632670

2671+
if "mean_type" not in metadata and not _called_from_ws_api: # type: ignore[unreachable]
2672+
report_usage( # type: ignore[unreachable]
2673+
"doesn't specify mean_type when calling async_import_statistics",
2674+
breaks_in_ha_version="2026.11",
2675+
exclude_integrations={DOMAIN},
2676+
)
26642677
if "unit_class" not in metadata and not _called_from_ws_api: # type: ignore[unreachable]
26652678
report_usage( # type: ignore[unreachable]
26662679
"doesn't specify unit_class when calling async_import_statistics",
@@ -2692,6 +2705,12 @@ def async_add_external_statistics(
26922705
if not metadata["source"] or metadata["source"] != domain:
26932706
raise HomeAssistantError("Invalid source")
26942707

2708+
if "mean_type" not in metadata and not _called_from_ws_api: # type: ignore[unreachable]
2709+
report_usage( # type: ignore[unreachable]
2710+
"doesn't specify mean_type when calling async_import_statistics",
2711+
breaks_in_ha_version="2026.11",
2712+
exclude_integrations={DOMAIN},
2713+
)
26952714
if "unit_class" not in metadata and not _called_from_ws_api: # type: ignore[unreachable]
26962715
report_usage( # type: ignore[unreachable]
26972716
"doesn't specify unit_class when calling async_add_external_statistics",

homeassistant/components/recorder/websocket_api.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,11 @@ def valid_units(
544544
{
545545
vol.Required("type"): "recorder/import_statistics",
546546
vol.Required("metadata"): {
547-
vol.Required("has_mean"): bool,
547+
vol.Optional("has_mean"): bool,
548+
vol.Optional("mean_type"): vol.All(
549+
vol.In(StatisticMeanType.__members__.values()),
550+
vol.Coerce(StatisticMeanType),
551+
),
548552
vol.Required("has_sum"): bool,
549553
vol.Required("name"): vol.Any(str, None),
550554
vol.Required("source"): str,
@@ -574,10 +578,12 @@ def ws_import_statistics(
574578
The unit_class specifies which unit conversion class to use, if applicable.
575579
"""
576580
metadata = msg["metadata"]
577-
# The WS command will be changed in a follow up PR
578-
metadata["mean_type"] = (
579-
StatisticMeanType.ARITHMETIC if metadata["has_mean"] else StatisticMeanType.NONE
580-
)
581+
if "mean_type" not in metadata:
582+
_LOGGER.warning(
583+
"WS command recorder/import_statistics called without specifying "
584+
"mean_type in metadata, this is deprecated and will stop working "
585+
"in HA Core 2026.11"
586+
)
581587
if "unit_class" not in metadata:
582588
_LOGGER.warning(
583589
"WS command recorder/import_statistics called without specifying "

tests/components/energy/test_websocket_api.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from homeassistant.components.energy import data, is_configured
99
from homeassistant.components.recorder import Recorder
10+
from homeassistant.components.recorder.models import StatisticMeanType
1011
from homeassistant.components.recorder.statistics import async_add_external_statistics
1112
from homeassistant.core import HomeAssistant
1213
from homeassistant.setup import async_setup_component
@@ -365,8 +366,8 @@ async def test_fossil_energy_consumption_no_co2(
365366
},
366367
)
367368
external_energy_metadata_1 = {
368-
"has_mean": False,
369369
"has_sum": True,
370+
"mean_type": StatisticMeanType.NONE,
370371
"name": "Total imported energy",
371372
"source": "test",
372373
"statistic_id": "test:total_energy_import_tariff_1",
@@ -400,8 +401,8 @@ async def test_fossil_energy_consumption_no_co2(
400401
},
401402
)
402403
external_energy_metadata_2 = {
403-
"has_mean": False,
404404
"has_sum": True,
405+
"mean_type": StatisticMeanType.NONE,
405406
"name": "Total imported energy",
406407
"source": "test",
407408
"statistic_id": "test:total_energy_import_tariff_2",
@@ -532,8 +533,8 @@ async def test_fossil_energy_consumption_hole(
532533
},
533534
)
534535
external_energy_metadata_1 = {
535-
"has_mean": False,
536536
"has_sum": True,
537+
"mean_type": StatisticMeanType.NONE,
537538
"name": "Total imported energy",
538539
"source": "test",
539540
"statistic_id": "test:total_energy_import_tariff_1",
@@ -567,8 +568,8 @@ async def test_fossil_energy_consumption_hole(
567568
},
568569
)
569570
external_energy_metadata_2 = {
570-
"has_mean": False,
571571
"has_sum": True,
572+
"mean_type": StatisticMeanType.NONE,
572573
"name": "Total imported energy",
573574
"source": "test",
574575
"statistic_id": "test:total_energy_import_tariff_2",
@@ -697,8 +698,8 @@ async def test_fossil_energy_consumption_no_data(
697698
},
698699
)
699700
external_energy_metadata_1 = {
700-
"has_mean": False,
701701
"has_sum": True,
702+
"mean_type": StatisticMeanType.NONE,
702703
"name": "Total imported energy",
703704
"source": "test",
704705
"statistic_id": "test:total_energy_import_tariff_1",
@@ -732,8 +733,8 @@ async def test_fossil_energy_consumption_no_data(
732733
},
733734
)
734735
external_energy_metadata_2 = {
735-
"has_mean": False,
736736
"has_sum": True,
737+
"mean_type": StatisticMeanType.NONE,
737738
"name": "Total imported energy",
738739
"source": "test",
739740
"statistic_id": "test:total_energy_import_tariff_2",
@@ -851,8 +852,8 @@ async def test_fossil_energy_consumption(
851852
},
852853
)
853854
external_energy_metadata_1 = {
854-
"has_mean": False,
855855
"has_sum": True,
856+
"mean_type": StatisticMeanType.NONE,
856857
"name": "Total imported energy",
857858
"source": "test",
858859
"statistic_id": "test:total_energy_import_tariff_1",
@@ -886,8 +887,8 @@ async def test_fossil_energy_consumption(
886887
},
887888
)
888889
external_energy_metadata_2 = {
889-
"has_mean": False,
890890
"has_sum": True,
891+
"mean_type": StatisticMeanType.NONE,
891892
"name": "Total imported energy",
892893
"source": "test",
893894
"statistic_id": "test:total_energy_import_tariff_2",
@@ -917,8 +918,8 @@ async def test_fossil_energy_consumption(
917918
},
918919
)
919920
external_co2_metadata = {
920-
"has_mean": True,
921921
"has_sum": False,
922+
"mean_type": StatisticMeanType.ARITHMETIC,
922923
"name": "Fossil percentage",
923924
"source": "test",
924925
"statistic_id": "test:fossil_percentage",
@@ -1105,8 +1106,8 @@ async def test_fossil_energy_consumption_check_missing_hour(
11051106
},
11061107
)
11071108
energy_metadata_1 = {
1108-
"has_mean": False,
11091109
"has_sum": True,
1110+
"mean_type": StatisticMeanType.NONE,
11101111
"name": "Total imported energy",
11111112
"source": "test",
11121113
"statistic_id": "test:total_energy_import",
@@ -1140,8 +1141,8 @@ async def test_fossil_energy_consumption_check_missing_hour(
11401141
},
11411142
)
11421143
co2_metadata = {
1143-
"has_mean": True,
11441144
"has_sum": False,
1145+
"mean_type": StatisticMeanType.ARITHMETIC,
11451146
"name": "Fossil percentage",
11461147
"source": "test",
11471148
"statistic_id": "test:fossil_percentage",
@@ -1202,8 +1203,8 @@ async def test_fossil_energy_consumption_missing_sum(
12021203
{"start": period4, "last_reset": None, "state": 3, "mean": 5},
12031204
)
12041205
external_energy_metadata_1 = {
1205-
"has_mean": True,
12061206
"has_sum": False,
1207+
"mean_type": StatisticMeanType.ARITHMETIC,
12071208
"name": "Mean imported energy",
12081209
"source": "test",
12091210
"statistic_id": "test:mean_energy_import_tariff",

tests/components/kitchen_sink/test_init.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ async def test_demo_statistics_growth(hass: HomeAssistant) -> None:
8383
"statistic_id": statistic_id,
8484
"unit_class": "volume",
8585
"unit_of_measurement": "m³",
86-
"has_mean": False,
86+
"mean_type": StatisticMeanType.NONE,
8787
"has_sum": True,
8888
}
8989
statistics = [

tests/components/opower/test_coordinator.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@
1010
from homeassistant.components.opower.const import DOMAIN
1111
from homeassistant.components.opower.coordinator import OpowerCoordinator
1212
from homeassistant.components.recorder import Recorder
13-
from homeassistant.components.recorder.models import StatisticData, StatisticMetaData
13+
from homeassistant.components.recorder.models import (
14+
StatisticData,
15+
StatisticMeanType,
16+
StatisticMetaData,
17+
)
1418
from homeassistant.components.recorder.statistics import (
1519
async_add_external_statistics,
1620
get_last_statistics,
@@ -186,6 +190,7 @@ async def test_coordinator_migration(
186190
statistic_id = "opower:pge_elec_111111_energy_consumption"
187191
metadata = StatisticMetaData(
188192
has_sum=True,
193+
mean_type=StatisticMeanType.NONE,
189194
name="Opower pge elec 111111 consumption",
190195
source=DOMAIN,
191196
statistic_id=statistic_id,

tests/components/recorder/auto_repairs/statistics/test_duplicates.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
delete_statistics_duplicates,
1515
delete_statistics_meta_duplicates,
1616
)
17+
from homeassistant.components.recorder.models import StatisticMeanType
1718
from homeassistant.components.recorder.statistics import async_add_external_statistics
1819
from homeassistant.components.recorder.util import session_scope
1920
from homeassistant.core import HomeAssistant
@@ -59,8 +60,8 @@ async def test_duplicate_statistics_handle_integrity_error(
5960
period2 = dt_util.as_utc(dt_util.parse_datetime("2021-09-30 23:00:00"))
6061

6162
external_energy_metadata_1 = {
62-
"has_mean": False,
6363
"has_sum": True,
64+
"mean_type": StatisticMeanType.NONE,
6465
"name": "Total imported energy",
6566
"source": "test",
6667
"statistic_id": "test:total_energy_import_tariff_1",

0 commit comments

Comments
 (0)