mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Add forecast service call for extra attributes for nws (#117254)
* add service call * fix snapshots in test * add tests * fix no data service;add test * remove unreachable code * use only extra attributes+context attributes * detailed descr. only in twice daily; add dewpoint * fix import from merge * Remove dewpoint from twice daily. nws recently removed it * cleanup unused snapshots * remove dewpoint; use short_forecast * return [] for forecasts instead of None * Use str for short_description Co-authored-by: G Johansson <goran.johansson@shiftit.se> --------- Co-authored-by: G Johansson <goran.johansson@shiftit.se>
This commit is contained in:
parent
ec937781ca
commit
f479b64ff9
@ -27,6 +27,7 @@ CONF_STATION = "station"
|
|||||||
|
|
||||||
ATTRIBUTION = "Data from National Weather Service/NOAA"
|
ATTRIBUTION = "Data from National Weather Service/NOAA"
|
||||||
|
|
||||||
|
ATTR_FORECAST_SHORT_DESCRIPTION: Final = "short_description"
|
||||||
ATTR_FORECAST_DETAILED_DESCRIPTION: Final = "detailed_description"
|
ATTR_FORECAST_DETAILED_DESCRIPTION: Final = "detailed_description"
|
||||||
|
|
||||||
CONDITION_CLASSES: dict[str, list[str]] = {
|
CONDITION_CLASSES: dict[str, list[str]] = {
|
||||||
|
5
homeassistant/components/nws/icons.json
Normal file
5
homeassistant/components/nws/icons.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"services": {
|
||||||
|
"get_forecasts_extra": "mdi:weather-cloudy-clock"
|
||||||
|
}
|
||||||
|
}
|
13
homeassistant/components/nws/services.yaml
Normal file
13
homeassistant/components/nws/services.yaml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
get_forecasts_extra:
|
||||||
|
target:
|
||||||
|
entity:
|
||||||
|
domain: weather
|
||||||
|
fields:
|
||||||
|
type:
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
select:
|
||||||
|
options:
|
||||||
|
- "hourly"
|
||||||
|
- "twice_daily"
|
||||||
|
translation_key: nws_forecast_type
|
@ -19,5 +19,25 @@
|
|||||||
"abort": {
|
"abort": {
|
||||||
"already_configured": "[%key:common::config_flow::abort::already_configured_service%]"
|
"already_configured": "[%key:common::config_flow::abort::already_configured_service%]"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"selector": {
|
||||||
|
"nws_forecast_type": {
|
||||||
|
"options": {
|
||||||
|
"hourly": "Hourly",
|
||||||
|
"twice_daily": "Twice daily"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"services": {
|
||||||
|
"get_forecasts_extra": {
|
||||||
|
"name": "Get extra forecasts data.",
|
||||||
|
"description": "Get extra data for weather forecasts.",
|
||||||
|
"fields": {
|
||||||
|
"type": {
|
||||||
|
"name": "Forecast type",
|
||||||
|
"description": "Forecast type: hourly or twice_daily."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,9 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from types import MappingProxyType
|
from types import MappingProxyType
|
||||||
from typing import TYPE_CHECKING, Any, Literal, cast
|
from typing import TYPE_CHECKING, Any, Literal, Required, TypedDict, cast
|
||||||
|
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.weather import (
|
from homeassistant.components.weather import (
|
||||||
ATTR_CONDITION_CLEAR_NIGHT,
|
ATTR_CONDITION_CLEAR_NIGHT,
|
||||||
@ -31,15 +33,22 @@ from homeassistant.const import (
|
|||||||
UnitOfSpeed,
|
UnitOfSpeed,
|
||||||
UnitOfTemperature,
|
UnitOfTemperature,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import (
|
||||||
from homeassistant.helpers import entity_registry as er
|
HomeAssistant,
|
||||||
|
ServiceResponse,
|
||||||
|
SupportsResponse,
|
||||||
|
callback,
|
||||||
|
)
|
||||||
|
from homeassistant.helpers import entity_platform, entity_registry as er
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.update_coordinator import TimestampDataUpdateCoordinator
|
from homeassistant.helpers.update_coordinator import TimestampDataUpdateCoordinator
|
||||||
|
from homeassistant.util.json import JsonValueType
|
||||||
from homeassistant.util.unit_conversion import SpeedConverter, TemperatureConverter
|
from homeassistant.util.unit_conversion import SpeedConverter, TemperatureConverter
|
||||||
|
|
||||||
from . import NWSConfigEntry, NWSData, base_unique_id, device_info
|
from . import NWSConfigEntry, NWSData, base_unique_id, device_info
|
||||||
from .const import (
|
from .const import (
|
||||||
ATTR_FORECAST_DETAILED_DESCRIPTION,
|
ATTR_FORECAST_DETAILED_DESCRIPTION,
|
||||||
|
ATTR_FORECAST_SHORT_DESCRIPTION,
|
||||||
ATTRIBUTION,
|
ATTRIBUTION,
|
||||||
CONDITION_CLASSES,
|
CONDITION_CLASSES,
|
||||||
DAYNIGHT,
|
DAYNIGHT,
|
||||||
@ -92,15 +101,27 @@ async def async_setup_entry(
|
|||||||
):
|
):
|
||||||
entity_registry.async_remove(entity_id)
|
entity_registry.async_remove(entity_id)
|
||||||
|
|
||||||
|
platform = entity_platform.async_get_current_platform()
|
||||||
|
|
||||||
|
platform.async_register_entity_service(
|
||||||
|
"get_forecasts_extra",
|
||||||
|
{vol.Required("type"): vol.In(("hourly", "twice_daily"))},
|
||||||
|
"async_get_forecasts_extra_service",
|
||||||
|
supports_response=SupportsResponse.ONLY,
|
||||||
|
)
|
||||||
|
|
||||||
async_add_entities([NWSWeather(entry.data, nws_data)], False)
|
async_add_entities([NWSWeather(entry.data, nws_data)], False)
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
class ExtraForecast(TypedDict, total=False):
|
||||||
|
"""Forecast extra fields from NWS."""
|
||||||
|
|
||||||
class NWSForecast(Forecast):
|
# common attributes
|
||||||
"""Forecast with extra fields needed for NWS."""
|
datetime: Required[str]
|
||||||
|
is_daytime: bool | None
|
||||||
detailed_description: str | None
|
# extra attributes
|
||||||
|
detailed_description: str | None
|
||||||
|
short_description: str | None
|
||||||
|
|
||||||
|
|
||||||
def _calculate_unique_id(entry_data: MappingProxyType[str, Any], mode: str) -> str:
|
def _calculate_unique_id(entry_data: MappingProxyType[str, Any], mode: str) -> str:
|
||||||
@ -217,17 +238,16 @@ class NWSWeather(CoordinatorWeatherEntity[TimestampDataUpdateCoordinator[None]])
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def _forecast(
|
def _forecast(
|
||||||
self, nws_forecast: list[dict[str, Any]] | None, mode: str
|
self,
|
||||||
) -> list[Forecast] | None:
|
nws_forecast: list[dict[str, Any]],
|
||||||
|
mode: str,
|
||||||
|
) -> list[Forecast]:
|
||||||
"""Return forecast."""
|
"""Return forecast."""
|
||||||
if nws_forecast is None:
|
if nws_forecast is None:
|
||||||
return None
|
return []
|
||||||
forecast: list[Forecast] = []
|
forecast: list[Forecast] = []
|
||||||
for forecast_entry in nws_forecast:
|
for forecast_entry in nws_forecast:
|
||||||
data: NWSForecast = {
|
data: Forecast = {
|
||||||
ATTR_FORECAST_DETAILED_DESCRIPTION: forecast_entry.get(
|
|
||||||
"detailedForecast"
|
|
||||||
),
|
|
||||||
ATTR_FORECAST_TIME: cast(str, forecast_entry.get("startTime")),
|
ATTR_FORECAST_TIME: cast(str, forecast_entry.get("startTime")),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,6 +293,30 @@ class NWSWeather(CoordinatorWeatherEntity[TimestampDataUpdateCoordinator[None]])
|
|||||||
forecast.append(data)
|
forecast.append(data)
|
||||||
return forecast
|
return forecast
|
||||||
|
|
||||||
|
def _forecast_extra(
|
||||||
|
self,
|
||||||
|
nws_forecast: list[dict[str, Any]] | None,
|
||||||
|
mode: str,
|
||||||
|
) -> list[ExtraForecast]:
|
||||||
|
"""Return forecast."""
|
||||||
|
if nws_forecast is None:
|
||||||
|
return []
|
||||||
|
forecast: list[ExtraForecast] = []
|
||||||
|
for forecast_entry in nws_forecast:
|
||||||
|
data: ExtraForecast = {
|
||||||
|
ATTR_FORECAST_TIME: cast(str, forecast_entry.get("startTime")),
|
||||||
|
}
|
||||||
|
if mode == DAYNIGHT:
|
||||||
|
data[ATTR_FORECAST_IS_DAYTIME] = forecast_entry.get("isDaytime")
|
||||||
|
|
||||||
|
data[ATTR_FORECAST_DETAILED_DESCRIPTION] = forecast_entry.get(
|
||||||
|
"detailedForecast"
|
||||||
|
)
|
||||||
|
|
||||||
|
data[ATTR_FORECAST_SHORT_DESCRIPTION] = forecast_entry.get("shortForecast")
|
||||||
|
forecast.append(data)
|
||||||
|
return forecast
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _async_forecast_hourly(self) -> list[Forecast] | None:
|
def _async_forecast_hourly(self) -> list[Forecast] | None:
|
||||||
"""Return the hourly forecast in native units."""
|
"""Return the hourly forecast in native units."""
|
||||||
@ -293,3 +337,13 @@ class NWSWeather(CoordinatorWeatherEntity[TimestampDataUpdateCoordinator[None]])
|
|||||||
for forecast_type in ("twice_daily", "hourly"):
|
for forecast_type in ("twice_daily", "hourly"):
|
||||||
if (coordinator := self.forecast_coordinators[forecast_type]) is not None:
|
if (coordinator := self.forecast_coordinators[forecast_type]) is not None:
|
||||||
await coordinator.async_request_refresh()
|
await coordinator.async_request_refresh()
|
||||||
|
|
||||||
|
async def async_get_forecasts_extra_service(self, type) -> ServiceResponse:
|
||||||
|
"""Get extra weather forecast."""
|
||||||
|
if type == "hourly":
|
||||||
|
nws_forecast = self._forecast_extra(self.nws.forecast_hourly, HOURLY)
|
||||||
|
else:
|
||||||
|
nws_forecast = self._forecast_extra(self.nws.forecast, DAYNIGHT)
|
||||||
|
return {
|
||||||
|
"forecast": cast(JsonValueType, nws_forecast),
|
||||||
|
}
|
||||||
|
@ -185,6 +185,7 @@ DEFAULT_FORECAST = [
|
|||||||
"temperature": 10,
|
"temperature": 10,
|
||||||
"windSpeedAvg": 10,
|
"windSpeedAvg": 10,
|
||||||
"windBearing": 180,
|
"windBearing": 180,
|
||||||
|
"shortForecast": "A short forecast.",
|
||||||
"detailedForecast": "A detailed forecast.",
|
"detailedForecast": "A detailed forecast.",
|
||||||
"timestamp": "2019-08-12T23:53:00+00:00",
|
"timestamp": "2019-08-12T23:53:00+00:00",
|
||||||
"iconTime": "night",
|
"iconTime": "night",
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
'number': 1,
|
'number': 1,
|
||||||
'probabilityOfPrecipitation': 89,
|
'probabilityOfPrecipitation': 89,
|
||||||
'relativeHumidity': 75,
|
'relativeHumidity': 75,
|
||||||
|
'shortForecast': 'A short forecast.',
|
||||||
'startTime': '2019-08-12T20:00:00-04:00',
|
'startTime': '2019-08-12T20:00:00-04:00',
|
||||||
'temperature': 10,
|
'temperature': 10,
|
||||||
'timestamp': '2019-08-12T23:53:00+00:00',
|
'timestamp': '2019-08-12T23:53:00+00:00',
|
||||||
@ -48,6 +49,7 @@
|
|||||||
'number': 1,
|
'number': 1,
|
||||||
'probabilityOfPrecipitation': 89,
|
'probabilityOfPrecipitation': 89,
|
||||||
'relativeHumidity': 75,
|
'relativeHumidity': 75,
|
||||||
|
'shortForecast': 'A short forecast.',
|
||||||
'startTime': '2019-08-12T20:00:00-04:00',
|
'startTime': '2019-08-12T20:00:00-04:00',
|
||||||
'temperature': 10,
|
'temperature': 10,
|
||||||
'timestamp': '2019-08-12T23:53:00+00:00',
|
'timestamp': '2019-08-12T23:53:00+00:00',
|
||||||
|
@ -1,95 +1,44 @@
|
|||||||
# serializer version: 1
|
# serializer version: 1
|
||||||
# name: test_forecast_service[get_forecast]
|
# name: test_detailed_forecast_service[hourly]
|
||||||
dict({
|
dict({
|
||||||
'forecast': list([
|
'weather.abc': dict({
|
||||||
dict({
|
'forecast': list([
|
||||||
'condition': 'lightning-rainy',
|
dict({
|
||||||
'datetime': '2019-08-12T20:00:00-04:00',
|
'datetime': '2019-08-12T20:00:00-04:00',
|
||||||
'detailed_description': 'A detailed forecast.',
|
'short_description': 'A short forecast.',
|
||||||
'dew_point': -15.6,
|
}),
|
||||||
'humidity': 75,
|
]),
|
||||||
'is_daytime': False,
|
}),
|
||||||
'precipitation_probability': 89,
|
|
||||||
'temperature': -12.2,
|
|
||||||
'wind_bearing': 180,
|
|
||||||
'wind_speed': 16.09,
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
# name: test_forecast_service[get_forecast].1
|
# name: test_detailed_forecast_service[twice_daily]
|
||||||
dict({
|
dict({
|
||||||
'forecast': list([
|
'weather.abc': dict({
|
||||||
dict({
|
'forecast': list([
|
||||||
'condition': 'lightning-rainy',
|
dict({
|
||||||
'datetime': '2019-08-12T20:00:00-04:00',
|
'datetime': '2019-08-12T20:00:00-04:00',
|
||||||
'detailed_description': 'A detailed forecast.',
|
'detailed_description': 'A detailed forecast.',
|
||||||
'dew_point': -15.6,
|
'is_daytime': False,
|
||||||
'humidity': 75,
|
'short_description': 'A short forecast.',
|
||||||
'precipitation_probability': 89,
|
}),
|
||||||
'temperature': -12.2,
|
]),
|
||||||
'wind_bearing': 180,
|
}),
|
||||||
'wind_speed': 16.09,
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
# name: test_forecast_service[get_forecast].2
|
# name: test_detailed_forecast_service_no_data[hourly]
|
||||||
dict({
|
dict({
|
||||||
'forecast': list([
|
'weather.abc': dict({
|
||||||
dict({
|
'forecast': list([
|
||||||
'condition': 'lightning-rainy',
|
]),
|
||||||
'datetime': '2019-08-12T20:00:00-04:00',
|
}),
|
||||||
'detailed_description': 'A detailed forecast.',
|
|
||||||
'dew_point': -15.6,
|
|
||||||
'humidity': 75,
|
|
||||||
'is_daytime': False,
|
|
||||||
'precipitation_probability': 89,
|
|
||||||
'temperature': -12.2,
|
|
||||||
'wind_bearing': 180,
|
|
||||||
'wind_speed': 16.09,
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
# name: test_forecast_service[get_forecast].3
|
# name: test_detailed_forecast_service_no_data[twice_daily]
|
||||||
dict({
|
dict({
|
||||||
'forecast': list([
|
'weather.abc': dict({
|
||||||
dict({
|
'forecast': list([
|
||||||
'condition': 'lightning-rainy',
|
]),
|
||||||
'datetime': '2019-08-12T20:00:00-04:00',
|
}),
|
||||||
'detailed_description': 'A detailed forecast.',
|
|
||||||
'dew_point': -15.6,
|
|
||||||
'humidity': 75,
|
|
||||||
'precipitation_probability': 89,
|
|
||||||
'temperature': -12.2,
|
|
||||||
'wind_bearing': 180,
|
|
||||||
'wind_speed': 16.09,
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
})
|
|
||||||
# ---
|
|
||||||
# name: test_forecast_service[get_forecast].4
|
|
||||||
dict({
|
|
||||||
'forecast': list([
|
|
||||||
dict({
|
|
||||||
'condition': 'lightning-rainy',
|
|
||||||
'datetime': '2019-08-12T20:00:00-04:00',
|
|
||||||
'detailed_description': 'A detailed forecast.',
|
|
||||||
'dew_point': -15.6,
|
|
||||||
'humidity': 75,
|
|
||||||
'precipitation_probability': 89,
|
|
||||||
'temperature': -12.2,
|
|
||||||
'wind_bearing': 180,
|
|
||||||
'wind_speed': 16.09,
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
})
|
|
||||||
# ---
|
|
||||||
# name: test_forecast_service[get_forecast].5
|
|
||||||
dict({
|
|
||||||
'forecast': list([
|
|
||||||
]),
|
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
# name: test_forecast_service[get_forecasts]
|
# name: test_forecast_service[get_forecasts]
|
||||||
@ -99,7 +48,6 @@
|
|||||||
dict({
|
dict({
|
||||||
'condition': 'lightning-rainy',
|
'condition': 'lightning-rainy',
|
||||||
'datetime': '2019-08-12T20:00:00-04:00',
|
'datetime': '2019-08-12T20:00:00-04:00',
|
||||||
'detailed_description': 'A detailed forecast.',
|
|
||||||
'dew_point': -15.6,
|
'dew_point': -15.6,
|
||||||
'humidity': 75,
|
'humidity': 75,
|
||||||
'is_daytime': False,
|
'is_daytime': False,
|
||||||
@ -119,7 +67,6 @@
|
|||||||
dict({
|
dict({
|
||||||
'condition': 'lightning-rainy',
|
'condition': 'lightning-rainy',
|
||||||
'datetime': '2019-08-12T20:00:00-04:00',
|
'datetime': '2019-08-12T20:00:00-04:00',
|
||||||
'detailed_description': 'A detailed forecast.',
|
|
||||||
'dew_point': -15.6,
|
'dew_point': -15.6,
|
||||||
'humidity': 75,
|
'humidity': 75,
|
||||||
'precipitation_probability': 89,
|
'precipitation_probability': 89,
|
||||||
@ -138,7 +85,6 @@
|
|||||||
dict({
|
dict({
|
||||||
'condition': 'lightning-rainy',
|
'condition': 'lightning-rainy',
|
||||||
'datetime': '2019-08-12T20:00:00-04:00',
|
'datetime': '2019-08-12T20:00:00-04:00',
|
||||||
'detailed_description': 'A detailed forecast.',
|
|
||||||
'dew_point': -15.6,
|
'dew_point': -15.6,
|
||||||
'humidity': 75,
|
'humidity': 75,
|
||||||
'is_daytime': False,
|
'is_daytime': False,
|
||||||
@ -158,7 +104,6 @@
|
|||||||
dict({
|
dict({
|
||||||
'condition': 'lightning-rainy',
|
'condition': 'lightning-rainy',
|
||||||
'datetime': '2019-08-12T20:00:00-04:00',
|
'datetime': '2019-08-12T20:00:00-04:00',
|
||||||
'detailed_description': 'A detailed forecast.',
|
|
||||||
'dew_point': -15.6,
|
'dew_point': -15.6,
|
||||||
'humidity': 75,
|
'humidity': 75,
|
||||||
'precipitation_probability': 89,
|
'precipitation_probability': 89,
|
||||||
@ -177,7 +122,6 @@
|
|||||||
dict({
|
dict({
|
||||||
'condition': 'lightning-rainy',
|
'condition': 'lightning-rainy',
|
||||||
'datetime': '2019-08-12T20:00:00-04:00',
|
'datetime': '2019-08-12T20:00:00-04:00',
|
||||||
'detailed_description': 'A detailed forecast.',
|
|
||||||
'dew_point': -15.6,
|
'dew_point': -15.6,
|
||||||
'humidity': 75,
|
'humidity': 75,
|
||||||
'precipitation_probability': 89,
|
'precipitation_probability': 89,
|
||||||
@ -202,7 +146,6 @@
|
|||||||
dict({
|
dict({
|
||||||
'condition': 'lightning-rainy',
|
'condition': 'lightning-rainy',
|
||||||
'datetime': '2019-08-12T20:00:00-04:00',
|
'datetime': '2019-08-12T20:00:00-04:00',
|
||||||
'detailed_description': 'A detailed forecast.',
|
|
||||||
'dew_point': -15.6,
|
'dew_point': -15.6,
|
||||||
'humidity': 75,
|
'humidity': 75,
|
||||||
'precipitation_probability': 89,
|
'precipitation_probability': 89,
|
||||||
@ -217,7 +160,6 @@
|
|||||||
dict({
|
dict({
|
||||||
'condition': 'lightning-rainy',
|
'condition': 'lightning-rainy',
|
||||||
'datetime': '2019-08-12T20:00:00-04:00',
|
'datetime': '2019-08-12T20:00:00-04:00',
|
||||||
'detailed_description': 'A detailed forecast.',
|
|
||||||
'dew_point': -15.6,
|
'dew_point': -15.6,
|
||||||
'humidity': 75,
|
'humidity': 75,
|
||||||
'precipitation_probability': 89,
|
'precipitation_probability': 89,
|
||||||
|
@ -554,3 +554,83 @@ async def test_forecast_subscription_with_failing_coordinator(
|
|||||||
)
|
)
|
||||||
msg = await client.receive_json()
|
msg = await client.receive_json()
|
||||||
assert not msg["success"]
|
assert not msg["success"]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("forecast_type"),
|
||||||
|
[
|
||||||
|
"hourly",
|
||||||
|
"twice_daily",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_detailed_forecast_service(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
freezer: FrozenDateTimeFactory,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
mock_simple_nws,
|
||||||
|
no_sensor,
|
||||||
|
forecast_type: str,
|
||||||
|
) -> None:
|
||||||
|
"""Test detailed forecast."""
|
||||||
|
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=nws.DOMAIN,
|
||||||
|
data=NWS_CONFIG,
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
response = await hass.services.async_call(
|
||||||
|
nws.DOMAIN,
|
||||||
|
"get_forecasts_extra",
|
||||||
|
{
|
||||||
|
"entity_id": "weather.abc",
|
||||||
|
"type": forecast_type,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
return_response=True,
|
||||||
|
)
|
||||||
|
assert response == snapshot
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("forecast_type"),
|
||||||
|
[
|
||||||
|
"hourly",
|
||||||
|
"twice_daily",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_detailed_forecast_service_no_data(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
freezer: FrozenDateTimeFactory,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
mock_simple_nws,
|
||||||
|
no_sensor,
|
||||||
|
forecast_type: str,
|
||||||
|
) -> None:
|
||||||
|
"""Test detailed forecast."""
|
||||||
|
instance = mock_simple_nws.return_value
|
||||||
|
instance.forecast = None
|
||||||
|
instance.forecast_hourly = None
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=nws.DOMAIN,
|
||||||
|
data=NWS_CONFIG,
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
response = await hass.services.async_call(
|
||||||
|
nws.DOMAIN,
|
||||||
|
"get_forecasts_extra",
|
||||||
|
{
|
||||||
|
"entity_id": "weather.abc",
|
||||||
|
"type": forecast_type,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
return_response=True,
|
||||||
|
)
|
||||||
|
assert response == snapshot
|
||||||
|
Loading…
x
Reference in New Issue
Block a user