mirror of
https://github.com/home-assistant/core.git
synced 2026-08-03 20:24:55 +02:00
Bump meteo-lt-pkg to 0.7.3 (#174391)
Co-authored-by: Erwin Douna <e.douna@gmail.com>
This commit is contained in:
@@ -8,6 +8,7 @@ from meteo_lt import MeteoLtAPI, Place
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
from .const import CONF_PLACE_CODE, DOMAIN
|
||||
|
||||
@@ -19,7 +20,6 @@ class MeteoLtConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize the config flow."""
|
||||
self._api = MeteoLtAPI()
|
||||
self._places: list[Place] = []
|
||||
self._selected_place: Place | None = None
|
||||
|
||||
@@ -49,9 +49,10 @@ class MeteoLtConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||
errors["base"] = "invalid_location"
|
||||
|
||||
if not self._places:
|
||||
api = MeteoLtAPI(session=async_get_clientsession(self.hass))
|
||||
try:
|
||||
await self._api.fetch_places()
|
||||
self._places = self._api.places
|
||||
await api.fetch_places()
|
||||
self._places = api.places
|
||||
except (aiohttp.ClientError, TimeoutError) as err:
|
||||
_LOGGER.error("Error fetching places: %s", err)
|
||||
return self.async_abort(reason="cannot_connect")
|
||||
|
||||
@@ -8,6 +8,7 @@ from meteo_lt import Forecast as MeteoLtForecast, MeteoLtAPI
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
from .const import DEFAULT_UPDATE_INTERVAL, DOMAIN
|
||||
@@ -27,7 +28,7 @@ class MeteoLtUpdateCoordinator(DataUpdateCoordinator[MeteoLtForecast]):
|
||||
config_entry: MeteoLtConfigEntry,
|
||||
) -> None:
|
||||
"""Initialize the coordinator."""
|
||||
self.client = MeteoLtAPI()
|
||||
self.client = MeteoLtAPI(session=async_get_clientsession(hass))
|
||||
self.place_code = place_code
|
||||
|
||||
super().__init__(
|
||||
@@ -42,7 +43,9 @@ class MeteoLtUpdateCoordinator(DataUpdateCoordinator[MeteoLtForecast]):
|
||||
async def _async_update_data(self) -> MeteoLtForecast:
|
||||
"""Fetch data from Meteo.lt API."""
|
||||
try:
|
||||
forecast = await self.client.get_forecast(self.place_code)
|
||||
forecast = await self.client.get_forecast(
|
||||
self.place_code, include_warnings=False
|
||||
)
|
||||
except aiohttp.ClientResponseError as err:
|
||||
raise UpdateFailed(
|
||||
f"API returned error status {err.status}: {err.message}"
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
"integration_type": "service",
|
||||
"iot_class": "cloud_polling",
|
||||
"quality_scale": "bronze",
|
||||
"requirements": ["meteo-lt-pkg==0.2.4"]
|
||||
"requirements": ["meteo-lt-pkg==0.7.3"]
|
||||
}
|
||||
|
||||
@@ -5,6 +5,19 @@ from datetime import datetime
|
||||
from typing import Any, override
|
||||
|
||||
from homeassistant.components.weather import (
|
||||
ATTR_CONDITION_CLEAR_NIGHT,
|
||||
ATTR_CONDITION_CLOUDY,
|
||||
ATTR_CONDITION_EXCEPTIONAL,
|
||||
ATTR_CONDITION_FOG,
|
||||
ATTR_CONDITION_HAIL,
|
||||
ATTR_CONDITION_LIGHTNING,
|
||||
ATTR_CONDITION_LIGHTNING_RAINY,
|
||||
ATTR_CONDITION_PARTLYCLOUDY,
|
||||
ATTR_CONDITION_POURING,
|
||||
ATTR_CONDITION_RAINY,
|
||||
ATTR_CONDITION_SNOWY,
|
||||
ATTR_CONDITION_SNOWY_RAINY,
|
||||
ATTR_CONDITION_SUNNY,
|
||||
Forecast,
|
||||
WeatherEntity,
|
||||
WeatherEntityFeature,
|
||||
@@ -16,13 +29,36 @@ from homeassistant.const import (
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import sun
|
||||
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from .const import ATTRIBUTION, DOMAIN, MANUFACTURER, MODEL
|
||||
from .coordinator import MeteoLtConfigEntry, MeteoLtUpdateCoordinator
|
||||
|
||||
_CONDITION_MAP: dict[str, str] = {
|
||||
"partly-cloudy": ATTR_CONDITION_PARTLYCLOUDY,
|
||||
"cloudy-with-sunny-intervals": ATTR_CONDITION_PARTLYCLOUDY,
|
||||
"cloudy": ATTR_CONDITION_CLOUDY,
|
||||
"thunder": ATTR_CONDITION_LIGHTNING,
|
||||
"isolated-thunderstorms": ATTR_CONDITION_LIGHTNING_RAINY,
|
||||
"thunderstorms": ATTR_CONDITION_LIGHTNING_RAINY,
|
||||
"heavy-rain-with-thunderstorms": ATTR_CONDITION_LIGHTNING_RAINY,
|
||||
"light-rain": ATTR_CONDITION_RAINY,
|
||||
"rain": ATTR_CONDITION_RAINY,
|
||||
"heavy-rain": ATTR_CONDITION_POURING,
|
||||
"light-sleet": ATTR_CONDITION_SNOWY_RAINY,
|
||||
"sleet": ATTR_CONDITION_SNOWY_RAINY,
|
||||
"freezing-rain": ATTR_CONDITION_SNOWY_RAINY,
|
||||
"hail": ATTR_CONDITION_HAIL,
|
||||
"light-snow": ATTR_CONDITION_SNOWY,
|
||||
"snow": ATTR_CONDITION_SNOWY,
|
||||
"heavy-snow": ATTR_CONDITION_SNOWY,
|
||||
"fog": ATTR_CONDITION_FOG,
|
||||
}
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
@@ -63,6 +99,19 @@ class MeteoLtWeatherEntity(CoordinatorEntity[MeteoLtUpdateCoordinator], WeatherE
|
||||
model=MODEL,
|
||||
)
|
||||
|
||||
def _map_condition(self, condition_code: str | None, datetime_str: str) -> str:
|
||||
"""Map a meteo.lt condition code to a Home Assistant condition string."""
|
||||
if condition_code is None:
|
||||
return ATTR_CONDITION_EXCEPTIONAL
|
||||
if condition_code == "clear":
|
||||
dt = dt_util.parse_datetime(datetime_str)
|
||||
return (
|
||||
ATTR_CONDITION_SUNNY
|
||||
if sun.is_up(self.hass, dt)
|
||||
else ATTR_CONDITION_CLEAR_NIGHT
|
||||
)
|
||||
return _CONDITION_MAP.get(condition_code, ATTR_CONDITION_EXCEPTIONAL)
|
||||
|
||||
@property
|
||||
@override
|
||||
def native_temperature(self) -> float | None:
|
||||
@@ -115,7 +164,8 @@ class MeteoLtWeatherEntity(CoordinatorEntity[MeteoLtUpdateCoordinator], WeatherE
|
||||
@override
|
||||
def condition(self) -> str | None:
|
||||
"""Return the current condition."""
|
||||
return self.coordinator.data.current_conditions.condition
|
||||
cc = self.coordinator.data.current_conditions
|
||||
return self._map_condition(cc.condition_code, cc.datetime)
|
||||
|
||||
def _convert_forecast_data(
|
||||
self, forecast_data: Any, include_templow: bool = False
|
||||
@@ -126,7 +176,9 @@ class MeteoLtWeatherEntity(CoordinatorEntity[MeteoLtUpdateCoordinator], WeatherE
|
||||
native_temperature=forecast_data.temperature,
|
||||
native_templow=forecast_data.temperature_low if include_templow else None,
|
||||
native_apparent_temperature=forecast_data.apparent_temperature,
|
||||
condition=forecast_data.condition,
|
||||
condition=self._map_condition(
|
||||
forecast_data.condition_code, forecast_data.datetime
|
||||
),
|
||||
native_precipitation=forecast_data.precipitation,
|
||||
precipitation_probability=None, # Not provided by API
|
||||
native_wind_speed=forecast_data.wind_speed,
|
||||
@@ -169,7 +221,9 @@ class MeteoLtWeatherEntity(CoordinatorEntity[MeteoLtUpdateCoordinator], WeatherE
|
||||
native_temperature=max_temp,
|
||||
native_templow=min_temp,
|
||||
native_apparent_temperature=midday_forecast.apparent_temperature,
|
||||
condition=midday_forecast.condition,
|
||||
condition=self._map_condition(
|
||||
midday_forecast.condition_code, midday_forecast.datetime
|
||||
),
|
||||
# Calculate precipitation: sum if any values, else None
|
||||
native_precipitation=(
|
||||
sum(
|
||||
|
||||
Generated
+1
-1
@@ -1571,7 +1571,7 @@ melnor-bluetooth==0.0.25
|
||||
messagebird==1.2.1
|
||||
|
||||
# homeassistant.components.meteo_lt
|
||||
meteo-lt-pkg==0.2.4
|
||||
meteo-lt-pkg==0.7.3
|
||||
|
||||
# homeassistant.components.meteoalarm
|
||||
meteoalertapi==0.3.1
|
||||
|
||||
@@ -38,9 +38,9 @@ def mock_meteo_lt_api() -> Generator[AsyncMock]:
|
||||
mock_api.places = mock_places
|
||||
mock_api.fetch_places.return_value = None
|
||||
|
||||
mock_forecast = Forecast.from_dict(forecast_data)
|
||||
|
||||
mock_api.get_forecast.return_value = mock_forecast
|
||||
mock_api.get_forecast.side_effect = lambda *args, **kwargs: Forecast.from_dict(
|
||||
forecast_data
|
||||
)
|
||||
|
||||
# Mock get_nearest_place to return Vilnius
|
||||
mock_api.get_nearest_place.return_value = mock_places[0]
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
"seaLevelPressure": 1029,
|
||||
"relativeHumidity": 55,
|
||||
"totalPrecipitation": 0.3,
|
||||
"conditionCode": "rainy"
|
||||
"conditionCode": "rain"
|
||||
},
|
||||
{
|
||||
"forecastTimeUtc": "2025-09-28 10:00:00",
|
||||
@@ -86,7 +86,7 @@
|
||||
"seaLevelPressure": 1028,
|
||||
"relativeHumidity": 50,
|
||||
"totalPrecipitation": 0.4,
|
||||
"conditionCode": "rainy"
|
||||
"conditionCode": "rain"
|
||||
},
|
||||
{
|
||||
"forecastTimeUtc": "2025-09-29 10:00:00",
|
||||
@@ -99,7 +99,7 @@
|
||||
"seaLevelPressure": 1027,
|
||||
"relativeHumidity": 45,
|
||||
"totalPrecipitation": 0.5,
|
||||
"conditionCode": "rainy"
|
||||
"conditionCode": "rain"
|
||||
},
|
||||
{
|
||||
"forecastTimeUtc": "2025-09-30 10:00:00",
|
||||
@@ -112,7 +112,7 @@
|
||||
"seaLevelPressure": 1026,
|
||||
"relativeHumidity": 40,
|
||||
"totalPrecipitation": 0.6,
|
||||
"conditionCode": "rainy"
|
||||
"conditionCode": "rain"
|
||||
},
|
||||
{
|
||||
"forecastTimeUtc": "2025-10-01 10:00:00",
|
||||
@@ -125,7 +125,7 @@
|
||||
"seaLevelPressure": 1025,
|
||||
"relativeHumidity": 35,
|
||||
"totalPrecipitation": 0.7,
|
||||
"conditionCode": "rainy"
|
||||
"conditionCode": "rain"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -61,6 +61,6 @@
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'sunny',
|
||||
'state': 'clear-night',
|
||||
})
|
||||
# ---
|
||||
|
||||
@@ -1,16 +1,39 @@
|
||||
"""Test Meteo.lt weather entity."""
|
||||
|
||||
from collections.abc import Generator
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from meteo_lt import Forecast
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.meteo_lt.const import DOMAIN
|
||||
from homeassistant.components.weather import (
|
||||
ATTR_CONDITION_CLEAR_NIGHT,
|
||||
ATTR_CONDITION_CLOUDY,
|
||||
ATTR_CONDITION_EXCEPTIONAL,
|
||||
ATTR_CONDITION_FOG,
|
||||
ATTR_CONDITION_HAIL,
|
||||
ATTR_CONDITION_LIGHTNING,
|
||||
ATTR_CONDITION_LIGHTNING_RAINY,
|
||||
ATTR_CONDITION_PARTLYCLOUDY,
|
||||
ATTR_CONDITION_POURING,
|
||||
ATTR_CONDITION_RAINY,
|
||||
ATTR_CONDITION_SNOWY,
|
||||
ATTR_CONDITION_SNOWY_RAINY,
|
||||
ATTR_CONDITION_SUNNY,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
async_load_json_object_fixture,
|
||||
snapshot_platform,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
@@ -36,12 +59,158 @@ async def test_weather_entity(
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
|
||||
@pytest.mark.freeze_time("2025-09-25 9:00:00")
|
||||
async def test_forecast_no_limits(
|
||||
@pytest.mark.freeze_time("2025-09-25 10:00:00")
|
||||
async def test_coordinator_requests_forecast_without_warnings(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_meteo_lt_api: AsyncMock,
|
||||
) -> None:
|
||||
"""Test that the coordinator fetches forecasts with warnings disabled."""
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert mock_config_entry.state is ConfigEntryState.LOADED
|
||||
mock_meteo_lt_api.get_forecast.assert_called_with("vilnius", include_warnings=False)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"expected_condition",
|
||||
[
|
||||
pytest.param(
|
||||
ATTR_CONDITION_SUNNY,
|
||||
marks=pytest.mark.freeze_time("2025-09-25 10:00:00"), # 13:00 in Vilnius
|
||||
id="day",
|
||||
),
|
||||
pytest.param(
|
||||
ATTR_CONDITION_CLEAR_NIGHT,
|
||||
marks=pytest.mark.freeze_time("2025-09-25 22:00:00"), # 01:00 in Vilnius
|
||||
id="night",
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_condition_clear_maps_day_night(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_meteo_lt_api: AsyncMock,
|
||||
expected_condition: str,
|
||||
) -> None:
|
||||
"""Test that a clear condition maps to sunny or clear-night by sun position at the forecast time."""
|
||||
hass.config.latitude = 54.68705 # Vilnius, matching the forecast place
|
||||
hass.config.longitude = 25.28291
|
||||
|
||||
forecast_data = await async_load_json_object_fixture(hass, "forecast.json", DOMAIN)
|
||||
current_hour = dt_util.utcnow().strftime("%Y-%m-%d %H:%M:%S")
|
||||
forecast_data["forecastTimestamps"][0]["forecastTimeUtc"] = current_hour
|
||||
forecast_data["forecastTimestamps"][0]["conditionCode"] = "clear"
|
||||
mock_meteo_lt_api.get_forecast.side_effect = lambda *args, **kwargs: (
|
||||
Forecast.from_dict(forecast_data)
|
||||
)
|
||||
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("weather.vilnius")
|
||||
assert state is not None
|
||||
assert state.state == expected_condition
|
||||
|
||||
|
||||
@pytest.mark.freeze_time("2025-09-25 10:00:00")
|
||||
@pytest.mark.parametrize(
|
||||
("condition_code", "expected_condition"),
|
||||
[
|
||||
pytest.param("partly-cloudy", ATTR_CONDITION_PARTLYCLOUDY, id="partly-cloudy"),
|
||||
pytest.param(
|
||||
"cloudy-with-sunny-intervals",
|
||||
ATTR_CONDITION_PARTLYCLOUDY,
|
||||
id="cloudy-with-sunny-intervals",
|
||||
),
|
||||
pytest.param("cloudy", ATTR_CONDITION_CLOUDY, id="cloudy"),
|
||||
pytest.param("thunder", ATTR_CONDITION_LIGHTNING, id="thunder"),
|
||||
pytest.param(
|
||||
"isolated-thunderstorms",
|
||||
ATTR_CONDITION_LIGHTNING_RAINY,
|
||||
id="isolated-thunderstorms",
|
||||
),
|
||||
pytest.param(
|
||||
"thunderstorms", ATTR_CONDITION_LIGHTNING_RAINY, id="thunderstorms"
|
||||
),
|
||||
pytest.param(
|
||||
"heavy-rain-with-thunderstorms",
|
||||
ATTR_CONDITION_LIGHTNING_RAINY,
|
||||
id="heavy-rain-with-thunderstorms",
|
||||
),
|
||||
pytest.param("light-rain", ATTR_CONDITION_RAINY, id="light-rain"),
|
||||
pytest.param("rain", ATTR_CONDITION_RAINY, id="rain"),
|
||||
pytest.param("heavy-rain", ATTR_CONDITION_POURING, id="heavy-rain"),
|
||||
pytest.param("light-sleet", ATTR_CONDITION_SNOWY_RAINY, id="light-sleet"),
|
||||
pytest.param("sleet", ATTR_CONDITION_SNOWY_RAINY, id="sleet"),
|
||||
pytest.param("freezing-rain", ATTR_CONDITION_SNOWY_RAINY, id="freezing-rain"),
|
||||
pytest.param("hail", ATTR_CONDITION_HAIL, id="hail"),
|
||||
pytest.param("light-snow", ATTR_CONDITION_SNOWY, id="light-snow"),
|
||||
pytest.param("snow", ATTR_CONDITION_SNOWY, id="snow"),
|
||||
pytest.param("heavy-snow", ATTR_CONDITION_SNOWY, id="heavy-snow"),
|
||||
pytest.param("fog", ATTR_CONDITION_FOG, id="fog"),
|
||||
],
|
||||
)
|
||||
async def test_condition_code_mapping(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_meteo_lt_api: AsyncMock,
|
||||
condition_code: str,
|
||||
expected_condition: str,
|
||||
) -> None:
|
||||
"""Test that each meteo.lt condition code maps to the expected HA condition."""
|
||||
forecast_data = await async_load_json_object_fixture(hass, "forecast.json", DOMAIN)
|
||||
forecast_data["forecastTimestamps"][0]["conditionCode"] = condition_code
|
||||
mock_meteo_lt_api.get_forecast.side_effect = lambda *args, **kwargs: (
|
||||
Forecast.from_dict(forecast_data)
|
||||
)
|
||||
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("weather.vilnius")
|
||||
assert state is not None
|
||||
assert state.state == expected_condition
|
||||
|
||||
|
||||
@pytest.mark.freeze_time("2025-09-25 10:00:00")
|
||||
@pytest.mark.parametrize(
|
||||
"condition_code",
|
||||
[None, "not-a-real-condition"],
|
||||
ids=["missing", "unknown"],
|
||||
)
|
||||
async def test_condition_unknown_maps_to_exceptional(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_meteo_lt_api: AsyncMock,
|
||||
condition_code: str | None,
|
||||
) -> None:
|
||||
"""Test that a missing or unmapped condition code maps to exceptional."""
|
||||
forecast_data = await async_load_json_object_fixture(hass, "forecast.json", DOMAIN)
|
||||
forecast_data["forecastTimestamps"][0]["conditionCode"] = condition_code
|
||||
mock_meteo_lt_api.get_forecast.side_effect = lambda *args, **kwargs: (
|
||||
Forecast.from_dict(forecast_data)
|
||||
)
|
||||
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("weather.vilnius")
|
||||
assert state is not None
|
||||
assert state.state == ATTR_CONDITION_EXCEPTIONAL
|
||||
|
||||
|
||||
@pytest.mark.freeze_time("2025-09-25 10:00:00")
|
||||
async def test_forecast_hourly(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test that forecast returns all available data from API without limits."""
|
||||
"""Test hourly forecast returns all entries with correct condition mapping."""
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
@@ -53,8 +222,23 @@ async def test_forecast_no_limits(
|
||||
blocking=True,
|
||||
return_response=True,
|
||||
)
|
||||
hourly_forecasts = result["weather.vilnius"]["forecast"]
|
||||
assert len(hourly_forecasts) == 9
|
||||
forecasts = result["weather.vilnius"]["forecast"]
|
||||
|
||||
assert len(forecasts) == 8
|
||||
assert forecasts[0]["condition"] == ATTR_CONDITION_PARTLYCLOUDY # 11:00
|
||||
assert forecasts[1]["condition"] == ATTR_CONDITION_CLOUDY # 12:00
|
||||
assert forecasts[3]["condition"] == ATTR_CONDITION_RAINY # 2025-09-27
|
||||
|
||||
|
||||
@pytest.mark.freeze_time("2025-09-25 10:00:00")
|
||||
async def test_forecast_daily(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test daily forecast aggregates hourly entries into per-day summaries."""
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
result = await hass.services.async_call(
|
||||
"weather",
|
||||
@@ -63,5 +247,15 @@ async def test_forecast_no_limits(
|
||||
blocking=True,
|
||||
return_response=True,
|
||||
)
|
||||
daily_forecasts = result["weather.vilnius"]["forecast"]
|
||||
assert len(daily_forecasts) == 7
|
||||
forecasts = result["weather.vilnius"]["forecast"]
|
||||
|
||||
assert len(forecasts) == 7
|
||||
|
||||
first_day = forecasts[0]
|
||||
assert first_day["temperature"] == 13.5 # max(12.2, 13.5)
|
||||
assert first_day["templow"] == 12.2 # min(12.2, 13.5)
|
||||
assert first_day["precipitation"] == pytest.approx(0.1) # sum: 0 + 0.1
|
||||
assert first_day["condition"] == ATTR_CONDITION_CLOUDY # midday 12:00 → "cloudy"
|
||||
|
||||
rainy_day = forecasts[2]
|
||||
assert rainy_day["condition"] == ATTR_CONDITION_RAINY # 2025-09-27 → "rain"
|
||||
|
||||
Reference in New Issue
Block a user